From a4e98df35f16087a32b1f4326b91d27572eec60a Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Fri, 19 Feb 2016 13:44:46 -0500 Subject: [PATCH 001/183] adding compiing support for HDF5 --- code/Makefile | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/code/Makefile b/code/Makefile index a9054310d..c539cc31e 100644 --- a/code/Makefile +++ b/code/Makefile @@ -16,7 +16,7 @@ SHELL = /bin/sh # SUFFIX = arbitrary suffix (after file to compile) # STANDARD_CHECK = checking for Fortran 2008, compiler dependend ######################################################################################## -# including PETSc files. PETSC_ARCH is loaded from these files. +# including PETSc files. PETSC_ARCH is loaded from these files. DAMASKVERSION :=$(shell cat ../VERSION) include ${PETSC_DIR}/lib/petsc/conf/variables @@ -27,6 +27,17 @@ LIBRARIES := $(PETSC_WITH_EXTERNAL_LIB) COMPILERNAME ?= $(FC) LINKERNAME ?= $(FLINKER) +# +# setting up for HDF5 support (hard link for now) +# 1. Location of HDF5 binaries (with include/ and lib/ underneath) +HDF5 = /mnt/research/CMM/opt/hdf5-1.8.16 +# 2. Location of External Libraries (missing in the 1.8.12 version) +LIBZ = $(HDF5)/lib/libz.a +LIBSZ = $(HDF5)/lib/libsz.a +# 3. Set libraries for HDF5 (LIBS: shared lib, LIBZ: external lib) +HDFLIBS = -I$(HDF5)/include $(HDF5)/lib/libhdf5_fortran.a $(HDF5)/lib/libhdf5.a +HDFLIBZ = $(LIBZ) $(LIBSZ) -lm + # MPI compiler wrappers will tell if they are pointing to ifort or gfortran COMPILEROUT :=$(shell $(FC) -show) # search in FC or COMPILEROUT for gfortran/ifort if not defined @@ -331,6 +342,9 @@ HYDROGENFLUX_FILES = \ HOMOGENIZATION_FILES = \ homogenization_RGC.o homogenization_isostrain.o homogenization_none.o +HDF5_FILES = \ + damask_hdf5.o + ##################### # Spectral Solver ##################### @@ -358,12 +372,13 @@ SPECTRAL_FILES = prec.o DAMASK_interface.o IO.o libs.o numerics.o debug.o math.o $(HOMOGENIZATION_FILES) homogenization.o \ CPFEM2.o \ spectral_utilities.o \ + $(HDF5_FILES) \ $(SPECTRAL_SOLVER_FILES) DAMASK_spectral.exe: DAMASK_spectral.o $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ -o DAMASK_spectral.exe DAMASK_spectral.o \ - $(SPECTRAL_FILES) $(LIBRARIES) $(SUFFIX) + $(SPECTRAL_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) DAMASK_spectral.o: DAMASK_spectral.f90 \ @@ -412,7 +427,7 @@ FEM_FILES = prec.o DAMASK_interface.o FEZoo.o IO.o libs.o numerics.o debug. DAMASK_FEM.exe: DAMASK_FEM_driver.o $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ -o DAMASK_FEM.exe DAMASK_FEM_driver.o \ - $(FEM_FILES) $(LIBRARIES) $(SUFFIX) + $(FEM_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) DAMASK_FEM_driver.o: DAMASK_FEM_driver.f90 $(FEM_SOLVER_FILES) $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c ../private/FEM/code/DAMASK_FEM_driver.f90 $(SUFFIX) @@ -649,6 +664,9 @@ prec.o: prec.f90 $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 $(SUFFIX) endif +damask_hdf5.o: damask_hdf5.f90 + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c damask_hdf5.f90 $(HDFLIBS) $(HDFLIBZ) + %.o : %.f90 $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $< $(SUFFIX) From 68a0599ae72a372673a8932babe8858470683bb1 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Fri, 19 Feb 2016 17:13:44 -0500 Subject: [PATCH 002/183] adding the dummy file for HDF5 support development --- code/damask_hdf5.f90 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 code/damask_hdf5.f90 diff --git a/code/damask_hdf5.f90 b/code/damask_hdf5.f90 new file mode 100644 index 000000000..34479f9b3 --- /dev/null +++ b/code/damask_hdf5.f90 @@ -0,0 +1,16 @@ +module HDF5_io + use prec + use IO + use hdf5 + +contains + +subroutine HDF5_init(filename, total_inc, total_time) + integer(pInt), intent(in) :: total_inc + real(pReal), intent(in) :: total_time + + write(6,*) 'pretend to write something' + +end subroutine HDF5_init + +end module HDF5_io \ No newline at end of file From d557c71b47b5013fc5b4521053baae1480db093c Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 22 Feb 2016 11:27:53 -0500 Subject: [PATCH 003/183] trying to use cmake for cross platform build --- CMakeLists.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..e69de29bb From 1edb0fff2cfbfa4fdcea5e00aaf4af215120f0a7 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 23 Feb 2016 16:27:37 -0500 Subject: [PATCH 004/183] set up build system with CMake --- Makefile_bk | 42 + code/DAMASK_marc2011.f90 | 1 + code/DAMASK_marc2012.f90 | 1 + code/DAMASK_marc2013.1.f90 | 1 + code/DAMASK_marc2013.f90 | 1 + code/DAMASK_marc2014.2.f90 | 1 + code/DAMASK_marc2014.f90 | 1 + code/DAMASK_marc2015.f90 | 1 + code/Makefile | 31 +- code/Makefile_bk | 699 +++++++++ code/quit__genmod.f90 | 8 + code/spectral/CMakeLists.txt | 14 + code/spectral/spectral_damage.f90 | 414 ++++++ code/spectral/spectral_interface.f90 | 568 ++++++++ code/spectral/spectral_mech_AL.f90 | 715 ++++++++++ code/spectral/spectral_mech_Basic.f90 | 569 ++++++++ code/spectral/spectral_mech_Polarisation.f90 | 712 ++++++++++ code/spectral/spectral_thermal.f90 | 419 ++++++ code/spectral/spectral_utilities.f90 | 1262 +++++++++++++++++ code/thermal/CMakeLists.txt | 10 + code/thermal/thermal_adiabatic.f90 | 422 ++++++ code/thermal/thermal_conduction.f90 | 444 ++++++ code/thermal/thermal_isothermal.f90 | 65 + code/vacancyflux/CMakeLists.txt | 10 + code/vacancyflux/vacancyflux_cahnhilliard.f90 | 606 ++++++++ code/vacancyflux/vacancyflux_isochempot.f90 | 329 +++++ code/vacancyflux/vacancyflux_isoconc.f90 | 63 + lib/damask/core.so | Bin 0 -> 2117501 bytes lib/damask/corientation.so | Bin 0 -> 2592705 bytes 29 files changed, 7393 insertions(+), 16 deletions(-) create mode 100755 Makefile_bk create mode 120000 code/DAMASK_marc2011.f90 create mode 120000 code/DAMASK_marc2012.f90 create mode 120000 code/DAMASK_marc2013.1.f90 create mode 120000 code/DAMASK_marc2013.f90 create mode 120000 code/DAMASK_marc2014.2.f90 create mode 120000 code/DAMASK_marc2014.f90 create mode 120000 code/DAMASK_marc2015.f90 create mode 100644 code/Makefile_bk create mode 100644 code/quit__genmod.f90 create mode 100644 code/spectral/CMakeLists.txt create mode 100644 code/spectral/spectral_damage.f90 create mode 100644 code/spectral/spectral_interface.f90 create mode 100644 code/spectral/spectral_mech_AL.f90 create mode 100644 code/spectral/spectral_mech_Basic.f90 create mode 100644 code/spectral/spectral_mech_Polarisation.f90 create mode 100644 code/spectral/spectral_thermal.f90 create mode 100644 code/spectral/spectral_utilities.f90 create mode 100644 code/thermal/CMakeLists.txt create mode 100644 code/thermal/thermal_adiabatic.f90 create mode 100644 code/thermal/thermal_conduction.f90 create mode 100644 code/thermal/thermal_isothermal.f90 create mode 100644 code/vacancyflux/CMakeLists.txt create mode 100644 code/vacancyflux/vacancyflux_cahnhilliard.f90 create mode 100644 code/vacancyflux/vacancyflux_isochempot.f90 create mode 100644 code/vacancyflux/vacancyflux_isoconc.f90 create mode 100755 lib/damask/core.so create mode 100755 lib/damask/corientation.so diff --git a/Makefile_bk b/Makefile_bk new file mode 100755 index 000000000..8be738090 --- /dev/null +++ b/Makefile_bk @@ -0,0 +1,42 @@ +SHELL = /bin/sh +######################################################################################## +# Makefile for the installation of DAMASK +######################################################################################## +.PHONY: all +all: spectral marc processing + +.PHONY: spectral +spectral: + $(MAKE) DAMASK_spectral.exe -C code + +.PHONY: FEM +FEM: + $(MAKE) DAMASK_FEM.exe -C code + +.PHONY: marc +marc: + @./installation/mods_MarcMentat/apply_DAMASK_modifications.sh ${MAKEFLAGS} + +.PHONY: processing +processing: + @if hash cython 2>/dev/null; then \ + cd ./lib/damask; \ + CC=gcc python setup_corientation.py build_ext --inplace; \ + rm -rv build; \ + rm *.c; \ + fi + @./installation/compile_CoreModule.py ${MAKEFLAGS} + +.PHONY: tidy +tidy: + @$(MAKE) tidy -C code >/dev/null + +.PHONY: clean +clean: + @$(MAKE) cleanDAMASK -C code >/dev/null + +.PHONY: install +install: + @./installation/symlink_Code.py ${MAKEFLAGS} + @./installation/symlink_Processing.py ${MAKEFLAGS} + diff --git a/code/DAMASK_marc2011.f90 b/code/DAMASK_marc2011.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/code/DAMASK_marc2011.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2012.f90 b/code/DAMASK_marc2012.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/code/DAMASK_marc2012.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2013.1.f90 b/code/DAMASK_marc2013.1.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/code/DAMASK_marc2013.1.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2013.f90 b/code/DAMASK_marc2013.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/code/DAMASK_marc2013.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2014.2.f90 b/code/DAMASK_marc2014.2.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/code/DAMASK_marc2014.2.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2014.f90 b/code/DAMASK_marc2014.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/code/DAMASK_marc2014.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2015.f90 b/code/DAMASK_marc2015.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/code/DAMASK_marc2015.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/code/Makefile b/code/Makefile index c539cc31e..a18cbebac 100644 --- a/code/Makefile +++ b/code/Makefile @@ -30,13 +30,13 @@ LINKERNAME ?= $(FLINKER) # # setting up for HDF5 support (hard link for now) # 1. Location of HDF5 binaries (with include/ and lib/ underneath) -HDF5 = /mnt/research/CMM/opt/hdf5-1.8.16 +HDF5 = /mnt/research/CMM/opt/hdf5 # 2. Location of External Libraries (missing in the 1.8.12 version) -LIBZ = $(HDF5)/lib/libz.a -LIBSZ = $(HDF5)/lib/libsz.a +LIBZ = /mnt/research/CMM/opt/hdf5/lib/libz.a +LIBSZ = /mnt/research/CMM/opt/hdf5/lib/libsz.a # 3. Set libraries for HDF5 (LIBS: shared lib, LIBZ: external lib) -HDFLIBS = -I$(HDF5)/include $(HDF5)/lib/libhdf5_fortran.a $(HDF5)/lib/libhdf5.a -HDFLIBZ = $(LIBZ) $(LIBSZ) -lm +HDFLIBS = -I$(HDF5)/include -L$(HDF5)/lib +HDFLIBZ = -L$(LIBZ) -L$(LIBSZ) # MPI compiler wrappers will tell if they are pointing to ifort or gfortran COMPILEROUT :=$(shell $(FC) -show) @@ -306,8 +306,8 @@ PRECISION_gfortran :=-fdefault-real-8 -fdefault-double-8 -DFLOAT=8 -DINT=4 #-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) ################################################################################################### -COMPILE =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(OPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) -COMPILE_MAXOPTI =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) +COMPILE =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(OPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) +COMPILE_MAXOPTI =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) ################################################################################################### SOURCE_FILES = \ source_thermal_dissipation.o source_thermal_externalheat.o \ @@ -342,9 +342,6 @@ HYDROGENFLUX_FILES = \ HOMOGENIZATION_FILES = \ homogenization_RGC.o homogenization_isostrain.o homogenization_none.o -HDF5_FILES = \ - damask_hdf5.o - ##################### # Spectral Solver ##################### @@ -364,7 +361,7 @@ DAMASK_spectral.o: INTERFACENAME := spectral_interface.f90 SPECTRAL_SOLVER_FILES = spectral_mech_AL.o spectral_mech_Basic.o spectral_mech_Polarisation.o \ spectral_thermal.o spectral_damage.o -SPECTRAL_FILES = prec.o DAMASK_interface.o IO.o libs.o numerics.o debug.o math.o \ +SPECTRAL_FILES = prec.o DAMASK_interface.o IO.o libs.o numerics.o debug.o math.o damask_hdf5.o \ FEsolving.o mesh.o material.o lattice.o \ $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ crystallite.o \ @@ -372,10 +369,10 @@ SPECTRAL_FILES = prec.o DAMASK_interface.o IO.o libs.o numerics.o debug.o math.o $(HOMOGENIZATION_FILES) homogenization.o \ CPFEM2.o \ spectral_utilities.o \ - $(HDF5_FILES) \ $(SPECTRAL_SOLVER_FILES) -DAMASK_spectral.exe: DAMASK_spectral.o +DAMASK_spectral.exe: DAMASK_spectral.o \ + $(SPECTRAL_FILES) $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ -o DAMASK_spectral.exe DAMASK_spectral.o \ $(SPECTRAL_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) @@ -662,10 +659,12 @@ DAMASK_interface.o: spectral_interface.f90 \ # -diag-disable 7410 should disable warning about directory statement in inquire function, but does not work. hence the other 2 statements prec.o: prec.f90 $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 $(SUFFIX) -endif -damask_hdf5.o: damask_hdf5.f90 - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c damask_hdf5.f90 $(HDFLIBS) $(HDFLIBZ) +damask_hdf5.o: damask_hdf5.f90 \ + prec.o \ + IO.o + $(PREFIX) $(COMPILERNAME) $(HDFLIBS) $(HDFLIBZ) -c damask_hdf5.f90 $(SUFFIX) -lm +endif %.o : %.f90 $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $< $(SUFFIX) diff --git a/code/Makefile_bk b/code/Makefile_bk new file mode 100644 index 000000000..a18cbebac --- /dev/null +++ b/code/Makefile_bk @@ -0,0 +1,699 @@ +SHELL = /bin/sh +######################################################################################## +# Makefile to compile the Material subroutine for BVP solution using spectral method +######################################################################################## +# Be sure to remove all files compiled with different options by using "make clean" +######################################################################################## +# OPTIONS = standard (alternative): meaning +#------------------------------------------------------------- +# F90 = ifort (gfortran): compiler type, choose Intel or GNU +# COMPILERNAME = name of the compiler executable (if not the same as the ype), e.g. using mpich-g90 instead of ifort +# PORTABLE = TRUE (FALSE): decision, if executable is optimized for the machine on which it was built. +# OPTIMIZATION = DEFENSIVE (OFF,AGGRESSIVE,ULTRA): Optimization mode: O2, O0, O3 + further options for most files, O3 + further options for all files +# OPENMP = TRUE (FALSE): OpenMP multiprocessor support +# PREFIX = arbitrary prefix (before compilername) +# OPTION = arbitrary option (just before file to compile) +# SUFFIX = arbitrary suffix (after file to compile) +# STANDARD_CHECK = checking for Fortran 2008, compiler dependend +######################################################################################## +# including PETSc files. PETSC_ARCH is loaded from these files. +DAMASKVERSION :=$(shell cat ../VERSION) + +include ${PETSC_DIR}/lib/petsc/conf/variables +include ${PETSC_DIR}/lib/petsc/conf/rules + +INCLUDE_DIRS := $(PETSC_FC_INCLUDES) -DPETSc -I../lib +LIBRARIES := $(PETSC_WITH_EXTERNAL_LIB) +COMPILERNAME ?= $(FC) +LINKERNAME ?= $(FLINKER) + +# +# setting up for HDF5 support (hard link for now) +# 1. Location of HDF5 binaries (with include/ and lib/ underneath) +HDF5 = /mnt/research/CMM/opt/hdf5 +# 2. Location of External Libraries (missing in the 1.8.12 version) +LIBZ = /mnt/research/CMM/opt/hdf5/lib/libz.a +LIBSZ = /mnt/research/CMM/opt/hdf5/lib/libsz.a +# 3. Set libraries for HDF5 (LIBS: shared lib, LIBZ: external lib) +HDFLIBS = -I$(HDF5)/include -L$(HDF5)/lib +HDFLIBZ = -L$(LIBZ) -L$(LIBSZ) + +# MPI compiler wrappers will tell if they are pointing to ifort or gfortran +COMPILEROUT :=$(shell $(FC) -show) +# search in FC or COMPILEROUT for gfortran/ifort if not defined +ifeq ($(strip $(F90)),) + F90 :=$(findstring gfortran,$(FC) $(COMPILEROUT)) +endif +ifeq ($(strip $(F90)),) + F90 :=$(findstring ifort,$(FC) $(COMPILEROUT)) +endif + +OPENMP ?= ON +OPTIMIZATION ?= DEFENSIVE + +ifeq "$(OPTIMIZATION)" "OFF" +OPTI := OFF +MAXOPTI := OFF +endif +ifeq "$(OPTIMIZATION)" "DEFENSIVE" +OPTI := DEFENSIVE +MAXOPTI := DEFENSIVE +endif +ifeq "$(OPTIMIZATION)" "AGGRESSIVE" +OPTI := AGGRESSIVE +MAXOPTI := DEFENSIVE +endif +ifeq "$(OPTIMIZATION)" "ULTRA" +OPTI := AGGRESSIVE +MAXOPTI := AGGRESSIVE +endif + +ifndef OPTI +OPTI := DEFENSIVE +MAXOPTI := DEFENSIVE +endif + +# settings for shared memory multicore support +ifeq "$(OPENMP)" "ON" +OPENMP_FLAG_ifort =-openmp -openmp-report0 -parallel +OPENMP_FLAG_gfortran =-fopenmp +endif + +ifdef STANDARD_CHECK +STANDARD_CHECK_ifort =$(STANDARD_CHECK) +STANDARD_CHECK_gfortran =$(STANDARD_CHECK) +endif + +STANDARD_CHECK_ifort ?=-stand f08 -standard-semantics +STANDARD_CHECK_gfortran ?=-std=f2008ts -pedantic-errors + +#-pedantic: more strict on standard, enables some warnings +# -pedantic-errors: like pedantic, but errors instead of warnings +OPTIMIZATION_OFF_ifort :=-O0 -no-ip +OPTIMIZATION_OFF_gfortran :=-O0 +OPTIMIZATION_DEFENSIVE_ifort :=-O2 +OPTIMIZATION_DEFENSIVE_gfortran :=-O2 +OPTIMIZATION_AGGRESSIVE_ifort :=-ipo -O3 -no-prec-div -fp-model fast=2 -xHost #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost +OPTIMIZATION_AGGRESSIVE_gfortran :=-O3 -ffast-math -funroll-loops -ftree-vectorize + + +LINK_OPTIONS_ifort :=-shared-intel +COMPILE_OPTIONS_ifort :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ + -fpp\ + -ftz\ + -assume byterecl,fpe_summary\ + -diag-disable 5268\ + -warn declarations\ + -warn general\ + -warn usage\ + -warn interfaces\ + -warn ignore_loc\ + -warn alignments\ + -warn unused + +################################################################################################### +#COMPILE SWITCHES +#-shared-intel: Link against shared Intel libraries instead of static ones +#-fpp: preprocessor +#-ftz: flush unterflow to zero, automatically set if O<0,1,2,3> >0 +#-assume byterecl record length is given in bytes (also set by -standard-semantics) +# fpe_summary print list of floating point exceptions occured during execution +#-fimplicit-none: assume "implicit-none" even if not present in source +#-diag-disable: disables warnings, where +# warning ID 5268: the text exceeds right hand column allowed on the line (we have only comments there) +#-warn: enables warnings, where +# declarations: any undeclared names (alternative name: -implicitnone) +# general: warning messages and informational messages are issued by the compiler +# usage: questionable programming practices +# interfaces: checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks +# ignore_loc: %LOC is stripped from an actual argument +# alignments: data that is not naturally aligned +# unused: declared variables that are never used +# stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) +# +################################################################################################### +#MORE OPTIONS FOR DEBUGGING DURING COMPILATION +#-warn: enables warnings, where +# truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) +# uncalled: Determines whether warnings occur when a statement function is never called +# all: +# -name as_is: case sensitive Fortran! + +DEBUG_OPTIONS_ifort :=-g\ + -traceback\ + -gen-interfaces\ + -fp-stack-check\ + -fp-model strict\ + -check bounds,format,output_conversion,pointers,uninit\ + -ftrapuv\ + -fpe-all0\ + -warn errors\ + -warn stderrors\ + -debug-parameters all + +################################################################################################### +#COMPILE SWITCHES FOR RUNTIME DEBUGGING +#-g: Generate symbolic debugging information in the object file +#-traceback: Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. +#-gen-interfaces: Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ +#-fp-stack-check: Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. +#-ftrapuv Trap uninitalized variables +#-check: checks at runtime, where +# bounds: check if an array index is too small (<1) or too large! +# format: Checking for the data type of an item being formatted for output. +# output_conversion: Checking for the fit of data items within a designated format descriptor field. +# pointers: Checking for certain disassociated or uninitialized pointers or unallocated allocatable objects. +# uninit: Checking for uninitialized variables. +#-fpe-all0 capture all floating-point exceptions, sets -ftz automatically +#-warn: enables warnings, where +# errors: warnings are changed to errors +# stderrors: warnings about Fortran standard violations are changed to errors +# information on http://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors/ +################################################################################################### +#MORE OPTIONS FOR RUNTIME DEBUGGING +#-heap-arrays: should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits +#-check: checks at runtime, where +# arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) +# stack: +LINK_OPTIONS_gfortran :=-Wl,-undefined,dynamic_lookup +COMPILE_OPTIONS_gfortran :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ + -xf95-cpp-input\ + -ffree-line-length-132\ + -fimplicit-none\ + -fmodule-private\ + -Wall\ + -Wextra\ + -Wcharacter-truncation\ + -Wunderflow\ + -Wsuggest-attribute=pure\ + -Wsuggest-attribute=noreturn\ + -Wconversion-extra\ + -Wimplicit-procedure\ + -Wno-unused-parameter +#-ffpe-summary=all only for newer gfortran +################################################################################################### +#COMPILE SWITCHES +#-shared +#-Wl,-undefined,dynamic_lookup:ensure to link against dynamic libraries +#-xf95-cpp-input: preprocessor +#-ffree-line-length-132: restrict line length to the standard 132 characters +#-ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) +#-fimplicit-none: assume "implicit-none" even if not present in source +#-fmodule-private: assume "private" even if not present in source +#-Wcharacter-truncation: warn if character expressions (strings) are truncated +#-Wunderflow: produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation +#-Wsuggest-attribute=pure: +#-Wsuggest-attribute=noreturn: +#-Wconversion-extra +#-Wimplicit-procedure +#-Wall: sets the following Fortran options: +# -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. +# -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line +# -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime +# -Wconversion: warn about implicit conversions between different type +# -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. +# -Wc-binding-type: +# -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error +# -Wno-tabs: do not allow tabs in source +# -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic +# -Wline-truncation: +# -Wtarget-lifetime: +# -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter +# -Wunused: a number of unused-xxx warnings +# these are general (non -Fortran options) implied by -Wall +# -Waddress +# -Warray-bounds (only with -O2) +# -Wc++11-compat +# -Wchar-subscripts +# -Wcomment +# -Wformat +# -Wmaybe-uninitialized +# -Wnonnull +# -Wparentheses +# -Wpointer-sign +# -Wreorder +# -Wreturn-type +# -Wsequence-point +# -Wstrict-aliasing +# -Wstrict-overflow=1 +# -Wswitch +# -Wtrigraphs +# -Wuninitialized +# -Wunknown-pragmas +# -Wunused-function +# -Wunused-label +# -Wunused-value +# -Wunused-variable +# -Wvolatile-register-var +#-Wextra: sets the following Fortran options: +# -Wunuses-parameter: +# -Wcompare-reals: +# these are general (non -Fortran options) implied by -Wextra +# -Wclobbered +# -Wempty-body +# -Wignored-qualifiers +# -Wmissing-field-initializers +# -Woverride-init +# -Wsign-compare +# -Wtype-limits +# -Wuninitialized +# -Wunused-but-set-parameter (only with -Wunused or -Wall) +# -Wno-globals + +################################################################################################### +#MORE OPTIONS FOR DEBUGGING DURING COMPILATION +#-Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): +#-Wimplicit-interface: no interfaces for lapack routines +#-Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. +#-Wstrict-overflow: + +DEBUG_OPTIONS_gfortran :=-g\ + -fbacktrace\ + -fdump-core\ + -fcheck=all\ + -ffpe-trap=invalid,zero,overflow + +################################################################################################### +#COMPILE SWITCHES FOR RUNTIME DEBUGGING +#-ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) +# zero,\ +# overflow +#-fcheck=all: sets the following Fortran options: +#array-temps +#bounds +#do +#mem +#pointer +#recursion +################################################################################################### +#MORE OPTIONS FOR RUNTIME DEBUGGING +#-ffpe-trap=precision,\ +# denormal, \ +# underflow + +ifeq "$(DEBUG)" "ON" +COMPILE_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) +LINK_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) +endif +LINK_OPTIONS_$(F90) += $(OPTIMIZATION_$(MAXOPTI)_$(F90)) + +PRECISION_ifort :=-real-size 64 -integer-size 32 -DFLOAT=8 -DINT=4 +#-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) +#-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) +PRECISION_gfortran :=-fdefault-real-8 -fdefault-double-8 -DFLOAT=8 -DINT=4 +#-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set +#-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used +#-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) + +################################################################################################### +COMPILE =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(OPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) +COMPILE_MAXOPTI =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) +################################################################################################### +SOURCE_FILES = \ + source_thermal_dissipation.o source_thermal_externalheat.o \ + source_damage_isoBrittle.o source_damage_isoDuctile.o source_damage_anisoBrittle.o source_damage_anisoDuctile.o \ + source_vacancy_phenoplasticity.o source_vacancy_irradiation.o source_vacancy_thermalfluc.o + +KINEMATICS_FILES = \ + kinematics_cleavage_opening.o kinematics_slipplane_opening.o \ + kinematics_thermal_expansion.o \ + kinematics_vacancy_strain.o kinematics_hydrogen_strain.o + +PLASTIC_FILES = \ + plastic_dislotwin.o plastic_disloUCLA.o plastic_isotropic.o plastic_j2.o \ + plastic_phenopowerlaw.o plastic_titanmod.o plastic_nonlocal.o plastic_none.o \ + plastic_phenoplus.o + +THERMAL_FILES = \ + thermal_isothermal.o thermal_adiabatic.o thermal_conduction.o + +DAMAGE_FILES = \ + damage_none.o damage_local.o damage_nonlocal.o + +VACANCYFLUX_FILES = \ + vacancyflux_isoconc.o vacancyflux_isochempot.o vacancyflux_cahnhilliard.o + +POROSITY_FILES = \ + porosity_none.o porosity_phasefield.o + +HYDROGENFLUX_FILES = \ + hydrogenflux_isoconc.o hydrogenflux_cahnhilliard.o + +HOMOGENIZATION_FILES = \ + homogenization_RGC.o homogenization_isostrain.o homogenization_none.o + +##################### +# Spectral Solver +##################### +DAMASK_spectral.exe: IGNORE := \# +DAMASK_spectral.exe: COMPILE += -DSpectral +DAMASK_spectral.exe: COMPILE_MAXOPTI += -DSpectral +DAMASK_spectral.exe: MESHNAME := mesh.f90 +DAMASK_spectral.exe: INTERFACENAME := spectral_interface.f90 + +DAMASK_spectral.o: IGNORE := \# +DAMASK_spectral.o: COMPILE += -DSpectral +DAMASK_spectral.o: COMPILE_MAXOPTI += -DSpectral +DAMASK_spectral.o: MESHNAME := mesh.f90 +DAMASK_spectral.o: INTERFACENAME := spectral_interface.f90 + + +SPECTRAL_SOLVER_FILES = spectral_mech_AL.o spectral_mech_Basic.o spectral_mech_Polarisation.o \ + spectral_thermal.o spectral_damage.o + +SPECTRAL_FILES = prec.o DAMASK_interface.o IO.o libs.o numerics.o debug.o math.o damask_hdf5.o \ + FEsolving.o mesh.o material.o lattice.o \ + $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ + crystallite.o \ + $(THERMAL_FILES) $(DAMAGE_FILES) $(VACANCYFLUX_FILES) $(HYDROGENFLUX_FILES) $(POROSITY_FILES) \ + $(HOMOGENIZATION_FILES) homogenization.o \ + CPFEM2.o \ + spectral_utilities.o \ + $(SPECTRAL_SOLVER_FILES) + +DAMASK_spectral.exe: DAMASK_spectral.o \ + $(SPECTRAL_FILES) + $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ + -o DAMASK_spectral.exe DAMASK_spectral.o \ + $(SPECTRAL_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) + + +DAMASK_spectral.o: DAMASK_spectral.f90 \ + $(SPECTRAL_SOLVER_FILES) + $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c DAMASK_spectral.f90 $(SUFFIX) + +spectral_mech_AL.o: spectral_mech_AL.f90 \ + spectral_utilities.o + +spectral_mech_Polarisation.o: spectral_mech_Polarisation.f90 \ + spectral_utilities.o + +spectral_mech_Basic.o: spectral_mech_Basic.f90 \ + spectral_utilities.o + +spectral_thermal.o: spectral_thermal.f90 \ + spectral_utilities.o + +spectral_damage.o: spectral_damage.f90 \ + spectral_utilities.o + +spectral_utilities.o: spectral_utilities.f90 \ + CPFEM2.o + +##################### +# FEM Solver +##################### +VPATH := ../private/FEM/code +DAMASK_FEM.exe: COMPILE += -DFEM +DAMASK_FEM.exe: COMPILE_MAXOPTI += -DFEM +DAMASK_FEM.exe: MESHNAME := ../private/FEM/code/meshFEM.f90 +DAMASK_FEM.exe: INTERFACENAME := ../private/FEM/code/DAMASK_FEM_interface.f90 +DAMASK_FEM.exe: INCLUDE_DIRS += -I./ + +FEM_SOLVER_FILES = FEM_mech.o FEM_thermal.o FEM_damage.o FEM_vacancyflux.o FEM_porosity.o FEM_hydrogenflux.o + +FEM_FILES = prec.o DAMASK_interface.o FEZoo.o IO.o libs.o numerics.o debug.o math.o \ + FEsolving.o mesh.o material.o lattice.o \ + $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ + crystallite.o \ + $(THERMAL_FILES) $(DAMAGE_FILES) $(VACANCYFLUX_FILES) $(HYDROGENFLUX_FILES) $(POROSITY_FILES) \ + $(HOMOGENIZATION_FILES) homogenization.o \ + CPFEM.o \ + FEM_utilities.o $(FEM_SOLVER_FILES) + +DAMASK_FEM.exe: DAMASK_FEM_driver.o + $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ + -o DAMASK_FEM.exe DAMASK_FEM_driver.o \ + $(FEM_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) + +DAMASK_FEM_driver.o: DAMASK_FEM_driver.f90 $(FEM_SOLVER_FILES) + $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c ../private/FEM/code/DAMASK_FEM_driver.f90 $(SUFFIX) + +FEM_mech.o: FEM_mech.f90 \ + FEM_utilities.o + +FEM_thermal.o: FEM_thermal.f90 \ + FEM_utilities.o + +FEM_damage.o: FEM_damage.f90 \ + FEM_utilities.o + +FEM_vacancyflux.o: FEM_vacancyflux.f90 \ + FEM_utilities.o + +FEM_porosity.o: FEM_porosity.f90 \ + FEM_utilities.o + +FEM_hydrogenflux.o: FEM_hydrogenflux.f90 \ + FEM_utilities.o + +FEM_utilities.o: FEM_utilities.f90 \ + CPFEM.o + +FEZoo.o: $(wildcard FEZoo.f90) \ + IO.o + $(IGNORE) $(PREFIX) $(COMPILERNAME) $(COMPILE) -c ../private/FEM/code/FEZoo.f90 $(SUFFIX) + touch FEZoo.o + +CPFEM.o: CPFEM.f90 \ + homogenization.o + +CPFEM2.o: CPFEM2.f90 \ + homogenization.o + +homogenization.o: homogenization.f90 \ + $(THERMAL_FILES) \ + $(DAMAGE_FILES) \ + $(VACANCYFLUX_FILES) \ + $(POROSITY_FILES) \ + $(HYDROGENFLUX_FILES) \ + $(HOMOGENIZATION_FILES) + +thermal_isothermal.o: thermal_isothermal.f90 \ + crystallite.o + +thermal_adiabatic.o: thermal_adiabatic.f90 \ + crystallite.o + +thermal_conduction.o: thermal_conduction.f90 \ + crystallite.o + +damage_none.o: damage_none.f90 \ + crystallite.o + +damage_local.o: damage_local.f90 \ + crystallite.o + +damage_nonlocal.o: damage_nonlocal.f90 \ + crystallite.o + +thermal_conduction.o: thermal_conduction.f90 \ + crystallite.o + +vacancyflux_isoconc.o: vacancyflux_isoconc.f90 \ + crystallite.o + +vacancyflux_isochempot.o: vacancyflux_isochempot.f90 \ + crystallite.o + +vacancyflux_cahnhilliard.o: vacancyflux_cahnhilliard.f90 \ + crystallite.o + +porosity_none.o: porosity_none.f90 \ + crystallite.o + +porosity_phasefield.o: porosity_phasefield.f90 \ + crystallite.o + +hydrogenflux_isoconc.o: hydrogenflux_isoconc.f90 \ + crystallite.o + +hydrogenflux_cahnhilliard.o: hydrogenflux_cahnhilliard.f90 \ + crystallite.o + +homogenization_RGC.o: homogenization_RGC.f90 \ + crystallite.o + +homogenization_isostrain.o: homogenization_isostrain.f90 \ + crystallite.o + +homogenization_none.o: homogenization_none.f90 \ + crystallite.o + +crystallite.o: crystallite.f90 \ + constitutive.o + +constitutive.o: constitutive.f90 \ + $(SOURCE_FILES) \ + $(KINEMATICS_FILES) \ + $(PLASTIC_FILES) + +source_thermal_dissipation.o: source_thermal_dissipation.f90 \ + lattice.o + +source_thermal_externalheat.o: source_thermal_externalheat.f90 \ + lattice.o + +source_damage_isoBrittle.o: source_damage_isoBrittle.f90 \ + lattice.o + +source_damage_isoDuctile.o: source_damage_isoDuctile.f90 \ + lattice.o + +source_damage_anisoBrittle.o: source_damage_anisoBrittle.f90 \ + lattice.o + +source_damage_anisoDuctile.o: source_damage_anisoDuctile.f90 \ + lattice.o + +source_vacancy_phenoplasticity.o: source_vacancy_phenoplasticity.f90 \ + lattice.o + +source_vacancy_irradiation.o: source_vacancy_irradiation.f90 \ + lattice.o + +source_vacancy_thermalfluc.o: source_vacancy_thermalfluc.f90 \ + lattice.o + +kinematics_cleavage_opening.o: kinematics_cleavage_opening.f90 \ + lattice.o + +kinematics_slipplane_opening.o: kinematics_slipplane_opening.f90 \ + lattice.o + +kinematics_thermal_expansion.o: kinematics_thermal_expansion.f90 \ + lattice.o + +kinematics_vacancy_strain.o: kinematics_vacancy_strain.f90 \ + lattice.o + +kinematics_hydrogen_strain.o: kinematics_hydrogen_strain.f90 \ + lattice.o + +plastic_nonlocal.o: plastic_nonlocal.f90 \ + lattice.o + +plastic_titanmod.o: plastic_titanmod.f90 \ + lattice.o + +plastic_disloUCLA.o: plastic_disloUCLA.f90 \ + lattice.o + +plastic_dislotwin.o: plastic_dislotwin.f90 \ + lattice.o + +plastic_phenopowerlaw.o: plastic_phenopowerlaw.f90 \ + lattice.o + +plastic_phenoplus.o: plastic_phenoplus.f90 \ + lattice.o + +plastic_isotropic.o: plastic_isotropic.f90 \ + lattice.o + +plastic_j2.o: plastic_j2.f90 \ + lattice.o + +plastic_none.o: plastic_none.f90 \ + lattice.o +ifeq "$(F90)" "gfortran" +lattice.o: lattice.f90 \ + material.o + $(PREFIX) $(COMPILERNAME) $(COMPILE) -ffree-line-length-240 -c lattice.f90 $(SUFFIX) +# long lines for interaction matrix +else +lattice.o: lattice.f90 \ + material.o +endif + +material.o: material.f90 \ + mesh.o + +mesh.o: mesh.f90 \ + $(wildcard meshFEM.f90) \ + FEsolving.o \ + math.o \ + FEZoo.o + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(MESHNAME) -o mesh.o $(SUFFIX) + +FEsolving.o: FEsolving.f90 \ + debug.o + +math.o: math.f90 \ + debug.o + +debug.o: debug.f90 \ + numerics.o + +numerics.o: numerics.f90 \ + libs.o + +libs.o: libs.f90 \ + IO.o + +IO.o: IO.f90 \ + DAMASK_interface.o + +ifeq "$(F90)" "gfortran" +DAMASK_interface.o: spectral_interface.f90 \ + $(wildcard DAMASK_FEM_interface.f90) \ + prec.o + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -fall-intrinsics -o DAMASK_interface.o $(SUFFIX) +#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored +# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external +# --> allows the use of 'getcwd' +prec.o: prec.f90 + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 -fno-range-check -fall-intrinsics -fno-fast-math $(SUFFIX) +# fno-range-check: Disable range checking on results of simplification of constant expressions during compilation +# --> allows the definition of DAMASK_NaN +#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored +# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external +# --> allows the use of 'isnan' +#-fno-fast-math: +# --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) +else +DAMASK_interface.o: spectral_interface.f90 \ + $(wildcard DAMASK_FEM_interface.f90) \ + prec.o + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -diag-remark 7410 -stand none -warn nostderrors -o DAMASK_interface.o $(SUFFIX) +# -diag-disable 7410 should disable warning about directory statement in inquire function, but does not work. hence the other 2 statements +prec.o: prec.f90 + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 $(SUFFIX) + +damask_hdf5.o: damask_hdf5.f90 \ + prec.o \ + IO.o + $(PREFIX) $(COMPILERNAME) $(HDFLIBS) $(HDFLIBZ) -c damask_hdf5.f90 $(SUFFIX) -lm +endif + +%.o : %.f90 + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $< $(SUFFIX) + +.PHONY: tidy +tidy: + @rm -rf *.o + @rm -rf *.mod + @rm -rf *.inst.f90 # for instrumentation + @rm -rf *.pomp.f90 # for instrumentation + @rm -rf *.pp.f90 # for instrumentation + @rm -rf *.pdb # for instrumnentation + @rm -rf *.opari.inc # for instrumnentation + +.PHONY: cleanDAMASK +cleanDAMASK: + @rm -rf *.exe + @rm -rf *.marc + @rm -rf *.o + @rm -rf *.mod + @rm -rf *.inst.f90 # for instrumentation + @rm -rf *.pomp.f90 # for instrumentation + @rm -rf *.pp.f90 # for instrumentation + @rm -rf *.pdb # for instrumentation + @rm -rf *.opari.inc # for instrumentation + +.PHONY: help +help: + F90="$(F90)" + COMPILERNAME="$(COMPILERNAME)" + COMPILEROUT="$(COMPILEROUT)" + diff --git a/code/quit__genmod.f90 b/code/quit__genmod.f90 new file mode 100644 index 000000000..c6b282470 --- /dev/null +++ b/code/quit__genmod.f90 @@ -0,0 +1,8 @@ + !COMPILER-GENERATED INTERFACE MODULE: Tue Feb 23 16:12:31 2016 + MODULE QUIT__genmod + INTERFACE + SUBROUTINE QUIT(STOP_ID) + INTEGER(KIND=4), INTENT(IN) :: STOP_ID + END SUBROUTINE QUIT + END INTERFACE + END MODULE QUIT__genmod diff --git a/code/spectral/CMakeLists.txt b/code/spectral/CMakeLists.txt new file mode 100644 index 000000000..a11ff1303 --- /dev/null +++ b/code/spectral/CMakeLists.txt @@ -0,0 +1,14 @@ +# group source for sepctral solver driver +set (SPECTRAL "spectral_damage" + "spectral_interface" + "spectral_mech_AL" + "spectral_mech_Basic" + "spectral_mech_Polarisation" + "spectral_thermal" + "spectral_utilities" + ) + +# compile spectral solver driver module +foreach (p ${SPECTRAL}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) diff --git a/code/spectral/spectral_damage.f90 b/code/spectral/spectral_damage.f90 new file mode 100644 index 000000000..0b79d5e5d --- /dev/null +++ b/code/spectral/spectral_damage.f90 @@ -0,0 +1,414 @@ +!-------------------------------------------------------------------------------------------------- +! $Id: spectral_damage.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Shaokang Zhang, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Spectral solver for nonlocal damage +!-------------------------------------------------------------------------------------------------- +module spectral_damage + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + use numerics, only: & + worldrank, & + worldsize + + implicit none + private +#include + + character (len=*), parameter, public :: & + spectral_damage_label = 'spectraldamage' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + +!-------------------------------------------------------------------------------------------------- +! PETSc data + SNES, private :: damage_snes + Vec, private :: solution + PetscInt, private :: xstart, xend, ystart, yend, zstart, zend + real(pReal), private, dimension(:,:,:), allocatable :: & + damage_current, & !< field of current damage + damage_lastInc, & !< field of previous damage + damage_stagInc !< field of staggered damage + +!-------------------------------------------------------------------------------------------------- +! reference diffusion tensor, mobility etc. + integer(pInt), private :: totalIter = 0_pInt !< total iteration in current increment + real(pReal), dimension(3,3), private :: D_ref + real(pReal), private :: mobility_ref + character(len=1024), private :: incInfo + + public :: & + spectral_damage_init, & + spectral_damage_solution, & + spectral_damage_forward, & + spectral_damage_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use spectral_utilities, only: & + wgt + use mesh, only: & + grid, & + grid3 + use damage_nonlocal, only: & + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility + + implicit none + DM :: damage_grid + Vec :: uBound, lBound + PetscErrorCode :: ierr + PetscObject :: dummy + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + integer(pInt) :: i, j, k, cell + character(len=100) :: snes_type + + mainProcess: if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- spectral_damage init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! initialize solver specific parts of PETSc + call SNESCreate(PETSC_COMM_WORLD,damage_snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(damage_snes,'damage_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & !< cut off stencil at boundary + DMDA_STENCIL_BOX, & !< Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & !< global grid + 1, 1, worldsize, & + 1, 0, & !< #dof (damage phase field), ghost boundary width (domain overlap) + grid(1),grid(2),localK, & !< local grid + damage_grid,ierr) !< handle, error + CHKERRQ(ierr) + call SNESSetDM(damage_snes,damage_grid,ierr); CHKERRQ(ierr) !< connect snes to da + call DMCreateGlobalVector(damage_grid,solution,ierr); CHKERRQ(ierr) !< global solution vector (grid x 1, i.e. every def grad tensor) + call DMDASNESSetFunctionLocal(damage_grid,INSERT_VALUES,spectral_damage_formResidual,dummy,ierr) !< residual vector of same shape as solution vector + CHKERRQ(ierr) + call SNESSetFromOptions(damage_snes,ierr); CHKERRQ(ierr) !< pull it all together with additional cli arguments + call SNESGetType(damage_snes,snes_type,ierr); CHKERRQ(ierr) + if (trim(snes_type) == 'vinewtonrsls' .or. & + trim(snes_type) == 'vinewtonssls') then + call DMGetGlobalVector(damage_grid,lBound,ierr); CHKERRQ(ierr) + call DMGetGlobalVector(damage_grid,uBound,ierr); CHKERRQ(ierr) + call VecSet(lBound,0.0,ierr); CHKERRQ(ierr) + call VecSet(uBound,1.0,ierr); CHKERRQ(ierr) + call SNESVISetVariableBounds(damage_snes,lBound,uBound,ierr) !< variable bounds for variational inequalities like contact mechanics, damage etc. + call DMRestoreGlobalVector(damage_grid,lBound,ierr); CHKERRQ(ierr) + call DMRestoreGlobalVector(damage_grid,uBound,ierr); CHKERRQ(ierr) + endif + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAGetCorners(damage_grid,xstart,ystart,zstart,xend,yend,zend,ierr) + CHKERRQ(ierr) + xend = xstart + xend - 1 + yend = ystart + yend - 1 + zend = zstart + zend - 1 + call VecSet(solution,1.0,ierr); CHKERRQ(ierr) + allocate(damage_current(grid(1),grid(2),grid3), source=1.0_pReal) + allocate(damage_lastInc(grid(1),grid(2),grid3), source=1.0_pReal) + allocate(damage_stagInc(grid(1),grid(2),grid3), source=1.0_pReal) + +!-------------------------------------------------------------------------------------------------- +! damage reference diffusion update + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + D_ref = D_ref + damage_nonlocal_getDiffusion33(1,cell) + mobility_ref = mobility_ref + damage_nonlocal_getMobility(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + +end subroutine spectral_damage_init + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the spectral damage scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function spectral_damage_solution(guess,timeinc,timeinc_old,loadCaseTime) + use numerics, only: & + itmax, & + err_damage_tolAbs, & + err_damage_tolRel + use spectral_utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use mesh, only: & + grid, & + grid3 + use damage_nonlocal, only: & + damage_nonlocal_putNonLocalDamage + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + integer(pInt) :: i, j, k, cell + PetscInt ::position + PetscReal :: minDamage, maxDamage, stagNorm, solnNorm + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + spectral_damage_solution%converged =.false. + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + params%timeinc = timeinc + params%timeincOld = timeinc_old + + call SNESSolve(damage_snes,PETSC_NULL_OBJECT,solution,ierr); CHKERRQ(ierr) + call SNESGetConvergedReason(damage_snes,reason,ierr); CHKERRQ(ierr) + + if (reason < 1) then + spectral_damage_solution%converged = .false. + spectral_damage_solution%iterationsNeeded = itmax + else + spectral_damage_solution%converged = .true. + spectral_damage_solution%iterationsNeeded = totalIter + endif + stagNorm = maxval(abs(damage_current - damage_stagInc)) + solnNorm = maxval(abs(damage_current)) + call MPI_Allreduce(MPI_IN_PLACE,stagNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + call MPI_Allreduce(MPI_IN_PLACE,solnNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + damage_stagInc = damage_current + spectral_damage_solution%stagConverged = stagNorm < err_damage_tolAbs & + .or. stagNorm < err_damage_tolRel*solnNorm + +!-------------------------------------------------------------------------------------------------- +! updating damage state + cell = 0_pInt !< material point = 0 + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt !< material point increase + call damage_nonlocal_putNonLocalDamage(damage_current(i,j,k),1,cell) + enddo; enddo; enddo + + call VecMin(solution,position,minDamage,ierr); CHKERRQ(ierr) + call VecMax(solution,position,maxDamage,ierr); CHKERRQ(ierr) + if (worldrank == 0) then + if (spectral_damage_solution%converged) & + write(6,'(/,a)') ' ... nonlocal damage converged .....................................' + write(6,'(/,a,f8.6,2x,f8.6,2x,f8.6,/)',advance='no') ' Minimum|Maximum|Delta Damage = ',& + minDamage, maxDamage, stagNorm + write(6,'(/,a)') ' ===========================================================================' + flush(6) + endif + +end function spectral_damage_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the spectral damage residual vector +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_formResidual(in,x_scal,f_scal,dummy,ierr) + use numerics, only: & + residualStiffness + use mesh, only: & + grid, & + grid3 + use math, only: & + math_mul33x3 + use spectral_utilities, only: & + scalarField_real, & + vectorField_real, & + utilities_FFTvectorForward, & + utilities_FFTvectorBackward, & + utilities_FFTscalarForward, & + utilities_FFTscalarBackward, & + utilities_fourierGreenConvolution, & + utilities_fourierScalarGradient, & + utilities_fourierVectorDivergence + use damage_nonlocal, only: & + damage_nonlocal_getSourceAndItsTangent,& + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility + + implicit none + DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, dimension( & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, dimension( & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscObject :: dummy + PetscErrorCode :: ierr + integer(pInt) :: i, j, k, cell + real(pReal) :: phiDot, dPhiDot_dPhi, mobility + + damage_current = x_scal +!-------------------------------------------------------------------------------------------------- +! evaluate polarization field + scalarField_real = 0.0_pReal + scalarField_real(1:grid(1),1:grid(2),1:grid3) = damage_current + call utilities_FFTscalarForward() + call utilities_fourierScalarGradient() !< calculate gradient of damage field + call utilities_FFTvectorBackward() + cell = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + vectorField_real(1:3,i,j,k) = math_mul33x3(damage_nonlocal_getDiffusion33(1,cell) - D_ref, & + vectorField_real(1:3,i,j,k)) + enddo; enddo; enddo + call utilities_FFTvectorForward() + call utilities_fourierVectorDivergence() !< calculate damage divergence in fourier field + call utilities_FFTscalarBackward() + cell = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + call damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, damage_current(i,j,k), 1, cell) + mobility = damage_nonlocal_getMobility(1,cell) + scalarField_real(i,j,k) = params%timeinc*scalarField_real(i,j,k) + & + params%timeinc*phiDot + & + mobility*damage_lastInc(i,j,k) - & + mobility*damage_current(i,j,k) + & + mobility_ref*damage_current(i,j,k) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! convolution of damage field with green operator + call utilities_FFTscalarForward() + call utilities_fourierGreenConvolution(D_ref, mobility_ref, params%timeinc) + call utilities_FFTscalarBackward() + where(scalarField_real(1:grid(1),1:grid(2),1:grid3) > damage_lastInc) & + scalarField_real(1:grid(1),1:grid(2),1:grid3) = damage_lastInc + where(scalarField_real(1:grid(1),1:grid(2),1:grid3) < residualStiffness) & + scalarField_real(1:grid(1),1:grid(2),1:grid3) = residualStiffness + +!-------------------------------------------------------------------------------------------------- +! constructing residual + f_scal = scalarField_real(1:grid(1),1:grid(2),1:grid3) - damage_current + +end subroutine spectral_damage_formResidual + +!-------------------------------------------------------------------------------------------------- +!> @brief spectral damage forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_forward(guess,timeinc,timeinc_old,loadCaseTime) + use mesh, only: & + grid, & + grid3 + use spectral_utilities, only: & + cutBack, & + wgt + use damage_nonlocal, only: & + damage_nonlocal_putNonLocalDamage, & + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + PetscErrorCode :: ierr + integer(pInt) :: i, j, k, cell + DM :: dm_local + PetscScalar, dimension(:,:,:), pointer :: x_scal + + if (cutBack) then + damage_current = damage_lastInc + damage_stagInc = damage_lastInc +!-------------------------------------------------------------------------------------------------- +! reverting damage field state + cell = 0_pInt + call SNESGetDM(damage_snes,dm_local,ierr); CHKERRQ(ierr) + call DMDAVecGetArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with + x_scal(xstart:xend,ystart:yend,zstart:zend) = damage_current + call DMDAVecRestoreArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + call damage_nonlocal_putNonLocalDamage(damage_current(i,j,k),1,cell) + enddo; enddo; enddo + else +!-------------------------------------------------------------------------------------------------- +! update rate and forward last inc + damage_lastInc = damage_current + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + D_ref = D_ref + damage_nonlocal_getDiffusion33(1,cell) + mobility_ref = mobility_ref + damage_nonlocal_getMobility(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + endif + + end subroutine spectral_damage_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_destroy() + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution,ierr); CHKERRQ(ierr) + call SNESDestroy(damage_snes,ierr); CHKERRQ(ierr) + +end subroutine spectral_damage_destroy + +end module spectral_damage diff --git a/code/spectral/spectral_interface.f90 b/code/spectral/spectral_interface.f90 new file mode 100644 index 000000000..b24c5f747 --- /dev/null +++ b/code/spectral/spectral_interface.f90 @@ -0,0 +1,568 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Interfacing between the spectral solver and the material subroutines provided +!! by DAMASK +!> @details Interfacing between the spectral solver and the material subroutines provided +!> by DAMASK. Interpretating the command line arguments or, in case of called from f2py, +!> the arguments parsed to the init routine to get load case, geometry file, working +!> directory, etc. +!-------------------------------------------------------------------------------------------------- +module DAMASK_interface + use prec, only: & + pInt + + implicit none + private +#ifdef PETSc +#include +#endif + logical, public, protected :: appendToOutFile = .false. !< Append to existing spectralOut file (in case of restart, not in case of regridding) + integer(pInt), public, protected :: spectralRestartInc = 1_pInt !< Increment at which calculation starts + character(len=1024), public, protected :: & + geometryFile = '', & !< parameter given for geometry file + loadCaseFile = '' !< parameter given for load case file + character(len=1024), private :: workingDirectory !< accessed by getSolverWorkingDirectoryName for compatibility reasons + + public :: & + getSolverWorkingDirectoryName, & + getSolverJobName, & + DAMASK_interface_init + private :: & + storeWorkingDirectory, & + getGeometryFile, & + getLoadCaseFile, & + rectifyPath, & + makeRelativePath, & + getPathSep, & + IIO_stringValue, & + IIO_intValue, & + IIO_lc, & + IIO_stringPos + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief initializes the solver by interpreting the command line arguments. Also writes +!! information on computation to screen +!-------------------------------------------------------------------------------------------------- +subroutine DAMASK_interface_init(loadCaseParameterIn,geometryParameterIn) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + + implicit none + character(len=1024), optional, intent(in) :: & + loadCaseParameterIn, & !< if using the f2py variant, the -l argument of DAMASK_spectral.exe + geometryParameterIn !< if using the f2py variant, the -g argument of DAMASK_spectral.exe + character(len=1024) :: & + commandLine, & !< command line call as string + loadCaseArg ='', & !< -l argument given to DAMASK_spectral.exe + geometryArg ='', & !< -g argument given to DAMASK_spectral.exe + workingDirArg ='', & !< -w argument given to DAMASK_spectral.exe + hostName, & !< name of machine on which DAMASK_spectral.exe is execute (might require export HOSTNAME) + userName, & !< name of user calling DAMASK_spectral.exe + tag + integer :: & + i, & + worldrank = 0 + integer, allocatable, dimension(:) :: & + chunkPos + integer, dimension(8) :: & + dateAndTime ! type default integer +#ifdef PETSc + PetscErrorCode :: ierr +#endif + external :: & + quit,& + MPI_Comm_rank,& + PETScInitialize, & + MPI_abort + +!-------------------------------------------------------------------------------------------------- +! PETSc Init +#ifdef PETSc + call PetscInitialize(PETSC_NULL_CHARACTER,ierr) ! according to PETSc manual, that should be the first line in the code + CHKERRQ(ierr) ! this is a macro definition, it is case sensitive + + open(6, encoding='UTF-8') ! modern fortran compilers (gfortran >4.4, ifort >11 support it) + call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) +#endif + mainProcess: if (worldrank == 0) then + call date_and_time(values = dateAndTime) + write(6,'(/,a)') ' <<<+- DAMASK_spectral -+>>>' + write(6,'(/,a)') ' Version: '//DAMASKVERSION + write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& + dateAndTime(2),'/',& + dateAndTime(1) + write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& + dateAndTime(6),':',& + dateAndTime(7) + write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' +#include "compilation_info.f90" + endif mainProcess + + if ( present(loadcaseParameterIn) .and. present(geometryParameterIn)) then ! both mandatory parameters given in function call + geometryArg = geometryParameterIn + loadcaseArg = loadcaseParameterIn + commandLine = 'n/a' + else if ( .not.( present(loadcaseParameterIn) .and. present(geometryParameterIn))) then ! none parameters given in function call, trying to get them from command line + call get_command(commandLine) + chunkPos = IIO_stringPos(commandLine) + do i = 1, chunkPos(1) + tag = IIO_lc(IIO_stringValue(commandLine,chunkPos,i)) ! extract key + select case(tag) + case ('-h','--help') + mainProcess2: if (worldrank == 0) then + write(6,'(a)') ' #######################################################################' + write(6,'(a)') ' DAMASK_spectral:' + write(6,'(a)') ' The spectral method boundary value problem solver for' + write(6,'(a)') ' the Düsseldorf Advanced Material Simulation Kit' + write(6,'(a,/)')' #######################################################################' + write(6,'(a,/)')' Valid command line switches:' + write(6,'(a)') ' --geom (-g, --geometry)' + write(6,'(a)') ' --load (-l, --loadcase)' + write(6,'(a)') ' --workingdir (-w, --wd, --workingdirectory, -d, --directory)' + write(6,'(a)') ' --restart (-r, --rs)' + write(6,'(a)') ' --regrid (--rg)' + write(6,'(a)') ' --help (-h)' + write(6,'(/,a)')' -----------------------------------------------------------------------' + write(6,'(a)') ' Mandatory arguments:' + write(6,'(/,a)')' --geom PathToGeomFile/NameOfGeom.geom' + write(6,'(a)') ' Specifies the location of the geometry definition file,' + write(6,'(a)') ' if no extension is given, .geom will be appended.' + write(6,'(a)') ' "PathToGeomFile" will be the working directory if not specified' + write(6,'(a)') ' via --workingdir.' + write(6,'(a)') ' Make sure the file "material.config" exists in the working' + write(6,'(a)') ' directory.' + write(6,'(a)') ' For further configuration place "numerics.config"' + write(6,'(a)')' and "numerics.config" in that directory.' + write(6,'(/,a)')' --load PathToLoadFile/NameOfLoadFile.load' + write(6,'(a)') ' Specifies the location of the load case definition file,' + write(6,'(a)') ' if no extension is given, .load will be appended.' + write(6,'(/,a)')' -----------------------------------------------------------------------' + write(6,'(a)') ' Optional arguments:' + write(6,'(/,a)')' --workingdirectory PathToWorkingDirectory' + write(6,'(a)') ' Specifies the working directory and overwrites the default' + write(6,'(a)') ' "PathToGeomFile".' + write(6,'(a)') ' Make sure the file "material.config" exists in the working' + write(6,'(a)') ' directory.' + write(6,'(a)') ' For further configuration place "numerics.config"' + write(6,'(a)')' and "numerics.config" in that directory.' + write(6,'(/,a)')' --restart XX' + write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' + write(6,'(a)') ' calculate total increment No. XX.' + write(6,'(a)') ' Appends to existing results file ' + write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' + write(6,'(a)') ' Works only if the restart information for total increment' + write(6,'(a)') ' No. XX-1 is available in the working directory.' + write(6,'(/,a)')' --regrid XX' + write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' + write(6,'(a)') ' calculate total increment No. XX.' + write(6,'(a)') ' Attention: Overwrites existing results file ' + write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' + write(6,'(a)') ' Works only if the restart information for total increment' + write(6,'(a)') ' No. XX-1 is available in the working directory.' + write(6,'(/,a)')' -----------------------------------------------------------------------' + write(6,'(a)') ' Help:' + write(6,'(/,a)')' --help' + write(6,'(a,/)')' Prints this message and exits' + call quit(0_pInt) ! normal Termination + endif mainProcess2 + case ('-l', '--load', '--loadcase') + loadcaseArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + case ('-g', '--geom', '--geometry') + geometryArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + case ('-w', '-d', '--wd', '--directory', '--workingdir', '--workingdirectory') + workingDirArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + case ('-r', '--rs', '--restart') + spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) + appendToOutFile = .true. + case ('--rg', '--regrid') + spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) + appendToOutFile = .false. + end select + enddo + endif + + if (len(trim(loadcaseArg)) == 0 .or. len(trim(geometryArg)) == 0) then + write(6,'(a)') ' Please specify geometry AND load case (-h for help)' + call quit(1_pInt) + endif + + workingDirectory = storeWorkingDirectory(trim(workingDirArg),trim(geometryArg)) + geometryFile = getGeometryFile(geometryArg) + loadCaseFile = getLoadCaseFile(loadCaseArg) + + call get_environment_variable('HOSTNAME',hostName) + call get_environment_variable('USER',userName) + mainProcess3: if (worldrank == 0) then + write(6,'(a,a)') ' Host name: ', trim(hostName) + write(6,'(a,a)') ' User name: ', trim(userName) + write(6,'(a,a)') ' Path separator: ', getPathSep() + write(6,'(a,a)') ' Command line call: ', trim(commandLine) + if (len(trim(workingDirArg))>0) & + write(6,'(a,a)') ' Working dir argument: ', trim(workingDirArg) + write(6,'(a,a)') ' Geometry argument: ', trim(geometryArg) + write(6,'(a,a)') ' Loadcase argument: ', trim(loadcaseArg) + write(6,'(a,a)') ' Working directory: ', trim(getSolverWorkingDirectoryName()) + write(6,'(a,a)') ' Geometry file: ', trim(geometryFile) + write(6,'(a,a)') ' Loadcase file: ', trim(loadCaseFile) + write(6,'(a,a)') ' Solver job name: ', trim(getSolverJobName()) + if (SpectralRestartInc > 1_pInt) & + write(6,'(a,i6.6)') ' Restart at increment: ', spectralRestartInc + write(6,'(a,l1,/)') ' Append to result file: ', appendToOutFile + endif mainProcess3 + +end subroutine DAMASK_interface_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief extract working directory from given argument or from location of geometry file, +!! possibly converting relative arguments to absolut path +!> @todo change working directory with call chdir(storeWorkingDirectory)? +!-------------------------------------------------------------------------------------------------- +character(len=1024) function storeWorkingDirectory(workingDirectoryArg,geometryArg) +#ifdef __INTEL_COMPILER + use IFPORT +#endif + + implicit none + character(len=*), intent(in) :: workingDirectoryArg !< working directory argument + character(len=*), intent(in) :: geometryArg !< geometry argument + character(len=1024) :: cwd + character :: pathSep + logical :: dirExists + external :: quit + integer :: error + + pathSep = getPathSep() + if (len(workingDirectoryArg)>0) then ! got working directory as input + if (workingDirectoryArg(1:1) == pathSep) then ! absolute path given as command line argument + storeWorkingDirectory = workingDirectoryArg + else + error = getcwd(cwd) ! relative path given as command line argument + storeWorkingDirectory = trim(cwd)//pathSep//workingDirectoryArg + endif + if (storeWorkingDirectory(len(trim(storeWorkingDirectory)):len(trim(storeWorkingDirectory))) & ! if path seperator is not given, append it + /= pathSep) storeWorkingDirectory = trim(storeWorkingDirectory)//pathSep +#ifdef __INTEL_COMPILER + inquire(directory = trim(storeWorkingDirectory)//'.', exist=dirExists) +#else + inquire(file = trim(storeWorkingDirectory), exist=dirExists) +#endif + if(.not. dirExists) then ! check if the directory exists + write(6,'(a20,a,a16)') ' working directory "',trim(storeWorkingDirectory),'" does not exist' + call quit(1_pInt) + endif + else ! using path to geometry file as working dir + if (geometryArg(1:1) == pathSep) then ! absolute path given as command line argument + storeWorkingDirectory = geometryArg(1:scan(geometryArg,pathSep,back=.true.)) + else + error = getcwd(cwd) ! relative path given as command line argument + storeWorkingDirectory = trim(cwd)//pathSep//& + geometryArg(1:scan(geometryArg,pathSep,back=.true.)) + endif + endif + storeWorkingDirectory = rectifyPath(storeWorkingDirectory) + +end function storeWorkingDirectory + + +!-------------------------------------------------------------------------------------------------- +!> @brief simply returns the private string workingDir +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getSolverWorkingDirectoryName() + + implicit none + getSolverWorkingDirectoryName = workingDirectory + +end function getSolverWorkingDirectoryName + + +!-------------------------------------------------------------------------------------------------- +!> @brief solver job name (no extension) as combination of geometry and load case name +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getSolverJobName() + + implicit none + integer :: posExt,posSep + character :: pathSep + character(len=1024) :: tempString + + pathSep = getPathSep() + + tempString = geometryFile + posExt = scan(tempString,'.',back=.true.) + posSep = scan(tempString,pathSep,back=.true.) + + getSolverJobName = tempString(posSep+1:posExt-1) + + tempString = loadCaseFile + posExt = scan(tempString,'.',back=.true.) + posSep = scan(tempString,pathSep,back=.true.) + + getSolverJobName = trim(getSolverJobName)//'_'//tempString(posSep+1:posExt-1) + +end function getSolverJobName + + +!-------------------------------------------------------------------------------------------------- +!> @brief basename of geometry file with extension from command line arguments +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getGeometryFile(geometryParameter) +#ifdef __INTEL_COMPILER + use IFPORT +#endif + + implicit none + character(len=1024), intent(in) :: & + geometryParameter + character(len=1024) :: & + cwd + integer :: posExt, posSep + character :: pathSep + integer :: error + + getGeometryFile = geometryParameter + pathSep = getPathSep() + posExt = scan(getGeometryFile,'.',back=.true.) + posSep = scan(getGeometryFile,pathSep,back=.true.) + + if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') ! no extension present + if (scan(getGeometryFile,pathSep) /= 1) then ! relative path given as command line argument + error = getcwd(cwd) + getGeometryFile = rectifyPath(trim(cwd)//pathSep//getGeometryFile) + else + getGeometryFile = rectifyPath(getGeometryFile) + endif + + getGeometryFile = makeRelativePath(getSolverWorkingDirectoryName(), getGeometryFile) + +end function getGeometryFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief relative path of loadcase from command line arguments +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getLoadCaseFile(loadCaseParameter) +#ifdef __INTEL_COMPILER + use IFPORT +#endif + + implicit none + character(len=1024), intent(in) :: & + loadCaseParameter + character(len=1024) :: & + cwd + integer :: posExt, posSep, error + character :: pathSep + + getLoadCaseFile = loadcaseParameter + pathSep = getPathSep() + posExt = scan(getLoadCaseFile,'.',back=.true.) + posSep = scan(getLoadCaseFile,pathSep,back=.true.) + + if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') ! no extension present + if (scan(getLoadCaseFile,pathSep) /= 1) then ! relative path given as command line argument + error = getcwd(cwd) + getLoadCaseFile = rectifyPath(trim(cwd)//pathSep//getLoadCaseFile) + else + getLoadCaseFile = rectifyPath(getLoadCaseFile) + endif + + getLoadCaseFile = makeRelativePath(getSolverWorkingDirectoryName(), getLoadCaseFile) + +end function getLoadCaseFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief remove ../ and /./ from path +!-------------------------------------------------------------------------------------------------- +function rectifyPath(path) + + implicit none + character(len=*) :: path + character(len=len_trim(path)) :: rectifyPath + character :: pathSep + integer :: i,j,k,l ! no pInt + + pathSep = getPathSep() + +!-------------------------------------------------------------------------------------------------- +! remove /./ from path + l = len_trim(path) + rectifyPath = path + do i = l,3,-1 + if (rectifyPath(i-2:i) == pathSep//'.'//pathSep) & + rectifyPath(i-1:l) = rectifyPath(i+1:l)//' ' + enddo + +!-------------------------------------------------------------------------------------------------- +! remove ../ and corresponding directory from rectifyPath + l = len_trim(rectifyPath) + i = index(rectifyPath(i:l),'..'//pathSep) + j = 0 + do while (i > j) + j = scan(rectifyPath(1:i-2),pathSep,back=.true.) + rectifyPath(j+1:l) = rectifyPath(i+3:l)//repeat(' ',2+i-j) + if (rectifyPath(j+1:j+1) == pathSep) then !search for '//' that appear in case of XXX/../../XXX + k = len_trim(rectifyPath) + rectifyPath(j+1:k-1) = rectifyPath(j+2:k) + rectifyPath(k:k) = ' ' + endif + i = j+index(rectifyPath(j+1:l),'..'//pathSep) + enddo + if(len_trim(rectifyPath) == 0) rectifyPath = pathSep + +end function rectifyPath + + +!-------------------------------------------------------------------------------------------------- +!> @brief relative path from absolute a to absolute b +!-------------------------------------------------------------------------------------------------- +character(len=1024) function makeRelativePath(a,b) + + implicit none + character (len=*) :: a,b + character :: pathSep + integer :: i,posLastCommonSlash,remainingSlashes !no pInt + + pathSep = getPathSep() + posLastCommonSlash = 0 + remainingSlashes = 0 + + do i = 1, min(1024,len_trim(a),len_trim(b)) + if (a(i:i) /= b(i:i)) exit + if (a(i:i) == pathSep) posLastCommonSlash = i + enddo + do i = posLastCommonSlash+1,len_trim(a) + if (a(i:i) == pathSep) remainingSlashes = remainingSlashes + 1 + enddo + makeRelativePath = repeat('..'//pathSep,remainingSlashes)//b(posLastCommonSlash+1:len_trim(b)) + +end function makeRelativePath + + +!-------------------------------------------------------------------------------------------------- +!> @brief counting / and \ in $PATH System variable the character occuring more often is assumed +! to be the path separator +!-------------------------------------------------------------------------------------------------- +character function getPathSep() + + implicit none + character(len=2048) :: & + path + integer(pInt) :: & + backslash = 0_pInt, & + slash = 0_pInt + integer :: i + + call get_environment_variable('PATH',path) + do i=1, len(trim(path)) + if (path(i:i)=='/') slash = slash + 1_pInt + if (path(i:i)=='\') backslash = backslash + 1_pInt + enddo + + if (backslash>slash) then + getPathSep = '\' + else + getPathSep = '/' + endif + +end function getPathSep + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_stringValue for documentation +!-------------------------------------------------------------------------------------------------- +pure function IIO_stringValue(string,chunkPos,myChunk) + + implicit none + integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + character(len=1+chunkPos(myChunk*2+1)-chunkPos(myChunk*2)) :: IIO_stringValue + character(len=*), intent(in) :: string !< raw input with known start and end of each chunk + + + valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then + IIO_stringValue = '' + else valuePresent + IIO_stringValue = string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) + endif valuePresent + +end function IIO_stringValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_intValue for documentation +!-------------------------------------------------------------------------------------------------- +integer(pInt) pure function IIO_intValue(string,chunkPos,myChunk) + + implicit none + character(len=*), intent(in) :: string !< raw input with known start and end of each chunk + integer(pInt), intent(in) :: myChunk !< position number of desired sub string + integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string + + + valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then + IIO_intValue = 0_pInt + else valuePresent + read(UNIT=string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)),ERR=100,FMT=*) IIO_intValue + endif valuePresent + return +100 IIO_intValue = huge(1_pInt) + +end function IIO_intValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_lc for documentation +!-------------------------------------------------------------------------------------------------- +pure function IIO_lc(string) + + implicit none + character(len=*), intent(in) :: string !< string to convert + character(len=len(string)) :: IIO_lc + + character(26), parameter :: LOWER = 'abcdefghijklmnopqrstuvwxyz' + character(26), parameter :: UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + + integer :: i,n ! no pInt (len returns default integer) + + IIO_lc = string + do i=1,len(string) + n = index(UPPER,IIO_lc(i:i)) + if (n/=0) IIO_lc(i:i) = LOWER(n:n) + enddo + +end function IIO_lc + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_stringPos for documentation +!-------------------------------------------------------------------------------------------------- +pure function IIO_stringPos(string) + + implicit none + integer(pInt), dimension(:), allocatable :: IIO_stringPos + character(len=*), intent(in) :: string !< string in which chunks are searched for + + character(len=*), parameter :: SEP=achar(44)//achar(32)//achar(9)//achar(10)//achar(13) ! comma and whitespaces + integer :: left, right ! no pInt (verify and scan return default integer) + + allocate(IIO_stringPos(1), source=0_pInt) + right = 0 + + do while (verify(string(right+1:),SEP)>0) + left = right + verify(string(right+1:),SEP) + right = left + scan(string(left:),SEP) - 2 + if ( string(left:left) == '#' ) exit + IIO_stringPos = [IIO_stringPos,int(left, pInt), int(right, pInt)] + IIO_stringPos(1) = IIO_stringPos(1)+1_pInt + enddo + +end function IIO_stringPos + + +end module diff --git a/code/spectral/spectral_mech_AL.f90 b/code/spectral/spectral_mech_AL.f90 new file mode 100644 index 000000000..a937dcc86 --- /dev/null +++ b/code/spectral/spectral_mech_AL.f90 @@ -0,0 +1,715 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief AL scheme solver +!-------------------------------------------------------------------------------------------------- +module spectral_mech_AL + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + + implicit none + private +#include + + character (len=*), parameter, public :: & + DAMASK_spectral_solverAL_label = 'al' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! PETSc data + DM, private :: da + SNES, private :: snes + Vec, private :: solution_vec + +!-------------------------------------------------------------------------------------------------- +! common pointwise data + real(pReal), private, dimension(:,:,:,:,:), allocatable :: & + F_lastInc, & !< field of previous compatible deformation gradients + F_lambda_lastInc, & !< field of previous incompatible deformation gradient + Fdot, & !< field of assumed rate of compatible deformation gradient + F_lambdaDot !< field of assumed rate of incopatible deformation gradient + +!-------------------------------------------------------------------------------------------------- +! stress, stiffness and compliance average etc. + real(pReal), private, dimension(3,3) :: & + F_aimDot, & !< assumed rate of average deformation gradient + F_aim = math_I3, & !< current prescribed deformation gradient + F_aim_lastInc = math_I3, & !< previous average deformation gradient + F_av = 0.0_pReal, & !< average incompatible def grad field + P_av = 0.0_pReal, & !< average 1st Piola--Kirchhoff stress + P_avLastEval = 0.0_pReal !< average 1st Piola--Kirchhoff stress last call of CPFEM_general + character(len=1024), private :: incInfo !< time and increment information + real(pReal), private, dimension(3,3,3,3) :: & + C_volAvg = 0.0_pReal, & !< current volume average stiffness + C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness + C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness + S = 0.0_pReal, & !< current compliance (filled up with zeros) + C_scale = 0.0_pReal, & + S_scale = 0.0_pReal + + real(pReal), private :: & + err_BC, & !< deviation from stress BC + err_curl, & !< RMS of curl of F + err_div !< RMS of div of P + logical, private :: ForwardData + integer(pInt), private :: & + totalIter = 0_pInt !< total iteration in current increment + + public :: & + AL_init, & + AL_solution, & + AL_forward, & + AL_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!> @todo use sourced allocation, e.g. allocate(Fdot,source = F_lastInc) +!-------------------------------------------------------------------------------------------------- +subroutine AL_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRestart + use FEsolving, only: & + restartInc + use numerics, only: & + worldrank, & + worldsize + use DAMASK_interface, only: & + getSolverJobName + use spectral_utilities, only: & + Utilities_constitutiveResponse, & + Utilities_updateGamma, & + Utilities_updateIPcoords + use mesh, only: & + grid, & + grid3 + use math, only: & + math_invSym3333 + + implicit none + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P + real(pReal), dimension(3,3) :: & + temp33_Real = 0.0_pReal + + PetscErrorCode :: ierr + PetscObject :: dummy + PetscScalar, pointer, dimension(:,:,:,:) :: xx_psc, F, F_lambda + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + character(len=1024) :: rankStr + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverAL init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif + +!-------------------------------------------------------------------------------------------------- +! 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_lambda_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate (F_lambdaDot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + +!-------------------------------------------------------------------------------------------------- +! PETSc Init + call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary + DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & ! global grid + 1 , 1, worldsize, & + 18, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) + grid(1),grid(2),localK, & ! local grid + da,ierr) ! handle, error + CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) + call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) + call DMDASNESSetFunctionLocal(da,INSERT_VALUES,AL_formResidual,dummy,ierr) + CHKERRQ(ierr) + call SNESSetConvergenceTest(snes,AL_converged,dummy,PETSC_NULL_FUNCTION,ierr) + CHKERRQ(ierr) + call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! places pointer xx_psc on PETSc data + F => xx_psc(0:8,:,:,:) + F_lambda => xx_psc(9:17,:,:,:) + restart: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading values of increment ', restartInc - 1_pInt, ' from file' + flush(6) + write(rankStr,'(a1,i0)')'_',worldrank + call IO_read_realFile(777,'F'//trim(rankStr), trim(getSolverJobName()),size(F)) + read (777,rec=1) F + close (777) + call IO_read_realFile(777,'F_lastInc'//trim(rankStr), trim(getSolverJobName()),size(F_lastInc)) + read (777,rec=1) F_lastInc + close (777) + call IO_read_realFile(777,'F_lambda'//trim(rankStr),trim(getSolverJobName()),size(F_lambda)) + read (777,rec=1) F_lambda + close (777) + call IO_read_realFile(777,'F_lambda_lastInc'//trim(rankStr),& + trim(getSolverJobName()),size(F_lambda_lastInc)) + read (777,rec=1) F_lambda_lastInc + close (777) + call IO_read_realFile(777,'F_aim', trim(getSolverJobName()),size(F_aim)) + read (777,rec=1) F_aim + close (777) + call IO_read_realFile(777,'F_aim_lastInc', trim(getSolverJobName()),size(F_aim_lastInc)) + read (777,rec=1) F_aim_lastInc + close (777) + call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) + read (777,rec=1) f_aimDot + close (777) + elseif (restartInc == 1_pInt) then restart + F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity + F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) + F_lambda = F + F_lambda_lastInc = F_lastInc + endif restart + + + call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) + call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & + 0.0_pReal,P,C_volAvg,C_minMaxAvg,temp33_Real,.false.,math_I3) + nullify(F) + nullify(F_lambda) + call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! write data back to PETSc + + readRestart: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading more values of increment', restartInc - 1_pInt, 'from file' + flush(6) + call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) + read (777,rec=1) C_volAvg + close (777) + call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) + read (777,rec=1) C_volAvgLastInc + close (777) + call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) + read (777,rec=1) C_minMaxAvg + close (777) + endif readRestart + + call Utilities_updateGamma(C_minMaxAvg,.True.) + C_scale = C_minMaxAvg + S_scale = math_invSym3333(C_minMaxAvg) + +end subroutine AL_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the AL scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function & + AL_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) + use IO, only: & + IO_error + use numerics, only: & + update_gamma + use math, only: & + math_invSym3333 + use spectral_utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use FEsolving, only: & + restartWrite, & + terminallyIll + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + logical, intent(in) :: & + guess + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + character(len=*), intent(in) :: & + incInfoIn + real(pReal), dimension(3,3), intent(in) :: rotation_BC + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + incInfo = incInfoIn + +!-------------------------------------------------------------------------------------------------- +! update stiffness (and gamma operator) + S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) + if (update_gamma) then + call Utilities_updateGamma(C_minMaxAvg,restartWrite) + C_scale = C_minMaxAvg + S_scale = math_invSym3333(C_minMaxAvg) + endif + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + mask_stress = P_BC%maskFloat + params%P_BC = P_BC%values + params%rotation_BC = rotation_BC + params%timeinc = timeinc + params%timeincOld = timeinc_old + +!-------------------------------------------------------------------------------------------------- +! solve BVP + call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) + CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! check convergence + call SNESGetConvergedReason(snes,reason,ierr) + CHKERRQ(ierr) + AL_solution%termIll = terminallyIll + terminallyIll = .false. + if (reason == -4) call IO_error(893_pInt) + if (reason < 1) AL_solution%converged = .false. + AL_solution%iterationsNeeded = totalIter + +end function AL_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the AL residual vector +!-------------------------------------------------------------------------------------------------- +subroutine AL_formResidual(in,x_scal,f_scal,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + polarAlpha, & + polarBeta, & + worldrank + use mesh, only: & + grid3, & + grid + use IO, only: & + IO_intOut + use math, only: & + math_rotate_backward33, & + math_transpose33, & + math_mul3333xx33, & + math_invSym3333, & + math_mul33x33 + use spectral_utilities, only: & + wgt, & + tensorField_real, & + utilities_FFTtensorForward, & + utilities_fourierGammaConvolution, & + utilities_FFTtensorBackward, & + Utilities_constitutiveResponse, & + Utilities_divergenceRMS, & + Utilities_curlRMS + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRotation + use homogenization, only: & + materialpoint_dPdF + use FEsolving, only: & + terminallyIll + + implicit none +!-------------------------------------------------------------------------------------------------- +! strange syntax in the next line because otherwise macros expand beyond 132 character limit + DMDALocalInfo, dimension(& + DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, target, dimension(3,3,2, & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, target, dimension(3,3,2, & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscScalar, pointer, dimension(:,:,:,:,:) :: & + F, & + F_lambda, & + residual_F, & + residual_F_lambda + PetscInt :: & + PETScIter, & + nfuncs + PetscObject :: dummy + PetscErrorCode :: ierr + integer(pInt) :: & + i, j, k, e + + F => x_scal(1:3,1:3,1,& + XG_RANGE,YG_RANGE,ZG_RANGE) + F_lambda => x_scal(1:3,1:3,2,& + XG_RANGE,YG_RANGE,ZG_RANGE) + residual_F => f_scal(1:3,1:3,1,& + X_RANGE,Y_RANGE,Z_RANGE) + residual_F_lambda => f_scal(1:3,1:3,2,& + X_RANGE,Y_RANGE,Z_RANGE) + + call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) + call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) + + F_av = sum(sum(sum(F,dim=5),dim=4),dim=3) * wgt + call MPI_Allreduce(MPI_IN_PLACE,F_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + + if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment + newIteration: if(totalIter <= PETScIter) then +!-------------------------------------------------------------------------------------------------- +! report begin of new iteration + totalIter = totalIter + 1_pInt + if (worldrank == 0_pInt) then + write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & + ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax + if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & + math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & + math_transpose33(F_aim) + flush(6) + endif + endif newIteration + +!-------------------------------------------------------------------------------------------------- +! + tensorField_real = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) + tensorField_real(1:3,1:3,i,j,k) = & + polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& + polarAlpha*math_mul33x33(F(1:3,1:3,i,j,k), & + math_mul3333xx33(C_scale,F_lambda(1:3,1:3,i,j,k) - math_I3)) + + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! doing convolution in Fourier space + call utilities_FFTtensorForward() + call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) + call utilities_FFTtensorBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + residual_F_lambda = polarBeta*F - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) + +!-------------------------------------------------------------------------------------------------- +! evaluate constitutive response + P_avLastEval = P_av + call Utilities_constitutiveResponse(F_lastInc,F - residual_F_lambda/polarBeta,params%timeinc, & + residual_F,C_volAvg,C_minMaxAvg,P_av,ForwardData,params%rotation_BC) + call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) + ForwardData = .False. + +!-------------------------------------------------------------------------------------------------- +! calculate divergence + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = residual_F + call utilities_FFTtensorForward() + err_div = Utilities_divergenceRMS() + call utilities_FFTtensorBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + e = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) + e = e + 1_pInt + residual_F(1:3,1:3,i,j,k) = math_mul3333xx33(math_invSym3333(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & + residual_F(1:3,1:3,i,j,k) - & + math_mul33x33(F(1:3,1:3,i,j,k), & + math_mul3333xx33(C_scale,F_lambda(1:3,1:3,i,j,k) - math_I3))) & + + residual_F_lambda(1:3,1:3,i,j,k) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! calculating curl + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F + call utilities_FFTtensorForward() + err_curl = Utilities_curlRMS() + call utilities_FFTtensorBackward() + +end subroutine AL_formResidual + + +!-------------------------------------------------------------------------------------------------- +!> @brief convergence check +!-------------------------------------------------------------------------------------------------- +subroutine AL_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + err_div_tolRel, & + err_div_tolAbs, & + err_curl_tolRel, & + err_curl_tolAbs, & + err_stress_tolAbs, & + err_stress_tolRel, & + worldrank + use math, only: & + math_mul3333xx33 + use FEsolving, only: & + terminallyIll + + implicit none + SNES :: snes_local + PetscInt :: PETScIter + PetscReal :: & + xnorm, & + snorm, & + fnorm + SNESConvergedReason :: reason + PetscObject :: dummy + PetscErrorCode ::ierr + real(pReal) :: & + curlTol, & + divTol, & + BC_tol + +!-------------------------------------------------------------------------------------------------- +! stress BC handling + F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc + err_BC = maxval(abs((-mask_stress+1.0_pReal)*math_mul3333xx33(C_scale,F_aim-F_av) + & + mask_stress *(P_av - params%P_BC))) ! mask = 0.0 for no bc + +!-------------------------------------------------------------------------------------------------- +! error calculation + curlTol = max(maxval(abs(F_aim-math_I3))*err_curl_tolRel,err_curl_tolAbs) + divTol = max(maxval(abs(P_av)) *err_div_tolRel,err_div_tolAbs) + BC_tol = max(maxval(abs(P_av)) *err_stress_tolrel,err_stress_tolabs) + + converged: if ((totalIter >= itmin .and. & + all([ err_div/divTol, & + err_curl/curlTol, & + err_BC/BC_tol ] < 1.0_pReal)) & + .or. terminallyIll) then + reason = 1 + elseif (totalIter >= itmax) then converged + reason = -1 + else converged + reason = 0 + endif converged + +!-------------------------------------------------------------------------------------------------- +! report + if (worldrank == 0_pInt) then + write(6,'(1/,a)') ' ... reporting .............................................................' + write(6,'(/,a,f12.2,a,es8.2,a,es9.2,a)') ' error curl = ', & + err_curl/curlTol,' (',err_curl,' -, tol =',curlTol,')' + write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & + err_div/divTol, ' (',err_div, ' / m, tol =',divTol,')' + write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error BC = ', & + err_BC/BC_tol, ' (',err_BC, ' Pa, tol =',BC_tol,')' + write(6,'(/,a)') ' ===========================================================================' + flush(6) + endif + +end subroutine AL_converged + +!-------------------------------------------------------------------------------------------------- +!> @brief forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine AL_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) + use math, only: & + math_mul33x33, & + math_mul3333xx33, & + math_transpose33, & + math_rotate_backward33 + use numerics, only: & + worldrank + use mesh, only: & + grid3, & + grid + use spectral_utilities, only: & + Utilities_calculateRate, & + Utilities_forwardField, & + Utilities_updateIPcoords, & + tBoundaryCondition, & + cutBack + use IO, only: & + IO_write_JobRealFile + use FEsolving, only: & + restartWrite + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + real(pReal), dimension(3,3), intent(in) :: rotation_BC + logical, intent(in) :: & + guess + PetscErrorCode :: ierr + PetscScalar, dimension(:,:,:,:), pointer :: xx_psc, F, F_lambda + integer(pInt) :: i, j, k + real(pReal), dimension(3,3) :: F_lambda33 + character(len=1024) :: rankStr + +!-------------------------------------------------------------------------------------------------- +! update coordinates and rate and forward last inc + call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr) + F => xx_psc(0:8,:,:,:) + F_lambda => xx_psc(9:17,:,:,:) + if (restartWrite) then + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' writing converged results for restart' + flush(6) + endif + write(rankStr,'(a1,i0)')'_',worldrank + call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file + write (777,rec=1) F + close (777) + call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file + write (777,rec=1) F_lastInc + close (777) + call IO_write_jobRealFile(777,'F_lambda'//trim(rankStr),size(F_lambda)) ! writing deformation gradient field to file + write (777,rec=1) F_lambda + close (777) + call IO_write_jobRealFile(777,'F_lambda_lastInc'//trim(rankStr),size(F_lambda_lastInc)) ! writing F_lastInc field to file + write (777,rec=1) F_lambda_lastInc + close (777) + if (worldrank == 0_pInt) then + call IO_write_jobRealFile(777,'F_aim',size(F_aim)) + write (777,rec=1) F_aim + close(777) + call IO_write_jobRealFile(777,'F_aim_lastInc',size(F_aim_lastInc)) + write (777,rec=1) F_aim_lastInc + close(777) + call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) + write (777,rec=1) F_aimDot + close(777) + call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) + write (777,rec=1) C_volAvg + close(777) + call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) + write (777,rec=1) C_volAvgLastInc + close(777) + endif + endif + + call utilities_updateIPcoords(F) + + if (cutBack) then + F_aim = F_aim_lastInc + F_lambda = reshape(F_lambda_lastInc,[9,grid(1),grid(2),grid3]) + F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) + C_volAvg = C_volAvgLastInc + else + ForwardData = .True. + C_volAvgLastInc = C_volAvg +!-------------------------------------------------------------------------------------------------- +! calculate rate for aim + if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F + f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) + elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed + f_aimDot = F_BC%maskFloat * F_BC%values + elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed + f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime + endif + if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old + F_aim_lastInc = F_aim + +!-------------------------------------------------------------------------------------------------- +! update coordinates and rate and forward last inc + call utilities_updateIPcoords(F) + Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & + timeinc_old,guess,F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3])) + F_lambdaDot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & + timeinc_old,guess,F_lambda_lastInc,reshape(F_lambda,[3,3,grid(1),grid(2),grid3])) + F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) + F_lambda_lastInc = reshape(F_lambda,[3,3,grid(1),grid(2),grid3]) + endif + + F_aim = F_aim + f_aimDot * timeinc + +!-------------------------------------------------------------------------------------------------- +! update local deformation gradient + F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim + math_rotate_backward33(F_aim,rotation_BC)), & + [9,grid(1),grid(2),grid3]) + F_lambda = reshape(Utilities_forwardField(timeinc,F_lambda_lastInc,F_lambdadot), & + [9,grid(1),grid(2),grid3]) ! does not have any average value as boundary condition + if (.not. guess) then ! large strain forwarding + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) + F_lambda33 = reshape(F_lambda(1:9,i,j,k),[3,3]) + F_lambda33 = math_mul3333xx33(S_scale,math_mul33x33(F_lambda33, & + math_mul3333xx33(C_scale,& + math_mul33x33(math_transpose33(F_lambda33),& + F_lambda33) -math_I3))*0.5_pReal)& + + math_I3 + F_lambda(1:9,i,j,k) = reshape(F_lambda33,[9]) + enddo; enddo; enddo + endif + call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) + +end subroutine AL_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine AL_destroy() + use spectral_utilities, only: & + Utilities_destroy + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) + call SNESDestroy(snes,ierr); CHKERRQ(ierr) + call DMDestroy(da,ierr); CHKERRQ(ierr) + +end subroutine AL_destroy + +end module spectral_mech_AL diff --git a/code/spectral/spectral_mech_Basic.f90 b/code/spectral/spectral_mech_Basic.f90 new file mode 100644 index 000000000..a8344fabe --- /dev/null +++ b/code/spectral/spectral_mech_Basic.f90 @@ -0,0 +1,569 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Basic scheme PETSc solver +!-------------------------------------------------------------------------------------------------- +module spectral_mech_basic + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + + implicit none + private +#include + + character (len=*), parameter, public :: & + DAMASK_spectral_SolverBasicPETSC_label = 'basicpetsc' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + +!-------------------------------------------------------------------------------------------------- +! PETSc data + DM, private :: da + SNES, private :: snes + Vec, private :: solution_vec + +!-------------------------------------------------------------------------------------------------- +! common pointwise data + real(pReal), private, dimension(:,:,:,:,:), allocatable :: F_lastInc, Fdot + +!-------------------------------------------------------------------------------------------------- +! stress, stiffness and compliance average etc. + real(pReal), private, dimension(3,3) :: & + F_aim = math_I3, & + F_aim_lastIter = math_I3, & + F_aim_lastInc = math_I3, & + P_av = 0.0_pReal, & + F_aimDot=0.0_pReal + character(len=1024), private :: incInfo + real(pReal), private, dimension(3,3,3,3) :: & + C_volAvg = 0.0_pReal, & !< current volume average stiffness + C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness + C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness + S = 0.0_pReal !< current compliance (filled up with zeros) + real(pReal), private :: err_stress, err_div + logical, private :: ForwardData + integer(pInt), private :: & + totalIter = 0_pInt !< total iteration in current increment + real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal + + public :: & + basicPETSc_init, & + basicPETSc_solution, & + BasicPETSc_forward, & + basicPETSc_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!-------------------------------------------------------------------------------------------------- +subroutine basicPETSc_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRestart + use FEsolving, only: & + restartInc + use numerics, only: & + worldrank, & + worldsize + use DAMASK_interface, only: & + getSolverJobName + use spectral_utilities, only: & + Utilities_constitutiveResponse, & + Utilities_updateGamma, & + utilities_updateIPcoords, & + wgt + use mesh, only: & + grid, & + grid3 + use math, only: & + math_invSym3333 + + implicit none + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P + PetscScalar, dimension(:,:,:,:), pointer :: F + PetscErrorCode :: ierr + PetscObject :: dummy + real(pReal), dimension(3,3) :: & + temp33_Real = 0.0_pReal + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + character(len=1024) :: rankStr + + mainProcess: if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverBasicPETSc init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! 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) + +!-------------------------------------------------------------------------------------------------- +! initialize solver specific parts of PETSc + call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary + DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & ! global grid + 1, 1, worldsize, & + 9, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) + grid (1),grid (2),localK, & ! local grid + da,ierr) ! handle, error + CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) + call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) ! global solution vector (grid x 9, i.e. every def grad tensor) + call DMDASNESSetFunctionLocal(da,INSERT_VALUES,BasicPETSC_formResidual,dummy,ierr) ! residual vector of same shape as solution vector + CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) ! connect snes to da + call SNESSetConvergenceTest(snes,BasicPETSC_converged,dummy,PETSC_NULL_FUNCTION,ierr) ! specify custom convergence check function "_converged" + CHKERRQ(ierr) + call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAVecGetArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) ! get the data out of PETSc to work with + + restart: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading values of increment ', restartInc - 1_pInt, ' from file' + flush(6) + write(rankStr,'(a1,i0)')'_',worldrank + call IO_read_realFile(777,'F'//trim(rankStr),trim(getSolverJobName()),size(F)) + read (777,rec=1) F + close (777) + call IO_read_realFile(777,'F_lastInc'//trim(rankStr),trim(getSolverJobName()),size(F_lastInc)) + read (777,rec=1) F_lastInc + close (777) + call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) + read (777,rec=1) f_aimDot + close (777) + F_aim = reshape(sum(sum(sum(F,dim=4),dim=3),dim=2) * wgt, [3,3]) ! average of F + F_aim_lastInc = sum(sum(sum(F_lastInc,dim=5),dim=4),dim=3) * wgt ! average of F_lastInc + elseif (restartInc == 1_pInt) then restart + F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity + F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) + endif restart + + call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) + call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & + 0.0_pReal, & + P, & + C_volAvg,C_minMaxAvg, & ! global average of stiffness and (min+max)/2 + temp33_Real, & + .false., & + math_I3) + + call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) ! write data back to PETSc + + restartRead: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading more values of increment', restartInc - 1_pInt, 'from file' + flush(6) + call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) + read (777,rec=1) C_volAvg + close (777) + call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) + read (777,rec=1) C_volAvgLastInc + close (777) + call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) + read (777,rec=1) C_minMaxAvg + close (777) + endif restartRead + + call Utilities_updateGamma(C_minmaxAvg,.True.) + +end subroutine basicPETSc_init + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the Basic PETSC scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function & + basicPETSc_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) + use IO, only: & + IO_error + use numerics, only: & + update_gamma + use spectral_utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use FEsolving, only: & + restartWrite, & + terminallyIll + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + character(len=*), intent(in) :: & + incInfoIn + real(pReal), dimension(3,3), intent(in) :: rotation_BC + logical, intent(in) :: & + guess + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + incInfo = incInfoIn + +!-------------------------------------------------------------------------------------------------- +! update stiffness (and gamma operator) + S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) + if (update_gamma) call Utilities_updateGamma(C_minmaxAvg,restartWrite) + + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + mask_stress = P_BC%maskFloat + params%P_BC = P_BC%values + params%rotation_BC = rotation_BC + params%timeinc = timeinc + params%timeincOld = timeinc_old + +!-------------------------------------------------------------------------------------------------- +! solve BVP + call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) + CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! check convergence + call SNESGetConvergedReason(snes,reason,ierr) + CHKERRQ(ierr) + basicPETSc_solution%termIll = terminallyIll + terminallyIll = .false. + BasicPETSc_solution%converged =.true. + if (reason == -4) call IO_error(893_pInt) + if (reason < 1) basicPETSC_solution%converged = .false. + basicPETSC_solution%iterationsNeeded = totalIter + +end function BasicPETSc_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the AL residual vector +!-------------------------------------------------------------------------------------------------- +subroutine BasicPETSC_formResidual(in,x_scal,f_scal,dummy,ierr) + use numerics, only: & + itmax, & + itmin + use numerics, only: & + worldrank + use mesh, only: & + grid, & + grid3 + use math, only: & + math_rotate_backward33, & + math_transpose33, & + math_mul3333xx33 + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRotation + use spectral_utilities, only: & + tensorField_real, & + utilities_FFTtensorForward, & + utilities_FFTtensorBackward, & + utilities_fourierGammaConvolution, & + Utilities_constitutiveResponse, & + Utilities_divergenceRMS + use IO, only: & + IO_intOut + use FEsolving, only: & + terminallyIll + + implicit none + DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, dimension(3,3, & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, dimension(3,3, & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscInt :: & + PETScIter, & + nfuncs + PetscObject :: dummy + PetscErrorCode :: ierr + + call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) + call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) + + if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment + newIteration: if (totalIter <= PETScIter) then +!-------------------------------------------------------------------------------------------------- +! report begin of new iteration + totalIter = totalIter + 1_pInt + if (worldrank == 0_pInt) then + write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & + ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax + if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & + math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & + math_transpose33(F_aim) + flush(6) + endif + endif newIteration + +!-------------------------------------------------------------------------------------------------- +! evaluate constitutive response + call Utilities_constitutiveResponse(F_lastInc,x_scal,params%timeinc, & + f_scal,C_volAvg,C_minmaxAvg,P_av,ForwardData,params%rotation_BC) + call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) + ForwardData = .false. + +!-------------------------------------------------------------------------------------------------- +! stress BC handling + F_aim_lastIter = F_aim + F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc + err_stress = maxval(abs(mask_stress * (P_av - params%P_BC))) ! mask = 0.0 for no bc + +!-------------------------------------------------------------------------------------------------- +! updated deformation gradient using fix point algorithm of basic scheme + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = f_scal + call utilities_FFTtensorForward() + err_div = Utilities_divergenceRMS() + call utilities_fourierGammaConvolution(math_rotate_backward33(F_aim_lastIter-F_aim,params%rotation_BC)) + call utilities_FFTtensorBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + f_scal = tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) + +end subroutine BasicPETSc_formResidual + + +!-------------------------------------------------------------------------------------------------- +!> @brief convergence check +!-------------------------------------------------------------------------------------------------- +subroutine BasicPETSc_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + err_div_tolRel, & + err_div_tolAbs, & + err_stress_tolRel, & + err_stress_tolAbs, & + worldrank + use FEsolving, only: & + terminallyIll + + implicit none + SNES :: snes_local + PetscInt :: PETScIter + PetscReal :: & + xnorm, & + snorm, & + fnorm + SNESConvergedReason :: reason + PetscObject :: dummy + PetscErrorCode :: ierr + real(pReal) :: & + divTol, & + stressTol + + divTol = max(maxval(abs(P_av))*err_div_tolRel,err_div_tolAbs) + stressTol = max(maxval(abs(P_av))*err_stress_tolrel,err_stress_tolabs) + + converged: if ((totalIter >= itmin .and. & + all([ err_div/divTol, & + err_stress/stressTol ] < 1.0_pReal)) & + .or. terminallyIll) then + reason = 1 + elseif (totalIter >= itmax) then converged + reason = -1 + else converged + reason = 0 + endif converged + +!-------------------------------------------------------------------------------------------------- +! report + if (worldrank == 0_pInt) then + write(6,'(1/,a)') ' ... reporting .............................................................' + write(6,'(1/,a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & + err_div/divTol, ' (',err_div,' / m, tol =',divTol,')' + write(6,'(a,f12.2,a,es8.2,a,es9.2,a)') ' error stress BC = ', & + err_stress/stressTol, ' (',err_stress, ' Pa, tol =',stressTol,')' + write(6,'(/,a)') ' ===========================================================================' + flush(6) + endif + +end subroutine BasicPETSc_converged + +!-------------------------------------------------------------------------------------------------- +!> @brief forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine BasicPETSc_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) + use math, only: & + math_mul33x33 ,& + math_rotate_backward33 + use mesh, only: & + grid, & + grid3 + use spectral_utilities, only: & + Utilities_calculateRate, & + Utilities_forwardField, & + utilities_updateIPcoords, & + tBoundaryCondition, & + cutBack + use IO, only: & + IO_write_JobRealFile + use FEsolving, only: & + restartWrite + use numerics, only: & + worldrank + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + real(pReal), dimension(3,3), intent(in) :: rotation_BC + logical, intent(in) :: & + guess + PetscScalar, pointer :: F(:,:,:,:) + PetscErrorCode :: ierr + character(len=1024) :: rankStr + + call DMDAVecGetArrayF90(da,solution_vec,F,ierr) +!-------------------------------------------------------------------------------------------------- +! restart information for spectral solver + if (restartWrite) then + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' writing converged results for restart' + flush(6) + endif + write(rankStr,'(a1,i0)')'_',worldrank + call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file + write (777,rec=1) F + close (777) + call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file + write (777,rec=1) F_lastInc + close (777) + if (worldrank == 0_pInt) then + call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) + write (777,rec=1) F_aimDot + close(777) + call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) + write (777,rec=1) C_volAvg + close(777) + call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) + write (777,rec=1) C_volAvgLastInc + close(777) + endif + endif + + call utilities_updateIPcoords(F) + + if (cutBack) then + F_aim = F_aim_lastInc + F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) + C_volAvg = C_volAvgLastInc + else + ForwardData = .True. + C_volAvgLastInc = C_volAvg +!-------------------------------------------------------------------------------------------------- +! calculate rate for aim + if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F + f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) + elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed + f_aimDot = F_BC%maskFloat * F_BC%values + elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed + f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime + endif + if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old + F_aim_lastInc = F_aim + +!-------------------------------------------------------------------------------------------------- +! update coordinates and rate and forward last inc + call utilities_updateIPcoords(F) + Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & + timeinc_old,guess,F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3])) + F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) + endif + F_aim = F_aim + f_aimDot * timeinc + +!-------------------------------------------------------------------------------------------------- +! update local deformation gradient + F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim + math_rotate_backward33(F_aim,rotation_BC)),[9,grid(1),grid(2),grid3]) + call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) + +end subroutine BasicPETSc_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine BasicPETSc_destroy() + use spectral_utilities, only: & + Utilities_destroy + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) + call SNESDestroy(snes,ierr); CHKERRQ(ierr) + call DMDestroy(da,ierr); CHKERRQ(ierr) + +end subroutine BasicPETSc_destroy + +end module spectral_mech_basic diff --git a/code/spectral/spectral_mech_Polarisation.f90 b/code/spectral/spectral_mech_Polarisation.f90 new file mode 100644 index 000000000..a28eb5adb --- /dev/null +++ b/code/spectral/spectral_mech_Polarisation.f90 @@ -0,0 +1,712 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Polarisation scheme solver +!-------------------------------------------------------------------------------------------------- +module spectral_mech_Polarisation + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + + implicit none + private +#include + + character (len=*), parameter, public :: & + DAMASK_spectral_solverPolarisation_label = 'polarisation' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! PETSc data + DM, private :: da + SNES, private :: snes + Vec, private :: solution_vec + +!-------------------------------------------------------------------------------------------------- +! common pointwise data + real(pReal), private, dimension(:,:,:,:,:), allocatable :: & + F_lastInc, & !< field of previous compatible deformation gradients + F_tau_lastInc, & !< field of previous incompatible deformation gradient + Fdot, & !< field of assumed rate of compatible deformation gradient + F_tauDot !< field of assumed rate of incopatible deformation gradient + +!-------------------------------------------------------------------------------------------------- +! stress, stiffness and compliance average etc. + real(pReal), private, dimension(3,3) :: & + F_aimDot, & !< assumed rate of average deformation gradient + F_aim = math_I3, & !< current prescribed deformation gradient + F_aim_lastInc = math_I3, & !< previous average deformation gradient + F_av = 0.0_pReal, & !< average incompatible def grad field + P_av = 0.0_pReal, & !< average 1st Piola--Kirchhoff stress + P_avLastEval = 0.0_pReal !< average 1st Piola--Kirchhoff stress last call of CPFEM_general + character(len=1024), private :: incInfo !< time and increment information + real(pReal), private, dimension(3,3,3,3) :: & + C_volAvg = 0.0_pReal, & !< current volume average stiffness + C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness + C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness + S = 0.0_pReal, & !< current compliance (filled up with zeros) + C_scale = 0.0_pReal, & + S_scale = 0.0_pReal + + real(pReal), private :: & + err_BC, & !< deviation from stress BC + err_curl, & !< RMS of curl of F + err_div !< RMS of div of P + logical, private :: ForwardData + integer(pInt), private :: & + totalIter = 0_pInt !< total iteration in current increment + + public :: & + Polarisation_init, & + Polarisation_solution, & + Polarisation_forward, & + Polarisation_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!> @todo use sourced allocation, e.g. allocate(Fdot,source = F_lastInc) +!-------------------------------------------------------------------------------------------------- +subroutine Polarisation_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRestart + use FEsolving, only: & + restartInc + use numerics, only: & + worldrank, & + worldsize + use DAMASK_interface, only: & + getSolverJobName + use spectral_utilities, only: & + Utilities_constitutiveResponse, & + Utilities_updateGamma, & + Utilities_updateIPcoords + use mesh, only: & + grid, & + grid3 + use math, only: & + math_invSym3333 + + implicit none + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P + real(pReal), dimension(3,3) :: & + temp33_Real = 0.0_pReal + + PetscErrorCode :: ierr + PetscObject :: dummy + PetscScalar, pointer, dimension(:,:,:,:) :: xx_psc, F, F_tau + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + character(len=1024) :: rankStr + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverPolarisation init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif + +!-------------------------------------------------------------------------------------------------- +! 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_tau_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate (F_tauDot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + +!-------------------------------------------------------------------------------------------------- +! PETSc Init + call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary + DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & ! global grid + 1 , 1, worldsize, & + 18, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) + grid (1),grid (2),localK, & ! local grid + da,ierr) ! handle, error + CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) + call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) + call DMDASNESSetFunctionLocal(da,INSERT_VALUES,Polarisation_formResidual,dummy,ierr) + CHKERRQ(ierr) + call SNESSetConvergenceTest(snes,Polarisation_converged,dummy,PETSC_NULL_FUNCTION,ierr) + CHKERRQ(ierr) + call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! places pointer xx_psc on PETSc data + F => xx_psc(0:8,:,:,:) + F_tau => xx_psc(9:17,:,:,:) + restart: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading values of increment', restartInc - 1_pInt, 'from file' + flush(6) + write(rankStr,'(a1,i0)')'_',worldrank + call IO_read_realFile(777,'F'//trim(rankStr),trim(getSolverJobName()),size(F)) + read (777,rec=1) F + close (777) + call IO_read_realFile(777,'F_lastInc'//trim(rankStr),trim(getSolverJobName()),size(F_lastInc)) + read (777,rec=1) F_lastInc + close (777) + call IO_read_realFile(777,'F_tau'//trim(rankStr),trim(getSolverJobName()),size(F_tau)) + read (777,rec=1) F_tau + close (777) + call IO_read_realFile(777,'F_tau_lastInc'//trim(rankStr),& + trim(getSolverJobName()),size(F_tau_lastInc)) + read (777,rec=1) F_tau_lastInc + close (777) + call IO_read_realFile(777,'F_aim', trim(getSolverJobName()),size(F_aim)) + read (777,rec=1) F_aim + close (777) + call IO_read_realFile(777,'F_aim_lastInc', trim(getSolverJobName()),size(F_aim_lastInc)) + read (777,rec=1) F_aim_lastInc + close (777) + call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) + read (777,rec=1) f_aimDot + close (777) + elseif (restartInc == 1_pInt) then restart + F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity + F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) + F_tau = 2.0_pReal* F + F_tau_lastInc = 2.0_pReal*F_lastInc + endif restart + + call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) + call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & + 0.0_pReal,P,C_volAvg,C_minMaxAvg,temp33_Real,.false.,math_I3) + nullify(F) + nullify(F_tau) + call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! write data back to PETSc + + readRestart: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading more values of increment', restartInc - 1_pInt, 'from file' + flush(6) + call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) + read (777,rec=1) C_volAvg + close (777) + call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) + read (777,rec=1) C_volAvgLastInc + close (777) + call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) + read (777,rec=1) C_minMaxAvg + close (777) + endif readRestart + + call Utilities_updateGamma(C_minMaxAvg,.True.) + C_scale = C_minMaxAvg + S_scale = math_invSym3333(C_minMaxAvg) + +end subroutine Polarisation_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the Polarisation scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function & + Polarisation_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) + use IO, only: & + IO_error + use numerics, only: & + update_gamma + use math, only: & + math_invSym3333 + use spectral_utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use FEsolving, only: & + restartWrite, & + terminallyIll + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + logical, intent(in) :: & + guess + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + character(len=*), intent(in) :: & + incInfoIn + real(pReal), dimension(3,3), intent(in) :: rotation_BC + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + incInfo = incInfoIn + +!-------------------------------------------------------------------------------------------------- +! update stiffness (and gamma operator) + S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) + if (update_gamma) then + call Utilities_updateGamma(C_minMaxAvg,restartWrite) + C_scale = C_minMaxAvg + S_scale = math_invSym3333(C_minMaxAvg) + endif + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + mask_stress = P_BC%maskFloat + params%P_BC = P_BC%values + params%rotation_BC = rotation_BC + params%timeinc = timeinc + params%timeincOld = timeinc_old + +!-------------------------------------------------------------------------------------------------- +! solve BVP + call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) + CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! check convergence + call SNESGetConvergedReason(snes,reason,ierr) + CHKERRQ(ierr) + Polarisation_solution%termIll = terminallyIll + terminallyIll = .false. + if (reason == -4) call IO_error(893_pInt) + if (reason < 1) Polarisation_solution%converged = .false. + Polarisation_solution%iterationsNeeded = totalIter + +end function Polarisation_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the Polarisation residual vector +!-------------------------------------------------------------------------------------------------- +subroutine Polarisation_formResidual(in,x_scal,f_scal,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + polarAlpha, & + polarBeta, & + worldrank + use mesh, only: & + grid3, & + grid + use IO, only: & + IO_intOut + use math, only: & + math_rotate_backward33, & + math_transpose33, & + math_mul3333xx33, & + math_invSym3333, & + math_mul33x33 + use spectral_utilities, only: & + wgt, & + tensorField_real, & + utilities_FFTtensorForward, & + utilities_fourierGammaConvolution, & + utilities_FFTtensorBackward, & + Utilities_constitutiveResponse, & + Utilities_divergenceRMS, & + Utilities_curlRMS + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRotation + use homogenization, only: & + materialpoint_dPdF + use FEsolving, only: & + terminallyIll + + implicit none +!-------------------------------------------------------------------------------------------------- +! strange syntax in the next line because otherwise macros expand beyond 132 character limit + DMDALocalInfo, dimension(& + DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, target, dimension(3,3,2, & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, target, dimension(3,3,2, & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscScalar, pointer, dimension(:,:,:,:,:) :: & + F, & + F_tau, & + residual_F, & + residual_F_tau + PetscInt :: & + PETScIter, & + nfuncs + PetscObject :: dummy + PetscErrorCode :: ierr + integer(pInt) :: & + i, j, k, e + + F => x_scal(1:3,1:3,1,& + XG_RANGE,YG_RANGE,ZG_RANGE) + F_tau => x_scal(1:3,1:3,2,& + XG_RANGE,YG_RANGE,ZG_RANGE) + residual_F => f_scal(1:3,1:3,1,& + X_RANGE,Y_RANGE,Z_RANGE) + residual_F_tau => f_scal(1:3,1:3,2,& + X_RANGE,Y_RANGE,Z_RANGE) + + call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) + call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) + + F_av = sum(sum(sum(F,dim=5),dim=4),dim=3) * wgt + call MPI_Allreduce(MPI_IN_PLACE,F_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + + if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment + newIteration: if(totalIter <= PETScIter) then +!-------------------------------------------------------------------------------------------------- +! report begin of new iteration + totalIter = totalIter + 1_pInt + if (worldrank == 0_pInt) then + write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & + ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax + if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & + math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & + math_transpose33(F_aim) + flush(6) + endif + endif newIteration + +!-------------------------------------------------------------------------------------------------- +! + tensorField_real = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) + tensorField_real(1:3,1:3,i,j,k) = & + polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& + polarAlpha*math_mul33x33(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)) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! doing convolution in Fourier space + call utilities_FFTtensorForward() + call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) + call utilities_FFTtensorBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + residual_F_tau = polarBeta*F - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) + +!-------------------------------------------------------------------------------------------------- +! evaluate constitutive response + P_avLastEval = P_av + call Utilities_constitutiveResponse(F_lastInc,F - residual_F_tau/polarBeta,params%timeinc, & + residual_F,C_volAvg,C_minMaxAvg,P_av,ForwardData,params%rotation_BC) + call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) + ForwardData = .False. + +!-------------------------------------------------------------------------------------------------- +! calculate divergence + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = residual_F + call utilities_FFTtensorForward() + err_div = Utilities_divergenceRMS() + call utilities_FFTtensorBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + e = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) + e = e + 1_pInt + residual_F(1:3,1:3,i,j,k) = & + math_mul3333xx33(math_invSym3333(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & + residual_F(1:3,1:3,i,j,k) - math_mul33x33(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) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! calculating curl + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F + call utilities_FFTtensorForward() + err_curl = Utilities_curlRMS() + call utilities_FFTtensorBackward() + +end subroutine Polarisation_formResidual + + +!-------------------------------------------------------------------------------------------------- +!> @brief convergence check +!-------------------------------------------------------------------------------------------------- +subroutine Polarisation_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + err_div_tolRel, & + err_div_tolAbs, & + err_curl_tolRel, & + err_curl_tolAbs, & + err_stress_tolAbs, & + err_stress_tolRel, & + worldrank + use math, only: & + math_mul3333xx33 + use FEsolving, only: & + terminallyIll + + implicit none + SNES :: snes_local + PetscInt :: PETScIter + PetscReal :: & + xnorm, & + snorm, & + fnorm + SNESConvergedReason :: reason + PetscObject :: dummy + PetscErrorCode ::ierr + real(pReal) :: & + curlTol, & + divTol, & + BC_tol + +!-------------------------------------------------------------------------------------------------- +! stress BC handling + F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc + err_BC = maxval(abs((-mask_stress+1.0_pReal)*math_mul3333xx33(C_scale,F_aim-F_av) + & + mask_stress *(P_av - params%P_BC))) ! mask = 0.0 for no bc + +!-------------------------------------------------------------------------------------------------- +! error calculation + curlTol = max(maxval(abs(F_aim-math_I3))*err_curl_tolRel,err_curl_tolAbs) + divTol = max(maxval(abs(P_av)) *err_div_tolRel,err_div_tolAbs) + BC_tol = max(maxval(abs(P_av)) *err_stress_tolrel,err_stress_tolabs) + + converged: if ((totalIter >= itmin .and. & + all([ err_div/divTol, & + err_curl/curlTol, & + err_BC/BC_tol ] < 1.0_pReal)) & + .or. terminallyIll) then + reason = 1 + elseif (totalIter >= itmax) then converged + reason = -1 + else converged + reason = 0 + endif converged + +!-------------------------------------------------------------------------------------------------- +! report +if (worldrank == 0_pInt) then + write(6,'(1/,a)') ' ... reporting .............................................................' + write(6,'(/,a,f12.2,a,es8.2,a,es9.2,a)') ' error curl = ', & + err_curl/curlTol,' (',err_curl,' -, tol =',curlTol,')' + write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & + err_div/divTol, ' (',err_div, ' / m, tol =',divTol,')' + write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error BC = ', & + err_BC/BC_tol, ' (',err_BC, ' Pa, tol =',BC_tol,')' + write(6,'(/,a)') ' ===========================================================================' + flush(6) +endif + +end subroutine Polarisation_converged + +!-------------------------------------------------------------------------------------------------- +!> @brief forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine Polarisation_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) + use math, only: & + math_mul33x33, & + math_mul3333xx33, & + math_transpose33, & + math_rotate_backward33 + use numerics, only: & + worldrank + use mesh, only: & + grid3, & + grid + use spectral_utilities, only: & + Utilities_calculateRate, & + Utilities_forwardField, & + Utilities_updateIPcoords, & + tBoundaryCondition, & + cutBack + use IO, only: & + IO_write_JobRealFile + use FEsolving, only: & + restartWrite + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + real(pReal), dimension(3,3), intent(in) :: rotation_BC + logical, intent(in) :: & + guess + PetscErrorCode :: ierr + PetscScalar, dimension(:,:,:,:), pointer :: xx_psc, F, F_tau + integer(pInt) :: i, j, k + real(pReal), dimension(3,3) :: F_lambda33 + character(len=1024) :: rankStr + +!-------------------------------------------------------------------------------------------------- +! update coordinates and rate and forward last inc + call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr) + F => xx_psc(0:8,:,:,:) + F_tau => xx_psc(9:17,:,:,:) + if (restartWrite) then + if (worldrank == 0_pInt) write(6,'(/,a)') ' writing converged results for restart' + flush(6) + write(rankStr,'(a1,i0)')'_',worldrank + call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file + write (777,rec=1) F + close (777) + call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file + write (777,rec=1) F_lastInc + close (777) + call IO_write_jobRealFile(777,'F_tau'//trim(rankStr),size(F_tau)) ! writing deformation gradient field to file + write (777,rec=1) F_tau + close (777) + call IO_write_jobRealFile(777,'F_tau_lastInc'//trim(rankStr),size(F_tau_lastInc)) ! writing F_lastInc field to file + write (777,rec=1) F_tau_lastInc + close (777) + if (worldrank == 0_pInt) then + call IO_write_jobRealFile(777,'F_aim',size(F_aim)) + write (777,rec=1) F_aim + close(777) + call IO_write_jobRealFile(777,'F_aim_lastInc',size(F_aim_lastInc)) + write (777,rec=1) F_aim_lastInc + close (777) + call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) + write (777,rec=1) F_aimDot + close(777) + call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) + write (777,rec=1) C_volAvg + close(777) + call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) + write (777,rec=1) C_volAvgLastInc + close(777) + endif + endif + call utilities_updateIPcoords(F) + + if (cutBack) then + F_aim = F_aim_lastInc + F_tau= reshape(F_tau_lastInc,[9,grid(1),grid(2),grid3]) + F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) + C_volAvg = C_volAvgLastInc + else + ForwardData = .True. + C_volAvgLastInc = C_volAvg +!-------------------------------------------------------------------------------------------------- +! calculate rate for aim + if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F + f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) + elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed + f_aimDot = F_BC%maskFloat * F_BC%values + elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed + f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime + endif + if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old + F_aim_lastInc = F_aim + +!-------------------------------------------------------------------------------------------------- +! update coordinates and rate and forward last inc + call utilities_updateIPcoords(F) + Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & + timeinc_old,guess,F_lastInc, & + reshape(F,[3,3,grid(1),grid(2),grid3])) + F_tauDot = Utilities_calculateRate(math_rotate_backward33(2.0_pReal*f_aimDot,rotation_BC), & + timeinc_old,guess,F_tau_lastInc, & + reshape(F_tau,[3,3,grid(1),grid(2),grid3])) + F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) + F_tau_lastInc = reshape(F_tau,[3,3,grid(1),grid(2),grid3]) + endif + + F_aim = F_aim + f_aimDot * timeinc + +!-------------------------------------------------------------------------------------------------- +! update local deformation gradient + F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim + math_rotate_backward33(F_aim,rotation_BC)), & + [9,grid(1),grid(2),grid3]) + F_tau = reshape(Utilities_forwardField(timeinc,F_tau_lastInc,F_taudot), & ! does not have any average value as boundary condition + [9,grid(1),grid(2),grid3]) + if (.not. guess) then ! large strain forwarding + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, 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,math_mul33x33(F_lambda33, & + math_mul3333xx33(C_scale,& + math_mul33x33(math_transpose33(F_lambda33),& + F_lambda33) -math_I3))*0.5_pReal)& + + 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,xx_psc,ierr); CHKERRQ(ierr) + +end subroutine Polarisation_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine Polarisation_destroy() + use spectral_utilities, only: & + Utilities_destroy + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) + call SNESDestroy(snes,ierr); CHKERRQ(ierr) + call DMDestroy(da,ierr); CHKERRQ(ierr) + +end subroutine Polarisation_destroy + +end module spectral_mech_Polarisation diff --git a/code/spectral/spectral_thermal.f90 b/code/spectral/spectral_thermal.f90 new file mode 100644 index 000000000..843642394 --- /dev/null +++ b/code/spectral/spectral_thermal.f90 @@ -0,0 +1,419 @@ +!-------------------------------------------------------------------------------------------------- +! $Id: spectral_thermal.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Shaokang Zhang, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Spectral solver for thermal conduction +!-------------------------------------------------------------------------------------------------- +module spectral_thermal + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + use numerics, only: & + worldrank, & + worldsize + + implicit none + private +#include + + character (len=*), parameter, public :: & + spectral_thermal_label = 'spectralthermal' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + +!-------------------------------------------------------------------------------------------------- +! PETSc data + SNES, private :: thermal_snes + Vec, private :: solution + PetscInt, private :: xstart, xend, ystart, yend, zstart, zend + real(pReal), private, dimension(:,:,:), allocatable :: & + temperature_current, & !< field of current temperature + temperature_lastInc, & !< field of previous temperature + temperature_stagInc !< field of staggered temperature + +!-------------------------------------------------------------------------------------------------- +! reference diffusion tensor, mobility etc. + integer(pInt), private :: totalIter = 0_pInt !< total iteration in current increment + real(pReal), dimension(3,3), private :: D_ref + real(pReal), private :: mobility_ref + character(len=1024), private :: incInfo + + public :: & + spectral_thermal_init, & + spectral_thermal_solution, & + spectral_thermal_forward, & + spectral_thermal_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use spectral_utilities, only: & + wgt + use mesh, only: & + grid, & + grid3 + use thermal_conduction, only: & + thermal_conduction_getConductivity33, & + thermal_conduction_getMassDensity, & + thermal_conduction_getSpecificHeat + use material, only: & + mappingHomogenization, & + temperature, & + thermalMapping + + implicit none + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + integer(pInt) :: i, j, k, cell + DM :: thermal_grid + PetscScalar, pointer :: x_scal(:,:,:) + PetscErrorCode :: ierr + PetscObject :: dummy + + mainProcess: if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- spectral_thermal init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! initialize solver specific parts of PETSc + call SNESCreate(PETSC_COMM_WORLD,thermal_snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(thermal_snes,'thermal_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary + DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & ! global grid + 1, 1, worldsize, & + 1, 0, & ! #dof (temperature field), ghost boundary width (domain overlap) + grid (1),grid(2),localK, & ! local grid + thermal_grid,ierr) ! handle, error + CHKERRQ(ierr) + call SNESSetDM(thermal_snes,thermal_grid,ierr); CHKERRQ(ierr) ! connect snes to da + call DMCreateGlobalVector(thermal_grid,solution ,ierr); CHKERRQ(ierr) ! global solution vector (grid x 1, i.e. every def grad tensor) + call DMDASNESSetFunctionLocal(thermal_grid,INSERT_VALUES,spectral_thermal_formResidual,dummy,ierr) ! residual vector of same shape as solution vector + CHKERRQ(ierr) + call SNESSetFromOptions(thermal_snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAGetCorners(thermal_grid,xstart,ystart,zstart,xend,yend,zend,ierr) + CHKERRQ(ierr) + xend = xstart + xend - 1 + yend = ystart + yend - 1 + zend = zstart + zend - 1 + allocate(temperature_current(grid(1),grid(2),grid3), source=0.0_pReal) + allocate(temperature_lastInc(grid(1),grid(2),grid3), source=0.0_pReal) + allocate(temperature_stagInc(grid(1),grid(2),grid3), source=0.0_pReal) + cell = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + temperature_current(i,j,k) = temperature(mappingHomogenization(2,1,cell))% & + p(thermalMapping(mappingHomogenization(2,1,cell))%p(1,cell)) + temperature_lastInc(i,j,k) = temperature_current(i,j,k) + temperature_stagInc(i,j,k) = temperature_current(i,j,k) + enddo; enddo; enddo + call DMDAVecGetArrayF90(thermal_grid,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with + x_scal(xstart:xend,ystart:yend,zstart:zend) = temperature_current + call DMDAVecRestoreArrayF90(thermal_grid,solution,x_scal,ierr); CHKERRQ(ierr) + + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + D_ref = D_ref + thermal_conduction_getConductivity33(1,cell) + mobility_ref = mobility_ref + thermal_conduction_getMassDensity(1,cell)* & + thermal_conduction_getSpecificHeat(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + +end subroutine spectral_thermal_init + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the Basic PETSC scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function spectral_thermal_solution(guess,timeinc,timeinc_old,loadCaseTime) + use numerics, only: & + itmax, & + err_thermal_tolAbs, & + err_thermal_tolRel + use spectral_utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use mesh, only: & + grid, & + grid3 + use thermal_conduction, only: & + thermal_conduction_putTemperatureAndItsRate + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + integer(pInt) :: i, j, k, cell + PetscInt :: position + PetscReal :: minTemperature, maxTemperature, stagNorm, solnNorm + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + spectral_thermal_solution%converged =.false. + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + params%timeinc = timeinc + params%timeincOld = timeinc_old + + call SNESSolve(thermal_snes,PETSC_NULL_OBJECT,solution,ierr); CHKERRQ(ierr) + call SNESGetConvergedReason(thermal_snes,reason,ierr); CHKERRQ(ierr) + + if (reason < 1) then + spectral_thermal_solution%converged = .false. + spectral_thermal_solution%iterationsNeeded = itmax + else + spectral_thermal_solution%converged = .true. + spectral_thermal_solution%iterationsNeeded = totalIter + endif + stagNorm = maxval(abs(temperature_current - temperature_stagInc)) + solnNorm = maxval(abs(temperature_current)) + call MPI_Allreduce(MPI_IN_PLACE,stagNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + call MPI_Allreduce(MPI_IN_PLACE,solnNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + temperature_stagInc = temperature_current + spectral_thermal_solution%stagConverged = stagNorm < err_thermal_tolAbs & + .or. stagNorm < err_thermal_tolRel*solnNorm + +!-------------------------------------------------------------------------------------------------- +! updating thermal state + cell = 0_pInt !< material point = 0 + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt !< material point increase + call thermal_conduction_putTemperatureAndItsRate(temperature_current(i,j,k), & + (temperature_current(i,j,k)-temperature_lastInc(i,j,k))/params%timeinc, & + 1,cell) + enddo; enddo; enddo + + call VecMin(solution,position,minTemperature,ierr); CHKERRQ(ierr) + call VecMax(solution,position,maxTemperature,ierr); CHKERRQ(ierr) + if (worldrank == 0) then + if (spectral_thermal_solution%converged) & + write(6,'(/,a)') ' ... thermal conduction converged ..................................' + write(6,'(/,a,f8.4,2x,f8.4,2x,f8.4,/)',advance='no') ' Minimum|Maximum|Delta Temperature = ',& + minTemperature, maxTemperature, stagNorm + write(6,'(/,a)') ' ===========================================================================' + flush(6) + endif + +end function spectral_thermal_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the spectral thermal residual vector +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_formResidual(in,x_scal,f_scal,dummy,ierr) + use mesh, only: & + grid, & + grid3 + use math, only: & + math_mul33x3 + use spectral_utilities, only: & + scalarField_real, & + vectorField_real, & + utilities_FFTvectorForward, & + utilities_FFTvectorBackward, & + utilities_FFTscalarForward, & + utilities_FFTscalarBackward, & + utilities_fourierGreenConvolution, & + utilities_fourierScalarGradient, & + utilities_fourierVectorDivergence + use thermal_conduction, only: & + thermal_conduction_getSourceAndItsTangent, & + thermal_conduction_getConductivity33, & + thermal_conduction_getMassDensity, & + thermal_conduction_getSpecificHeat + + implicit none + DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, dimension( & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, dimension( & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscObject :: dummy + PetscErrorCode :: ierr + integer(pInt) :: i, j, k, cell + real(pReal) :: Tdot, dTdot_dT + + temperature_current = x_scal +!-------------------------------------------------------------------------------------------------- +! evaluate polarization field + scalarField_real = 0.0_pReal + scalarField_real(1:grid(1),1:grid(2),1:grid3) = temperature_current + call utilities_FFTscalarForward() + call utilities_fourierScalarGradient() !< calculate gradient of damage field + call utilities_FFTvectorBackward() + cell = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + vectorField_real(1:3,i,j,k) = math_mul33x3(thermal_conduction_getConductivity33(1,cell) - D_ref, & + vectorField_real(1:3,i,j,k)) + enddo; enddo; enddo + call utilities_FFTvectorForward() + call utilities_fourierVectorDivergence() !< calculate damage divergence in fourier field + call utilities_FFTscalarBackward() + cell = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + call thermal_conduction_getSourceAndItsTangent(Tdot, dTdot_dT, temperature_current(i,j,k), 1, cell) + scalarField_real(i,j,k) = params%timeinc*scalarField_real(i,j,k) + & + params%timeinc*Tdot + & + thermal_conduction_getMassDensity (1,cell)* & + thermal_conduction_getSpecificHeat(1,cell)*(temperature_lastInc(i,j,k) - & + temperature_current(i,j,k)) + & + mobility_ref*temperature_current(i,j,k) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! convolution of damage field with green operator + call utilities_FFTscalarForward() + call utilities_fourierGreenConvolution(D_ref, mobility_ref, params%timeinc) + call utilities_FFTscalarBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + f_scal = temperature_current - scalarField_real(1:grid(1),1:grid(2),1:grid3) + +end subroutine spectral_thermal_formResidual + +!-------------------------------------------------------------------------------------------------- +!> @brief forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_forward(guess,timeinc,timeinc_old,loadCaseTime) + use mesh, only: & + grid, & + grid3 + use spectral_utilities, only: & + cutBack, & + wgt + use thermal_conduction, only: & + thermal_conduction_putTemperatureAndItsRate, & + thermal_conduction_getConductivity33, & + thermal_conduction_getMassDensity, & + thermal_conduction_getSpecificHeat + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + integer(pInt) :: i, j, k, cell + DM :: dm_local + PetscScalar, pointer :: x_scal(:,:,:) + PetscErrorCode :: ierr + + if (cutBack) then + temperature_current = temperature_lastInc + temperature_stagInc = temperature_lastInc + +!-------------------------------------------------------------------------------------------------- +! reverting thermal field state + cell = 0_pInt !< material point = 0 + call SNESGetDM(thermal_snes,dm_local,ierr); CHKERRQ(ierr) + call DMDAVecGetArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with + x_scal(xstart:xend,ystart:yend,zstart:zend) = temperature_current + call DMDAVecRestoreArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt !< material point increase + call thermal_conduction_putTemperatureAndItsRate(temperature_current(i,j,k), & + (temperature_current(i,j,k) - & + temperature_lastInc(i,j,k))/params%timeinc, & + 1,cell) + enddo; enddo; enddo + else +!-------------------------------------------------------------------------------------------------- +! update rate and forward last inc + temperature_lastInc = temperature_current + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + D_ref = D_ref + thermal_conduction_getConductivity33(1,cell) + mobility_ref = mobility_ref + thermal_conduction_getMassDensity(1,cell)* & + thermal_conduction_getSpecificHeat(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + endif + + end subroutine spectral_thermal_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_destroy() + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution,ierr); CHKERRQ(ierr) + call SNESDestroy(thermal_snes,ierr); CHKERRQ(ierr) + +end subroutine spectral_thermal_destroy + +end module spectral_thermal diff --git a/code/spectral/spectral_utilities.f90 b/code/spectral/spectral_utilities.f90 new file mode 100644 index 000000000..bde088ccb --- /dev/null +++ b/code/spectral/spectral_utilities.f90 @@ -0,0 +1,1262 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Utilities used by the different spectral solver variants +!-------------------------------------------------------------------------------------------------- +module spectral_utilities + use, intrinsic :: iso_c_binding + use prec, only: & + pReal, & + pInt + use math, only: & + math_I3 + + implicit none + private +#include + include 'fftw3-mpi.f03' + + logical, public :: cutBack =.false. !< cut back of BVP solver in case convergence is not achieved or a material point is terminally ill + integer(pInt), public, parameter :: maxPhaseFields = 2_pInt + integer(pInt), public :: nActiveFields = 0_pInt + +!-------------------------------------------------------------------------------------------------- +! field labels information + enum, bind(c) + enumerator :: FIELD_UNDEFINED_ID, & + FIELD_MECH_ID, & + FIELD_THERMAL_ID, & + FIELD_DAMAGE_ID, & + FIELD_VACANCYDIFFUSION_ID + end enum + +!-------------------------------------------------------------------------------------------------- +! grid related information information + real(pReal), public :: wgt !< weighting factor 1/Nelems + +!-------------------------------------------------------------------------------------------------- +! variables storing information for spectral method and FFTW + integer(pInt), public :: grid1Red !< grid(1)/2 + real (C_DOUBLE), public, dimension(:,:,:,:,:), pointer :: tensorField_real !< real representation (some stress or deformation) of field_fourier + complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:,:), pointer :: tensorField_fourier !< field on which the Fourier transform operates + real(C_DOUBLE), public, dimension(:,:,:,:), pointer :: vectorField_real !< vector field real representation for fftw + complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:), pointer :: vectorField_fourier !< vector field fourier representation for fftw + real(C_DOUBLE), public, dimension(:,:,:), pointer :: scalarField_real !< scalar field real representation for fftw + complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:), pointer :: scalarField_fourier !< scalar field fourier representation for fftw + complex(pReal), private, dimension(:,:,:,:,:,:,:), allocatable :: gamma_hat !< gamma operator (field) for spectral method + complex(pReal), private, dimension(:,:,:,:), allocatable :: xi1st !< wave vector field for first derivatives + complex(pReal), private, dimension(:,:,:,:), allocatable :: xi2nd !< wave vector field for second derivatives + real(pReal), private, dimension(3,3,3,3) :: C_ref !< mechanic reference stiffness + real(pReal), protected, public, dimension(3) :: scaledGeomSize !< scaled geometry size for calculation of divergence (Basic, Basic PETSc) + +!-------------------------------------------------------------------------------------------------- +! plans for FFTW + type(C_PTR), private :: & + planTensorForth, & !< FFTW MPI plan P(x) to P(k) + planTensorBack, & !< FFTW MPI plan F(k) to F(x) + planVectorForth, & !< FFTW MPI plan v(x) to v(k) + planVectorBack, & !< FFTW MPI plan v(k) to v(x) + planScalarForth, & !< FFTW MPI plan s(x) to s(k) + planScalarBack !< FFTW MPI plan s(k) to s(x) + +!-------------------------------------------------------------------------------------------------- +! variables controlling debugging + logical, private :: & + debugGeneral, & !< general debugging of spectral solver + debugRotation, & !< also printing out results in lab frame + debugPETSc !< use some in debug defined options for more verbose PETSc solution + +!-------------------------------------------------------------------------------------------------- +! derived types + type, public :: tSolutionState !< return type of solution from spectral solver variants + logical :: converged = .true. + logical :: regrid = .false. + logical :: stagConverged = .true. + logical :: termIll = .false. + integer(pInt) :: iterationsNeeded = 0_pInt + end type tSolutionState + + type, public :: tBoundaryCondition !< set of parameters defining a boundary condition + real(pReal), dimension(3,3) :: values = 0.0_pReal + real(pReal), dimension(3,3) :: maskFloat = 0.0_pReal + logical, dimension(3,3) :: maskLogical = .false. + character(len=64) :: myType = 'None' + end type tBoundaryCondition + + type, public :: tLoadCase + real(pReal), dimension (3,3) :: rotation = math_I3 !< rotation of BC + type(tBoundaryCondition) :: P, & !< stress BC + deformation !< deformation BC (Fdot or L) + real(pReal) :: time = 0.0_pReal !< length of increment + integer(pInt) :: incs = 0_pInt, & !< number of increments + outputfrequency = 1_pInt, & !< frequency of result writes + restartfrequency = 0_pInt, & !< frequency of restart writes + logscale = 0_pInt !< linear/logarithmic time inc flag + logical :: followFormerTrajectory = .true. !< follow trajectory of former loadcase + integer(kind(FIELD_UNDEFINED_ID)), allocatable :: ID(:) + end type tLoadCase + + type, public :: tSolutionParams !< @todo use here the type definition for a full loadcase including mask + real(pReal), dimension(3,3) :: P_BC, rotation_BC + real(pReal) :: timeinc + real(pReal) :: timeincOld + real(pReal) :: density + end type tSolutionParams + + type(tSolutionParams), private :: params + + type, public :: phaseFieldDataBin !< set of parameters defining a phase field + real(pReal) :: diffusion = 0.0_pReal, & !< thermal conductivity + mobility = 0.0_pReal, & !< thermal mobility + phaseField0 = 0.0_pReal !< homogeneous damage field starting condition + logical :: active = .false. + character(len=64) :: label = '' + end type phaseFieldDataBin + + enum, bind(c) + enumerator :: DERIVATIVE_CONTINUOUS_ID, & + DERIVATIVE_CENTRAL_DIFF_ID, & + DERIVATIVE_FWBW_DIFF_ID + end enum + integer(kind(DERIVATIVE_CONTINUOUS_ID)) :: & + spectral_derivative_ID + + public :: & + utilities_init, & + utilities_updateGamma, & + utilities_FFTtensorForward, & + utilities_FFTtensorBackward, & + utilities_FFTvectorForward, & + utilities_FFTvectorBackward, & + utilities_FFTscalarForward, & + utilities_FFTscalarBackward, & + utilities_fourierGammaConvolution, & + utilities_fourierGreenConvolution, & + utilities_divergenceRMS, & + utilities_curlRMS, & + utilities_fourierScalarGradient, & + utilities_fourierVectorDivergence, & + utilities_fourierVectorGradient, & + utilities_fourierTensorDivergence, & + utilities_maskedCompliance, & + utilities_constitutiveResponse, & + utilities_calculateRate, & + utilities_forwardField, & + utilities_destroy, & + utilities_updateIPcoords, & + FIELD_UNDEFINED_ID, & + FIELD_MECH_ID, & + FIELD_THERMAL_ID, & + FIELD_DAMAGE_ID + private :: & + utilities_getFreqDerivative + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, sets debug flags, create plans for FFTW +!> @details Sets the debug levels for general, divergence, restart and FFTW from the biwise coding +!> provided by the debug module to logicals. +!> Allocates all fields used by FFTW and create the corresponding plans depending on the debug +!> level chosen. +!> Initializes FFTW. +!-------------------------------------------------------------------------------------------------- +subroutine utilities_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_error, & + IO_warning, & + IO_timeStamp, & + IO_open_file + use numerics, only: & + spectral_derivative, & + fftw_planner_flag, & + fftw_timelimit, & + memory_efficient, & + petsc_defaultOptions, & + petsc_options, & + divergence_correction, & + worldrank + use debug, only: & + debug_level, & + debug_SPECTRAL, & + debug_LEVELBASIC, & + debug_SPECTRALDIVERGENCE, & + debug_SPECTRALFFTW, & + debug_SPECTRALPETSC, & + debug_SPECTRALROTATION + use debug, only: & + PETSCDEBUG + use math + use mesh, only: & + grid, & + grid3, & + grid3Offset, & + geomSize + + implicit none + + external :: & + PETScOptionsClear, & + PETScOptionsInsertString, & + MPI_Abort + + PetscErrorCode :: ierr + integer(pInt) :: i, j, k + integer(pInt), dimension(3) :: k_s + type(C_PTR) :: & + tensorField, & !< field containing data for FFTW in real and fourier space (in place) + vectorField, & !< field containing data for FFTW in real space when debugging FFTW (no in place) + scalarField !< field containing data for FFTW in real space when debugging FFTW (no in place) + integer(C_INTPTR_T), dimension(3) :: gridFFTW + integer(C_INTPTR_T) :: alloc_local, local_K, local_K_offset + integer(C_INTPTR_T), parameter :: & + scalarSize = 1_C_INTPTR_T, & + vecSize = 3_C_INTPTR_T, & + tensorSize = 9_C_INTPTR_T + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- spectral_utilities init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! set debugging parameters + debugGeneral = iand(debug_level(debug_SPECTRAL),debug_LEVELBASIC) /= 0 + debugRotation = iand(debug_level(debug_SPECTRAL),debug_SPECTRALROTATION) /= 0 + debugPETSc = iand(debug_level(debug_SPECTRAL),debug_SPECTRALPETSC) /= 0 + + if(debugPETSc .and. worldrank == 0_pInt) write(6,'(3(/,a),/)') & + ' Initializing PETSc with debug options: ', & + trim(PETScDebug), & + ' add more using the PETSc_Options keyword in numerics.config ' + flush(6) + call PetscOptionsClear(ierr); CHKERRQ(ierr) + if(debugPETSc) call PetscOptionsInsertString(trim(PETSCDEBUG),ierr); CHKERRQ(ierr) + call PetscOptionsInsertString(trim(petsc_defaultOptions),ierr); CHKERRQ(ierr) + call PetscOptionsInsertString(trim(petsc_options),ierr); CHKERRQ(ierr) + + grid1Red = grid(1)/2_pInt + 1_pInt + wgt = 1.0/real(product(grid),pReal) + + if (worldrank == 0) then + write(6,'(a,3(i12 ))') ' grid a b c: ', grid + write(6,'(a,3(es12.5))') ' size x y z: ', geomSize + endif + + select case (spectral_derivative) + case ('continuous') ! default, no weighting + spectral_derivative_ID = DERIVATIVE_CONTINUOUS_ID + case ('central_difference') ! cosine curve with 1 for avg and zero for highest freq + spectral_derivative_ID = DERIVATIVE_CENTRAL_DIFF_ID + case ('fwbw_difference') ! gradient, might need grid scaling as for cosine filter + spectral_derivative_ID = DERIVATIVE_FWBW_DIFF_ID + case default + call IO_error(892_pInt,ext_msg=trim(spectral_derivative)) + end select + +!-------------------------------------------------------------------------------------------------- +! scale dimension to calculate either uncorrected, dimension-independent, or dimension- and +! resolution-independent divergence + if (divergence_correction == 1_pInt) then + do j = 1_pInt, 3_pInt + if (j /= minloc(geomSize,1) .and. j /= maxloc(geomSize,1)) & + scaledGeomSize = geomSize/geomSize(j) + enddo + elseif (divergence_correction == 2_pInt) then + do j = 1_pInt, 3_pInt + if (j /= minloc(geomSize/grid,1) .and. j /= maxloc(geomSize/grid,1)) & + scaledGeomSize = geomSize/geomSize(j)*grid(j) + enddo + else + scaledGeomSize = geomSize + endif + + +!-------------------------------------------------------------------------------------------------- +! MPI allocation + gridFFTW = int(grid,C_INTPTR_T) + alloc_local = fftw_mpi_local_size_3d(gridFFTW(3), gridFFTW(2), gridFFTW(1)/2 +1, & + MPI_COMM_WORLD, local_K, local_K_offset) + allocate (xi1st (3,grid1Red,grid(2),grid3),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies, only half the size for first dimension + allocate (xi2nd (3,grid1Red,grid(2),grid3),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies, only half the size for first dimension + + tensorField = fftw_alloc_complex(tensorSize*alloc_local) + call c_f_pointer(tensorField, tensorField_real, [3_C_INTPTR_T,3_C_INTPTR_T, & + 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real tensor representation + call c_f_pointer(tensorField, tensorField_fourier, [3_C_INTPTR_T,3_C_INTPTR_T, & + gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T , gridFFTW(2),local_K]) ! place a pointer for a fourier tensor representation + + vectorField = fftw_alloc_complex(vecSize*alloc_local) + call c_f_pointer(vectorField, vectorField_real, [3_C_INTPTR_T,& + 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real vector representation + call c_f_pointer(vectorField, vectorField_fourier,[3_C_INTPTR_T,& + gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T, gridFFTW(2),local_K]) ! place a pointer for a fourier vector representation + + scalarField = fftw_alloc_complex(scalarSize*alloc_local) ! allocate data for real representation (no in place transform) + call c_f_pointer(scalarField, scalarField_real, & + [2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1),gridFFTW(2),local_K]) ! place a pointer for a real scalar representation + call c_f_pointer(scalarField, scalarField_fourier, & + [ gridFFTW(1)/2_C_INTPTR_T + 1 ,gridFFTW(2),local_K]) ! place a pointer for a fourier scarlar representation + +!-------------------------------------------------------------------------------------------------- +! tensor MPI fftw plans + planTensorForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock + tensorField_real, tensorField_fourier, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + if (.not. C_ASSOCIATED(planTensorForth)) call IO_error(810, ext_msg='planTensorForth') + planTensorBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock + tensorField_fourier,tensorField_real, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision + if (.not. C_ASSOCIATED(planTensorBack)) call IO_error(810, ext_msg='planTensorBack') + +!-------------------------------------------------------------------------------------------------- +! vector MPI fftw plans + planVectorForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock + vectorField_real, vectorField_fourier, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + if (.not. C_ASSOCIATED(planVectorForth)) call IO_error(810, ext_msg='planVectorForth') + planVectorBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock + vectorField_fourier,vectorField_real, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision + if (.not. C_ASSOCIATED(planVectorBack)) call IO_error(810, ext_msg='planVectorBack') + +!-------------------------------------------------------------------------------------------------- +! scalar MPI fftw plans + planScalarForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock + scalarField_real, scalarField_fourier, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + if (.not. C_ASSOCIATED(planScalarForth)) call IO_error(810, ext_msg='planScalarForth') + planScalarBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order, no. of transforms + scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock + scalarField_fourier,scalarField_real, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + if (.not. C_ASSOCIATED(planScalarBack)) call IO_error(810, ext_msg='planScalarBack') + +!-------------------------------------------------------------------------------------------------- +! general initialization of FFTW (see manual on fftw.org for more details) + if (pReal /= C_DOUBLE .or. pInt /= C_INT) call IO_error(0_pInt,ext_msg='Fortran to C') ! check for correct precision in C + call fftw_set_timelimit(fftw_timelimit) ! set timelimit for plan creation + + if (debugGeneral .and. worldrank == 0_pInt) write(6,'(/,a)') ' FFTW initialized' + flush(6) + +!-------------------------------------------------------------------------------------------------- +! calculation of discrete angular frequencies, ordered as in FFTW (wrap around) + do k = grid3Offset+1_pInt, grid3Offset+grid3 + k_s(3) = k - 1_pInt + if(k > grid(3)/2_pInt + 1_pInt) k_s(3) = k_s(3) - grid(3) ! running from 0,1,...,N/2,N/2+1,-N/2,-N/2+1,...,-1 + do j = 1_pInt, grid(2) + k_s(2) = j - 1_pInt + if(j > grid(2)/2_pInt + 1_pInt) k_s(2) = k_s(2) - grid(2) ! running from 0,1,...,N/2,N/2+1,-N/2,-N/2+1,...,-1 + do i = 1_pInt, grid1Red + k_s(1) = i - 1_pInt ! symmetry, junst running from 0,1,...,N/2,N/2+1 + xi2nd(1:3,i,j,k-grid3Offset) = utilities_getFreqDerivative(k_s) ! if divergence_correction is set, frequencies are calculated on unit length + where(mod(grid,2)==0 .and. [i,j,k] == grid/2+1 .and. & + spectral_derivative_ID == DERIVATIVE_CONTINUOUS_ID) ! for even grids, set the Nyquist Freq component to 0.0 + xi1st(1:3,i,j,k-grid3Offset) = cmplx(0.0_pReal,0.0_pReal,pReal) + elsewhere + xi1st(1:3,i,j,k-grid3Offset) = xi2nd(1:3,i,j,k-grid3Offset) + endwhere + enddo; enddo; enddo + + if(memory_efficient) then ! allocate just single fourth order tensor + allocate (gamma_hat(3,3,3,3,1,1,1), source = cmplx(0.0_pReal,0.0_pReal,pReal)) + else ! precalculation of gamma_hat field + allocate (gamma_hat(3,3,3,3,grid1Red,grid(2),grid3), source = cmplx(0.0_pReal,0.0_pReal,pReal)) + endif + +end subroutine utilities_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief updates references stiffness and potentially precalculated gamma operator +!> @details Sets the current reference stiffness to the stiffness given as an argument. +!> If the gamma operator is precalculated, it is calculated with this stiffness. +!> In case of a on-the-fly calculation, only the reference stiffness is updated. +!> Also writes out the current reference stiffness for restart. +!-------------------------------------------------------------------------------------------------- +subroutine utilities_updateGamma(C,saveReference) + use IO, only: & + IO_write_jobRealFile + use numerics, only: & + memory_efficient, & + worldrank + use mesh, only: & + grid3Offset, & + grid3,& + grid + use math, only: & + math_det33, & + math_invert + + implicit none + real(pReal), intent(in), dimension(3,3,3,3) :: C !< input stiffness to store as reference stiffness + logical , intent(in) :: saveReference !< save reference stiffness to file for restart + complex(pReal), dimension(3,3) :: temp33_complex, xiDyad_cmplx + real(pReal), dimension(6,6) :: matA, matInvA + integer(pInt) :: & + i, j, k, & + l, m, n, o + logical :: ierr + + C_ref = C + if (saveReference) then + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' writing reference stiffness to file' + flush(6) + call IO_write_jobRealFile(777,'C_ref',size(C_ref)) + write (777,rec=1) C_ref + close(777) + endif + endif + + if(.not. memory_efficient) then + gamma_hat = cmplx(0.0_pReal,0.0_pReal,pReal) ! for the singular point and any non invertible A + do k = grid3Offset+1_pInt, grid3Offset+grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid1Red + if (any([i,j,k] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + xiDyad_cmplx(l,m) = conjg(-xi1st(l,i,j,k-grid3Offset))*xi1st(m,i,j,k-grid3Offset) + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_complex(l,m) = sum(C_ref(l,1:3,m,1:3)*xiDyad_cmplx) + matA(1:3,1:3) = real(temp33_complex); matA(4:6,4:6) = real(temp33_complex) + matA(1:3,4:6) = aimag(temp33_complex); matA(4:6,1:3) = -aimag(temp33_complex) + if (abs(math_det33(matA(1:3,1:3))) > 1e-16) then + call math_invert(6_pInt, matA, matInvA, ierr) + temp33_complex = cmplx(matInvA(1:3,1:3),matInvA(1:3,4:6),pReal) + forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, o=1_pInt:3_pInt) & + gamma_hat(l,m,n,o,i,j,k-grid3Offset) = temp33_complex(l,n)* & + conjg(-xi1st(o,i,j,k-grid3Offset))*xi1st(m,i,j,k-grid3Offset) + endif + endif + enddo; enddo; enddo + endif + +end subroutine utilities_updateGamma + +!-------------------------------------------------------------------------------------------------- +!> @brief forward FFT of data in field_real to field_fourier +!> @details Does an unweighted filtered FFT transform from real to complex +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTtensorForward() + implicit none + +!-------------------------------------------------------------------------------------------------- +! doing the tensor FFT + call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) + +end subroutine utilities_FFTtensorForward + + +!-------------------------------------------------------------------------------------------------- +!> @brief backward FFT of data in field_fourier to field_real +!> @details Does an weighted inverse FFT transform from complex to real +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTtensorBackward() + implicit none + + call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real) + tensorField_real = tensorField_real * wgt ! normalize the result by number of elements + +end subroutine utilities_FFTtensorBackward + +!-------------------------------------------------------------------------------------------------- +!> @brief forward FFT of data in scalarField_real to scalarField_fourier +!> @details Does an unweighted filtered FFT transform from real to complex +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTscalarForward() + implicit none + +!-------------------------------------------------------------------------------------------------- +! doing the scalar FFT + call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier) + +end subroutine utilities_FFTscalarForward + + +!-------------------------------------------------------------------------------------------------- +!> @brief backward FFT of data in scalarField_fourier to scalarField_real +!> @details Does an weighted inverse FFT transform from complex to real +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTscalarBackward() + implicit none + + call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) + scalarField_real = scalarField_real * wgt ! normalize the result by number of elements + +end subroutine utilities_FFTscalarBackward + + +!-------------------------------------------------------------------------------------------------- +!> @brief forward FFT of data in field_real to field_fourier with highest freqs. removed +!> @details Does an unweighted filtered FFT transform from real to complex. +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTvectorForward() + implicit none + +!-------------------------------------------------------------------------------------------------- +! doing the vector FFT + call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier) + +end subroutine utilities_FFTvectorForward + + +!-------------------------------------------------------------------------------------------------- +!> @brief backward FFT of data in field_fourier to field_real +!> @details Does an weighted inverse FFT transform from complex to real +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTvectorBackward() + implicit none + + call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) + vectorField_real = vectorField_real * wgt ! normalize the result by number of elements + +end subroutine utilities_FFTvectorBackward + + +!-------------------------------------------------------------------------------------------------- +!> @brief doing convolution gamma_hat * field_real, ensuring that average value = fieldAim +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierGammaConvolution(fieldAim) + use numerics, only: & + memory_efficient + use math, only: & + math_det33, & + math_invert + use numerics, only: & + worldrank + use mesh, only: & + grid3, & + grid, & + grid3Offset + + implicit none + real(pReal), intent(in), dimension(3,3) :: fieldAim !< desired average value of the field after convolution + complex(pReal), dimension(3,3) :: temp33_complex, xiDyad_cmplx + real(pReal) :: matA(6,6), matInvA(6,6) + + integer(pInt) :: & + i, j, k, & + l, m, n, o + logical :: ierr + + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' ... doing gamma convolution ...............................................' + flush(6) + endif + +!-------------------------------------------------------------------------------------------------- +! do the actual spectral method calculation (mechanical equilibrium) + memoryEfficient: if(memory_efficient) then + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid1Red + if (any([i,j,k+grid3Offset] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + xiDyad_cmplx(l,m) = conjg(-xi1st(l,i,j,k))*xi1st(m,i,j,k) + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_complex(l,m) = sum(C_ref(l,1:3,m,1:3)*xiDyad_cmplx) + matA(1:3,1:3) = real(temp33_complex); matA(4:6,4:6) = real(temp33_complex) + matA(1:3,4:6) = aimag(temp33_complex); matA(4:6,1:3) = -aimag(temp33_complex) + if (abs(math_det33(matA(1:3,1:3))) > 1e-16) then + call math_invert(6_pInt, matA, matInvA, ierr) + temp33_complex = cmplx(matInvA(1:3,1:3),matInvA(1:3,4:6),pReal) + forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, o=1_pInt:3_pInt) & + gamma_hat(l,m,n,o,1,1,1) = temp33_complex(l,n)*conjg(-xi1st(o,i,j,k))*xi1st(m,i,j,k) + else + gamma_hat(1:3,1:3,1:3,1:3,1,1,1) = cmplx(0.0_pReal,0.0_pReal,pReal) + endif + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3,1,1,1)*tensorField_fourier(1:3,1:3,i,j,k)) + tensorField_fourier(1:3,1:3,i,j,k) = temp33_Complex + endif + enddo; enddo; enddo + else memoryEfficient + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3,i,j,k) * tensorField_fourier(1:3,1:3,i,j,k)) + tensorField_fourier(1:3,1:3,i,j,k) = temp33_Complex + enddo; enddo; enddo + endif memoryEfficient + + if (grid3Offset == 0_pInt) & + tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim/wgt,0.0_pReal,pReal) + +end subroutine utilities_fourierGammaConvolution + + +!-------------------------------------------------------------------------------------------------- +!> @brief doing convolution DamageGreenOp_hat * field_real +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierGreenConvolution(D_ref, mobility_ref, deltaT) + + use math, only: & + math_mul33x3, & + PI + use mesh, only: & + grid, & + grid3 + + implicit none + real(pReal), dimension(3,3), intent(in) :: D_ref !< desired average value of the field after convolution + real(pReal), intent(in) :: mobility_ref, deltaT !< desired average value of the field after convolution + complex(pReal) :: GreenOp_hat + integer(pInt) :: i, j, k + +!-------------------------------------------------------------------------------------------------- +! do the actual spectral method calculation + do k = 1_pInt, grid3; do j = 1_pInt, grid(2) ;do i = 1_pInt, grid1Red + GreenOp_hat = cmplx(1.0_pReal,0.0_pReal,pReal)/ & + (cmplx(mobility_ref,0.0_pReal,pReal) + & + deltaT*sum(conjg(xi1st(1:3,i,j,k))*matmul(D_ref,xi1st(1:3,i,j,k)))) ! why not use dot_product + scalarField_fourier(i,j,k) = scalarField_fourier(i,j,k)*GreenOp_hat + enddo; enddo; enddo + +end subroutine utilities_fourierGreenConvolution + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate root mean square of divergence of field_fourier +!-------------------------------------------------------------------------------------------------- +real(pReal) function utilities_divergenceRMS() + use numerics, only: & + worldrank + use mesh, only: & + geomSize, & + grid, & + grid3 + + implicit none + integer(pInt) :: i, j, k + PetscErrorCode :: ierr + + external :: & + MPI_Allreduce + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' ... calculating divergence ................................................' + flush(6) + endif + +!-------------------------------------------------------------------------------------------------- +! calculating RMS divergence criterion in Fourier space + utilities_divergenceRMS = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2) + do i = 2_pInt, grid1Red -1_pInt ! Has somewhere a conj. complex counterpart. Therefore count it twice. + utilities_divergenceRMS = utilities_divergenceRMS & + + 2.0_pReal*(sum (real(matmul(tensorField_fourier(1:3,1:3,i,j,k),& ! (sqrt(real(a)**2 + aimag(a)**2))**2 = real(a)**2 + aimag(a)**2. do not take square root and square again + conjg(-xi1st(1:3,i,j,k))*geomSize/scaledGeomSize))**2.0_pReal)& ! --> sum squared L_2 norm of vector + +sum(aimag(matmul(tensorField_fourier(1:3,1:3,i,j,k),& + conjg(-xi1st(1:3,i,j,k))*geomSize/scaledGeomSize))**2.0_pReal)) + enddo + utilities_divergenceRMS = utilities_divergenceRMS & ! these two layers (DC and Nyquist) do not have a conjugate complex counterpart (if grid(1) /= 1) + + sum( real(matmul(tensorField_fourier(1:3,1:3,1 ,j,k), & + conjg(-xi1st(1:3,1,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & + + sum(aimag(matmul(tensorField_fourier(1:3,1:3,1 ,j,k), & + conjg(-xi1st(1:3,1,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & + + sum( real(matmul(tensorField_fourier(1:3,1:3,grid1Red,j,k), & + conjg(-xi1st(1:3,grid1Red,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & + + sum(aimag(matmul(tensorField_fourier(1:3,1:3,grid1Red,j,k), & + conjg(-xi1st(1:3,grid1Red,j,k))*geomSize/scaledGeomSize))**2.0_pReal) + enddo; enddo + if(grid(1) == 1_pInt) utilities_divergenceRMS = utilities_divergenceRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 + call MPI_Allreduce(MPI_IN_PLACE,utilities_divergenceRMS,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + utilities_divergenceRMS = sqrt(utilities_divergenceRMS) * wgt ! RMS in real space calculated with Parsevals theorem from Fourier space + + +end function utilities_divergenceRMS + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate max of curl of field_fourier +!-------------------------------------------------------------------------------------------------- +real(pReal) function utilities_curlRMS() + use numerics, only: & + worldrank + use mesh, only: & + geomSize, & + grid, & + grid3 + + implicit none + integer(pInt) :: i, j, k, l + complex(pReal), dimension(3,3) :: curl_fourier + PetscErrorCode :: ierr + + external :: & + MPI_Reduce, & + MPI_Allreduce + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' ... calculating curl ......................................................' + flush(6) + endif + + !-------------------------------------------------------------------------------------------------- +! calculating max curl criterion in Fourier space + utilities_curlRMS = 0.0_pReal + + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); + do i = 2_pInt, grid1Red - 1_pInt + do l = 1_pInt, 3_pInt + curl_fourier(l,1) = (+tensorField_fourier(l,3,i,j,k)*xi1st(2,i,j,k)*geomSize(2)/scaledGeomSize(2) & + -tensorField_fourier(l,2,i,j,k)*xi1st(3,i,j,k)*geomSize(3)/scaledGeomSize(3)) + curl_fourier(l,2) = (+tensorField_fourier(l,1,i,j,k)*xi1st(3,i,j,k)*geomSize(3)/scaledGeomSize(3) & + -tensorField_fourier(l,3,i,j,k)*xi1st(1,i,j,k)*geomSize(1)/scaledGeomSize(1)) + curl_fourier(l,3) = (+tensorField_fourier(l,2,i,j,k)*xi1st(1,i,j,k)*geomSize(1)/scaledGeomSize(1) & + -tensorField_fourier(l,1,i,j,k)*xi1st(2,i,j,k)*geomSize(2)/scaledGeomSize(2)) + enddo + utilities_curlRMS = utilities_curlRMS + & + 2.0_pReal*sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! Has somewhere a conj. complex counterpart. Therefore count it twice. + enddo + do l = 1_pInt, 3_pInt + curl_fourier = (+tensorField_fourier(l,3,1,j,k)*xi1st(2,1,j,k)*geomSize(2)/scaledGeomSize(2) & + -tensorField_fourier(l,2,1,j,k)*xi1st(3,1,j,k)*geomSize(3)/scaledGeomSize(3)) + curl_fourier = (+tensorField_fourier(l,1,1,j,k)*xi1st(3,1,j,k)*geomSize(3)/scaledGeomSize(3) & + -tensorField_fourier(l,3,1,j,k)*xi1st(1,1,j,k)*geomSize(1)/scaledGeomSize(1)) + curl_fourier = (+tensorField_fourier(l,2,1,j,k)*xi1st(1,1,j,k)*geomSize(1)/scaledGeomSize(1) & + -tensorField_fourier(l,1,1,j,k)*xi1st(2,1,j,k)*geomSize(2)/scaledGeomSize(2)) + enddo + utilities_curlRMS = utilities_curlRMS + & + sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! this layer (DC) does not have a conjugate complex counterpart (if grid(1) /= 1) + do l = 1_pInt, 3_pInt + curl_fourier = (+tensorField_fourier(l,3,grid1Red,j,k)*xi1st(2,grid1Red,j,k)*geomSize(2)/scaledGeomSize(2) & + -tensorField_fourier(l,2,grid1Red,j,k)*xi1st(3,grid1Red,j,k)*geomSize(3)/scaledGeomSize(3)) + curl_fourier = (+tensorField_fourier(l,1,grid1Red,j,k)*xi1st(3,grid1Red,j,k)*geomSize(3)/scaledGeomSize(3) & + -tensorField_fourier(l,3,grid1Red,j,k)*xi1st(1,grid1Red,j,k)*geomSize(1)/scaledGeomSize(1)) + curl_fourier = (+tensorField_fourier(l,2,grid1Red,j,k)*xi1st(1,grid1Red,j,k)*geomSize(1)/scaledGeomSize(1) & + -tensorField_fourier(l,1,grid1Red,j,k)*xi1st(2,grid1Red,j,k)*geomSize(2)/scaledGeomSize(2)) + enddo + utilities_curlRMS = utilities_curlRMS + & + sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! this layer (Nyquist) does not have a conjugate complex counterpart (if grid(1) /= 1) + enddo; enddo + + call MPI_Allreduce(MPI_IN_PLACE,utilities_curlRMS,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + utilities_curlRMS = sqrt(utilities_curlRMS) * wgt + if(grid(1) == 1_pInt) utilities_curlRMS = utilities_curlRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 + +end function utilities_curlRMS + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates mask compliance tensor used to adjust F to fullfill stress BC +!-------------------------------------------------------------------------------------------------- +function utilities_maskedCompliance(rot_BC,mask_stress,C) + use prec, only: & + prec_isNaN + use IO, only: & + IO_error + use numerics, only: & + worldrank + use math, only: & + math_Plain3333to99, & + math_plain99to3333, & + math_rotate_forward3333, & + math_rotate_forward33, & + math_invert + + implicit none + real(pReal), dimension(3,3,3,3) :: utilities_maskedCompliance !< masked compliance + real(pReal), intent(in) , dimension(3,3,3,3) :: C !< current average stiffness + real(pReal), intent(in) , dimension(3,3) :: rot_BC !< rotation of load frame + logical, intent(in), dimension(3,3) :: mask_stress !< mask of stress BC + integer(pInt) :: j, k, m, n + logical, dimension(9) :: mask_stressVector + real(pReal), dimension(9,9) :: temp99_Real + integer(pInt) :: size_reduced = 0_pInt + real(pReal), dimension(:,:), allocatable :: & + s_reduced, & !< reduced compliance matrix (depending on number of stress BC) + c_reduced, & !< reduced stiffness (depending on number of stress BC) + sTimesC !< temp variable to check inversion + logical :: errmatinv + character(len=1024):: formatString + + mask_stressVector = reshape(transpose(mask_stress), [9]) + size_reduced = int(count(mask_stressVector), pInt) + if(size_reduced > 0_pInt )then + allocate (c_reduced(size_reduced,size_reduced), source =0.0_pReal) + allocate (s_reduced(size_reduced,size_reduced), source =0.0_pReal) + allocate (sTimesC(size_reduced,size_reduced), source =0.0_pReal) + temp99_Real = math_Plain3333to99(math_rotate_forward3333(C,rot_BC)) + + if(debugGeneral .and. worldrank == 0_pInt) then + write(6,'(/,a)') ' ... updating masked compliance ............................................' + write(6,'(/,a,/,9(9(2x,f12.7,1x)/))',advance='no') ' Stiffness C (load) / GPa =',& + transpose(temp99_Real)/1.e9_pReal + flush(6) + endif + k = 0_pInt ! calculate reduced stiffness + do n = 1_pInt,9_pInt + if(mask_stressVector(n)) then + k = k + 1_pInt + j = 0_pInt + do m = 1_pInt,9_pInt + if(mask_stressVector(m)) then + j = j + 1_pInt + c_reduced(k,j) = temp99_Real(n,m) + endif; enddo; endif; enddo + + call math_invert(size_reduced, c_reduced, s_reduced, errmatinv) ! invert reduced stiffness + if (any(prec_isNaN(s_reduced))) errmatinv = .true. + if(errmatinv) call IO_error(error_ID=400_pInt,ext_msg='utilities_maskedCompliance') + temp99_Real = 0.0_pReal ! fill up compliance with zeros + k = 0_pInt + do n = 1_pInt,9_pInt + if(mask_stressVector(n)) then + k = k + 1_pInt + j = 0_pInt + do m = 1_pInt,9_pInt + if(mask_stressVector(m)) then + j = j + 1_pInt + temp99_Real(n,m) = s_reduced(k,j) + endif; enddo; endif; enddo + +!-------------------------------------------------------------------------------------------------- +! check if inversion was successful + sTimesC = matmul(c_reduced,s_reduced) + do m=1_pInt, size_reduced + do n=1_pInt, size_reduced + if(m==n .and. abs(sTimesC(m,n)) > (1.0_pReal + 10.0e-12_pReal)) errmatinv = .true. ! diagonal elements of S*C should be 1 + if(m/=n .and. abs(sTimesC(m,n)) > (0.0_pReal + 10.0e-12_pReal)) errmatinv = .true. ! off diagonal elements of S*C should be 0 + enddo + enddo + if((debugGeneral .or. errmatinv) .and. (worldrank == 0_pInt)) then ! report + write(formatString, '(I16.16)') size_reduced + formatString = '(/,a,/,'//trim(formatString)//'('//trim(formatString)//'(2x,es9.2,1x)/))' + write(6,trim(formatString),advance='no') ' C * S (load) ', & + transpose(matmul(c_reduced,s_reduced)) + write(6,trim(formatString),advance='no') ' S (load) ', transpose(s_reduced) + endif + if(errmatinv) call IO_error(error_ID=400_pInt,ext_msg='utilities_maskedCompliance') + deallocate(c_reduced) + deallocate(s_reduced) + deallocate(sTimesC) + else + temp99_real = 0.0_pReal + endif + if(debugGeneral .and. worldrank == 0_pInt) & ! report + write(6,'(/,a,/,9(9(2x,f12.7,1x)/),/)',advance='no') ' Masked Compliance (load) * GPa =', & + transpose(temp99_Real*1.e9_pReal) + flush(6) + utilities_maskedCompliance = math_Plain99to3333(temp99_Real) + +end function utilities_maskedCompliance + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate scalar gradient in fourier field +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierScalarGradient() + use mesh, only: & + grid3, & + grid + + implicit none + integer(pInt) :: i, j, k + + vectorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) + forall(k = 1_pInt:grid3, j = 1_pInt:grid(2), i = 1_pInt:grid1Red) & + vectorField_fourier(1:3,i,j,k) = scalarField_fourier(i,j,k)*xi1st(1:3,i,j,k) + +end subroutine utilities_fourierScalarGradient + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate vector divergence in fourier field +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierVectorDivergence() + use mesh, only: & + grid3, & + grid + + implicit none + integer(pInt) :: i, j, k + + scalarField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) + forall(k = 1_pInt:grid3, j = 1_pInt:grid(2), i = 1_pInt:grid1Red) & + scalarField_fourier(i,j,k) = scalarField_fourier(i,j,k) + & + sum(vectorField_fourier(1:3,i,j,k)*conjg(-xi1st(1:3,i,j,k))) + +end subroutine utilities_fourierVectorDivergence + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate vector gradient in fourier field +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierVectorGradient() + use mesh, only: & + grid3, & + grid + + implicit none + integer(pInt) :: i, j, k, m, n + + tensorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red + do m = 1_pInt, 3_pInt; do n = 1_pInt, 3_pInt + tensorField_fourier(m,n,i,j,k) = vectorField_fourier(m,i,j,k)*xi1st(n,i,j,k) + enddo; enddo + enddo; enddo; enddo +end subroutine utilities_fourierVectorGradient + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate tensor divergence in fourier field +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierTensorDivergence() + use mesh, only: & + grid3, & + grid + + implicit none + integer(pInt) :: i, j, k, m, n + + vectorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red + do m = 1_pInt, 3_pInt; do n = 1_pInt, 3_pInt + vectorField_fourier(m,i,j,k) = & + vectorField_fourier(m,i,j,k) + & + tensorField_fourier(m,n,i,j,k)*conjg(-xi1st(n,i,j,k)) + enddo; enddo + enddo; enddo; enddo +end subroutine utilities_fourierTensorDivergence + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates constitutive response +!-------------------------------------------------------------------------------------------------- +subroutine utilities_constitutiveResponse(F_lastInc,F,timeinc, & + P,C_volAvg,C_minmaxAvg,P_av,forwardData,rotation_BC) + use debug, only: & + debug_reset, & + debug_info + use numerics, only: & + worldrank + use math, only: & + math_transpose33, & + math_rotate_forward33, & + math_det33 + use mesh, only: & + grid,& + grid3 + use FEsolving, only: & + restartWrite + use CPFEM2, only: & + CPFEM_general + use homogenization, only: & + materialpoint_F0, & + materialpoint_F, & + materialpoint_P, & + materialpoint_dPdF + + implicit none + real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & + F_lastInc, & !< target deformation gradient + F !< previous deformation gradient + real(pReal), intent(in) :: timeinc !< loading time + logical, intent(in) :: forwardData !< age results + real(pReal), intent(in), dimension(3,3) :: rotation_BC !< rotation of load frame + + real(pReal),intent(out), dimension(3,3,3,3) :: C_volAvg, C_minmaxAvg !< average stiffness + real(pReal),intent(out), dimension(3,3) :: P_av !< average PK stress + real(pReal),intent(out), dimension(3,3,grid(1),grid(2),grid3) :: P !< PK stress + + logical :: & + age + + integer(pInt) :: & + j,k + real(pReal), dimension(3,3,3,3) :: max_dPdF, min_dPdF + real(pReal) :: max_dPdF_norm, min_dPdF_norm, defgradDetMin, defgradDetMax, defgradDet + PetscErrorCode :: ierr + + external :: & + MPI_Reduce, & + MPI_Allreduce + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' ... evaluating constitutive response ......................................' + flush(6) + endif + age = .False. + + if (forwardData) then ! aging results + age = .True. + materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) + endif + if (cutBack) then ! restore saved variables + age = .False. + endif + + materialpoint_F = reshape(F,[3,3,1,product(grid(1:2))*grid3]) + call debug_reset() + +!-------------------------------------------------------------------------------------------------- +! calculate bounds of det(F) and report + if(debugGeneral) then + defgradDetMax = -huge(1.0_pReal) + defgradDetMin = +huge(1.0_pReal) + do j = 1_pInt, product(grid(1:2))*grid3 + defgradDet = math_det33(materialpoint_F(1:3,1:3,1,j)) + defgradDetMax = max(defgradDetMax,defgradDet) + defgradDetMin = min(defgradDetMin,defgradDet) + end do + call MPI_reduce(MPI_IN_PLACE,defgradDetMax,1,MPI_DOUBLE,MPI_MAX,0,PETSC_COMM_WORLD,ierr) + call MPI_reduce(MPI_IN_PLACE,defgradDetMin,1,MPI_DOUBLE,MPI_MIN,0,PETSC_COMM_WORLD,ierr) + if (worldrank == 0_pInt) then + write(6,'(a,1x,es11.4)') ' max determinant of deformation =', defgradDetMax + write(6,'(a,1x,es11.4)') ' min determinant of deformation =', defgradDetMin + flush(6) + endif + endif + + call CPFEM_general(age,timeinc) + + max_dPdF = 0.0_pReal + max_dPdF_norm = 0.0_pReal + min_dPdF = huge(1.0_pReal) + min_dPdF_norm = huge(1.0_pReal) + do k = 1_pInt, product(grid(1:2))*grid3 + if (max_dPdF_norm < sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal)) then + max_dPdF = materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k) + max_dPdF_norm = sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal) + endif + if (min_dPdF_norm > sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal)) then + min_dPdF = materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k) + min_dPdF_norm = sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal) + endif + end do + + call MPI_Allreduce(MPI_IN_PLACE,max_dPdF,81,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + call MPI_Allreduce(MPI_IN_PLACE,min_dPdF,81,MPI_DOUBLE,MPI_MIN,PETSC_COMM_WORLD,ierr) + + C_minmaxAvg = 0.5_pReal*(max_dPdF + min_dPdF) + C_volAvg = sum(sum(materialpoint_dPdF,dim=6),dim=5) * wgt + + call MPI_Allreduce(MPI_IN_PLACE,C_volAvg,81,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + + call debug_info() + + restartWrite = .false. ! reset restartWrite status + cutBack = .false. ! reset cutBack status + + P = reshape(materialpoint_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 .and. worldrank == 0_pInt) & + write(6,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress (lab) / MPa =',& + math_transpose33(P_av)*1.e-6_pReal + P_av = math_rotate_forward33(P_av,rotation_BC) + if (worldrank == 0_pInt) then + write(6,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress / MPa =',& + math_transpose33(P_av)*1.e-6_pReal + flush(6) + endif + +end subroutine utilities_constitutiveResponse + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates forward rate, either guessing or just add delta/timeinc +!-------------------------------------------------------------------------------------------------- +pure function utilities_calculateRate(avRate,timeinc_old,guess,field_lastInc,field) + use mesh, only: & + grid3, & + grid + + implicit none + real(pReal), intent(in), dimension(3,3) :: avRate !< homogeneous addon + real(pReal), intent(in) :: & + timeinc_old !< timeinc of last step + logical, intent(in) :: & + guess !< guess along former trajectory + real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & + field_lastInc, & !< data of previous step + field !< data of current step + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: & + utilities_calculateRate + + if (guess) then + utilities_calculateRate = (field-field_lastInc) / timeinc_old + else + utilities_calculateRate = spread(spread(spread(avRate,3,grid(1)),4,grid(2)),5,grid3) + endif + +end function utilities_calculateRate + + +!-------------------------------------------------------------------------------------------------- +!> @brief forwards a field with a pointwise given rate, if aim is given, +!> ensures that the average matches the aim +!-------------------------------------------------------------------------------------------------- +function utilities_forwardField(timeinc,field_lastInc,rate,aim) + use mesh, only: & + grid3, & + grid + + implicit none + real(pReal), intent(in) :: & + timeinc !< timeinc of current step + real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & + field_lastInc, & !< initial field + rate !< rate by which to forward + real(pReal), intent(in), optional, dimension(3,3) :: & + aim !< average field value aim + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: & + utilities_forwardField + real(pReal), dimension(3,3) :: fieldDiff !< - aim + PetscErrorCode :: ierr + + external :: & + MPI_Allreduce + + utilities_forwardField = field_lastInc + rate*timeinc + if (present(aim)) then !< correct to match average + fieldDiff = sum(sum(sum(utilities_forwardField,dim=5),dim=4),dim=3)*wgt + call MPI_Allreduce(MPI_IN_PLACE,fieldDiff,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + fieldDiff = fieldDiff - aim + utilities_forwardField = utilities_forwardField - & + spread(spread(spread(fieldDiff,3,grid(1)),4,grid(2)),5,grid3) + endif + +end function utilities_forwardField + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates filter for fourier convolution depending on type given in numerics.config +!-------------------------------------------------------------------------------------------------- +pure function utilities_getFreqDerivative(k_s) + use math, only: & + PI + use mesh, only: & + geomSize, & + grid + + implicit none + integer(pInt), intent(in), dimension(3) :: k_s !< indices of frequency + complex(pReal), dimension(3) :: utilities_getFreqDerivative + + select case (spectral_derivative_ID) + case (DERIVATIVE_CONTINUOUS_ID) + utilities_getFreqDerivative = cmplx(0.0_pReal, 2.0_pReal*PI*real(k_s,pReal)/geomSize,pReal) + + case (DERIVATIVE_CENTRAL_DIFF_ID) + utilities_getFreqDerivative = cmplx(0.0_pReal, sin(2.0_pReal*PI*real(k_s,pReal)/real(grid,pReal)), pReal)/ & + cmplx(2.0_pReal*geomSize/real(grid,pReal), 0.0_pReal, pReal) + + case (DERIVATIVE_FWBW_DIFF_ID) + utilities_getFreqDerivative(1) = & + cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) - 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & + cmplx(4.0_pReal*geomSize(1)/real(grid(1),pReal), 0.0_pReal, pReal) + utilities_getFreqDerivative(2) = & + cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) - 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & + cmplx(4.0_pReal*geomSize(2)/real(grid(2),pReal), 0.0_pReal, pReal) + utilities_getFreqDerivative(3) = & + cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) - 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & + cmplx(4.0_pReal*geomSize(3)/real(grid(3),pReal), 0.0_pReal, pReal) + + end select + +end function utilities_getFreqDerivative + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate coordinates in current configuration for given defgrad field +! using integration in Fourier space. Similar as in mesh.f90, but using data already defined for +! convolution +!-------------------------------------------------------------------------------------------------- +subroutine utilities_updateIPcoords(F) + use math, only: & + math_mul33x3 + use mesh, only: & + grid, & + grid3, & + grid3Offset, & + geomSize, & + mesh_ipCoordinates + implicit none + + real(pReal), dimension(3,3,grid(1),grid(2),grid3), intent(in) :: F + integer(pInt) :: i, j, k, m + real(pReal), dimension(3) :: step, offset_coords + real(pReal), dimension(3,3) :: Favg + PetscErrorCode :: ierr + external & + MPI_Bcast + +!-------------------------------------------------------------------------------------------------- +! integration in Fourier space + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F + call utilities_FFTtensorForward() + call utilities_fourierTensorDivergence() + + do k = 1_pInt, grid3; do j = 1_pInt, grid(2) ;do i = 1_pInt, grid1Red + if (any(abs(xi1st(1:3,i,j,k)) > tiny(0.0_pReal))) & + vectorField_fourier(1:3,i,j,k) = vectorField_fourier(1:3,i,j,k)/ & + sum(conjg(-xi1st(1:3,i,j,k))*xi1st(1:3,i,j,k)) + enddo; enddo; enddo + call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) + +!-------------------------------------------------------------------------------------------------- +! average F + if (grid3Offset == 0_pInt) Favg = real(tensorField_fourier(1:3,1:3,1,1,1),pReal)*wgt + call MPI_Bcast(Favg,9,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) + +!-------------------------------------------------------------------------------------------------- +! add average to fluctuation and put (0,0,0) on (0,0,0) + step = geomSize/real(grid, pReal) + if (grid3Offset == 0_pInt) offset_coords = vectorField_real(1:3,1,1,1) + call MPI_Bcast(offset_coords,3,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) + offset_coords = math_mul33x3(Favg,step/2.0_pReal) - offset_coords + m = 1_pInt + do k = 1_pInt,grid3; do j = 1_pInt,grid(2); do i = 1_pInt,grid(1) + mesh_ipCoordinates(1:3,1,m) = vectorField_real(1:3,i,j,k) & + + offset_coords & + + math_mul33x3(Favg,step*real([i,j,k+grid3Offset]-1_pInt,pReal)) + m = m+1_pInt + enddo; enddo; enddo + +end subroutine utilities_updateIPcoords + + +!-------------------------------------------------------------------------------------------------- +!> @brief cleans up +!-------------------------------------------------------------------------------------------------- +subroutine utilities_destroy() + implicit none + + call fftw_destroy_plan(planTensorForth) + call fftw_destroy_plan(planTensorBack) + call fftw_destroy_plan(planVectorForth) + call fftw_destroy_plan(planVectorBack) + call fftw_destroy_plan(planScalarForth) + call fftw_destroy_plan(planScalarBack) + +end subroutine utilities_destroy + + +end module spectral_utilities diff --git a/code/thermal/CMakeLists.txt b/code/thermal/CMakeLists.txt new file mode 100644 index 000000000..b9d3f8ff9 --- /dev/null +++ b/code/thermal/CMakeLists.txt @@ -0,0 +1,10 @@ +# group source related themal module +set (THERMAL "thermal_isothermal" + "thermal_adiabatic" + "thermal_conduction" + ) + +# compiler theraml module +foreach (p ${THERMAL}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) diff --git a/code/thermal/thermal_adiabatic.f90 b/code/thermal/thermal_adiabatic.f90 new file mode 100644 index 000000000..7bb8620e7 --- /dev/null +++ b/code/thermal/thermal_adiabatic.f90 @@ -0,0 +1,422 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for adiabatic temperature evolution +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module thermal_adiabatic + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + thermal_adiabatic_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + thermal_adiabatic_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + thermal_adiabatic_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + thermal_adiabatic_Noutput !< number of outputs per instance of this thermal model + + enum, bind(c) + enumerator :: undefined_ID, & + temperature_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + thermal_adiabatic_outputID !< ID of each post result output + + + public :: & + thermal_adiabatic_init, & + thermal_adiabatic_updateState, & + thermal_adiabatic_getSourceAndItsTangent, & + thermal_adiabatic_getSpecificHeat, & + thermal_adiabatic_getMassDensity, & + thermal_adiabatic_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine thermal_adiabatic_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + thermal_type, & + thermal_typeInstance, & + homogenization_Noutput, & + THERMAL_ADIABATIC_label, & + THERMAL_adiabatic_ID, & + material_homog, & + mappingHomogenization, & + thermalState, & + thermalMapping, & + thermal_initialT, & + temperature, & + temperatureRate, & + material_partHomogenization + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_ADIABATIC_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(thermal_type == THERMAL_adiabatic_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(thermal_adiabatic_sizePostResults(maxNinstance), source=0_pInt) + allocate(thermal_adiabatic_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(thermal_adiabatic_output (maxval(homogenization_Noutput),maxNinstance)) + thermal_adiabatic_output = '' + allocate(thermal_adiabatic_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(thermal_adiabatic_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (thermal_type(section) == THERMAL_adiabatic_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = thermal_typeInstance(section) ! which instance of my thermal is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('temperature') + thermal_adiabatic_Noutput(instance) = thermal_adiabatic_Noutput(instance) + 1_pInt + thermal_adiabatic_outputID(thermal_adiabatic_Noutput(instance),instance) = temperature_ID + thermal_adiabatic_output(thermal_adiabatic_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingFile + + initializeInstances: do section = 1_pInt, size(thermal_type) + if (thermal_type(section) == THERMAL_adiabatic_ID) then + NofMyHomog=count(material_homog==section) + instance = thermal_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,thermal_adiabatic_Noutput(instance) + select case(thermal_adiabatic_outputID(o,instance)) + case(temperature_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + thermal_adiabatic_sizePostResult(o,instance) = mySize + thermal_adiabatic_sizePostResults(instance) = thermal_adiabatic_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 1_pInt + thermalState(section)%sizeState = sizeState + thermalState(section)%sizePostResults = thermal_adiabatic_sizePostResults(instance) + allocate(thermalState(section)%state0 (sizeState,NofMyHomog), source=thermal_initialT(section)) + allocate(thermalState(section)%subState0(sizeState,NofMyHomog), source=thermal_initialT(section)) + allocate(thermalState(section)%state (sizeState,NofMyHomog), source=thermal_initialT(section)) + + nullify(thermalMapping(section)%p) + thermalMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(temperature(section)%p) + temperature(section)%p => thermalState(section)%state(1,:) + deallocate(temperatureRate(section)%p) + allocate (temperatureRate(section)%p(NofMyHomog), source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine thermal_adiabatic_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates adiabatic change in temperature based on local heat generation model +!-------------------------------------------------------------------------------------------------- +function thermal_adiabatic_updateState(subdt, ip, el) + use numerics, only: & + err_thermal_tolAbs, & + err_thermal_tolRel + use material, only: & + mappingHomogenization, & + thermalState, & + temperature, & + temperatureRate, & + thermalMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + subdt + logical, dimension(2) :: & + thermal_adiabatic_updateState + integer(pInt) :: & + homog, & + offset + real(pReal) :: & + T, Tdot, dTdot_dT + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,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)) & + <= err_thermal_tolAbs & + .or. abs(T - thermalState(homog)%state(1,offset)) & + <= err_thermal_tolRel*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) + use math, only: & + math_Mandel6to33 + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + thermal_typeInstance, & + phase_Nsources, & + phase_source, & + SOURCE_thermal_dissipation_ID, & + SOURCE_thermal_externalheat_ID + use source_thermal_dissipation, only: & + source_thermal_dissipation_getRateAndItsTangent + use source_thermal_externalheat, only: & + source_thermal_externalheat_getRateAndItsTangent + use crystallite, only: & + crystallite_Tstar_v, & + crystallite_Lp + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + T + real(pReal), intent(out) :: & + Tdot, dTdot_dT + real(pReal) :: & + my_Tdot, my_dTdot_dT + integer(pInt) :: & + phase, & + homog, & + offset, & + instance, & + grain, & + source + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + instance = thermal_typeInstance(homog) + + Tdot = 0.0_pReal + dTdot_dT = 0.0_pReal + do grain = 1, homogenization_Ngrains(homog) + phase = phaseAt(grain,ip,el) + do source = 1, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_thermal_dissipation_ID) + call source_thermal_dissipation_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & + crystallite_Tstar_v(1:6,grain,ip,el), & + crystallite_Lp(1:3,1:3,grain,ip,el), & + grain, ip, el) + + case (SOURCE_thermal_externalheat_ID) + call source_thermal_externalheat_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & + grain, ip, el) + + case default + my_Tdot = 0.0_pReal + my_dTdot_dT = 0.0_pReal + end select + Tdot = Tdot + my_Tdot + dTdot_dT = dTdot_dT + my_dTdot_dT + enddo + enddo + + Tdot = Tdot/homogenization_Ngrains(homog) + dTdot_dT = dTdot_dT/homogenization_Ngrains(homog) + +end subroutine thermal_adiabatic_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized specific heat capacity +!-------------------------------------------------------------------------------------------------- +function thermal_adiabatic_getSpecificHeat(ip,el) + use lattice, only: & + lattice_specificHeat + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + thermal_adiabatic_getSpecificHeat + integer(pInt) :: & + homog, grain + + thermal_adiabatic_getSpecificHeat = 0.0_pReal + + homog = mappingHomogenization(2,ip,el) + + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + thermal_adiabatic_getSpecificHeat = thermal_adiabatic_getSpecificHeat + & + lattice_specificHeat(material_phase(grain,ip,el)) + enddo + + thermal_adiabatic_getSpecificHeat = & + thermal_adiabatic_getSpecificHeat/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function thermal_adiabatic_getSpecificHeat + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized mass density +!-------------------------------------------------------------------------------------------------- +function thermal_adiabatic_getMassDensity(ip,el) + use lattice, only: & + lattice_massDensity + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + thermal_adiabatic_getMassDensity + integer(pInt) :: & + homog, grain + + thermal_adiabatic_getMassDensity = 0.0_pReal + + homog = mappingHomogenization(2,ip,el) + + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + thermal_adiabatic_getMassDensity = thermal_adiabatic_getMassDensity + & + lattice_massDensity(material_phase(grain,ip,el)) + enddo + + thermal_adiabatic_getMassDensity = & + thermal_adiabatic_getMassDensity/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function thermal_adiabatic_getMassDensity + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of thermal results +!-------------------------------------------------------------------------------------------------- +function thermal_adiabatic_postResults(ip,el) + use material, only: & + mappingHomogenization, & + thermal_typeInstance, & + thermalMapping, & + temperature + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(thermal_adiabatic_sizePostResults(thermal_typeInstance(mappingHomogenization(2,ip,el)))) :: & + thermal_adiabatic_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = thermalMapping(homog)%p(ip,el) + instance = thermal_typeInstance(homog) + + c = 0_pInt + thermal_adiabatic_postResults = 0.0_pReal + + do o = 1_pInt,thermal_adiabatic_Noutput(instance) + select case(thermal_adiabatic_outputID(o,instance)) + + case (temperature_ID) + thermal_adiabatic_postResults(c+1_pInt) = temperature(homog)%p(offset) + c = c + 1 + end select + enddo +end function thermal_adiabatic_postResults + +end module thermal_adiabatic diff --git a/code/thermal/thermal_conduction.f90 b/code/thermal/thermal_conduction.f90 new file mode 100644 index 000000000..2f9b766eb --- /dev/null +++ b/code/thermal/thermal_conduction.f90 @@ -0,0 +1,444 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for temperature evolution from heat conduction +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module thermal_conduction + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + thermal_conduction_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + thermal_conduction_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + thermal_conduction_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + thermal_conduction_Noutput !< number of outputs per instance of this damage + + enum, bind(c) + enumerator :: undefined_ID, & + temperature_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + thermal_conduction_outputID !< ID of each post result output + + + public :: & + thermal_conduction_init, & + thermal_conduction_getSourceAndItsTangent, & + thermal_conduction_getConductivity33, & + thermal_conduction_getSpecificHeat, & + thermal_conduction_getMassDensity, & + thermal_conduction_putTemperatureAndItsRate, & + thermal_conduction_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine thermal_conduction_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + thermal_type, & + thermal_typeInstance, & + homogenization_Noutput, & + THERMAL_conduction_label, & + THERMAL_conduction_ID, & + material_homog, & + mappingHomogenization, & + thermalState, & + thermalMapping, & + thermal_initialT, & + temperature, & + temperatureRate, & + material_partHomogenization + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_CONDUCTION_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(thermal_type == THERMAL_conduction_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(thermal_conduction_sizePostResults(maxNinstance), source=0_pInt) + allocate(thermal_conduction_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(thermal_conduction_output (maxval(homogenization_Noutput),maxNinstance)) + thermal_conduction_output = '' + allocate(thermal_conduction_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(thermal_conduction_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (thermal_type(section) == THERMAL_conduction_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = thermal_typeInstance(section) ! which instance of my thermal is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('temperature') + thermal_conduction_Noutput(instance) = thermal_conduction_Noutput(instance) + 1_pInt + thermal_conduction_outputID(thermal_conduction_Noutput(instance),instance) = temperature_ID + thermal_conduction_output(thermal_conduction_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingFile + + initializeInstances: do section = 1_pInt, size(thermal_type) + if (thermal_type(section) == THERMAL_conduction_ID) then + NofMyHomog=count(material_homog==section) + instance = thermal_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,thermal_conduction_Noutput(instance) + select case(thermal_conduction_outputID(o,instance)) + case(temperature_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + thermal_conduction_sizePostResult(o,instance) = mySize + thermal_conduction_sizePostResults(instance) = thermal_conduction_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 0_pInt + thermalState(section)%sizeState = sizeState + thermalState(section)%sizePostResults = thermal_conduction_sizePostResults(instance) + allocate(thermalState(section)%state0 (sizeState,NofMyHomog)) + allocate(thermalState(section)%subState0(sizeState,NofMyHomog)) + allocate(thermalState(section)%state (sizeState,NofMyHomog)) + + nullify(thermalMapping(section)%p) + thermalMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(temperature (section)%p) + allocate (temperature (section)%p(NofMyHomog), source=thermal_initialT(section)) + deallocate(temperatureRate(section)%p) + allocate (temperatureRate(section)%p(NofMyHomog), source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine thermal_conduction_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns heat generation rate +!-------------------------------------------------------------------------------------------------- +subroutine thermal_conduction_getSourceAndItsTangent(Tdot, dTdot_dT, T, ip, el) + use math, only: & + math_Mandel6to33 + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + thermal_typeInstance, & + phase_Nsources, & + phase_source, & + SOURCE_thermal_dissipation_ID, & + SOURCE_thermal_externalheat_ID + use source_thermal_dissipation, only: & + source_thermal_dissipation_getRateAndItsTangent + use source_thermal_externalheat, only: & + source_thermal_externalheat_getRateAndItsTangent + use crystallite, only: & + crystallite_Tstar_v, & + crystallite_Lp + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + T + real(pReal), intent(out) :: & + Tdot, dTdot_dT + real(pReal) :: & + my_Tdot, my_dTdot_dT + integer(pInt) :: & + phase, & + homog, & + offset, & + instance, & + grain, & + source + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + instance = thermal_typeInstance(homog) + + Tdot = 0.0_pReal + dTdot_dT = 0.0_pReal + do grain = 1, homogenization_Ngrains(homog) + phase = phaseAt(grain,ip,el) + do source = 1, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_thermal_dissipation_ID) + call source_thermal_dissipation_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & + crystallite_Tstar_v(1:6,grain,ip,el), & + crystallite_Lp(1:3,1:3,grain,ip,el), & + grain, ip, el) + + case (SOURCE_thermal_externalheat_ID) + call source_thermal_externalheat_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & + grain, ip, el) + + case default + my_Tdot = 0.0_pReal + my_dTdot_dT = 0.0_pReal + + end select + Tdot = Tdot + my_Tdot + dTdot_dT = dTdot_dT + my_dTdot_dT + enddo + enddo + + Tdot = Tdot/homogenization_Ngrains(homog) + dTdot_dT = dTdot_dT/homogenization_Ngrains(homog) + +end subroutine thermal_conduction_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized thermal conductivity in reference configuration +!-------------------------------------------------------------------------------------------------- +function thermal_conduction_getConductivity33(ip,el) + use lattice, only: & + lattice_thermalConductivity33 + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + thermal_conduction_getConductivity33 + integer(pInt) :: & + homog, & + grain + + homog = mappingHomogenization(2,ip,el) + + thermal_conduction_getConductivity33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + thermal_conduction_getConductivity33 = thermal_conduction_getConductivity33 + & + crystallite_push33ToRef(grain,ip,el,lattice_thermalConductivity33(:,:,material_phase(grain,ip,el))) + enddo + + thermal_conduction_getConductivity33 = & + thermal_conduction_getConductivity33/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function thermal_conduction_getConductivity33 + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized specific heat capacity +!-------------------------------------------------------------------------------------------------- +function thermal_conduction_getSpecificHeat(ip,el) + use lattice, only: & + lattice_specificHeat + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + thermal_conduction_getSpecificHeat + integer(pInt) :: & + homog, grain + + thermal_conduction_getSpecificHeat = 0.0_pReal + + homog = mappingHomogenization(2,ip,el) + + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + thermal_conduction_getSpecificHeat = thermal_conduction_getSpecificHeat + & + lattice_specificHeat(material_phase(grain,ip,el)) + enddo + + thermal_conduction_getSpecificHeat = & + thermal_conduction_getSpecificHeat/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function thermal_conduction_getSpecificHeat + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized mass density +!-------------------------------------------------------------------------------------------------- +function thermal_conduction_getMassDensity(ip,el) + use lattice, only: & + lattice_massDensity + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + thermal_conduction_getMassDensity + integer(pInt) :: & + homog, grain + + thermal_conduction_getMassDensity = 0.0_pReal + + homog = mappingHomogenization(2,ip,el) + + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + thermal_conduction_getMassDensity = thermal_conduction_getMassDensity + & + lattice_massDensity(material_phase(grain,ip,el)) + enddo + + thermal_conduction_getMassDensity = & + thermal_conduction_getMassDensity/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function thermal_conduction_getMassDensity + +!-------------------------------------------------------------------------------------------------- +!> @brief updates thermal state with solution from heat conduction PDE +!-------------------------------------------------------------------------------------------------- +subroutine thermal_conduction_putTemperatureAndItsRate(T,Tdot,ip,el) + use material, only: & + mappingHomogenization, & + temperature, & + temperatureRate, & + thermalMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + T, & + Tdot + integer(pInt) :: & + homog, & + offset + + homog = mappingHomogenization(2,ip,el) + offset = thermalMapping(homog)%p(ip,el) + temperature (homog)%p(offset) = T + temperatureRate(homog)%p(offset) = Tdot + +end subroutine thermal_conduction_putTemperatureAndItsRate + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of thermal results +!-------------------------------------------------------------------------------------------------- +function thermal_conduction_postResults(ip,el) + use material, only: & + mappingHomogenization, & + thermal_typeInstance, & + temperature, & + thermalMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(thermal_conduction_sizePostResults(thermal_typeInstance(mappingHomogenization(2,ip,el)))) :: & + thermal_conduction_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = thermalMapping(homog)%p(ip,el) + instance = thermal_typeInstance(homog) + + c = 0_pInt + thermal_conduction_postResults = 0.0_pReal + + do o = 1_pInt,thermal_conduction_Noutput(instance) + select case(thermal_conduction_outputID(o,instance)) + + case (temperature_ID) + thermal_conduction_postResults(c+1_pInt) = temperature(homog)%p(offset) + c = c + 1 + end select + enddo +end function thermal_conduction_postResults + +end module thermal_conduction diff --git a/code/thermal/thermal_isothermal.f90 b/code/thermal/thermal_isothermal.f90 new file mode 100644 index 000000000..8c9d3a782 --- /dev/null +++ b/code/thermal/thermal_isothermal.f90 @@ -0,0 +1,65 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for isothermal temperature field +!-------------------------------------------------------------------------------------------------- +module thermal_isothermal + + implicit none + private + + public :: & + thermal_isothermal_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine thermal_isothermal_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog, & + sizeState + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_isothermal_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (thermal_type(homog) == THERMAL_isothermal_ID) then + NofMyHomog = count(material_homog == homog) + sizeState = 0_pInt + thermalState(homog)%sizeState = sizeState + thermalState(homog)%sizePostResults = sizeState + allocate(thermalState(homog)%state0 (sizeState,NofMyHomog), source=0.0_pReal) + allocate(thermalState(homog)%subState0(sizeState,NofMyHomog), source=0.0_pReal) + allocate(thermalState(homog)%state (sizeState,NofMyHomog), source=0.0_pReal) + + deallocate(temperature (homog)%p) + allocate (temperature (homog)%p(1), source=thermal_initialT(homog)) + deallocate(temperatureRate(homog)%p) + allocate (temperatureRate(homog)%p(1), source=0.0_pReal) + + endif myhomog + enddo initializeInstances + + +end subroutine thermal_isothermal_init + +end module thermal_isothermal diff --git a/code/vacancyflux/CMakeLists.txt b/code/vacancyflux/CMakeLists.txt new file mode 100644 index 000000000..4a4c4f31c --- /dev/null +++ b/code/vacancyflux/CMakeLists.txt @@ -0,0 +1,10 @@ +# group source file +set (VACANCYFLUX "vacancyflux_isoconc" + "vacancyflux_isochempot" + "vacancyflux_cahnhilliard" + ) + +# compiler as module +foreach (p ${VACANCYFLUX}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) diff --git a/code/vacancyflux/vacancyflux_cahnhilliard.f90 b/code/vacancyflux/vacancyflux_cahnhilliard.f90 new file mode 100644 index 000000000..16a380ffc --- /dev/null +++ b/code/vacancyflux/vacancyflux_cahnhilliard.f90 @@ -0,0 +1,606 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for conservative transport of vacancy concentration field +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module vacancyflux_cahnhilliard + use prec, only: & + pReal, & + pInt, & + p_vec + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + vacancyflux_cahnhilliard_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + vacancyflux_cahnhilliard_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + vacancyflux_cahnhilliard_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + vacancyflux_cahnhilliard_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + vacancyflux_cahnhilliard_flucAmplitude + + type(p_vec), dimension(:), allocatable, private :: & + vacancyflux_cahnhilliard_thermalFluc + + real(pReal), parameter, private :: & + kB = 1.3806488e-23_pReal !< Boltzmann constant in J/Kelvin + + enum, bind(c) + enumerator :: undefined_ID, & + vacancyConc_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + vacancyflux_cahnhilliard_outputID !< ID of each post result output + + + public :: & + vacancyflux_cahnhilliard_init, & + vacancyflux_cahnhilliard_getSourceAndItsTangent, & + vacancyflux_cahnhilliard_getMobility33, & + vacancyflux_cahnhilliard_getDiffusion33, & + vacancyflux_cahnhilliard_getChemPotAndItsTangent, & + vacancyflux_cahnhilliard_putVacancyConcAndItsRate, & + vacancyflux_cahnhilliard_postResults + private :: & + vacancyflux_cahnhilliard_getFormationEnergy, & + vacancyflux_cahnhilliard_getEntropicCoeff, & + vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_cahnhilliard_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + vacancyflux_type, & + vacancyflux_typeInstance, & + homogenization_Noutput, & + VACANCYFLUX_cahnhilliard_label, & + VACANCYFLUX_cahnhilliard_ID, & + material_homog, & + mappingHomogenization, & + vacancyfluxState, & + vacancyfluxMapping, & + vacancyConc, & + vacancyConcRate, & + vacancyflux_initialCv, & + material_partHomogenization, & + material_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o,offset + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_cahnhilliard_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(vacancyflux_type == VACANCYFLUX_cahnhilliard_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(vacancyflux_cahnhilliard_sizePostResults(maxNinstance), source=0_pInt) + allocate(vacancyflux_cahnhilliard_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(vacancyflux_cahnhilliard_output (maxval(homogenization_Noutput),maxNinstance)) + vacancyflux_cahnhilliard_output = '' + allocate(vacancyflux_cahnhilliard_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(vacancyflux_cahnhilliard_Noutput (maxNinstance), source=0_pInt) + + allocate(vacancyflux_cahnhilliard_flucAmplitude (maxNinstance)) + allocate(vacancyflux_cahnhilliard_thermalFluc (maxNinstance)) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (vacancyflux_type(section) == VACANCYFLUX_cahnhilliard_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = vacancyflux_typeInstance(section) ! which instance of my vacancyflux is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('vacancyconc') + vacancyflux_cahnhilliard_Noutput(instance) = vacancyflux_cahnhilliard_Noutput(instance) + 1_pInt + vacancyflux_cahnhilliard_outputID(vacancyflux_cahnhilliard_Noutput(instance),instance) = vacancyConc_ID + vacancyflux_cahnhilliard_output(vacancyflux_cahnhilliard_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('vacancyflux_flucamplitude') + vacancyflux_cahnhilliard_flucAmplitude(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingHomog + + initializeInstances: do section = 1_pInt, size(vacancyflux_type) + if (vacancyflux_type(section) == VACANCYFLUX_cahnhilliard_ID) then + NofMyHomog=count(material_homog==section) + instance = vacancyflux_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,vacancyflux_cahnhilliard_Noutput(instance) + select case(vacancyflux_cahnhilliard_outputID(o,instance)) + case(vacancyConc_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + vacancyflux_cahnhilliard_sizePostResult(o,instance) = mySize + vacancyflux_cahnhilliard_sizePostResults(instance) = vacancyflux_cahnhilliard_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 0_pInt + vacancyfluxState(section)%sizeState = sizeState + vacancyfluxState(section)%sizePostResults = vacancyflux_cahnhilliard_sizePostResults(instance) + allocate(vacancyfluxState(section)%state0 (sizeState,NofMyHomog)) + allocate(vacancyfluxState(section)%subState0(sizeState,NofMyHomog)) + allocate(vacancyfluxState(section)%state (sizeState,NofMyHomog)) + + allocate(vacancyflux_cahnhilliard_thermalFluc(instance)%p(NofMyHomog)) + do offset = 1_pInt, NofMyHomog + call random_number(vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset)) + vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset) = & + 1.0_pReal - & + vacancyflux_cahnhilliard_flucAmplitude(instance)* & + (vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset) - 0.5_pReal) + enddo + + nullify(vacancyfluxMapping(section)%p) + vacancyfluxMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(vacancyConc (section)%p) + allocate (vacancyConc (section)%p(NofMyHomog), source=vacancyflux_initialCv(section)) + deallocate(vacancyConcRate(section)%p) + allocate (vacancyConcRate(section)%p(NofMyHomog), source=0.0_pReal) + + endif + + enddo initializeInstances + +end subroutine vacancyflux_cahnhilliard_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates homogenized vacancy driving forces +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_cahnhilliard_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + phase_source, & + phase_Nsources, & + SOURCE_vacancy_phenoplasticity_ID, & + SOURCE_vacancy_irradiation_ID, & + SOURCE_vacancy_thermalfluc_ID + use source_vacancy_phenoplasticity, only: & + source_vacancy_phenoplasticity_getRateAndItsTangent + use source_vacancy_irradiation, only: & + source_vacancy_irradiation_getRateAndItsTangent + use source_vacancy_thermalfluc, only: & + source_vacancy_thermalfluc_getRateAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Cv + integer(pInt) :: & + phase, & + grain, & + source + real(pReal) :: & + CvDot, dCvDot_dCv, localCvDot, dLocalCvDot_dCv + + CvDot = 0.0_pReal + dCvDot_dCv = 0.0_pReal + do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) + phase = phaseAt(grain,ip,el) + do source = 1_pInt, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_vacancy_phenoplasticity_ID) + call source_vacancy_phenoplasticity_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) + + case (SOURCE_vacancy_irradiation_ID) + call source_vacancy_irradiation_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) + + case (SOURCE_vacancy_thermalfluc_ID) + call source_vacancy_thermalfluc_getRateAndItsTangent(localCvDot, dLocalCvDot_dCv, grain, ip, el) + + end select + CvDot = CvDot + localCvDot + dCvDot_dCv = dCvDot_dCv + dLocalCvDot_dCv + enddo + enddo + + CvDot = CvDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + dCvDot_dCv = dCvDot_dCv/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + +end subroutine vacancyflux_cahnhilliard_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized vacancy mobility tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function vacancyflux_cahnhilliard_getMobility33(ip,el) + use lattice, only: & + lattice_vacancyfluxMobility33 + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + vacancyflux_cahnhilliard_getMobility33 + integer(pInt) :: & + grain + + vacancyflux_cahnhilliard_getMobility33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + vacancyflux_cahnhilliard_getMobility33 = vacancyflux_cahnhilliard_getMobility33 + & + crystallite_push33ToRef(grain,ip,el,lattice_vacancyfluxMobility33(:,:,material_phase(grain,ip,el))) + enddo + + vacancyflux_cahnhilliard_getMobility33 = & + vacancyflux_cahnhilliard_getMobility33/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function vacancyflux_cahnhilliard_getMobility33 + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized vacancy diffusion tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function vacancyflux_cahnhilliard_getDiffusion33(ip,el) + use lattice, only: & + lattice_vacancyfluxDiffusion33 + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + vacancyflux_cahnhilliard_getDiffusion33 + integer(pInt) :: & + grain + + vacancyflux_cahnhilliard_getDiffusion33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + vacancyflux_cahnhilliard_getDiffusion33 = vacancyflux_cahnhilliard_getDiffusion33 + & + crystallite_push33ToRef(grain,ip,el,lattice_vacancyfluxDiffusion33(:,:,material_phase(grain,ip,el))) + enddo + + vacancyflux_cahnhilliard_getDiffusion33 = & + vacancyflux_cahnhilliard_getDiffusion33/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function vacancyflux_cahnhilliard_getDiffusion33 + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized vacancy formation energy +!-------------------------------------------------------------------------------------------------- +real(pReal) function vacancyflux_cahnhilliard_getFormationEnergy(ip,el) + use lattice, only: & + lattice_vacancyFormationEnergy, & + lattice_vacancyVol, & + lattice_vacancySurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + integer(pInt) :: & + grain + + vacancyflux_cahnhilliard_getFormationEnergy = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + vacancyflux_cahnhilliard_getFormationEnergy = vacancyflux_cahnhilliard_getFormationEnergy + & + lattice_vacancyFormationEnergy(material_phase(grain,ip,el))/ & + lattice_vacancyVol(material_phase(grain,ip,el))/ & + lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) + enddo + + vacancyflux_cahnhilliard_getFormationEnergy = & + vacancyflux_cahnhilliard_getFormationEnergy/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function vacancyflux_cahnhilliard_getFormationEnergy + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized vacancy entropy coefficient +!-------------------------------------------------------------------------------------------------- +real(pReal) function vacancyflux_cahnhilliard_getEntropicCoeff(ip,el) + use lattice, only: & + lattice_vacancyVol, & + lattice_vacancySurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_homog, & + material_phase, & + temperature, & + thermalMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + integer(pInt) :: & + grain + + vacancyflux_cahnhilliard_getEntropicCoeff = 0.0_pReal + do grain = 1, homogenization_Ngrains(material_homog(ip,el)) + vacancyflux_cahnhilliard_getEntropicCoeff = vacancyflux_cahnhilliard_getEntropicCoeff + & + kB/ & + lattice_vacancyVol(material_phase(grain,ip,el))/ & + lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) + enddo + + vacancyflux_cahnhilliard_getEntropicCoeff = & + vacancyflux_cahnhilliard_getEntropicCoeff* & + temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))/ & + homogenization_Ngrains(material_homog(ip,el)) + +end function vacancyflux_cahnhilliard_getEntropicCoeff + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized kinematic contribution to chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCv, Cv, ip, el) + use lattice, only: & + lattice_vacancySurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_homog, & + phase_kinematics, & + phase_Nkinematics, & + material_phase, & + KINEMATICS_vacancy_strain_ID + use crystallite, only: & + crystallite_Tstar_v, & + crystallite_Fi0, & + crystallite_Fi + use kinematics_vacancy_strain, only: & + kinematics_vacancy_strain_ChemPotAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Cv + real(pReal), intent(out) :: & + KPot, dKPot_dCv + real(pReal) :: & + my_KPot, my_dKPot_dCv + integer(pInt) :: & + grain, kinematics + + KPot = 0.0_pReal + dKPot_dCv = 0.0_pReal + do grain = 1_pInt,homogenization_Ngrains(material_homog(ip,el)) + do kinematics = 1_pInt, phase_Nkinematics(material_phase(grain,ip,el)) + select case (phase_kinematics(kinematics,material_phase(grain,ip,el))) + case (KINEMATICS_vacancy_strain_ID) + call kinematics_vacancy_strain_ChemPotAndItsTangent(my_KPot, my_dKPot_dCv, & + crystallite_Tstar_v(1:6,grain,ip,el), & + crystallite_Fi0(1:3,1:3,grain,ip,el), & + crystallite_Fi (1:3,1:3,grain,ip,el), & + grain,ip, el) + + case default + my_KPot = 0.0_pReal + my_dKPot_dCv = 0.0_pReal + + end select + KPot = KPot + my_KPot/lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) + dKPot_dCv = dKPot_dCv + my_dKPot_dCv/lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) + enddo + enddo + + KPot = KPot/homogenization_Ngrains(material_homog(ip,el)) + dKPot_dCv = dKPot_dCv/homogenization_Ngrains(material_homog(ip,el)) + +end subroutine vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized chemical potential and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_cahnhilliard_getChemPotAndItsTangent(ChemPot,dChemPot_dCv,Cv,ip,el) + use numerics, only: & + vacancyBoundPenalty, & + vacancyPolyOrder + use material, only: & + mappingHomogenization, & + vacancyflux_typeInstance, & + porosity, & + porosityMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Cv + real(pReal), intent(out) :: & + ChemPot, & + dChemPot_dCv + real(pReal) :: & + VoidPhaseFrac, kBT, KPot, dKPot_dCv + integer(pInt) :: & + homog, o + + homog = mappingHomogenization(2,ip,el) + VoidPhaseFrac = porosity(homog)%p(porosityMapping(homog)%p(ip,el)) + kBT = vacancyflux_cahnhilliard_getEntropicCoeff(ip,el) + + ChemPot = vacancyflux_cahnhilliard_getFormationEnergy(ip,el) + dChemPot_dCv = 0.0_pReal + do o = 1_pInt, vacancyPolyOrder + ChemPot = ChemPot + kBT*((2.0_pReal*Cv - 1.0_pReal)**real(2_pInt*o-1_pInt,pReal))/ & + real(2_pInt*o-1_pInt,pReal) + dChemPot_dCv = dChemPot_dCv + 2.0_pReal*kBT*(2.0_pReal*Cv - 1.0_pReal)**real(2_pInt*o-2_pInt,pReal) + enddo + + ChemPot = VoidPhaseFrac*VoidPhaseFrac*ChemPot & + - 2.0_pReal*(1.0_pReal - Cv)*(1.0_pReal - VoidPhaseFrac)*(1.0_pReal - VoidPhaseFrac) + + dChemPot_dCv = VoidPhaseFrac*VoidPhaseFrac*dChemPot_dCv & + + 2.0_pReal*(1.0_pReal - VoidPhaseFrac)*(1.0_pReal - VoidPhaseFrac) + + call vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCv, Cv, ip, el) + ChemPot = ChemPot + KPot + dChemPot_dCv = dChemPot_dCv + dKPot_dCv + + if (Cv < 0.0_pReal) then + ChemPot = ChemPot - 3.0_pReal*vacancyBoundPenalty*Cv*Cv + dChemPot_dCv = dChemPot_dCv - 6.0_pReal*vacancyBoundPenalty*Cv + elseif (Cv > 1.0_pReal) then + ChemPot = ChemPot + 3.0_pReal*vacancyBoundPenalty*(1.0_pReal - Cv)*(1.0_pReal - Cv) + dChemPot_dCv = dChemPot_dCv - 6.0_pReal*vacancyBoundPenalty*(1.0_pReal - Cv) + endif + + ChemPot = ChemPot* & + vacancyflux_cahnhilliard_thermalFluc(vacancyflux_typeInstance(homog))%p(mappingHomogenization(1,ip,el)) + dChemPot_dCv = dChemPot_dCv* & + vacancyflux_cahnhilliard_thermalFluc(vacancyflux_typeInstance(homog))%p(mappingHomogenization(1,ip,el)) + +end subroutine vacancyflux_cahnhilliard_getChemPotAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief updated vacancy concentration and its rate with solution from transport PDE +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_cahnhilliard_putVacancyConcAndItsRate(Cv,Cvdot,ip,el) + use material, only: & + mappingHomogenization, & + vacancyConc, & + vacancyConcRate, & + vacancyfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Cv, & + Cvdot + integer(pInt) :: & + homog, & + offset + + homog = mappingHomogenization(2,ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + vacancyConc (homog)%p(offset) = Cv + vacancyConcRate(homog)%p(offset) = Cvdot + +end subroutine vacancyflux_cahnhilliard_putVacancyConcAndItsRate + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of vacancy transport results +!-------------------------------------------------------------------------------------------------- +function vacancyflux_cahnhilliard_postResults(ip,el) + use material, only: & + mappingHomogenization, & + vacancyflux_typeInstance, & + vacancyConc, & + vacancyfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(vacancyflux_cahnhilliard_sizePostResults(vacancyflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & + vacancyflux_cahnhilliard_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + instance = vacancyflux_typeInstance(homog) + + c = 0_pInt + vacancyflux_cahnhilliard_postResults = 0.0_pReal + + do o = 1_pInt,vacancyflux_cahnhilliard_Noutput(instance) + select case(vacancyflux_cahnhilliard_outputID(o,instance)) + + case (vacancyConc_ID) + vacancyflux_cahnhilliard_postResults(c+1_pInt) = vacancyConc(homog)%p(offset) + c = c + 1 + end select + enddo +end function vacancyflux_cahnhilliard_postResults + +end module vacancyflux_cahnhilliard diff --git a/code/vacancyflux/vacancyflux_isochempot.f90 b/code/vacancyflux/vacancyflux_isochempot.f90 new file mode 100644 index 000000000..35db8d159 --- /dev/null +++ b/code/vacancyflux/vacancyflux_isochempot.f90 @@ -0,0 +1,329 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for locally evolving vacancy concentration +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module vacancyflux_isochempot + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + vacancyflux_isochempot_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + vacancyflux_isochempot_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + vacancyflux_isochempot_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + vacancyflux_isochempot_Noutput !< number of outputs per instance of this damage + + enum, bind(c) + enumerator :: undefined_ID, & + vacancyconc_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + vacancyflux_isochempot_outputID !< ID of each post result output + + + public :: & + vacancyflux_isochempot_init, & + vacancyflux_isochempot_updateState, & + vacancyflux_isochempot_getSourceAndItsTangent, & + vacancyflux_isochempot_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_isochempot_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + vacancyflux_type, & + vacancyflux_typeInstance, & + homogenization_Noutput, & + VACANCYFLUX_isochempot_label, & + VACANCYFLUX_isochempot_ID, & + material_homog, & + mappingHomogenization, & + vacancyfluxState, & + vacancyfluxMapping, & + vacancyConc, & + vacancyConcRate, & + vacancyflux_initialCv, & + material_partHomogenization + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_isochempot_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(vacancyflux_type == VACANCYFLUX_isochempot_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(vacancyflux_isochempot_sizePostResults(maxNinstance), source=0_pInt) + allocate(vacancyflux_isochempot_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(vacancyflux_isochempot_output (maxval(homogenization_Noutput),maxNinstance)) + vacancyflux_isochempot_output = '' + allocate(vacancyflux_isochempot_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(vacancyflux_isochempot_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (vacancyflux_type(section) == VACANCYFLUX_isochempot_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = vacancyflux_typeInstance(section) ! which instance of my vacancyflux is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('vacancyconc') + vacancyflux_isochempot_Noutput(instance) = vacancyflux_isochempot_Noutput(instance) + 1_pInt + vacancyflux_isochempot_outputID(vacancyflux_isochempot_Noutput(instance),instance) = vacancyconc_ID + vacancyflux_isochempot_output(vacancyflux_isochempot_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingFile + + initializeInstances: do section = 1_pInt, size(vacancyflux_type) + if (vacancyflux_type(section) == VACANCYFLUX_isochempot_ID) then + NofMyHomog=count(material_homog==section) + instance = vacancyflux_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,vacancyflux_isochempot_Noutput(instance) + select case(vacancyflux_isochempot_outputID(o,instance)) + case(vacancyconc_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + vacancyflux_isochempot_sizePostResult(o,instance) = mySize + vacancyflux_isochempot_sizePostResults(instance) = vacancyflux_isochempot_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 1_pInt + vacancyfluxState(section)%sizeState = sizeState + vacancyfluxState(section)%sizePostResults = vacancyflux_isochempot_sizePostResults(instance) + allocate(vacancyfluxState(section)%state0 (sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) + allocate(vacancyfluxState(section)%subState0(sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) + allocate(vacancyfluxState(section)%state (sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) + + nullify(vacancyfluxMapping(section)%p) + vacancyfluxMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(vacancyConc(section)%p) + vacancyConc(section)%p => vacancyfluxState(section)%state(1,:) + deallocate(vacancyConcRate(section)%p) + allocate(vacancyConcRate(section)%p(NofMyHomog), source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine vacancyflux_isochempot_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates change in vacancy concentration based on local vacancy generation model +!-------------------------------------------------------------------------------------------------- +function vacancyflux_isochempot_updateState(subdt, ip, el) + use numerics, only: & + err_vacancyflux_tolAbs, & + err_vacancyflux_tolRel + use material, only: & + mappingHomogenization, & + vacancyflux_typeInstance, & + vacancyfluxState, & + vacancyConc, & + vacancyConcRate, & + vacancyfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + subdt + logical, dimension(2) :: & + vacancyflux_isochempot_updateState + integer(pInt) :: & + homog, & + offset, & + instance + real(pReal) :: & + Cv, Cvdot, dCvDot_dCv + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + instance = vacancyflux_typeInstance(homog) + + Cv = vacancyfluxState(homog)%subState0(1,offset) + call vacancyflux_isochempot_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) + Cv = Cv + subdt*Cvdot + + vacancyflux_isochempot_updateState = [ abs(Cv - vacancyfluxState(homog)%state(1,offset)) & + <= err_vacancyflux_tolAbs & + .or. abs(Cv - vacancyfluxState(homog)%state(1,offset)) & + <= err_vacancyflux_tolRel*abs(vacancyfluxState(homog)%state(1,offset)), & + .true.] + + vacancyConc (homog)%p(vacancyfluxMapping(homog)%p(ip,el)) = Cv + vacancyConcRate(homog)%p(vacancyfluxMapping(homog)%p(ip,el)) = & + (vacancyfluxState(homog)%state(1,offset) - vacancyfluxState(homog)%subState0(1,offset))/(subdt+tiny(0.0_pReal)) + +end function vacancyflux_isochempot_updateState + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates homogenized vacancy driving forces +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_isochempot_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + phase_source, & + phase_Nsources, & + SOURCE_vacancy_phenoplasticity_ID, & + SOURCE_vacancy_irradiation_ID, & + SOURCE_vacancy_thermalfluc_ID + use source_vacancy_phenoplasticity, only: & + source_vacancy_phenoplasticity_getRateAndItsTangent + use source_vacancy_irradiation, only: & + source_vacancy_irradiation_getRateAndItsTangent + use source_vacancy_thermalfluc, only: & + source_vacancy_thermalfluc_getRateAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Cv + integer(pInt) :: & + phase, & + grain, & + source + real(pReal) :: & + CvDot, dCvDot_dCv, localCvDot, dLocalCvDot_dCv + + CvDot = 0.0_pReal + dCvDot_dCv = 0.0_pReal + do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) + phase = phaseAt(grain,ip,el) + do source = 1_pInt, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_vacancy_phenoplasticity_ID) + call source_vacancy_phenoplasticity_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) + + case (SOURCE_vacancy_irradiation_ID) + call source_vacancy_irradiation_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) + + case (SOURCE_vacancy_thermalfluc_ID) + call source_vacancy_thermalfluc_getRateAndItsTangent(localCvDot, dLocalCvDot_dCv, grain, ip, el) + + end select + CvDot = CvDot + localCvDot + dCvDot_dCv = dCvDot_dCv + dLocalCvDot_dCv + enddo + enddo + + CvDot = CvDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + dCvDot_dCv = dCvDot_dCv/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + +end subroutine vacancyflux_isochempot_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of vacancy transport results +!-------------------------------------------------------------------------------------------------- +function vacancyflux_isochempot_postResults(ip,el) + use material, only: & + mappingHomogenization, & + vacancyflux_typeInstance, & + vacancyConc, & + vacancyfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(vacancyflux_isochempot_sizePostResults(vacancyflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & + vacancyflux_isochempot_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + instance = vacancyflux_typeInstance(homog) + + c = 0_pInt + vacancyflux_isochempot_postResults = 0.0_pReal + + do o = 1_pInt,vacancyflux_isochempot_Noutput(instance) + select case(vacancyflux_isochempot_outputID(o,instance)) + + case (vacancyconc_ID) + vacancyflux_isochempot_postResults(c+1_pInt) = vacancyConc(homog)%p(offset) + c = c + 1 + end select + enddo +end function vacancyflux_isochempot_postResults + +end module vacancyflux_isochempot diff --git a/code/vacancyflux/vacancyflux_isoconc.f90 b/code/vacancyflux/vacancyflux_isoconc.f90 new file mode 100644 index 000000000..63cfb1b62 --- /dev/null +++ b/code/vacancyflux/vacancyflux_isoconc.f90 @@ -0,0 +1,63 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for constant vacancy concentration +!-------------------------------------------------------------------------------------------------- +module vacancyflux_isoconc + + implicit none + private + + public :: & + vacancyflux_isoconc_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_isoconc_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_isoconc_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (vacancyflux_type(homog) == VACANCYFLUX_isoconc_ID) then + NofMyHomog = count(material_homog == homog) + vacancyfluxState(homog)%sizeState = 0_pInt + vacancyfluxState(homog)%sizePostResults = 0_pInt + allocate(vacancyfluxState(homog)%state0 (0_pInt,NofMyHomog)) + allocate(vacancyfluxState(homog)%subState0(0_pInt,NofMyHomog)) + allocate(vacancyfluxState(homog)%state (0_pInt,NofMyHomog)) + + deallocate(vacancyConc (homog)%p) + allocate (vacancyConc (homog)%p(1), source=vacancyflux_initialCv(homog)) + deallocate(vacancyConcRate(homog)%p) + allocate (vacancyConcRate(homog)%p(1), source=0.0_pReal) + + endif myhomog + enddo initializeInstances + + +end subroutine vacancyflux_isoconc_init + +end module vacancyflux_isoconc diff --git a/lib/damask/core.so b/lib/damask/core.so new file mode 100755 index 0000000000000000000000000000000000000000..7f744dafa08ce566942c429233d709e85fbcf11b GIT binary patch literal 2117501 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 z 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%0D*Ti17!eSW|(;6 ziQ;`}wNY>RQKTvq@pMILU)~y767SJ@e#%CQG7*f3msb;SYcg*Z5%1=K0&kSUn*wTq zm+>tSFEdQMsbqOZq8MtSm=0F-ht?Ke-Wt=V3j1FDjvw!%iZUIHh?iFrZ)Y+e#3H_~ zy@0AiF{S~R2$pJJNmL;+pZ%JG1Xkk!@M`*|&{ zZgvRCb=6lM7MJs|nUtw`Czz?bxLVuEf3=`z4d$mr?41T}XSd zGbYy-hY&U=iqTeIjx!A}7W+Lgl-LmkuYl=v{(B5KB6-eQ{@4#eybFZilMp6E@d?X75Hj$AK0hhb~ zVm9d_jj!VrWBB_xgIQS-$*BOhz9I{YM?{{BTcZ=K9Fgl~lIum1Yo5t<)a%eZh%2+C zXUrK)u0MIfmD}(&-<)(})pr_mCbK>>w%kn*ks6d0jR3Wzo5@?C8p-na|Fr>Bv%vwn z&S@uf9S3@$Yux-$RLqhC(m9jJwKq@!!7vL!Sy3f2k}&wiQ6s!H_UVE~vuHG5+~H@y znjdKa!m=V>@GK7#7ENc7MY2dcs|em`hSCe;Iz*!sZ;k1oiD>2n1F*Na81*)b0(|XW zptvCWG6RptthKom`J!kW8K0w|X-i++2#InYnUodrg4b_}asi91m&(5oRKzKZERjWc zL4#tEVitK-*(<2X%_7dsESE)ik*&6e z&EZz`DBi5r^P)$0)K}rPJ-obUE8ch*o0u_ia~U$t7xy&p&BlcjMVY4Th0359M}Kj9 zW-|sYUqH9?wmX7|zmytam)dUJqaM6hY{v~IPB-J?8k*?#c3q7-K2Vi)Z(Ri1FK8u~ zJ}BO~9E}pYSRZzzIG5oLx2Ik9KHp-qfm=W9(T69>L8?c8A`5ILldrGsOj5e^+tOY7 z-JOw@=g}Y2Joul-Qin2X{X(3t6e2kF&-PH*0D+a7wpb<^FwId3y-bg3lV*}nU*^n_T(E< zM@%tGa|r7IMfU3rRMl0;46Lfho)J}*h-80Nb&bIfhj%ukVKC@DogXl zs;cOT9dTww7>kNTB@}@}U?s3*SS3_Wh*$|ZD340GMO>0QiAw{O;JxtQtb}U|{zxSp zf!v7gWfL+3D`EfBq7uG9vQ-Hm;8%l{@a>#Pm5`63^;JUg?^nY0?BKo4(!n9H5?C^< z67GQSL}&>$z=lew7MJ8*;?h7R9OZtCf2SqPd-ji1!eq#eSP6edW?&`!`6*EeeUPjw z0ZTfSFT=)+ItXALsRi6$hs&0D^c5bx)T5VaL(i9fjxeR?VP8p~ZxKNCyVBwG<*=Ho zEK4*Tmp%Y3B|pWZ4@Dz*BFk9Ge%agXM}$RbX^7j1AE9PO93mfMk93j`8Ab!%WOz;d zR&O%QpdIC#49_7q50$_KIbKE0Oc>c|m1ECiqHJQ?m*LRKE#I@uMCSkdLubR?%FL1e##F_^rHPHg@JH zFPMZli75eeyTAQrehfCbJKl)Ic)-{_3cC8b#^1)#OvVqme4YhYH+nDOA-vClMyZM_m&+i1PY4<`>(RU*fYSzS${~my?IvTNKY<1-~{@ zb6T0F#2*-Y~qqGW8oIqr0~k{ta8AP?nph z0+!gvGc|BQ#)*mMO8eAdNXH9q9ag*2O0c?*4G7p?rrAolsNO2un{>0wR*|hIP1EX1 zT$!u$54rV{-oB(Ptdirs{v$VF&xw~iO7o8#813Rmv3KC@pIbR8ft{zD z@r38vc!rxHQhWJg8~5-!`u5NrKlbpp*F3iJ9{R&SVl}eVgW2<+kv~Y3@@aLh%xz<@ z)b!0*RE`lJ>b8|=w(Y=Q>C(%wvjE!)ys?*b)3cxZ4WDOa1+pYQx{D1+m=hk>M~uE( zqkiDUs;1?4cj2C*63dF1i$X9vKRBC?U+0YDa00jYgB1L5`Eo)&l`TFvyPw|z_kPO4 zMiHWiXXu^|n>RCLPp1~Ki+0@33glO}F zvqU2`dLucog`H(%Xt^9OS2hN6=MoN|jP+xJd4l9swBMy zNKSY0q$%tdE;Wikl2i1v`27179$`W@k)^W53FkMQVlK*`s~BA`4o z)gO_BEhmF{h$46N3qv^&RQ1`ivajEkHz}0Yz!ckh*N^gq=&zHvyhxM>;sJ3J47ol; z{?0psA?}2a;z*q)qKQ?n2kejn@2~(zB+5TNGz(C}>N(*B9%KQmdYJ{DL4o?zJBwze zD&cPO+yM}n`iZJ`fhUk33jwlcDO?}`$Q33Krd20}1DOi};*n1w|0Q3kifMqT>fLa* z5D8DSKtNL{H4E@Tx0>hjgcP`)1^B$KB>c@RKql4Ch8MVj1^BeC3fylN;FD=}Zg_zN z7T{~vszAC~fCjF_qbA;voF<$@h3!w6)ZsUO2T@x0AW@y4=*r> z1p?|}j#+?)kYAGacd8=7jAj9vP)T@L7HGVLlPd@A4Z-u*;cy@Nfug>}q^1=Pq=!(a zgs7V+sO^Q9gToRrQ{|m0x?L`$bLmyY>$0LQ=!$6{@9nV#XJYJAkK+gW>pUduGsT&Z zdJ)f<6ajyE7Lv_?ulo7j=d9SzZ16%~;Uiy6-jELt+%t|o!X99`#-CxI9LE>zMZi9V z9)K*20*o_ULw9nA-44y(2aEOHLplwFUQPcI-<`&WXSaUZxZw$osKTkh7~KTU@7r!% z2d3ioN5qcPh#i66@zZ0%J6dbrB94YD=#KFWdtjq%2a1>>uu0}FO#!2kz3`)Ggx9L%(wmtENp$Y(!Qj}a29 z-$k_|7X9ou#DQL5z_z5^^L3O){7eqFV9J3<{H01*Dxi@)7_n5=flmHXFS8Vbm6Fv# zmO4LJ*0ZRsNg$Hn!d6bKohpS*Fov0iM&=dnURSJ(Yi1Gs8!xS6RA9BHpwaez*jj#k zUJS#1$!`?+dktFFcn^M!fo9R0I6MUYP2cfP4t=RUKR=R9A#m>6kyFpKVBK&mw|RSZ z#D>0N?AI%f!b{taIo{>)v2SO&m2u=Y?D-q}?Qr{!?RX;xFYO$t;+x%$cU=Wv$GQrB zOUVDm>AfqxXw#TjXVben=XkGbTH(Y4v25icc%J&2jon^Yg1-@`EvIIS`R4wO#eDMu z32FTt&`1HJQs2RZNO#STpGRZb~xwEt^LVWv1wiaOIs zh~g{KLezy}qL_tIC`FZ1)JTW|dwQ_Fur->8RFZX#V>9vmP@7n!9T7Fzm1uk7wDais}zhHiW1>iINo2B_z_ri7p`#_H+tP zXZ{Q#o=z9SsX2+*6L5(79f@uYCpy{_L=4>|T0kQ4VqtKf@;!;z;gHBnq7(QLBCd=? z>|{tZoJ1AjL<>p8rb!|vi8#Ou;q(fL82(7qmPDL^4I!FDA~shNof-z87#2b?oD>Wm zr1*{$-9jjG19^Nxij)wF8%bf>@I_F#hkn`xO|5&u_{G1$DUQH5BD(m;PT}Hzi>2S? zR0yX#)FZ^db1Hc9kERc*G@>!wQ1a)94g!xWd?JVQ;FR*xzp(eo7zU$(oj9p-#PWEHLJ|friB-i~h!XBMXuD!yz zG7Gace{h4x>9v)w&QjOFNcA_|@hQm)ZS!6Qt;hY;U_ zt;H-Qcq9eC%Pz(n*IEx0e76)_Ou@xQc0+p=Hh~`6HkR6Irna3zel;DG8zfK zS))A>`F`J3Sficbn=?gJL2fA1oGFZV;5gk_1pA&UorIqaFnvKX{WeNOsCgnnH4bAs zk8K(eW`S`Zm|{azwl0DoUMp;d_jYR0-Fb^@F~Gq@ggXAzKwQM&NG#)f#fm+qW()*Q zw^y#_d&SzmIQ~>D4d|=+iY4C5(a&HUQtY;^#wr?K>RbuYE?+`4&L$BXKub6xvKM_w zMB@DsYyho}ar*|~)R|KI)R&NsH8l?ot4iDE@wIP^jiZ=g+u_2gGnim&(Y*|tKKW0) zySXj@$Z@BAVzv+aKua(^_YF>{$*dgpCudpgKS-q2;Vr~Uo(HqaZQG>bZO6=0_Q^w0 zaRF;`)em5AL@P%?c9m8cCccs{fCF`oVPdph?x@t#!m-uuFro9Mo~R59!DCcL;ssFqA}18J#goc z2?HCD8dY0o6^lpys=??6%ZkhygzDR{LkR;eabB{R75+*RnA6MEw_t;lNx+2z<26aZ zdj^Q=-VhOf+A(LT15Z0P1_`-L7GXu7!)RH(182eFIp*^TILEFdpx7HczfPWAhnIX^ z`c@n&=kzvmW;T8%6EAnTd8)%1qZ_0k0E^#vr`+M|UZ=-8jHVnn;!{Pw(GF~UI8#@u z4|K#DCmuRhrw$1#6>_cfiMYx1KJ3Wf;l{oOw_btCk!^1MJ8yHR{)6szEO6^vw4tl9 zYT@=ac6*<|#^0@oYp3!5sLNK17b{)*Z&*6@q~RsRbIy`Omt@-xI5(cn@wUYt@qrEl z?;_slI<>=N`w@S=Ej_kM_s}(-p;+k{?yLJkX~$+dJN|K;M8f0-Tv;X@3q!Z(}WE2i`dx=%^%|VjS0YeNS)F#X!*so3StN zsVCuo`-`i;5nV9t>ZM(wdpQeKxV^M1MASmfr#qY!3lLZU!V86Cv+>HJ$JZs*m3GE$ z`vINtExmk6PjvTo>5E>khd0U9P4D7@guY1Xjo-cSyBB`<#w(7l%oF+F`P?@~`);et z+&=bFIF1MFXZDZQyKIIhZEvZ_=eb^w>-Fe$4{+9R}|YboO%(Js*ov_Gw*F z0h+gOXSWygbvP-ms0x^SFJo-0o4razufH6zr)FUwO9${ zkS)rUR@~dyK8ww_rnj%-BsSbyyh@zNR&Hpv{R{=g8V{x%4#OM!d@o(UByB1Q!6Nr@8e6l z9u?9m2CJkO#K!dXC8Y)bY#;pdI`Olw@8OkEvIG`-^FMR5^|EbLVP^nrSm((+GwLGE zo9!@Mwi3LMiQT*$AxAO#;dSvth#+p88|vbGyvbL?#tb#ZY-i7V3<>kV zk#RyvOPo+bM)smLNS5zm`0k7szRJg3x4s!+C+$ZV76o=U7USCOJdUJ=R+jx8A($^H z9icf|WS@xQA8e7$K7q}#*(cI*KuNroc|3o&D|7p(BrGi30e-tIh_UW=j&(~!y9M+C zfS$us*sg+b^a*HjjWzfH*3IMXMVyn#(YG-GmsDTU;ZTn48@X(`@ibmUMmtA4!tCk_ zEo}?l9nQz(r1)2Js|#Dnd=Iz7n0sX+jt&{sTTe>urT4o!-jlg8e^+;(yCtJVcII~b zb7Gi}zQ%WNJi3={I9nuujozjPr<8Bo++p>`GulwJ%HHX&YTw9Ob{7Tk$F&zJ=2)s;{1q?(sc5h&O)%=*P9p{rS7H zeeP?cof6X6OQ0EYE`}eh4ua!OD|P8f*sEV_Zk;a0YmL>b(b0FpTT! zMf=i*HpdJV!j64f5gy+(FZzp@Cjl7x-w_(x%?KW418*PaO2dIT_vND1@a^y#ka+N( z8=9wEy~qPMa12H=TxFOe9%1@?mu<5<4Tl?SMnI4a6NS-W!7dMjgh_lo4)?iisEB$= z>Eg6J++?|JTU<6AUt8!X2SdDqFj9Cy@;y)Bp&qCpw4WnO)4Mp>wp+7Zr)X%@sTx?N z)6oaBlNo_s1-*Q2W1t~G<_VS2cPWVZmfeSKZ7bnD9;^Thq=E1)~ho4^kZiHVR$TMTwXkHO-H z+cDCOqmGI}A%YuDTf{B8X-HotIPy>myrhj(k8PKR7pv!r+ZBAnDIGk-!M@8JQ;_Py zdvU-q3AcTG5^j#=UsuVISoY)2)p;7#N5wf({w@qk=# z8e#9RyaNJ)cYcmPc%2`;d-i6WV}aJY!9H~aD6)0z(5O4L0~MRjm*ZJIPFp480`#D+ zr*_~sU2EtL4Vy~Q8XlwO@yKGe){-&m6?<|Z4(|%!>ap$B)XV6{y4e#GYWX+zG=dzC zUrV?E$IA|gZFS6^hjS7KG>gVIfn(k6EfP{ZI5`864=;)-w%|dwZXlT=6jcU5K5c?M zuC!E^BAFzT_IhlqR7PiH^zn7sJ@7xeXY>;mOlCbSxEA5ei!HUkni4!7sw|A6F$ z9U4WkV>q9ELeh00?TmsCS0tijTbiV$gQX6z)Ub_-D0UD(uYFn-yN<=$Ux%LRmLB%R z?1~f=>nMtKX*E3CK42Bgjo+Ap`@AwH#5q|q$KI;Z@Sf$nX1giEYnul z4`te$1_$xO6)7w;47O7?Z>-8Fo6~YA(?yyL71dG58efsla-(51d)_(7>bl_uWinLr zEtJk zl@6y#OxVG{vEO5o2{!{0;7$W#FEHEI+t?k0N+XZ~88dnbBtupCG6wgYb4 zaW|e$Ci9S4H;&0*Xu+_jHKj7VaE{9+`w4gEHv8l_K_}uef*|<0(HsX8mTee17f})c zTk!0GXVdC$G1;wjwvat_Hxc0eF<#B?~+*OzcU+jbQw`}$%p zU|TeBF9V`RY5E2paxy~P%Gc-FodpKQY;{%%ZBKwQE*{-mig*h<$u*H;E_T zQW@1Y0Bg83*-c4ihiy*jiLkPnKGm`#@wDuc z1fO1y|2UInz>oO975@+8|31ct_56bzwoF6}wj6{G(M-#+A_}s0#qxUX5?(>w>?7PT z&{yCOS}Ojc?e(;`a95xbR$$=voqcj2hL=_UraIXh1@10M61_dO%$~Z{p1Kbx)}tK` zh~3P;(3BUb%FFo8XtzSI!vu$8Bm-0tK@^D3UMp2OA+OgS;uX|!KjWr8Rk8zAxgDyo zkBEYAxHGFq^ExqgKJl^eZ+i(Xc0BI!X<= zez##ig7@$=F9vNGpaBL)eHdmTW^nk1ww}r{SUQHWcoA?45SC)}%I_{=++1BFMzQjF z(c2i07zOw=+`|R6F{AG(sI`sm#-BIvX9|BtmloU-Gv-Xe&Cz2{@GSf7SWCrO_M_T2 zib78Gn5u%CZKL-d*j8|hZOpd?H^+?LeqbHbSL1%n*DNs)B@VpL{0-nT`rv_ba>TuD zbk%|K;PJG;li6rYJPSU7f|%Bt1Ou7x7b4jX#0av@aeEiY@=EaIPSW4U3R{6+_u?k; zf!6rNqnU@}Ch;-!*LgrQ;8ENpK9P!FJc@QKZ&pFZ|04gyiRlyqX%pD>C-&@&pJlik z(4#Yd_sxRO9ph$m4T7Ejg&Cf_xY3o5h;2|Mreg=DcYO#(yMcT5AT1B`AX-{=# z;YArERoVs?&KJTLWiTSJ@Onx~C1GJk7Un<*XfFx7WifGC#u5@TYBTXEF`QVIQLIXD zpcsL1Mh2&FSb84`Zx^x)Gx%0C#R$W8>wFA>9HS4gt0MQ=85;9(H#H*{cdmk!ty%i+ zEdK44#ggBU`X|xTwZ?4=L=xLdSHWqUee%}`V|)m94uUggv-zp{CI9zVoJ5atMbFOg zM>jkZ^GYK;*gxm}Xc9Ag30ZFM1)j9C?zHbbJ~uWG+tzvLq@J`b9@_?w4QJ8eG|)93 z+jfr)Q{e~X9C2DXpF?ZJ!|iy-Ech~?QjMi_8O+zm+pG@qjlpIa+18+#Ean9DJ< zd7+qJRQI@!@!`ocuv>tU;4<`Pz46lk&Cg=OO-3(a_C5E+8%}J1(2xqsk+7!rV`}y>1 zqZ*cABA|o&TWze?g^agSx%f`8v)jxi9{Ac?YN5~~V}2W}ogrg>D%a>);;lCR#>Nts z28-HQ%?%lgQu9~>8q9BFwK*s;-!FWA8>`(3878V_ZLG$JjAf}@#V4ypZLAguR*U?o z7PYZjp%5 zIy4i(ciMCeMmX1rwGjVQ7^a)8^(D?Hvsu-00v}6Ea!UCD1O+!v=F)LO=6)9rLAOf;bqv5vaFfi_SE**b|og0k5i_X#ckyCiCSl-MySA!co z1xEMsWw+yvE1pLRb1;ZW`T-k}G9VFaQr+=mH&XMqBjv%?_;rH6zQ?a8`EZUgGk*RE zE4Fl{V#qvTBgf5^{KMz&R;}?MenDG=%eqGP$*eWJL5K&!|3lr|heugmd&AL*m{#h{ z0M%4!O>0_HC)EhFO*PdCLVFL+K-y}Zv0zhCntD)kDB9GbO#$1CVR|^dIDK+>I6WyB zr-#GKQ)ylvPnwIigQ!GpHGW4_j9)c~AHffZP~rXk)?Vwr?-}qs*ZaPIJnzeOF}Y{$ zwbx!>d#|-W?mf7q>d=Jmx35O>P`?`=vvwn>=RS-7%?OpT^zK%K$WeSvG51)rTRLwv zy9bc3G5=V%n}Pu6RX}nzfNa=Ji8yVH=Dt&hlD+u<8hTW`{v>RsvAre#h(%WHH#A_O zU9LGj2%h?pz3sUfZU?<$e*>BONObz^%mc^M*ct2EG5x;g&KFOd)wN^x%Hq-+XRmxZ zdRr^KG#WeS|2z(#UumEd*ME|qvpz}g=Q`%`J^e|t|4W~HfG+(c`Tv#AK0xz7NdbQ2 zECRj(y84q8;Wa$Q7k{Lpx$C*+uHDUtcQ)_eJv(~mk><|79*0NF_CDL(dG7>(_G2#k zey}RE9IA-k`Ly(}Ny6GBum7}oVo#f zl`t>|m{T}ld-4A@Ov)EOiy7&T<5Rf&yKB#n90x@I-_bt$?1bowRb-+x-$iez-w&>0 zv-X$S4Y2h763YRyW`DWu09?1f+Oof@nFa`?*=RIFQe<|f3>*F18K4b#O6p$i(yAgpF*Yn{*D%pOx`(k(|lHilm zh2%J#>Lzb?wC>?q(Ykxnh3ptga+CNmlWzJ`j$9l*hgjpM6cmUfs4z;LYZ(`r>H*_% zp#NM#9KJjTtfyFZ1>N?S62}03G+K8MeeY&CZtPbUs-6Vy+r&kB2p5;I1KcN~b*};U zTBPo=TU$^rE&P_D1Qp)I|MywxW=XEDWmcVi5+89gANyt%SbU4+)A;pQJu1e#0KZ7^ zRpdPOTZxLO`3}GRW&~J3_!|*!#yNXl;e}n-LDD{e0@q*-_YB(Dy$NQ;KWapbyER*> z4iV!^Yb7~605O(Og4iD=-XWT7lf_&?Y`|xHR;}oe)N(VKJ;eT~VGgLmJXwM&fXQ4G z?Eo2LI zh}1MG9479aN*kzK6m<#4tvG%l$l)MKZWlyNO@P>Mh#1Y{%WBC4h=D!P#hsFPNaICA zgtNr4ePM`KbO=RBD+F=S5bIC?%y#21cZDeJPDvXCb;wZRRPn28vqp1$rz?ovDd~dX zij!0BMv}#fo=^5FQSqJ36r_7A?1zIFgzHsN>52%`sNpT-)jBi^JuvZ38g&M;T3oa0O>Dr0Kg+?2nBO z23l2CT0?f7%Xa#uF)OVLN(cSYYAbCBN@J>yZL*Le?W$9ftE^utqXD@}`gL!uA^Q3F z9{6LM(-gGZipHR=Vd6L^Y*6($Csfx1ruswOzM z4vZ0~0Cfxz$9YSgs>9h(I~XiHqNL$1zJ)84>20^(U@Q7-S6WL%ey4jK`eB)2D-Dej)eeTzPAipe;p(>frCY2tfst+vhfknFR^LM34_2 zA@)j1Wylu@-At|IW?}_*t7L5H#BR1d?hrMaFyRV-I;JwY3V^~iDYb=w!X$z1A)xwR zZe~XaIIMCl7XbsZBL)|l2!|B+3d!tawsrnK#@a%+DmdbiyR6ZReqhJz^}qivgV}pfES>2peJCaKc6yRA9LgJcFAAG=iJ4lo^2$Rh&#DkVr+}0|>pR zOUaa2!eVDhr?8M&(kU!bmUN0yqZzium;%c!ku|u+C@k8RzK{8%@H$N&K%UmHn|g)4c{C#N{SP4^q_#7@r({B{5p_?1vfk_!xpKF4g?1egr2LT;SRql$~rKI>@s9<&~h5DOO=E0(Y7F|x*mpqPlHF=MlwB|uT` zWuYn6fG8_AE8UU7Xq^~s?G_^`92hls91unqMLRDdQx)trK#~O1{emNqTqaUfO6#k_ zNWpw}fF34?S0D4h)e7=|hEdj-2mr(^WP%;njHPdw{w}hj!||UZtb( zUW1$CDZI|$q6M_8@CJjM*C@Qv;Kfqwo_L*3UZy~hL#8S9LQ9qwn_^8o0;S@e*a1&19S%aH!w3)26 z9>Zo9PJNqML{&{~RAMrW`$1I;EvWj#xxy{3`Xjo+i$<)>d_4v?2^D|H;3lEM{Qzqc z(tM?(`*aQ|TWi~uLU}(MHh8ZyxA}Xg!OLv6#o%Q&vv^x-Go1_enK)t?odx!pEDDtQ zU!Mu$PXYUe$(YUpms1!-T{nW{21ZcE@M_~2qOA-yqpTAE8wEI43QP)cycFm{Z3Tr4 zs=H8IRSL{X^;jveRe;q7^h2%4fWhDT63*t^oN+`MP%TKP?KA!r*g>*=#=ihDe`iI) zO$3E^8Qi2$_-ccjAPVm>xXGgMUW1!B>^=0moHI$uv|ytmt3}Fo2;A{_(Tz!_4%~0` zOgM!X4Q|3Ie9+(~oWh3;Zo(;i*x)9d!bc2l!m;B}@Z5k@3E66^JG?64J=e#IUjD&U zVqYjY2$NKdNvA55uY_CclGJRLgxB7kp!YMrKf>-Xr7ta^sK6mlQ$j1QsBf zcUf_pzbHJQ&4O01c_JHHE;Dr zHL3XIAh%qk6#8u?^i2j*jeh}xxVWjdiLIpq{CsD%tD1XOnleUN74nRr5S?m-W$R75 z%Z+PEiq^?`ub=Oz%(=CV%91#MJ3Z{@J7&N2CQlGwsRL#@jNql2&NvBzj{#8!l%uXS zXmC+S0QU@T>QH=(s?v3!rWPH2Sn5mQ#$b* zpq#X@(it`SRi*GTgO>@HHMlPvgm4+Bn7O1sS*VrHMByydYPZ>_#H2g}HSeNWJ8T#NDZFv0BvB!(?q z%x78FSBEn3MTxee6deDRq6SujJPK?SU}GsTDZpeYP@-+0R|=G9+t*SG%u4laDX>+5 ztpcxapcm+*+ z49is++=Ns7n88grg;yKggj2YMn*kF};UWRsZDmDvYX~>~0hS|<&3Nk+UzOCM?Uoy@ z*Wit%_)?w9PL{$&Ergp~N?)oIZgMGHsuONsJF^(%Ugle3b@-l6 zNW<$@;M}Hmt;1Ec`03gT-be))^~4CyyU@Ve4n-DoZ;;Fp?LAuCls9)}bJq9oH!6Ad2uG9zppi8Y$qe0NEagg{0)M_Z`iZXzyy>nP8 zmyZ@A7&t5+=eHPsQd?9ye$e&8a0|L7jv!mmHCYtcAoevuf}q>xT67zdJTpbTwFAgE ziQ0AS6MZ1wVkdNtAanrXsBqjUMIst?g>Q)9Nda~#+X{4%cXcVyMc$rLU{TTGy&HLAtDZYoyn!jljaETEXA+WcFT>{U~rR5=`gn?p-LK2Vx@g8I2BcHv=+nf;sZM@8h2~WCYDkj zH%t>t;e!S@u@vqZd}E06`{Fol4&twmxv;MB%?*b6hrGn$kkPu7TDj3GDE={wCb6Ax zsTe3*Vmsj`of>D<=$mv3A2YZ~N8`BAs#0KC2jpc@X0wZ!`06qsYg;p*q7z$iu|ei2 zV|m7!9HSs>^&29c(m}WzQZ5FB3wZHncX9|A)OK#uMkR(HVlHWXS_rpW-1~xxb-6;$}#NH0#A_oRNUP1QNa(~Wm(}quE8ktTRhNENqz=WEz_nQ3Cc8x?t3VfW2TOrTR__}s z1-g)H*3jxLf@$I^(1l!+P=T$2X+m*%+)Z{(m@la?nC#*$7$OgdAmCs6pG|g+e+9ab zYy4|Z?bN6-U?M2o54k3V!u^nIf+*Y%xh9LkdyT${6NFq7=R6fBG})y%UIG^Ygma?M zWY;7Ug$3uY`%E~67q#(H`{?#C?PkI$z8`W;IEDKm*Mw8}h|xFUf{<&%nXQ78O=2qw z_dy}ogi{Sx(6?w~6Heh(1|L%AQ+UkaCY-{n4Q|3I+z+`XoWg4i--HW7t_c@dt`*3s zguLb3N8^P??+&HYS1g718rzR4AY zT$3v>+G<7ijrKty*Mw8$i4Klov=*Z`q|62(*Thl^I6cqd#C z0{U6w$Ak+au?ZL0jPvJILZYy5HcnnCpDJsk(iclts6mFB>0h5nz;Wl?ozVpCWD1w*wGGTz4Gl^8Aou;`#J_H(7vSpzwIPMz^ zjR-$3Astr=a&U(SYu!mYeWOQ0@^WRlGfHz0>=kZ6r9-S!gy{Nzf?v_w8K#L7)Lh4&lWgj0Bn!A&?S)h(5pSc)mUz@z$1EQQNROL!S4o>4Zj zNSXaw$0E0wrsk5i=&rOCebE|G9d#+Oa+?ud+}y-ce372?Oe}?ahHt_teAMWdwL4~T z6Hf871~=hoGdE2;+GZ`0jX0||W z;s~-WP@60YY!DYQK@?amz!pb5{sm0ji-2%r825a#tk0u44h*LvcX9OKr8X#)KreUH z^krRLMD3&@V6RMpxWAJ?huP+1wgi~%K4vz+?C>#L1I$hzQ$n_*X`EN#N@TK@#`IWr zw6RWM@!)ofKv@Qa1o(NFsH^;w#vbeJ26w6%Uu7tCnE}4B zlVMFrA|$@b`kl)N0LPnQN>NgVKH(i$huO#xyxEJ(51}4LKHPoF@J?QEa}FMtC#fsT zZ&U1#}`G_2|zB~a*ho;xc3yOy^1QXBZ_D+Tq?uq&Alk#ZXBf`>|nXuO^`Km z11aJ162dP`5N!IB6yWr0^)a?NqF`S0(I<@K<_TWIfh$xUJIiTK;k@5*GYHfH;ZZyA zO1ZTT_iIQeS}sN)fkCCs3eM%_-Yr-`Mmy6#+3*}`-ka4&C4<{p-HZ5=599)uW?s50=|dvUr-9(zgI_T0DTpyK1UUburVwG^v!n&-KH%V*rYP7 za_^jSAK5&fd&G3&n9~qD+j^A&cNaSq;wG6~pUA*o+2eq?5(Z2DtR-$G@hO^h8__1f zDz_#KR^61u2>?e^0iNRT=CD^ofZ;L$J_hKz+I9zB>kH87T7NVoz>o;A#TDRI9AALV zZXuXsB6Oev@I^YL5udc@KW93* zPsT-|-$L`DJ3R8zOD18tm$idiJaE0}e@AE@ajy~Ur5!RJ%e5YvND(ur(M&?#@4&?# zq1!wjM?IOoaBTno^_3oYMJY+8BleVB=%Fq_Fx@G1p+}Zxh156KrSY2}Qc*Da9X#%) z5P|`d;mu%~mIxud=i4H<6>JjA?c4l~EnMY+@A?vqwrUrDh^q;9hqavqWep)p8E@j@ z^0^t4N&luSKk*VTDg|#fpO3G2VIDPCxoC%)ynO?gfdD&npNEWz#D&e{YwUF!!9D6q zj~?X+FVRz+27Xn#N8RcnLqF-lyW_~zL%2s>>>;BEaqB1q&O`dh03LO>hole0rpDd1 z+{VTFP6l=gSfxr2*1_HN9vj@iEL?-eQ8#=P9RYX4$7cU9GF9g;`S?mS-W130$o~rv zrKww6U1#Gf)M7Uo%kYHpPxUno1$bAVpSZh2YzQ9zs7njb1-9)YuPQDl#_#na8be(ywdRdq79H zQ5PcKL~nyv*11}ANY#AoPBkM+yOdJ+<_29>Kxw;`iu5w?xHIWsC{;U`+}xn_P+DW{ ziuA6oY7?bxRw~lF(rT3t0o+POdRN-&msT5BBE6K_Z64^EP4T&fiO>2T65Q#bs+apb za78l7`R>r~44w-+L4^t$BoSsSU7%+{88&e)kk<;--Vh_fa~D04os5~^xTadAADJd4kVZw zh(qv(4ywU_HI2>}TPO24aQhnt=~RvQuL8@9*qi0_5RlyJyD2qvJqO&s zvKlEQ4|5~Y?sT>(xtt?O#iHAcJCxOmGBay0m4^y@tgtl%>@{Fp2&i6AdP9dsozfdR zY~(F{5q@QDQAG~kg@+uW8#?fV1ds_~)Hw#PHiHzRmrzX4hJZsRy>PFXTMQ`NE3jxl zTHR>I4A>C@jwrDF_JMJOi&01f+*8GRFGppSQ@0Lra#2c<39Bu-lt{@n1nmY4+n`F7 zP;w!J#*tDRX!t0#fv45WZJ;ASuEYkRt2vrP3PdsG>1JH_vdWJu6j|K&=CBn;)UGAB zqxc~-Y=u^{Y}g8eRy}M5i<9M6=v3sAJ0PU9;C2-D4YfjrsZV@Jw2uo3Xsr^}j~+|) zV+IVnf6{=$x|*}!fWo>0dzHm<)o(PoIZ)YM9H#oLDM?h{!f)oX7QX`RTi6OZfG)@0 z9O&JGRG@TyXD4(YjfSLBb!#vx(Y34^x|?X6u4lO@#Cw7CY7o_SwoKczT+j(!d!koC zgj^gupHeHVWKkCl7gn+blyW6oC<*)<#2A451fLEx`l-|Ix&A&*m^b(HXzCpPqA;edW(UG1; z`jFJ^=ZkV6X$6HuR;ZZ%&@&7&z} zl=pP$ZCSu~cYa_flVgZ}0G4()sqS2h?gzhE*}X|F{11nja2JU{*Od~yR{FuqDO*|_ z(h8#_WH*f9+F=ypyqOltp1ixd0C2r72O{KnF!LxB*=jyWI^O)Q#FOc=uTH#$YBY zH#pe)9W1)4$EZ@)3)La+d>9g9BB)T3KfE!K||U;s$90f|g(0VDZo&3zUvo%O49AZi@ED z0)=;y4bnGZ$e~Li#h=lSW=LQRCXDXZjZkbCJ?d1k{K^drlYUoLrH`2bx2PTzo;0|0 z#lYbG1}~Q4_wp+pK?D!*=@&;CNp@zOkvKkxT*2JWUAO_cEO3g7G;sQtCMmF5lqRjv ztoSDD$46O8BWS6aG>Dek$l|C8qBN7zP}n-5k=nP8PUzG$8co$MSmxj4@P#Yf1Pr7X-7}Hn+}7{0e$l0IySrD}9eS6jW_EReov=-$p<#Y&%m) z(-;nAoW~pd=E@_=p}Kyf!A&BCTTm^3(Y(d*O(Mn58r&pOc&ovy_z>8v&EO`H;&&L_ zB;q(nY4zR>+Kk-*A*WMO%Z;?!;3kqPtHmRo9z!A&gHaM9o<7B%dm?l3up zjmnNQZgy+5D3G|jN%RU6=-qXIOMngCup!Y9a3LGIVMC%J;BL2C8Q_=*7wa#ylWDjXcyPH&;_>2a?B_+c-caxqPCcWk6CGsxCI(IAr zBqaM;E3SgZHn_tCfXjl(deN!yD=`sp_qvDa^i2x0RvbiX4?4}}Bn4XELMD_JwAh0} z^jl{G6)(3ut4PXMr$cg?k4O&Y*S0Fso19Ea=EE=womGT0A5jF*<;n?BVx86#pRg!O zP4F#SvZl^5N<7x2BKYR5tO*9?V^&UuFlDkZruCCnZi-QOzrjUC0li+3k@iFl0eqvu zMRLMnQWsf8I1F@6jg&kTSw~n0sL~BBqMEf8=pt&#fMDl?C{d_-9oZ@!uPvgQ3`&!H zC~yO4YZWPMP}k>OW`63;jISugQ^zAzd-pyK~EH_fo;H^d< zU5euBB?8=poZzex(`3%w7XtrlBp}e{u(DKcts#S(XsXRE1~<_ZUNpFgrtp}-O*Dm% z7(B~|fS+-Ln`l9Ru5m^2rjwnu>MT#KQxdARE+tX^-haEnO(eyacun0UOX*0wCfr0) zd_PE=NDB9i9}`L8)z+?w!~xJ9Ulx%<)*4h)caa6P0#rH0R&JjWb%FBUG-PlSM)fU` z8o~s<36$MAIAH>9l_frl-S3vTtf#>-hIl=yN^*IJs1n1$I{)Ge3FK>~b-*{cBW$4V zvK~<-d)&#ixn@26rXW!$YPpNgtwZHDi9!K)SDX{>T5m-~h_ROtX?K&zf?c~A7drRP zhTWf_S?)(xWTnQx7G%Er5gM2Em`GRSa1!Xcl*i=Ztdl^;qg)7F<@ z^Bv=$Sn>iEb*c`vnjcoXO5qj!O8nKOa8u=g*;DCM8GdgmevQF58XV%eB&f|59Tiq7 z9XS`(59m86Fcr}rpDx_?f0dlpk2^lLWvTWx(g6XFa5Av ziA@};)xEPLY@n5+vLM;Nby<)&hs5nx>eMA6(kOuQ-Rq(*{}D9;s6VOZk{@Z5J?ui( z*5t=#p>A+OmCbHR7Z}uOZd0#QHIg5Rk$$_>B!Wn2$!7~O>FyKkk`0c(?qIH7wIQzw zyICm+GFWQC@**pPxURTJpu|^~6Ada4?q+RegMR=v*ajPM z^>XX$v;#`A<6mkoI&|-RLj&%8-hj0lREFTrd&ZQ~S{rz|_!K`!qbroz;IPG31EL|2 zbZ<*jyV83=Tl-z3l9Sh_!_##w_pDqr64Yxk_z)igc-G+5NC@6)aM477-)8X9Qv42s zj~N_}EB?_ZG94@0_A9D(&DBbx{2limgPTa!l?`qpDSV^BO(cc;QPxCKxF2OrB!w4k zNHCFtC~G1eHHoE2w2B#9tsR+(c7+p-;FV1o%>&a1%}OV=8j_^#md* z@l7p@JxDLLC)lDU@#~i?SwGaJl3WBD9bizq!vqsXhe&$CYR{TqO920I*mnHlSnb^K&7l3>Ce2C z_94D5O3V_&*u{k=MG&M-3O5y8=1w!or5-Z<4cR42vZbA8nLE=|Y81O0$@muyFLPV4 z<+phFp}Nc*t3SXT60gaI2@>4=I8KX8pTQQayq)U8v^zSRlNX^w0~rIg=t;V{>3*yK zTd94qu=VsMPwG`z2=FV^(fVXqARK|xkT3wx zS?AvT0Nf=)ssk(pWfkA$LdrnAkt8$~YE|ysr4Et`wP_`qCAUci62Mowd;9#x8zDVL z*f&W_n%yMQaBs016_EmUDru)!A+cIXyQLtLE4YEpWj-d?2LC*h%X~~O{i#Vb>@puy ztlI;tbBsx+SZODma>L@A!Xl({*M)$95Oy!l!e^4SD2m;?iZG=DpkYQ-*zH9YuUDPm zQde~W@&R=h9gew5|Uu>08s<0yUXj)hMRI!Xm$5CBUqK!g;@sG z4x4ICg`3?Qp@K%MNt=QyoeZFIcimznM5|g6q>BcxQMPs5jv1W#4RwB1KtL1lNbZHai@9ei5TpR{X>rkyqIqIGTk%;t7G{tXIRhM6E z;u+jTQ~YXcR}CoVol5V zaoHqNOc$3;90jt=m)%-oak<1W7MD$mATFB}ZX4R-vJ+vM+sG9aEpxBAly)AA%Oys! zxNQ7u^$xOH-e>%{TxJeGE}Il;CZS0>CWyi<$_}(RbHgY&eO#oYx#*mU42h~dl&2Fz zcD3b$4r83whX=}w^ZwlzcpF0DL<_FJ!0A4Ek&oZz3=fyCQ@F!#S2*7HE5YyZ@oP%( zJAM4d5`2^C!(1bpBUfwuuSH)dxD=ObF^vL`V)38*75>s9M0H&2J2tD_8>JvXm(Mx&(D)knE-B#d8VXTE zH0EC72b9+!z_4r}n&aETE~7ziA`Fo_vVf#3FTEgy913UP&>R};TwxCB3Ovc*$oj$? zgsY@*dM5>>FyU6YgG#t=A`rlCsTg4|1W)4EB9*A0#SqrFEw8MEEe45=*5n6JoGru* z60rb(fR)x8%bROE6<>(?84u4E0r@XPcK2~y9F0#T@3;fS=_AztMxEGl`D$C)N~ba6^8mO9i`u>fIsme>bRHeF-0{!(_#{p^qvf-W%pZ0Kzx%P zR8J?in;iU`EVzN{uCZ_zy6|2dyc5sMEc7ZDu6ou0628&G-Te^0&VuKM`11_#TVWIG z#dat_r59PG@s1_bFiaKRPA>hqDxgoj1$|CE9&FCXR1lk}&X+(a3qri9BH*zVkf9PD z+W`q*TCo_jzS0{jbQ`nu(h3|0aoQ}ow?bEE!&g^$-QlY%rcCnkHAi!=q2LJ=WS?F%J9_U+#|b`bz9co8qeH+LdSVgg8u-5p zzi{4yR_5@Xf$jLe4_NmTeJ85t-bL+4KqB`T9**$gZ>Y@jp`EDx6mYV`xGSSmv@vOB z3>1d&e}rwnejG_WOk%I`=@nGpj)$RlS$f}bEci26&b~q5!vwMkEkQ%M=UISiLwDmL zyNkGBK0BQ5p4XV}J{2z&r;s+Cb_sqJ0bv<;&1Mo0<6dX@?P)urXOJlj8$>Ehq?u>{Xzw*ANH|*bjV)VBABIqENK`Xgt0buYb#2`d*#TXTqHt>I4_6E*w2gLfB{rom*Yt6my%!r^c2439%bP! ze8j7pyYB0{zxnX?{kvvI?|iuPh2!?`>bz^hyu$pU@zjAGQ4or*T+7cp@1ugFcRqqY z&)`4rCn4xAoDo>G8XaX4r|*+s-CWay)bZj68whxd&r2U{r54{O;5`DiJxEU`jJK;# z8YOJ=gGGfg7Eanv*wzQhxYQM7=(uUnTe1Ck?}Gc6+`i|(qwv4vEPBRDpvZvwzkxq* z#lZ>D72_NhVS}mYwXvm7lo)f_6Q$N%`GoZF5_7J4qDTo!?78L%>V>c}gH9dtj@-p| zm#o_JV;PTQbL!Bp_}dlqx2s}g1`dbM)4bd6i>|y1c(bS9*E}!*G^am;x%Z>^|7RHY zZtQhnl?HuuW;9m+;8*b8gR|UK)8t-9U&$Q?hT57dBCsoaGk}|Y zdvncW(h&(f6K_F^Sug+^e*hkf12ONA@_zg2D!2}@pv!tF!@;0g>iPr^hfr*{r-_7v+*|z zK83C3OPeoi{$}&#-?+^C$!k^6zt?@jmdDP*xNN~Oc0$`7CjgAM_LKPU#rRhC7Kp_Q z9Qx(&s@fv|cDGcgyR$W3w^s+;2H-Y&-N_{Jng4shr?Yt7QLp=}Eop#9r5Z-4{2EC& zyh77)JijwUIM7G%7mCHuwVqG;@pQo(&m^{|yVp1tuz&4Xh-dQE=|XZWl^ADX5$N39 z9^~Krsi51O${)mhC6hl54;Uu}(Y3^Tpz@~?oouG_X8=9vMIOSneqLmII&vT9pd%>4 z&GKFzGT{UmzvYkPqllD0ZqH9xSNY<|ENnXVSii{PJlLH2p;W%9iX3^4SK$$jJE2b{ z4e~KJKQ%fxKjlPY25qCY5tMkYVe&91U-==vuRy3zZ*_@_TA{C?w&fY z!0BxC%E5I0Rj;6T&PU@~m|tAm;_bxS%EyyF9n@?gbt%j|3*2$4q$ij^FP)!j~WDB3p=pH+8G|#i=S?Tf;A+FO<~r3pGZx27VdQ zFYqh#G2~GELOoGm8|CkOT;s?Dg)UbFB-5R1Om%;V-q???sqU|}q*fe)_Z`AFXu~aE zrVA6lhJJ=`6;NxsFy-r_DAq_Pc%7JYKRjp-9Ysn?X4%t={21g160z)Yd_X+Srg*F|2K4y8xP5SaWq@| zF=ov8M5FaIKpdZ<0|-7dnr-?RKI8a=Iwl^6&-ldSnvdK)>jK>J2mMBWKJqt=@#u>5 zAtbXLG#7lU`P`Fmf%sSam$h{yc|@#3_;7dCybF}M%v&+9ihZ*V4-ex%k8Q?J14oj%O=2Cr zz^axBN~vv5vXDfQ5m*w8Me5Y2sEs&TC) zeqO3@$yhqUL{8S*mr&LR(7?5gL}%)dyCO-h;wX5GRnEbKOccLP^^FkiTI3bEs~A`1 zM!h-mByv;Y?8_*fNg|x{U|y@7zKAb_sr>d!3NyZiYh6e!+SQXF)=KpfDj9ei73F{k~k1HSXDJL@nsy~@VI-ei4A7;Ow_+e&3(KC>gb)x@rX!~vzJ}$4} z>*>+hyhd&YMswdz@*0L{?gwZ$_f>F_n}?w>_gy^AAH&1tvFPO=fAjVeKw$n0Xp@~V zb_PE#hY#W)YczhPjJSf>i!+^B<~!~NnfGcAw@fWGaAile#1eq$H`Hy%bcxGNQN_?c5!~6^Uar|u%9BitP1~XQ{ z!NtV*%Q{8;9sT*HeMcA*rJ=%?PyHD*hWOXQI%vQ31jGsCSp1tV;L;;7$aJY)zORye zh-pHrv~ie;Lc2V^$5f#ckJF0`eyi~$OIPw2@5taU90@lQxd-Gx?qN;shwY^|+v4|sgJ|$5OKVU01tW{$jgV{z9+v7kiQNcU$cc{=&Y< zM%@E45BGozBq1t_u#)Q@Hq_R*ht0JO?g4wQ?g3}^@gRDVzt9i^tJExO>bi zeECneVd9ZL$dt1k4W#n#c?GO)18aJbdaZ%1Y3RF0Y&NBK^q0Spy0H~5=d6g{cCnZZ zH#yRb@S1A<-Xh<(iiyNE(gkO?)< z;+pEdsSO)5KTdVeMV5ZWdi*wm4AOuVd|uGVlk)}W~4~2&C4H39eCC|@N_!zDn7l) zu5@Cb2L|d8|1h>9H^-g29@6;gd4;C4na^kE7Mebri5yH7>Q5s#t#b>N(^$~q73x2h zitNrrFzY}X&Pdyh7047wccWe^vWs{0v}PhtczCm;jf;uxX>8h)Ssfqdb~k-0b>!Ym zz9}-dd)cR|=H;7C;zJA%0;xukKx*)iU{M_&PUk}d9xmWRBao#i>8-fS!YhG`$t$k?8V&JACBGo1=h}l z9QBju<(E!|WXmSU=5{YWvzmo9EQBQWiA;WJqAHVLmXN{*7B;dFvh08?^(UeBNvwTR zOr#o*ELlr|M1mKw9+2*azjV`Iz?SF10+^eRA+zm8M{{}Yj_Lc+9cL^*0jo08?@Jd> zc=^{SR5bsdt8$~$e!cI=-Ulu1wbg`l_g67dJ{5T{rcmQm(UqJXrt*)b^7p+xD|*8T zFReHMv!$nyXf5)h*B{0j$_>!cQ;VXDk1UFQ|M8l)qc?nh3vjSlk?#J;^*he0$V7&* zHnH^{Jl$4|uKZVcC>G|fZ=2fuNA^`dcTD7G`;%Gc33l|SnroZ<(9ltpm`xyRz zCx)e)tKLUrS8-+VhIfhHQq9lSDncJ(`3v~o`00ni##2>`@N^%(AHst1p$C!EOq$3A z-5d4*JNFbnp2ydB_TlNBK|EcbWfM2t4-R60egEMad|ve^t31o^kJrpuICTgp@9g5o zAV0V^^$uZ=aXtC5cUj}HbfM{KR(QMSlES+8N8o6n(fH{X2-{x+-gZ?Hc^9CM?Zd~R zzfzAoSo}_eTt5O;7Qr;v!XF#v#~3TTh^lWzfcBUaU~&1eCl{rox4w+R>t0%vir)I< zqUd#xz(%)bDi&o>a7m&5V$iJQ&12+g*2c6eVMy?2XKxzCV+{ClkHnjX4YF(-wzli#ZGHG434p3iDsbTT1oM&0V-`tP-hN zta2YdbCnNYQkeSVxeJ@d(5>edmc1`C+Lg~0p#r9Hvpxz>7)9rtu;d=BdSQVp9eGOD z+LpfrXWnxm{4Cvl!YX(SmJ;bkKl}-js&w@FdlyA-*qvF}QVSJ4T9a9rtx0WvF#>@W z7w2Kp3e+!O2vkhA9z|h2FzdX?y{YXlMCKKyehVnO(%m0_sdyIOXog!}vT*)jrT4w3 z)xXY!fBhYe50B(0d=a1U#b!Dqo%_Vt5!@xau){z&in@lcl29 z?<5g=);n)3B1v_&L$B}&`yy~I=WF6#;#v3@ah|D8N-q@ughYH8qeH>v=z-#Hbi=o2 zM{kX~0(@mZI3?=)A%%b5Ii9#?bM%xG(KSZlccaYdC*fo9B<9nxg*6y}-{8~V)zOh^ zAK+)btgmi3L)-^T`yb~+>d1Dw($$k>3b%MtU7E|JT)#aFrI;Yte16AjWS-oUgh!pf zovWfV@Ur25cEXLl{9EvnO04ugn(n^51zR$0={%MPFXiIYBMhZ=EXypc#-ANr^F(Z{ zlI<9jVG(r}LWwMGF8u^UFGgMO06c6le&rh69C(%yGMSFNkw(x#y)*+mt_MhW<5&wr zabv1b`HUE%9Q-O~k$rR!5IB~c|=498kQh8@)BA8Cc z7FIzERWf(VosMeqs^`U+PvjOzz1c`ikXS-tmlT?w^N>Vwi$4`PoJ#x+40?(8Q0X0t zU+n?0g}O#M!bKI#56(y}?3eBC1 zJygK_45eIvz+@SoTo_`U9E#U(n)SB#U(I2+m&OZfS7Gly?Ytbg3_-^7|p=Tg!#)3kIgMqo{b-ygG)1SqBD`14%WW_XAy08QKi`a*bw?6DHn;uAl}SAq5({E)VQ}=ayX5yFoLS2d!chOoVlT3;4b3E%&l^kX>OtZ{7m9m z{J994=jE~Ro*M8kmn~jQCjKx;N|5_D@mo+h$@$&0K)YWY53@Mc+9fq?VseJVI3`(u z0!a>+6~vMt^Nku3`zP|3i9DA{ppWoH(9|7Cc(JiXT3oOIYz=KvOd#D#PJB zk93hKAY&N8K#u`lbm~TKs4p77h_lyLPV};z=wWt-6o8wJo#0xM2e`YW7;uCgl91rx zeh(Op;0n(V^9&kQiDx*bJ5q&b_}gZY7SFGF-IcZJ!qm8AAppG1N?m9I0pgrY;+ahT zahPh0sei}bRrbQ`y!a;;QZ zBA=}d#B6KiXM2*Lyu6=!FD&~q(!{Nj!oXywXAvPkCb83MY=qL`V!&5qj?>Hvy2t`NjCQ<-QPcwfb;;IDQB1NGtl!IU-Y!M=gvcfd zVaKJn`}C19ke@-okTft3)o3d`S@mbOl69?MRfi4Dk%qiBYpB<62sGJ!HWGlLgyDok z$!ev?Tn{O?+ejuQ?04a_1sblr7i%qEVy~Cj<6#IKlA3Ot7AP1|@v|JKbAadvEszmL zu8`_kEJiK;az!e!Pb}i`@5Dp~#$y+w>9#+(N~Ah_fyh0{bE$9OS@6C6Nw( z+5w;a3?XyKHp{4bhz~nL!>Pmp(ZfDf#ULvp!%7#LF2LVg;A8Jl5v0JBS$IbeKJ#0geXd5fJ=C4K#7r5mI>&&RDop(%i^ydrG7jx=MK!TIop_%r za5font`t9stCeC6P((j<=LzuqCoO__?amD0tx|r9);Au^$~2%f@n{bV<^`fQ_d0|rwL9Ms5VNhYXx^B zqem+8oON~g`)x99U|Y9{d8ru4b`G0z{xFt`yoq&aa3L=76jVuhsWKu_=P=iFWMTMo zVJ3pBjIifHGMug+LRilvUPfd^=0a&0^+*^w6S4;EUXZE8ZgOxU!t%LP>cm=J_F}J_L80$}_l~Mh4hIC21KFKBKc1)q(WBEB4 z)ENjnu#hH8&KQs}Tmu)3VYI{|^qfNF`CbBh*zkFTd`TcAQDA+f+z44g8i3J&DLUgA zG<}z40ry!JfHmrMGS@;W`W~(u!oy2cKo5k*^Il;T4{yO`-^E`Hn#cpV5`nmXuB`!J z5$zM11g1ppr@irr7?*38NH-0+ikzRK!nwY|#DRvU4|L)$QO}1~5X$lKVSer4Ae>8b zG|72PwGqwnaYYqB5xnu)LiOdcJPD9%ZR97yIX)3y@rl5R&$c8#+dY1Ew2<%;ET?dV zq)>UXBpz6(gty<5O59CPsS_4?o{4KNa2Bk^G{Mo_JDI%6no?!?iJ$HvpRK9LP8|12 zC3vTN{6r`SgmhkrMiF)KnQTLQ7ZTov22znDUSg-TxXo@pidUs02iQ(8{0>AOU^PTi ze0uHa$ap4kfF9j~>Y2nl;w|u^Q#cWVE3=2uVWM~Jr)LjKBTq86vIOL?Y~?DG;MZ~3 zXup?u>ypBh>8S*dljK@D$o(fSVaV|kPjIwNB_2aXPCarGNaLSM6{ehwLO@4Q$c8#V zod`Xh;F=F|@-u!mFwf!F-Y&pX5KL;lj#`A`EC(8!20DmTYutPW;Ek)5i2N9k3sx94 zPa%#|+mm1#3=_~w5uBw8i)8s%z^2knpw9gMZok^N+&XAm%GpU+p-q+vHWn+no9 zgfcdF4kk;?%$|Vd)ZboZg=-l;+uG9L%i1wZY^eNGvx*ZU% zAcwit92)r0V`2GIbErsE7{OQqy3{1fC5p$-2K;qjc>woTYyGo{gt=_fG#0a`awv;D z0k%DczWww&7t$Vtqv@sY(9uQMwKN@YzDI4d<;cSx_f`=~(F2efJpeU>2Bw&)#Ge^6 z*alJvpdfy;1AZYDk#+xzFcO2CcqHY9;}7X9wS!EdBKu4#av$17_MA>Uol3k0s*HAB zBnkFw@R!banKyg^4i+WuyhE1lHfNH~}ML z!Ks>FHVw;vq=r;<>P7S|hs~n)81Tt9&lXK*q$R$TRC7AiuDr>p0J5DRE1@61R(Yai z8XotWxw{KBV;`X;1HfTYyAl1Uk~7v@B%PdH1&MPR`MgX%-PXZ1@_e0q z-YAo_Td;i3sM|fGR-UM{-|j;HR8J%6&7*=PNyaE^6WD z^;v%2)XL9W+Zb`#UAzcZu%VR{C!kOfkF~;W8sHvuz$&0n(R2dldvpSJ+7|vrw$Oq_ zG@Pu8;{+KpJDd*%96j>9bOMXIdueHo!IBeE2{9^wA2+p=>kgWBHXVTq-JU7bo|2*8 zA+yq-ngOq~8S3L1Wc9Dm9g9x6gA^kp8v1D`K>Yf1ni0#6$XGLp7g=jcE$AX9Y!FW& z&Sf&y`sHe1f_1DhZIB!oOL%O#P#b0Ikt3|U0CBDU6B&jy&^rv0Smg#i^ormHjs+6Q zYLW8dy*5-j7YGOgZleazud>l!^(cqeNbA?h=Wluy_}h(+nJ=Low-zhB-nNdsV@ zvJZ_@c=jw3yirk;p{3nb2 zjQf~UK>jn3vJ0^TB0nZ{vMflJDWyk-Aa*4ceK()*1I@_ZVdfgl0=`6^u*nk5T}Rj- zi>OA>PuWEPxQ5W*GRolZZ^rRAllUt_-uY+@1m(mnaJNv zN}Mn2*+X|riNn!65BA$}rVuE;p|wy0D22hakD#_DUa(yMbDG5qU*=CC&n zadWK5Au!!tkD(bs!QZQ{;w-ZUr@UmYgjEREx&~wI5FfCkjM~?=dXYzEL{I0R^swgF z010I%2JcsYw1S)0;O<~*VOv!yaS(~rv*hS%ytz?m!f^WxrqiT0wU(=xcv!$iM|Q!S zUIj3qz zg{52N!K@8@1KzR@%A{&HO! zZ?o2oA$^h52r)k*%D$0##0VRM0{|7T`Fr_&@DCp7mmTT*QxWEnkEaq3dx;0hP!A+V z%ETUkxd8pr6E6@xB3Q}JxrUwOJhKVJZkS;UJwc_@b!P{*^qL_LpMmB;c zlKcDVne<3VFPApRQt zryuOITdr0q7h?p79K;$vS(0sLj#D$fB>hn(gx3nrHPxv6B~*4v0ba(bZ=jD*9n21@acMxK7vZ%WxJQb8i6aQc zS}ePA3X2lx`Xr7W>fLe6y$WG}}35#E#y9c$dy&yv4)^!+Z({;i7kJ7hTk_ z!RQ@s*E-Ey08?9RhhPN4#2Q)6b`L|a2P}@FgOD8*$<@T_bbbgVR=ViOJy6=jLrB76 zYX;j~2`p6O(nbK;Fb~5t;#poiY6J_?D!V8ZtbJ+%rrwy@T$qaNMa!AUiyp?+ zh8UlkAPvR{Y%B;vHoLYB^kdDS-IOtpaKmg&P6W6W8t{QrbwY=m`1!{Hz*`w;l*f8- z3L=j%$N1&;$t5krT%7%_2&4>@#MqfiU<|P7C%b)R3I*FDn3MG$v-A&BS zcgc(yyHlUVd(8NbgL7Cv!NVy1uf~gT!Ttxx&+uAR?#Fddd=Bp^amrA|&v}jfbo24c zlYDlw@^5>5c60OZ%9Q#BE_cUgd;z58?wzJ7ctXPM)~aQNWsR6uwleMQ-F329CmG|M zLgn$P$PR1~z#Z4QwM7Ie%uAdNFfm7)@k)j~#58AkxIzP5fy~$v0d*sD;UBaT{NpwX z$SF1^+xU(tG=Lp^{8=ZABJas_xnhtWO;=zMX48Cs?R>y7Wyb3@#02~w*pd0*=Fb0Z zHNIj7f)j~{h}KS{(%bNtqx~SsfzZ_RfrQZv9(M@m*g+K&XLLp-hKVyBj%$Z6@~M6* zc8ZSYXwwM-+>b(w|4J7EhRmYFljnc$RWf%7Jq!vnPRHq$<4_Oi+%4oB8Q`XBoFIX^ z2*z4laJJ_^8K8)FOPvg{pO9(tIw!T%M%kani4@KKXFvXO^>J8u8|F}jl%$iT9C%Md z+gOjp_yuXlWsZ!!dMX0+YbajjC&0knTx*hc0h!nY2oG@nsYo(t&7DTXd>79@yixR7LEWJI2Q_dFdH0y+`x3rzhd_)1p(LNgRL@;fK>XQUF!)oI*8Uj> z6sVmvfIg8rhD)mvf$k>r|4<#Ef$b@@*174(d#IL)@aNLu?o5tQ0gIc!m`Xy=@Ts;E zPnhqzd8sTFYTKt0eSy=Qe15x%knds#X$X-q!xvz$do|RFR$Yh3Mrh>(xFALp zh{ioqZk}RL#rh$R+h7QOkmFU;@oBtG4&f@#NhkPzM||Q`aoPDYNMe)DrBz_)0d{Z~ zKHb?aM9>SkOpGPNI;vXU7*1EpT@U(?Anh~fJUk4Cf4BUu&53p5T|GmN^zJ3>|-Gjvmfpz zU@(&k;IvLEB7)DwOKRv5$m~;*hj4a%8unvdE(KQWd2E{ZZ$e|(3Pq1;JyuG9Ochxu zG=kS@kYzG4z=IqkW_x(Xeias7-Sg94_e6&57i?7>lc06N&?SY+GePC=JG{sa3-Fi+ zxrsb#;M_iFvj+fvV2-d*$vJG@WvgP*O*?)019ZL*Oa3D_>i~688{Sn7l$B@D>OYDrb>j{WDS)uL}T?&M(qixfdvKZ6*K{g ziqEowoIs4%o_dL5bMZNH7^OIOvDKxI)D|%Rc}#g}<j7oIJe5t^`gsGVqh*~g)bsZhplcLu71&BiOwxP%*N zfcmPy>BXg31A@iGh-gVPh5^2;d9t37hk4RE >0c>OoqEI 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

0em~kYd-wU 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
*QxiQ}XqIc;G9102 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

=mW!IC#?9NETN@Tv_Pq7 zkT^rkofqD$kngw_r$$Qav|CqvGEk4o_{$sa<%#0YON*C_Y!xC?x@kDnXm|a@tJojU zOrm+V+|hNZwOYltK&fKK47hs+T`Ao_t?~W#;z#hL9phH_$~jQ0RF7E=Fyv3tE9U64 zpy;cw)wA~DFnCDl7ei>#^fCq4fg<{lg#Jm-;!mQ;X9DDGg#6itC`NR-nRb$Nm*k+i z(fJnp!xGVV#EMClY(&}1GUXShtfPcbk~p$zwNXPNiPofgUzS+K-*Gj+sc-$y?%;WU z>r3zYR(tV7rd%>XweN~+Mdcb%zThY!Z!#;~-fyX}?o^g{1t1mSRFmF$YreOdXm>CgAbwT3V%lUSB(z z4Jm0}h!$|g=a2S3@Sy$VS)@2_(bCoa{Wv)#7QMx%;>t}WcUQT+tvB2@osY!ta;Qd} zH6w^th3`y9xxM@pn`C(DK?g62%Q_5q@ms(Cx1X#-_L7gNpQvl< zcyFVZ9|wDWu)XYX`gfG{Yc0|VLYTNO!s<8#Me&}YbU$P2-BCg@X^C#{&igcfP4ai} z)X&AUK{5JZ$vcE{%z*)pl9jCsi*M1nMJT1UX$mp`|I!-KI)>Piy(8iQf5d20YAxqC@F0s_Z^gfBSJe`H zpV2C6dyvIyQ%aGKva3i2Hl0+rYQx2DHSDT7g8L{&4G(E$=bLWtb2D1N?>MRPbA!JN zq+n%<5cCOWX##I?(g^TpP8vq`ADuMPP4*|9Wf*vylSY9-b`#lu4P2@0Ywgx`&XTnw zrr{WA5a9axs5Z5%eKWg?paFvuP8wNY@Yp~~l|}%ir`ArIIoH@n>?*Wbh&sweW&N*0 zC#0{RPAjdB)4cwHHu!X>t(lqH@?guYGnub-*#m9xxlUU%E3NOrmOI~MUT9Zoyi_zS zZ*!I=@KPt$-(m25fdqWNlbYRR2SLLK3Z;g-mFl7N)mG=vyzb1dPb4f;Yinl0{tGXb zRo;i>yR7tITuN3sEcZK06Ih#8+B>CIpJMRgfdt&tNtsiT9Rv*{D3r?VqErv1XIh<4 z^SU#;X4$R1?W#@%@9V{~%8?9fMHtqt^l>hw1$={(8t*jtfj~;52SKMeOA~mplSY7- zIcXT#A97Nb(~-T_S%!g^IB66ZWH*uhvA~t;eX8Ahsk3A`o$7InxDmL1KDyrOxWVgc z-DU6z4I)9=XKehXU!t2EQ9f-2}bWSsDnsI*@?Z zIH{G(ZltnrH}0)AD(_TuYgq1d!OcG#oaLo5x59$pX|*+9t??t2%N#q`L_XK9QttK| zKlb(dvW|7W-TJt*w1B^uj%}Iwl={4vY65@jrLr7CsV{h`Vc;LU)M)DJFB@y0hG6x9;uEGTn68+;zz+dc57*u{+C<-FjAcmILfoy*tae-8!;6%SyYox;x7& z?AEKgv%JM_y}dij<#y{sb}iO!hHv#^V`;m6&2HV~ESWoN8<&N4x2yD`3k|jdDHWWT zYEtSQUMlNYd8y&NRMxF>mMmYP{4%e5WVyjJ1L@@k-xWxyT?kt0EDZ#$3nbvnoYcx? zXC3xxhiy{oJEhiD&^cbJ3B1cm zBf$HdG>q&`Ty~aOQSw!x6!2~*jRJ%0CbBno*;)QYcH{uy`Z?g$rU~woWkA}vZ!?xl zUFnSFO1pJUcb4nz))%|8eA{k)zdOrpbIDHbnig>HhkGmUWALMalp3|c1U=m}Il!({ zYpZ6x+v>g2>(8c_!^XbMuG4C(uCKk(_}|{W+#2IQKa~4w?G?s8?csh+<;)y3FjE#y{K3wVq;dD3F4iO7ys-l&Em=6hwq_^*P43zl+Mcf8B14 zIZNv}gR255Rp5NPb#q|(k-=XF(jN^z(w!PwWG229rxaigrgGUF_GJ_`v(wPRY2&B|Y$PR*<2wLl0H!syh z(4m2p3VOKRLL+Io>ub5F%#sCG?ray`dXvG61L+cjmj}{^41PY4Qk{?;1T_(Kg_mj~ z=(B;83OdzpAxK(j*IZI&+f7#N9+%vj{>W1H47*ChZDw%mKzgFVp+HJiLUs_;M9?-~ zs)?Xy22v{Me@r<9NyFVz%S8>R<@Pj@N4x0ONd`{|q|*(a9Y_}#yeyEq$qs^=2zr&5 zY9go|NU5MB>=uH=xSMLZsNuBS)mH8X7u^E>)JY@1GI)=ZTEM|al_ICqvS|vkzviWy zz#loOf$ShC+iTj>>Ug`?)dIfDNyDjWlzOSNWP>a$qt4P*O3PUe>sHYsXE_{*dQ)pB zr=@Dg8~eFltPZ5ul-l8GF-irNOrNVw;167I3;0tfWrp5mw`M=Ota3_iczc6;2U4oe zRJ%2!e-?ezoQm1fic_OhJ{e1un7WBs+5!%T3cBI-|WRker53OTb2SUde@f|NgIiz={p>Nuy4DtMlP(8s`U@! z-pT5dx&2Kwew^h>WKTt=*ezJ4+$|O5vR&9qt=z|5bnA--za2=ambcrj$2|tGw4P{i z-#|Lu;QIp!_%S0*tF0Vu-()|29QY=$u$fobq{0umpeFFcUg4Um3Y(KxIGk5FOohMq z3bWqwO1p*SG9K*M<_B(&^x-B>tDB zI(*J#eATX^CT;Y~KuSv;VYg1|&T@d=IykTZacRYqj=PL|`c`F?Vmf6Z&X{QWDI|$k*C#8xV=V&yIU;SHkt;C33WoJDb7|ykO@3gDL0`R|` zG?GfLTeWN5$kt^BKNd(|F!-%NN(CKdw-98m$c1H2M1?gbK_4@N&obJ>YtzoHmpjgF zXqUJ$!_;z3Bm#`?BH{u>K*JubvSud`x3g=-z>215pvA!Fx;AxSP_Ti5pNkX(ql`2d zuu8Azx?b6sw5Q!#>@2P03|<&W*BktPAl+{8VcV3=DIInzgO3fQw5eZgrKnD`6~e#d z!m~u1vJ_5FWOED@wIvzPYNuKj#H3*DVypPwu0S2DX1FO??6s3psuRUFw_;U#{@%*n z@3m#-KGll9pnL64v|Bp|7GTRsS!*w_TPvKU1$@F|X~(f04PGBesmsnc0q<}@b>K`d z)yM^P)#&{uNIeGrXb=wko0CR>GrYc0>YE!#z)v`71lYqoZr$XiTHiK!dm#PP;I9HH z^%H`=uQXgimlO=NQE!$?Pzq@r9<7I0rQT~JfH<&0d?VY#HkQiJa@ zNz)!jIJJQHIH_^3!L1$-S7U2~R|HZw*{8UmCZ%@wQq9E%&kCeB7<@+{rLtdUGXLbV z>nORYm#RO{;AkMFf(A^$es-N&J0WGMoN5pZWCJzQ4db9OwTw*B-SW(*i@_rRWNi$scx z!zuMFFO{_crS5lChba~6$};H;6G&Yfqbh`FdW{VrVk=gPdm8u2UaAFrnUP{=oMW^L z1AFQWBvM?QL8;e!smvLa8g-UoN`<;IXB=bP)aA~AaJGwU01;c^j7yFCW-rwO{>(_R zGk#;VzXbNw8AznKID=Au@=}>IDD`P)8KzXID|5zIjhnjM84!N$;u=82Ryd=!U1`h= zyGl2Ciouhe)Bv7hq>XDQmOTf;YXUFuwN7fCYw!vuW!<$x4^*OZSr7xMcEjuOC{qz9 z=sNe!MthH|pJlQkyLF&lrPwU2epB~iSKF;m1eRM3Zv2F@VZ>_S3?sSK5FQtJfsc1m zYg>a)aZ={}3O!JX%Ks&LeBO-53F>{+f3mBed4Ire?HX8KWbkY!HGt^ZUj>8hSy_nQxPYq8&Ur~u72jmtL@e&0t;})Y>!6ZOeeJ- zY4C|o%3SkM%Kp6Rd#hd5TvXc5Rm#l$nXx|*ie>Yf0V_Tp#4I;>ULbwS;NzcIEB;9m z9WppCkji`E|IOJYMz(HZgu5kLXFQ>@I+cCXZb?$V$>4Va>1Kns1=2kR?+c^{3~uCF z)@#YX*Bi^Fc9rTdb9VPqZ%In&dYocATd}HLjqh1G)UOz^er+t6Q?X0NEzA?oW-a>& z(*mt3#2jQS3xb`%>+7o2s)*>-Esz_ORYi9lLl z@T5RWHAK+v&eF^UHFH6k(g=F83mOLQ>7;rtyN>Lm1J^MIR|gUhQ>NBd+v@*x;@%mf9D|akea?5=OGg>|abB!(p}`<2OONZ!`R9a20KU~p z4d7)?8ctQZ+HQTqSz5sFI;jD?)k#?oy4`O5Ca?e>_vErxN%N04I5&`hyE*A!Dtk}! zZQZVt)DAPaAdnUsJSvbEhAWP zcOU`rjvPu^HwA5iqqE820`u4z?!p%EGfry!(cojPlS!WhKEp|^VS`6F$@B{@c)bZi zpysk?8v8Q4R!zGp7wObTZSSz!D5aYo;NQ7*W2piajrLXJ{)U&T1Hb2_27*wnVupH& zaifMj?wBdNyZrpM3mZikZkbZcMuwH1=~5sC)mg*{`R8`e0)wLofQS}#*s^Gr_ zRe_ti4@ZG$AG`mm$o*h^F0l;6qRHIfbobYROPw^DT3OX1`u&xHv)W;lj=hTpX;O%9DGk80k?1m5AS4fejowIoiqYmd+`_mD^#&|j_V=i1z0lyA zK)S@>djct~D;Lzv1vPU)HjNMB(Bu%WYvEA_j|rrc48A6if`}3!V5B?C)pqO4&eFQs z;N5|=t*uO-Y**>aXQorl=YtlCi8TcU4N;;ivlTCa$mbO5m zbG-Tn8eJ4fsqF8XfID1J9YK%uQdwWT)NcLISz5r8Y;`8nyN4|(YkQ7eg>;iO(huz_ zq(>iFa&2$ds(GPRbFEj`1cvGwRQG+au0eI1y6i??UE^@O`_jNwsucc@!4GrmhJiOY zY2>>Ge;Y`DH25=@odpH5gDHn$$`)?QVY%M~fgY@RpGwIC-BYpGWw+kOO`1m$8VUN7s3XCcT z(yq#7-8LjAo7o4y(NUtl8g7;d7Np7efj~mBVlhFf-uW!;R~2(!1U+X#sZMns?xyss zt(3MZ_&k?X2a+2kbpYcu0S+!0#|2m*C4ppOtrHwPWj!+}jDcH4s)Bb3ssg9`;4`|X z!TkaW?QeEc9k{tC@zGRM*`#{6-3^M`ydzhXmQee^uMCO;f90fX;M9@~qWD(kwm`D6 zGD{b-G$GZ6U>^Yn4H~%yja-999$1ZBgKV*U zlC}3sz1_!vA8=AO=6=)MgtC&c$+?iO_0n}9CPm!8HZGhS-O5d@W8z$o$oeh@X>W-J ztbSGC0=A75RYOo*8Mv=97(zOm3O?Cb8eVD)h$d3UUu+x-@l_%s9EV8u%B}6ypeS9D z_K;1(iW&^2c^zYT6nmuS0C93801~E7tDU}Qn;+P{MX>wAht1gY@t(?p(pk4lm6le_ zm91+2^=s>H?LcbOB=KmA$gMqo58K1wo`D1;gKEiCW2N;|BejPbN1vM2nC0vTTVpm! z$f|0l#-&9tnh=wt@~Q1YBD9|7U8G5C(G7(wb0t-k-4{An1GvCRO<<@l%e7P&WDg_zXcv^tyDKz$k#SR} z_z~En`dm;8L7`N(PRmO*C`FzB%IY=jsehTdL1|ztk@vK}&3oEuv!^EYEAwHshcB3x zb?JXX+BaUdUed5l^-XOeknl~#%=+o(u4hJWdx*rGZ&h4lSLva^Tb(rWV}s9FT&hu_ zGlH)0QcWNNrHB6B?%v~E4Peb>H-VwLtcOxvkUfm-ja^XILn}1;n`uIwn(0hHkLq(l zEd+&9Sr5%iH7G@$|H|q$I;sB=X0y`3SkkM9rY7|(Q+nt`-b4QhX$$fm+DjU?RrOE; z3Exyi`wbQ~H`?_f6fzy4rUS7`}Oo& zhO_zD`4)n2wd;)9X>y2h*7O}_rZ&S#n@p>1@_^?;Oe%<}<^^#waZ_u9nKY%P!jv|- ztdOPAOq)2Dl}}J>N0rhywrfRpg=JG`$(Dz(^daSuCPftlZ{?Efz~@G6sr?VKwp6sl z(g{;D=OP^4RL`_zufEbxd8zr&2liDnTA+a>GGIR*dPL+!Fd`#S^Mn5<^L5pmlzUq7 zgI!Duc#4x6YYqM=kkZN!w9r|alzL+zOlAxd8rNU5h$8tb)h;A+fQ8ltW>QAz{jlU{vjL)J5`HskqO zSKE*kNN4`YE?EsHnCY>rZZ;Y&s2nJ6H>Tg)wIU(sELoi9EZI5&mOooX+DPDgz4AKn ziAR^wploSeAgT|YsX@i0qAQyU*}V$(ilu(aOB0@#H(^ytv_N%9qQHI}^oPjTU_?fu zwlQA|DRuRL-Fl9*w1CGrsd22qZv;{|LBr0{q|_?{Y4TFTlzOd~%5p6lR@8N}m&#(8 zQj46$?FywD7uww(rXuLyRQ+M5;i%iO5T)CJlzJMav0gh2uEu<&A?kf5N@-wx(yM=L z$a*R}@P@2FI_hzGM_p*9$FBN{(QrX!uD!{aZnJAeuFYApIL%qITno$3ts-qC@Nc~G zI`EP99X4f4;{s8A=u8bNCKX-TRLJgCuvaYgQ(l^I-@FN{N}>g-OEv`dx+2%kwp&kkmKN}ECpBJV@Y8{mwi$xr?LZY$O@#R&dxjPu$dma>f=Vk1(mt>dSkl5t`)g9XUXC;XUTFcEZ?z;w2{EK zc;$76$ClBcY-wB|st=v1LB*t^E1L@0y$beY-?8u58we#Y8+_r1A){{(4ez4DYYb!CNDKisbyX&%e81&QP&H- zR2IXO+Q(Vku28D6+V1u+6+!=|>W56j-QA9bD1AmCrJhDO*I0(ArYbl}&~0UIlx_Qa|OT39rtZu&N|lpt>YTU_TDJE^;Cm zk&&q12KT3~t{qoWcC~9oc;qZuc)+rUNzvBW$MCX<_D|Fviw0ALm+tRrX2{%$t%8xczvlSNQc)UTVH&o2=%QX3n{8Rtxx#rKN%L6zc# zwc=m^g8thDHTN+AV=kz9nF;u~3u=DN;7x&)I`$QblKM$Ow4^@${t39|qDFJgvs3O! z|Bpz~4J*1S`&PjYnt`8bGxHV@1UYfX|uoUyO_Z-)=NHmAsSHy_f4SRyTN)U5gP4 zzdhd+D~O}^18oaps$1m%hjw^MjXK5ZJJYVyYbVLy<+*(dztKlt6u?b1uoh1>6t+}9 zA*I?0sax~^DDoT_&&{ZvE+2V5Y1Z`Zq5R2xS_e)wL#EbFo3*jw=QvH?)i8_`HYtVH zw%=hEq_ZP-@MT7m6bJmcvz;~ze6!OA+W2cLYcSOae+_u3)q927_oJez$9A-;p5avv zwrQ%fmoM6JEPj8C6>32=;M4MmeB-EiJJVEvH+%M^09yO=UdZS^2SOb-o zC3t1FLuCYI#RO>3+H60&N^c<@EDEHwHE9W~60g5t_~8XtHcZ@QVzygeN)aV~ZgAt{ zAvJb4xK|*3-r!dP=^F;W6-c)l{Ba=t*5DrkDK!A4t~X7zYoOJit(elfm5Yo4B1&cz zNczvR4+YUqni|-T$xn)01)l3|S_i({NfSUSj-9++{khbM~VW`t5-k_M~ZEKc)kPa^Lf&CbHIu%Qo1)m-C0tW3zh9rFO*k@H0xp_qz4D_0>g&w)SRiGz$*S za=b8Juvr@)qnhMTAR!=(uiLE6FQQ+l=Wf>K7oAn8ui324FYFZRt2WELU0YGwe3)Hj zXabI{EN@9~TWoOdNlr>#g`g1^)C6AZq%j2j{R9M!%|Ee(f48e-ojI#Y((~;qq)QEM zvDypnZSdwmx^qo=cVpKxd(ko1bNEK9`4_H1zWr+^V3NGf0qoB@>JU@z{MQ=1t*K74 zMlIaRTR7-Bik>|h9ohKe|GA}zKiq+OV7w!sHDtZgYR|PP#esE zp><5L1iHfW^#t%#BWV@jS37O64StK$hT7n(oHoz~f7WS(ZSajw8}c4}uhRzG4;W?? zles)_*Qld|_jcNxHkg5LYHg?u9x*-O2=JFqY5)m0kq=~^BC>!)omL4Z>VyqQ(1|c0F(+I=LQc4VM4WH|Z?xbN zt~(79dqPU%ObX^zMA>#e=W3)uCMDAt6Ez4oLQP!;eym5& z2yh1{)q$^YQUe$waRf+2s(kQ|yyOUwh*UOkh|Wfu-t({r4ChWB=n7G%n;2W(jEqiCu36zf}A@o%qm<+3K0h3`> z9jVRK9tU0wP_@|x|>%fpwvUTW(%m?&Ml>}z2 zQul)ytTfWVj8+=Bc!N%-Wx;ehEeod8Rd>LliVnEpI~xxEorRd{0{)}Z=C;9AJ+S5T zn4vcK2&c_ygXx`dPrcCj2HW5_J8h^9rq$J_U$gtnbBY|#kEyorpp6M;c+tXO;-YdP zMr4GHo5#9VK z;9yV(>6{D)Kt?}tGLW%POM)5v zgbm0HPuakPsjvb6H_`)4u!_F3zyz*}ONY4svDm!Vu2X6Y53)!&!mdKP%HU@L35VCr zX~Kmcj}0VT_TE4mGp(2Uz`hVgxAOf>`*v8+_9r&%{?eE3&2Y0sbV25pYA#*y0y9r` zaO&ASPZ`N945Gp~*5(HRDN~wsKrIB4f(Sk#zObD(rVyL$uba{2nS%IW43Yh_MLd_S znnk4c#QdoZ@jXnT@5J{~i{g8!Ve!2OW1sALt$b}?EhU@_&#h>x@zl&xBnHw}Lfz=x ztg(dp>DPK|(cy%8^K0Auq78+5?Q64+MKrRc*GT};$ka}040oZE&gm-asTTYiux!bl z<{hE|?9~AzeGo1amY-D`c!lTe2JXAbGOv{E){xJv(CbaE*9fq;UL)vrXrvc7=#{PC zWfbbB*PIHyP(s$LGzVj%yU1Cv+CL-knq-51Bt2GI?sLMq{Hc+`^M>1 z*9H;+_On1D*2t67%^Eo7S-&W&BctI1^^Q(T2{3IGc}TUW;(=tM?#4?4z3X{Vvm?m zVPKXW!UkmeBf@}Jna_j^$f94kfHwxNI}QFRkos}32xC^v97#xw)MP#(k=>aMiDC@i zFY#z?5Ww+l`mq+1r+RFT5R+suk)O85tBw0IFI8t=^W{KFOYLdXfuns|&;q`~NsXTv z-2ddVyx7uB&`K}W1b)v+V+i_{lbXPDU3RwMJ=M5B>!rrfq>oaO9jVf<$^?(+g0r)m zS6QiRT%9^FXgG?X6Wp%s)G^h+&IC=Zt(*Z4l17jeY#m7rxz{AXD*FwSvt(`fWK(r# zSGf)hf-@^NHSX<0DPSm-X?(tMU+1M-z%5THb(bjH$>3iCDYXkhH@l!Fa2qc*k_+mp z5vAo1$6jXwzUG34yH&r1v1sN3Q>iRifEc1|siyJskL0DYAWTciEO#Zd@U*zx+k<B^7kTq%ohL8l9W|87I%;0Z^F%0> z#nnGd!%bZs@08CDq`eF_0x1oaw0dpk)Yht||Nncr+S<}n&#TUMBPvRLhJUoHbjtHgv-i7(^^X|*LLg11v^H~UYgN;4Fa@4&y6qZtJjmb+18J$j zQv(TmFAAg$Wn9`O{W|4eU2di2qIY>tYJJw=w*#qlTIrV+c9q0=xxx1ZQtG>0b`#lO zbJ@*YcD8T+R^vuVS?Sfl?{P^Z2uGq!GA}mmKId9yy{DZB-$;Z{-{F8oRsCKo9xyd z&e8%t@$|9^nUM?_JmIBIN~=fE=3c5vsXYQ|g~3w-=}iW|97w-2_&Bew*)X^;kh*EG zu?reTgZ%<2uWp#?{vNotv}%F|ndfj*Wbi|29o22?N;VEQ*rQb_^?yQ1Ow-JYZManC zHvT72pka5_P=w*VWXeMn`IPYnl(xfh9wg-$dK&hM#c zuyD{@l!AJQBkjT%7|Ml62<7sfqK(XZI7a@Q=S(~qQcXRrE@i0-q)SXR>1kSR^{h4- zgEUbPQ|Vu^l0UYqOvh4|@7k?j*tJT5JMG@x&a-+}Drc&tEA*+T>KVo| z@>1Dcai;lYclS@G4lK)^B{K?^t6o-Gp?TsHhQAxpZZrIumj}LJcZrbIhemOAV5*hQ z3XC-XqluhwyZ8)#^rO}*E6iElhdCET<-q71>H1A$6Vm!`6rEV z{rXCaCqLbqvtOBO&6lF#?%TF6wqKFndu-cI>p0aS^KEujFMz-2w81ubb8m~GHn{Gz zIc+@uw}=Lw>1{pK20y`R`IO;UtN#MmW1tOwv(confgg6#2=L=hssn%Lq*35qPO1a9 z_gESM&UaG%K!X@AN&t^?t_H67gOlp1CnOi8j*#6ueDX~5jjYo4Hh5GZ0g2D52?icK z*i=v+FdB<=;74845fZ=;0ttIiPlbVlsv|&DRyHs?i`~FjeJ~+gk*fQ&s7hB9qn2I{ zTWuksJm9lJm;hhnqy~@xm6!m2FcJnP9EA<|RTnl2{8dyEOo&QJhoOGV(K1JgnE zNIaOZuUhC3p+SCdZ73H!G~^j@pbf@Va-MUIcb=yA{o&MY!nZ1O(uPz-hABTEnpPg) zOB-rK>LA0~1+S^_Ml)4N7*Bmo<_>xzV}r&On7$xM?cfiP$l=G4{ zKQ?3q*cs1^u@~pZ_Z~_eB$GU6v&`Emx)gAclSY6? zJE;zQo0CR?mpZ8q{I-)ufWLN9{ci>_T$BKAW%h{sam95`s;8ciyqr2hvNt|?zza4W zWqpgz&}Zx7!GD;-+PYvg7EwS_g{Xz{=%OXTL9Y=Y`Y9Wj{v^`+iNrp2tx^mv@Q!M+ zK2`1*xd%KqG&k_sPHF%NM~ML7SR@Qg@Ch666c;uMd{a~sOh8IW;D@~A2=HrBNpKXe zKzyhE0sqs{slsRgnqIU8(hgN^B5dg-V108BU9p%rn->UYonT`oJx}?-bUmG5gNgB~ z2{sWL?#lWSGGT5KYkJue`i1b6chJ5r!3yEtLV|K(*O2KvnhLpUa0tRt4#z0A9_{a zW0h*Ffv~%}Vs&!P-&v2h+yV@3(LBqaQ5Uz&{Id0{pF$ z8bG2-nj1(uRwcm1kgx$6JEgsWyGN}AjzSEG2ebn4`UO<%Gg?bj1LC?WHws%iH1+Du zbPJu5f{8Yrx}yJ$Zu(Fg99lSEN)y;YR`5kA7b4?MmoLjc!Tv8g>-^65`>fnLdDt8 z1=d_=db730UQ_yKfn8;$bcew|1ybt6Tu>81i@j76L4OaV$psCg+%H|pMlO4pYBqjt zDN^$CEQ8HJN~=Tmey=X?sKXC2OeIP~Dk7EEP1ZfH3bGz+vYr~r2UDly1gac2HX$uH z_}8f9Yw_EHnF!H6_eR0ZqwPwFHU}!v%#$XyLzL#1a-+L%LfPUhEji1y`H52OQ zPimtlx=9}bMh@KMNqsr+2i9GK1LszBt+^Gl^1s%W%979eUVTO;t)!;TE2(K`y~DKI zEb6S_{hc=02A|=yp*Hw)PMgyv-e2YMKBo=7)M-O)@KsLBM`x^^>hk6LWQHGZSIH2- z9i21++{sCG;Fyy}feW2f2fo2cBf$4MseY|N3>PJUH#=7YSG?3r6t2`0((_YC$bf}U zKI;V=-!@1;mWWK-w<;Cm!Rt&bPiDl+*j=p(8GfK;Koocc;oY)?*`gn+)}I{`0)$x{KIJ|SFRv7q$2SuA+0>V zmp0Uf)ImmK+5FDE(M%N*#){2vdLtu&h8mc@C5ee4fFv*37kEwRW@*4k!8Bf^U>YvM zl{)Bno8GYiP_39sGdow>WaXq0PU7PeY5DlxWOCMTaS*!g1&5!RS#rVQv`nz%g2Ph{ zSZGAD>aWga)hlFWd0~OAXFlTVnig>0xn;%D1}`#rb|Agh;7#W_*TY{|!WY|B3NA3X z=mO_D#^5DyaMEQ4?+>IY7nXOQZdZ{tWN`OD+RNZ2fpnR{4+PSO41Ow*t~dDKfpnw6 zTLbCG27ePszc+YKAl+|p`WxM#5`_QfUT)&$sqWHIT>6PXT6%sdVjS z1pdiMql-+bH@KeJ1D#x{;k>#=UfnR&o#)jxzG(34P8tRVr5d?Xjo_marAlc}##JF8 z8wBLb+*J*{_jM1*1_3$Z0ofoRu~d355Fcxm;Bk-J262l+q$KbSX0?_CU+kV}5Z*XR zN&<0?mIU7uO418<@>Xon3+4wBy#V)$d?3wVXl5lY4khUklL5rv|3p8usM09re<<}5%m27b8!g}GS*6*Jl2Z6rQrH~Z%WZV2m0rR4 zI*aO8d34urHF#Sf0q=6sIFRlklUt&DoyS!@ZMa;6u>~fR^rdfIg6XxgubFmDAyFTu zSL}X1#5s!Q>79?TqId4WksBh<;F16IoRT-sKR>4-#AIqh^HfZ87$by>=Bb$Z5Ol&t z^W5)UV1!|yzsV5Msx?{%`A?r8)og%fz^;5tdt)2ecklte{x}<+ck*F6O9Zt19X7$$ z?7O4Q8lG-fr7?ZDEuw*c>9dSFa35DeWVFFHRL>!hYjTy?#<_)ERe-S(cti8TWn)1nR;G>MBCI8FtXCoT;8(y>y{DqSy zfPaljg17dlo&fG`B&`%2dd);Sdr~&~2pvPl1mJc)CQPLBA}vXeVCJJVF!LO72#|S> zvVocCNTom~I?4w2nNDp2*lWoAfHlxfp`m_hkk*k3FEp2a!o6L;!6052E}XrYJG=f= zgRMZqY-W5?Ff}_e5#5E9jQwJ|UyiyDn8jtu$*<6PSQC6S}MseGP-i6;aYMMu{&7A zDkqp(eyKaZ2BD972vZ-x;5!|H&ei0ib z?}iGGcuq{n5EyDJn6QZX`-zK~|G`E_EQ5&Y6(cc!Kampi_lg%{A?Alx6(6)%%)g=9 zO`_mY^ZM=9kDb@1{X)0)g*#nYn;T41Nj1CA`)9iK;(7gc>zVV~{WO+nw9UMBuV$hn z3+J=uwfRLu3H8W%ZGKfX8y#6V_Ys|}vy;Gu`r3JIe$l;!`s#UAoqg%NY)BK{YvxsT z_BYJS#x>#n$h>wsv?7NNK50nMPG(R@D$u)v2ped{wK_*))p()AeAQET1~9{e0&_TUv*F z@OfT8JOiG$*ZRb5(6jNGJ{=p%`peI)9@b$p9R)^9GSUS@i=+)^1ihDEB=7CqnOVNM z!!-DdCzm?aea2UN*&KN*yG26NT!1Q*J z)S34{>SRAwddW;1&sguj(Ziv+msxg1_wfvYQD4Gu6@3X;N{>rDDI^@(yL(~gf7CFK6#Xub)W4^^Z$6B6vc3yH1u(4yHUb440> zwpF*6UFFFm)ipfq#!|=4v?tmvf5_efUhbrk=e?;c_kO#|+Zn(=IB8_Ji%PB++EuuK zYn?Rm7K2|4q~~8;7ChLlQV{qVCuOI*a@CvY`5ITM`F(>y&n9~A?;14GVA!k6W|w(& z!+7d@?x_YEoah=11A_*Qhg;3FU4sTnEpXB>FgUM)^SC%tO(9)OxEt2fHCJO zuKO6~pu4hx(O3cvxZ2cGHZb}L8*rU@S=qqny64A$sIP3@^ha0aLD_3ef2Dy51KD&s zcUqfYAC43OQ)|ij&(`~K(Xd4rX9EF`yp((8rt7Jhszhq1u&u9|LI1}3 z=wH<+Ro*5nWuQ54ng{6@qaX#NNXhw7=t6gi2U7Gy3-v0PNQn6f1+)eNT&KVO)M_7RN$8`p~`-JcANlSGsXkmLqP74#{6=Lgo0a zq|*(ejF5n_Uf{2L$vW^mMpBc&m?6@D{aAEZWD$5pun2gzlN!KwR1$oJv(yIr-I3v-GPA z&WeX?^g|2P9gGe!KeUHJFR}cPgWG5snshvG((zt;6Zsm=+o?Dmt5Ru7ONCX9X}PQr z!)R93MUU7Nt`j1+NW{m%k-x4IZ;9`u-l(g>PbTQdWU zAyaFo&%grIl|OZqtC`I_?lKFW`qt6_Q4{!1CpG@-ZROoP?JBF55rgeO+WwM~>)Cb{ zu2&j7H;~?F@UlQkeTPzya}Bbo04)DwEZW>NOcf+og#hI+@;}Pn*cdQI$si2u$G+<# zzkm@LiF$&!UOjDN^&ahgNMNJg7aB>~z~=_Giw#~Dv8C~$MUS#5SnJVH2NFBV1}1pK z1Ykejm=k&9rH0?&w9{sSZ#9}sHGsisqxc_B$t)d+SEL~DZgvfCw9K zePcz%;SKB+aln28Q38JOJV?x7>xt{+Jw^4;Lwl$Ro*6UR5S2XtXIes>71!;e$lg(6HJ(t zocwwybcv^={b&^PKNNb=RATuP=C`*ukD-}Rx1C?>=6esMVTC#{KTFs` zecJqXKh~_VsHE%ZCKWh@=Lq2$LU9EBqGSm~Wl5>PD1QPmLAcT>$?m4rK6ce(Gu?QI z)naZ;YG61hi0Ob(5Yxb{oLZv?b?B5itwL#O4N6NZsG4r)@K zbk8(DMw4m+aGnorO(2>_+=SAb19!K&{-fr4H~^(|IuFJv5?nLz2Byn&J~ug=&R=cb zxX-=P0&Zz-Aybr=!MiUlT_&W|cL@5m3u*$t_;yN-oo|BP?Xt%nWinrAR~e9BWN<|w z{n}vAV62w>LxUf=23@Uvrd6*2m)cepg#T?Ku}I!<0RD@Oqj6*z0{pwXcLW%kZVb4) zd)!-dv6IGt!M#}n;{yb$pTPSENkH5x6K^2GdwCdlDi8RZZeSfq#S$z?C$xkFyfbQM z!i<>G3c#0#IQxLXPdcd%>_`0vEKpSX98-ILyXpu4KGIDZ1^&TF4IoykG|Z%>lm^CL znIZw(-Xfzwydhk4FsxN!V0xOc0sFChTeniS2MuGbSUwAUmYX>atTGcjR5NfeV4T(* z@ManZ(p*{+j3F`y2KKUPhUrMts3Dw(f8wN3AXaFV7;$pcTfo>N6C5C>#AbzbUI${Sl*CRVOiO~X zQ`msLS_aFj^siEks^x2b7q$5j`x{J;C>Z(i%BW$$Xjw4wV?(Np1LH}3Kbpt`KTV)v0mc9+{NXLy{Gtt%6HFip=XbX7u);{8-nd0Y8W`)x z;(Ro%7&^0Ya%bypB)l$ZKkZHxO9-YIf44zJCbKu$%N=;+IEzr3kO0Xb5jV!(5xA3# zQll;=718{HzSiG7FcqZJRfJ-QJVc*?1*j|2)m+VN0#|!Ssrd8kDry3sa9Mdv#;tLK zKYXW?QhO0J-vu=hbc2(|PcuQUbJ^oZ5;T~ zhz(4*ii3dtIOtGwhSvCU!xua4^qJs0+-al0`<*lf#E&WsM-mH41LIMd=mYVdBvG7p zoB38tf*){yj{$L%lmy}^EeZan`*9T5kAs%GGvtHChH;8Kf|~`t#=S8Ctnvots%Btf zN!|?sR>crOqD8?NEJcCX8{1Bh2pfQKx4%mVo!Vz+CyQZ%rTd3*|S~faKgEE%Zlzd){m)D z`0On`Az`c}K_DGb7+M2G0tl%ME@rkltxE2Mw~BFdEFVQkoc2#g&$})P3fHNOR!7SaTc}HNtP*cMV`@ zmvP{1ca%5PK~5S62H$0^hYt{_ege-8l7P5XCVD`G_wq3AR37lh-M~7KiX}LZPTU9y zNC>GgFtJn-R?3#fmC}f@pShKF;BFRk$_8HTJzyO8#)u6}xQc^-{W$2E<_xWIk>OLE zcKS^4*WGEOz#lnj42U098jd6ulm^D5G6(>JBS&%CXUsub68sZ)+87W=N%{riC@l%T z()~CJ?8iX|yE6vbV4R{eVesqS8xz1PZ(y!!1}2td0tzHGDI4w}NR$S~U?~d3-q?16 zMA(1?iL!z5i?9LvanU)Ei@@)3chrHzjZ8LyRUX0xsu(x~#|Uu!Jv7qGL)a_I0sAq% z$^bM}1HiPQOlCHk;w}2!D8RueS#t8L9`$%IdX}90+K^h~<9I@fCFrYGf{DtQzn2As zYRpf3Vo!Vz+CyQZc=7jJ^=uie6VCg#s_21Z{g^6+XKd{`31cM>0_lswIBn~!XA1Qn zTebV~Lq2v_4Aj}Ee1vsdvYKSLsv&^PMR-f(IFQaZcx52H+-eRQ zWRqbuxYw%F#E>ekv~)831JgLt9QZHR9EZtd82B~!T>}`}WgJ*@M|o2{%}L|H;Jd8# z@BsqVPv9+sBp_~;xgHSVy*!LNl?Qy08(0TYu>=Rwi5npS2_Y2*CYCC~O4-u5QW`P# zdAG6-+{R)~*}zTj0pq|m5gV9r6$b(PanKe~=eTP8tK^N7Wxk z5(`QL<53v|fWeWYIPDU1kd_30)}1y6#8HxdfjCM_g3oh5jsp8}(9_)+18p!)(aA9Q zMEAx7u*w^ltD1p{C7FW)NlnUzI|ve`fiYN$0N2i7%dA%er!mUad12v#SFAn6TyUJ%-_oZ;xy(bII$%3vrSMlD;|U34B?$uQh{E`V$7J17sGoUEyB|N~19!zJoejy)vOY^n z)0r@s9xF+fv_)(S3H{NnVkXQ4XH%<0=C;@0R?dWps*63hH-V)6h?_cI@A*8N2~!tS znrL=Ihm~nB0~7&OF%wP&=}Z`*7@{*_EI?hE3Fm5NGvQ0kf=9fMIc{sl2TQn}T}AUv zuPjMh*i}gBd=f#ozrVbr-SYQ_xBNh$J<;%d6Qz9JWIZHGp&-i1WCa-O2}WNzSohvD z_|cE@S4NHiQ+HJ7{Sg~@bMuj~QR5kr3&F1oY;Q66tB8$ue2TTBdK%pDwylpFToy?8 z8GLfoMqo@A-MTf~Op7J0aHW}drki=vOz@3HljH*o4jQ3RaEfpNAM1vX;0qieW9RKX zd_hdBYG527MS;h;FUEj$0pSA9irfQ!qW6$7VDMOW_KQxlyL(4=1r6g8Rh1~HYF^Ax zKJ=$8l}2Ntq0+jw+!2u;U|LHKVa)=+-CJ%PNXx1Cyy?bix+)7M(-zGML0RVj@og`o zE{Kc*f6xu61M##*(ohBgQlm-sLHwvt>lh)CqU~HFKs~Rddy}mxCS2YUVL$v^t zDr9t@Ii<}nbd2>S_DfEFp{8_-`Lm0gm7N4b(>#N3!J-k*5^N*jQlda;adebb{kKFP2hG$ zinviMOb)WiP+FJFAE*O?{mnA|o+z!8p==#)UGS@&HrNJ#!D&Nn@J5~?=Xjpm z`~PF_%;T*Z+y9>?GNdwtp1Iyqf>$C9)_)OL0a|C#SNrm9WCPm;ACdJ@LlOpg_lM2D_O^W_f zWX5F>U|l;ibl{NRL}yW4WtW5;w#zOE`JBQs;rt+<>c?ms^Q^57V7j%HKQXfeE7}^8 z+wqhcv9u0yddqVT6N&j@c-;|QU{RDShfkUd(arnMk_WjXN|?+!$Bs@ zhAf%jtCm>^&IvN%U^@rXgIxOIjAiHM9sVD0=`3{D7|b>!a{#i+Lc|D;=8ikLi%qGL_Q^*N4>tXorixbyQ2P^V{o5!2IpBC z9m@_#jMon?w>a2qIn%i93T7Xaqa3FgP9k!22iK*$W7!Qx63cEcl2~?g5m(s-)Ju=; ze9>~{BjNN5N?i5}iZspvoV{<;-)8y1DK0){@O4$%0y$8NtL#8q>an|*9m6{fRQ%PX z4%fcu^NMvUr>bWZSEo{+67L$UQ*nKwxG0sDD*lv8e>bS(wQaXf3zbRBcl4Zq>E!n)*=rJJb5tfDf@5C;-!iR><;aNy$zP zvQ%XE0o&Rf6`rri0+2+I9l?zZW|@c$oMMd?fGj3)f%8%q$Wjs)xH${#F;BcQ+r`97}`wmFB?Bne{h>ToA8Mrw!%JI&P46bQ26@jc!IaHTjpDvRbU?m2} z{mq>x1|6IXHfQ|#mNwgs8yVbJ_X_!NaA(C4MC@$N3A34aC(-}LSi;|)HfKbk|9@j# ztSXuFflWsA(Iv*nM7=?ZGpWkba!Zcm6Z@Pvhc&T1kQFQHy-ms;!$rNj$%xIFo0+;x zvg^4rPH?(;7O;7yn_>auJkYXLxgLc5Uvc}(e*jAG|OdJ~8 z>HvSTWr*O9y-)>QnA;zE-;uKH`Mq^+hK{Zuw{ z@C}pV8H%+kR7~9RxhCG;;~<@iw4|n&4ya|Wl3hH$u2XUK*{5>S#tk}^9>Lp9ivRTt zwqpkGvAHQIKZEVc&tN-d@CBQ}0%ov^&0syG(yrFe1#tTJbWnYF}7z>0K6m>Eut1gu_Xgjo!Uk${!%j4%r)F%qyT zI3vs=ON<0;4bBJ$JHdq9-)$qCy9n!_!8Tv8VvNViFPhZ%6_1U_o78lI#|vIJspdqF z=j&9?@^j{U>6MSo_4&6R-~G;{Qb zm6~t;)U$8|cD9y8~9X^c)qTBO*qyCwEioSI6j6nmU!uB#PirBc-%{;#*|RGJ^I zxMxpGJXCQ~D$P-BbiTPRRs1uRs`v7LJx{07{CLIo7g*wXihrfjj=lX~U)8B3PFHMj zp(PGb-2WnznkWuQrS*!VFE-ai#mg=+=?29UE;T7q9Ft1*FY|w0tWz1+8pXDkTjET` z`>rr)q~hg$OuA9=A6J^xTk+jgYIl|Y>mFB|tC`|msdT_K{;#WbD&wkst(Qu5DpIxU zyfjazB7NG|OWEuFRHVBU`}8yE7sWIBn^chVxL1)$uPg2{z@&ONc${^kNoy6S4m4@8 zVxyZ(YH_p2s)J0rU9rh6Cf%rb#;qm|RBU&fN!Kejy4|EA#S`x^X^>*a!6x0Vc#ZomY8|ofZa zZ>q;S~R z+oa)&J>NI!F2!h$NrM!-d|=Wv#cSr8RCAukMLLzycl*#wH9s=f^NR6&lPZ7g@fDp) zV$V;!wCktlnxuI50+Z@}=5e3TO*-xikGn54X}Ds?MJBCReCbP*PFw78zfzM%Dt1_6 zQl+mvzOGXlYUXP%HU7q26BRF9YSRASdMwhZB<}W|mwwQxNZT#*(nmTKX`AIpXRzmvEVP0o>P2wqe;sY=SfK!_fOhtu$9LhDw=e$Vy8+bO;UWOvPo5{ zc>F=9(pKlHUW&IiSBc`VZA_|M&EqPaO5!Qod8yX+<{G1T&kiQ-T;1b*ol4@(J9_DT zor?5h4KH=5X^Cgo@_5ruCOxkBTPii!+5h!Eol09{6@O2q<9G3{u{ssk9K}|aI9CmENxH|9X8Lb8T$x@#HopUD(@WiB4q@JKpc5k98_i-v_)jU8f>_ z^`MtNc*svhI%}B6rml zpi_}{KgCP0=~ScxPW95eIu+@t)4cSNPDMK7bT1X_RHUB&@KWV7{8XeO#VM)u_?iB% zC!A%jX^K4}lU69+-p-`D?LB66D$SqX!AmQ2DpLQBUV2NXBE8zlOPvb*RHU_vL(ev; z@i`tp(5blkcJ|Ulor*N2ix|%35O8ZXQSKR9wBz z_0lMviZs2um(D-W5*zmLc#%%UHMFOf4nN;q8x_0tGU?n4JpQFqNu1r=OS@iZu469p z*hi=0ny7fx#pY_OI4PCpD4ueOxjHM}pGw~-w!YL{Jrzq*>3hYVmznF%>pgy^QyJIj zeqQ=Zry?!w@1=)wme`=kV_%($tH%H@P1LDKqi*n0e4{1)qIlLolUm*6@jjhO;=MO} z>7+sCTA_HtEhe?T)nk!PCGnQqywvP=b1heFbB9T%4fgn`P9<^d5HFp3r@8jL%j2~= z71xb-dufGEMcS#@OZ{~!(n!TU@3FRyRqUHea}-Y+YOeDXpGl?lidWuiu42XQ?lY;O z;`6CAQ*rzI&DC3RRVr=!fdA_mI+f9nQ#|oOOFUQc$5g8RkpJr_ol4?##chXK;sC|E z!%b?c*e{hfC_eD8x!zLj`iMz4E7pJ1q)v(trP6+n`M*xlsf=r#VzUvJI9KuF$4wfe zc7U*;QK#biOmUCr{GUYXqxfSgRUhU5dZ$jsHA?a5(U#a=@sU*8pg8Dx zb3LiJG?hAx@qb;RQ)zzd7rgYCPDOe{G4rCe)lYF+Dm5?hfBjOYlK8vg@nbFV1;utR znRLD4o-dnplH&4IsyEL6^#Ywr^Xn9cy<&-T6l=a}(u<1i$D4Go;xQ9Ux>j+|*G%fA z_-rb*dfor^JDtiP4u8W-SLsxwgC=@uu1-bTf0CDG>r|wD-t^K8ow~%gv@M;Abi`yY zEzqe*$4>E5PNyQBKGjP<>Qtoc+g_^jj-QHjrDC0FCf%#JD3xA**Z;NibaQ>Axa$m) z{!n~!rb!KFd7PtD>9ON`UfQ5jk%r9n(kD6<>7Dnzbm1I773mMf6FxBMfVm#u*QvNJ zn&+jOADZh$#ZDiYv{CWY`6iw9vBzI@Ds7GU#7kf4RHXHvdg-wRme}z#j~jF+RO+_c|Mg{^%D9eQzKgMfy$g=%1|l zX^NMvHK{~#+n-H(L~(U0-SvzAYx8yH8l?DnD&>ClfBjgeGKhZbz0~M8ODs}ckV*qL zXrfLfameppI^hpXd{}W!Dvkcr|FzOz=9;2-)kc#RDjrk8-?AaiuU9;ME0cDw=<$7> zimO#6FFl}Bk$PA5(iEMF^k5Y)omSOPMVh6!&(KrC$_J+umGvDlSc>MmzYwj@79QVvb_N>Xz6? zaat z$1=C7RjhDT4Q}O1M^#vURE6b7Rakyhh2=+8$Zm7xrHnHU{ESALo{kyQX z+;PRS-*U$lOJd6%S1gGwcU-X~w%l>WlGt*`6-#2v9ak)gEq7e8B(~gf#gf=^#}!Lr z%No@*V#^&@EQu|5T(KnnXLnq2`JcO=lF~2S#=$)tiO9ur z?&3&9Zq?yFjzr8`cZQoxxR)bwZdN^+JVPuVkY|X+1M&>9ctD;Z77xfX#Nq*YhFClx z&k)PkePW2azM8C!3huTan3^^+!wYf*4{CuMXT0ELUxMZ%orcJkt_fPc=Evh&gjZ{6p2Rri z4R3f~r!p_#T9p!C*&;r!K??eG`Xrd?1Hbe^u+c8a<=G+@(f!f!Tz!!$HvHSkx4ee zg$MY%qul(!JeQal3A&$<8ewijON@RaPXE7MH|slfD&^2XHfYH!&9Oc8O1G!dT%K*G zG?!;PDb3|s*QL2U>$)`Gx)x_ezx0B2SekDgmgZZBrTNxjX)e#|D$QBJ61^QQnfE-a zrZkslHI(L98 z$#G0ssC&EH^5EbIP+Y_jAlTiDi#D~pQ@l%-O>q&yGg`^Zbpr>-h2kQ%73zE?*#s2* za@jD|zY-$>rNEpK4vsX%MR|@i#YO+Yk*2sP&yl9MD9@3mxG2w&rno52k!DT4O}Ds+ zBhA!@(<2Q`&6Q+f5R52EjW9J<{K^^c4L!E?kFdL?22-XWF%s;(duoJvK0h%M%(*Z% z!aR?k7zrlollZP{m`CyxBf%tnrrsIh;P_fxlxHU{F5>vgL$WR#<^k2D8-jj%gS#`r z!G2v_lpa|j)0>;l1;!NL52fzU`TufoE%&)@DwfaC&rQ-0Y?jI5ab}?aydra zub&~D22WE>QbCR$Nf!hktw`4s92_A^@|~Yb{*%ulCHc-{CHc-{C3YU`znkANlaUit z)z2bsu3?TIiIIR4pNMnw9ZE`a97=9}JUv3d96gdI2{?SXzTx0dQj#O!@ZpRwM~|dM zg57UUj}Y+IcX%x^5?nkuHNq4CNsI))eV!WOqrdQ)Y!zUUN|HM_NAPIs1GipigPEHn zh*gyKz~azH@O|n7S1$_MBj5<;7FV7FSV@ip7{?-Kgb&@>Ka7(s1%gjilo5iRb`5+4 z*QzK!aQtrOo0}u}NJa61d(;Vh1i?YF42F)CezM8?-p@XCE|OABY6E zsOY+Z|NBSXd-Yp{ES+mA`6Jt$%6=*mxXPqLF!RBs3v<9uW|n}Xt~0{_g(Gl5*(0z#R#x_drrgxGIUh5{mhX_v;h96T*g!r) zN}nLdYH@)VOiqtOaNVh1lNANld>1JL@*z_ex zT1A%&Z@nroZsr+fMs8DQl*`gH%8VQVry18ZXPJ_9LDvMQZSbNq!ogW)M!wJXGdB6z zo->MTky8pM4X42eRk70ycve-U0`Tc=>_jmmN5HwqHOFrWoNbadK)~t78DY*giIITQ zjWfc*sb_|L_qe?lL(G6Y!I?D34;Ev04aQ9{Uq#tn!AknIMRr%Pu1Oh??=#{8`R3wA z40GlZ8^}4z+2Eg^3&uv!YZNmUgT*ElfD28E!Fr=fEC4wNCQF2Xlb{<3%sDVI5^xf9 zMtHRT+#H>GQ32T7qzpLHqyn(b ztt4i^%Wgv|0GF8*gNNOYD+5L*6@Z-hWxE17@4NYiAJMOcVgtV#Li+_^?YodN;Q4nW z6@ZVMlmTZKn+vRY4^jqfJQS$_yw0QyINqcJu-&~RX21vTLn;8jH7Nt~X-D=7Fy9BC zSM6!*3|OH74`3I74Nb~`eBYGzLB4Lfr4REFDcRNu_#onpaPXmI#{cMRq4cn<-0xo^ zPTs69hDmn5&mm<$bR;eE8RO-5((?$+r-Q^uknek79X-3dr2unAPm&2Zr8^_c89gx) za87qdm{WRUB;W+@j4fSeHy4n~vzrw5}_I~Z|If2#^zH|GnHjIPwKy74v0 zjgCW6sa{W)_BasjH$6QN!C%bqnw;>#H70fCOAbdUX$;JFu;TlN8wY%keLac6QNb|{ zo@BPJ?<=+}Z#AJDo}& zC+^~XUuoV$ai$$K#*_$X7_dNZECN*On+{c z838Axzd)Df2=?Ed-)7>!yGXaG-=Ae(i*4WLM-LGvZ1RIfO}$-0_Os3Wm@y&8-hIb= z>D~=r^}g4nCYMyas(U*l4U`_=Ngv{b96|$A;|YZ~2u=G`6q&dC0phy;89aJ{f|vx_>7uis7do3_(hE3>CM z4Q5A`Z4nIjS-AhxeoV<&2!2b&^*MsqpADP@52RnX*XIa09wcoN@EO955#}I~7zy|c z;fydxj>JgtuMQ&|QaGF>$pp9Q@xk>1Pg6~d>vIId_w)x6XM}@~4(tD|j}Ck^NO~aP zn!M`)=J1gi3Bu0_Fo%!CNN~zrzcsrS%YFt(jGH=a6zP8LlJo7(`Sx6P(nk9Gq09Y$ zwd=8$MZv|H|LvVDS*ZDTvo25go#u0$x&^~t#_r;@e0xd09b(l>zP*37?X#J)rMf=; zhv&fw`ObqgHhCUogO$ZHVUwS7`DtH_Gwe(_Z(h3f!fddKks#kmZ$Ys2!UgHY(-}E} zzACyU1GBj&y%2Evaz>baATbhf`f^5?9V0OkgnJ3h-jWyz{@Z7*e{qJIk;}L5uphAx zB_kyG-#TkaCll;DYu%^(M(-9Z%ubYyhTu{C!PXgJ_M*f{z}p( zmpwU4^P4)jaVLpeVtfSV(w);dZtyFfbPBH4D|RyHAQ$Y!RrVJ?k@$hHncn{)LyHvo znNQjR`6@1n;GcSrh$NQ%axN||-BtX>FHLC+>}pa6aEwU>VC7#)?7)2`ZS}qqX&$`T zr1sot@?nvR@ZOD*J6gq)mNU;2w9k+V~NV`}mwz{$qTH zd^c+3JD~CTm@7=KxqKIm@?B8L_Y+*cU)%ECqmb`*gunaD@xGRLc4MR5Gq)Q!jpGsr z7pHODV5e~!%wDrqg$Uf-uX6cLiko{{%XfO%oTGlJR(f@_08dU!U{A;quxy+Wo}E^} zo{%FbRWWH%d8=3a;+KU2HZZ9Z*j6Pu?=8p?Jf)&*4jyN@5y+!aaz7y0Z=UbeWx|70 zlYxLMOv-?beoQmrqg0bj@IIAfyd^n;cdPrOf$J5XubSk7hwR8fBMY8dFU^F{R!uU& zS4_%+Zy%gy!t+#XfQb!! zaRP(RfN!akj8FN4)CMkANd{7qBj9PWWXJ@OK9(pK_rbv`CCOz!h`NqBSMa$qX^`Oh zN$DzvN2w;O7@TiX1{|Wd1iLQak*Y~1INziKaAlAQ|7NxbXncBds0~R zUj$bNxiC*NB}Rf*0wc`#!o)~WV==3-0OV#>H@omIrQRmF%W?z_Rg~R?yIH?d$>qYo zn=J<01;4++{Gu#NbhQ5YZJkO7Wq+k}9Xz8y&b@607IW7}^-oBI< zfP6WZk;n&*^?r`-*Qv{ehpASrLjMX!HYlpF&%U*h_?|9*8lZndY7$(;gZaWP;|DkQ z%V1xr_~8CYDp;(N%)o>k0c8k8T#zeUhaeI8g3kqgH>+^p^qy%Z_4#?QQ)`!zTGVFKP!A3&7mKz_53jf86<{AM8%_>(1O!D?DA zAz8!()J>3m4t%{R{UI2xcLQ@Df#X$jiyWSt+Q7;;l9>e;4@^6NTilE-0*`(qwZY9* zljQ-nHz@|sR!QcxBuDVxqx2AiT%L8a01tZ{TlBjkmzSIk9;26<36d+1a$!N*ieRv5u~Q`21d0@WlJ zeDiH@OL7UG`7F(aOH`9w@Ewz4aHdL0a|FkI;hU4S4Tit_!Q4kKJ%B&f@V6Md#SWic zi`$MP@N<=%4PKVoz?wUenFYJ=mUaO5QccDIzFpfgL8=M3KH;0|VvE4qd!!w}2dX9= zfE`VW!Crf&nefbd)&Y1*%hU#+p_+66j%`I|3?A7!&4f=;Cg`Xwr2)nkQ-HYu!6GSi|?j=!V^`KKEdiUye*kmf(KM|^9nz% zn&g6q&Z5^Cl+!cj)OO(n?Qo{iCcs@cN^@l#GvH`(x5vcpued-oV(T zEVv@bgjbs_0x2UepVUAqRJr+w=N`{^vtSb~U?t-%E+U|;k~9Z$ncX!97u(xMBapjZ zwyMw>} zCD_#Uqo?#5(OjL%k%R3gX3QMGc7;( zii^vdd_fY4uSHK+uumgpzZ8k9{5OD@5BpT&5*NG64g0aV#ASCEaj{XoZyQxye*1~3 z%+;oqwe?IJkJV2!$zOI#|9?=IE=yb1KiA`C>Yui$kgKpw{RWK>9l`SNrdP+(zqHXc za=xvZh}CeIu7=di+Td6I^e<(9<4^y>np^q`zY|2@_a?>Q4zHRE+}WfUJldoPY;IBv zb}%Vo1Ig)zA`7eR29l1r>~@m=rR?UC{-x}fMCpJ-Wh*^=iUf8rDF!*9ii_=mB5fk2 ztKAbNoVYydcHt{^-QFEs6@?#3uZn{2sFdv11iuEkFxO1QxFAPxv~Di0W4Lv?34v@? zNhbuuf?Rl1nhSC*G07$PEx0HNZ+nDoGa%Q=-H0hgQ-Cjpn7Tt6_Eml7iZ_a(@@l)cpCa=Fq( zDH*YWV}pxN@LP7JDFUfDBR`ygz2EdJ!*u`;QcX5wu$o=q$$%Hwr4}hts{D{$YKg$< zCS|}Yf~zm^4R)y|0`Gap4^5WQvK$Xd{-mNCFI;_^ZBXEIDoJi>j^F@&h{@%`o$SG; z=vKwI4`lGhYJ4Q%l0)CO)esa^S-ykc(h8Z|5J6XtF&cRdb%SAB8`4g4iY zg)7+IU=etdNioR1W6~J-sk+=Ef>&B*1h$=Rt7bxupo@ww7an9~|%NL$)+U2$3g{ECm8{VLr{8n|RUQc^Xr*3ml z{LZ9vxSYmCGPgirE;%JTK0$ifC(C6YuFS|05#$<-?DycW!F3y$>oRh22&68Q8wlJr zy^;f#sN`%gwW6d`kc&6Y2Dj6THp#w9Ks6F)gt?@X7f=*>~%JV?dgxsbcNIFX&NRqh&7pmmCfPXeyJDyhJ0+X}-uGgJv+f}4(BtKw!b2UP=}a!RB7S;sdrD2_LERm96vDM@_C$LiHUha!CXcRxznd!qa^)=P zfuOHl9?O7SIZJ#5OHv=mwX?)Wz=br~bjm)`=VpQnX*>?$G?)?qvYmhw0B|<=C9M}H zHjtVC$w&yohkxOL`arO3#XK??J`W5(W|e&+9udy>WZ^7(MmXZZLhej<1BRcmB0gEL zu(n<3Sdb%_t)d*8z?13(K7z3-iVr+u_rOO`sG|75dUXRI!6_<=58QQ+z(;VMisA$R z2z>@DV(qqWHiT`vpFNf2t@xuwehdM{t9R;sY-`An*|k zQ&D{2eGLO2LFEIzC_eCYm6GK`@J;Fi7atU~M{rgnYY(h`aNr~8tD^J^o^VLuBj~N7 z_`u5#4SWQ{RTLjM=CHs=uxDd0iVs|=QZl~;yBuylu;CFwdjxl@DD8oTM+QEE=_-m3 z9C=jWBlti?@qs@a9ry@pALB*wfo+-uK7yB36dyROY2YJxTSf7KKQs$`1es&4U+|3P zfsdezigHQ-4>`_K!F^f;sRSpgC_@1U9v}D!MyM!0aODYsk09I9`UOvE75E5xswnM& zBU=YPf;w%iJ+R`5fsbH>if(+0-P;B}f&nUu4}AEfz(+7aMe%{9CkH-)j;DB0eBgek z20nt;DvA%h@U*~3@TH3411Fpw_y{upuzta6X9PZiMk-2sV3#ukAHlUMiVqxrR^TIO z6j{IEIF*uJnqXe)1IM-t+9TMny|o99S1DXPXb)=A58Cg8nK>zu^9z10TUZRTLk1a+knI&_hM>ffsZQ zd<1u>C_eE1!oWvRE%u`Lz^N)F^GmQe^?|E1L3;$}WvxAMzixq#;8_)=UodlS;3Md( zqWHi?p^so=>H~Xr585O6OhsuATow8Vwmr}01H4+LWVsM5Pkmt39znkZom7;5!Qr8g zV0`KW5A7MWM-Ztf?SXSbA3^K$Z9c$DRZ8ZAU~uXKtM>}}B^aop^b3v;eFXI`uztbw zR7(0KxFPj{JN6FxB{*C~=@*8-H(V0*OYo$M(k~cY8u$p_QBizg{mTL$K?@bd2d)Wy1U)Xd`2c6C zl*|Xg=~tK!9H~;`Bbb`{z#IDn<0E)VMHwI1`^vyaut-Jmf$gped<2)OC_b>+)q#&- zjEdp|54a}q5j>}&_`urN20ntLRTLjs?Yh86&`3q`f!x-bEI$HnXmwwIxucbPQJn@i zy54sp9|=L;#Ut$%7ZD741YZ{9hR>v5g6|(SA9(bLU_J;2sVMUSaypFY*~z|ExLoulxhqv$mPDG($-jDy@~ z>RMYh+GqTvQyB-y1JQB?0HnY}vMT;6@u}RR>YC$5)ar z?GZe!qO=FT5&8(0rath*eS-D~id2;Lz`3E1pyj?kS$yDGDkaN>U})+CKMj2ZwHjD^ z;JGR#?Gb#M`oM2PAHm-HS$p86Dkbd^j7xpsZ=sLifc>pK@J5xA_6TOAK5&-T}nOYn8-0~;P3^h+>QMd=qT4SfU!hgiSh!zv~H5>z?Vd|(Ha5+A{& z)CcZ%STH_&)WPAiok2W7TN~Od{u=6qI1Ba@V_y~4uVm>gZQsN`{ zF7<&uoBGtmNAQ7)GQVI!v%p92xr*WgPdzs95xlIT_`qYE2R?$QRTLlCy>y3_~qd_dwOsM^-r1J5`qm|ueLRFwGu$DJJb2+lmk+5`7I zHSiHUsiL$8=1vQI1bd!t?SZ8#CG$aW+CR((9)3p99>FUrO26REX9hlkA5;_{`0-hR zkKlyJ`UQ_@7x)Oqt0?V(L)!;Ff z+14KTx=P7%CTMVu`M?iUN_+$zJDU&uPNl?0(5{R5z&}(W&$6eg{e4%ft?M2oJ$dgJ*GQsl~n-An!rNl?@@}=ejYhC80#7A(PiZW>M;m}7g zE%kv1=+jI|djz+uDD8nf{gn6!YF%OD19|=_@evH}V?MCUmBD-v+^nMX3w|5=2nw#U z_Q1X>CH)f2OnqSWtAlH{ynHfWDv zp^DNTSpB-dM{tRX;saj_eFO_rA6U>gXpi6q6{S6}>h*z-;2IUh2aXSY1WQsM*sEXA z9>J$7N_*hm{R1Dt5EaD-E((1FTjzYT_`qQ*CEE+Z+o=ycw$g zMe%_@g+7ALH`w^Vu_`6wBiQ3c^MQj@N_+$_rarLqz+ij?H>oJ&1Do9x_z0d;QG6iJ zG$#EL@JyroH3;SjL@_SQ5iGmS_u`B&uTGL5#Xz1^bT*jh5|j1__P)aw49Ihd$p8r| z+-Y+sHyLWctC7SxIY+>wiAgsE4em{c4O4kgjHNk(gYUQTfPEjZt{3D8R;VZo7UZ4c z$+!u4skn&6MFd|Cw@$!@j|80%Jf@;_0^av%;3IfZMe%{ZJQnx}dXKPv!NSJ_AHj4L zr9E)c6M>K5I~BzT)_W@O5uBo;_`tzW2R?$IR1_ch?a07Ku+uYM6dxEp8~6y`Qc-;1 z>;DXV1p7T_?STi33VZ}7sVMD%ydOSU=>)tWK3VAm3rnmMaMzcDP6&=xQ91#8y&U)m z2CFDOaLTyAN3cXi@qzVT4SWPGR1_arG(PYV{HUV%z(o@RAHn6Xc~N}e>8}Sqf>%`( zANax>fsf#Q6~zZ`KPm7L?60Euz)Ri?d;~*O6d(BhTY-<@I~BzTHkcCl2;NdreBh9& zfzN`sy(qp)itBWmY(xaNy<b5v-hHK9Fai z6Cc5_S>^+8dM_9s!CNZ2<)V1!?7&AbTSf7K#qS3`f_GFDA9(Maz(??*isAzw`XKNT zRGsTZ@qt5BO6Hefw|V9Rhp6Oz8mvrx;JqIP{Ss_YQThdM_$crZ{Gy`xz<%=sAHfbE z+xWl%DkbA1Sdsd`&prv-Be>*KYY#kbLEs}8qoRxt9QIk@BRJ@DYY*f(`eb|ry}rN~ zgGDMOK7uu=58QfT&@Vw>73FqkusHM){F?ee9_df|CFuSosg#z%1O*X9G8eiO7uFiS=07rc3C;3N1|Me%|2z72c? zgTAwV!2^~BK7vP7l=i@VmIpq9aVm-r+Y%`fHyw_oR_#7FR$iZVX1<*$K{;AIuX2liPX z_y{WhX8nTCsFd_eP-lbr!0mqz+9N1ZQThe1_#^NUe59iIKx%v>{SvJE%lZYW=aKjb zx>le}Ko&e?D=#HJg0oeWe!+t(20nt0DvA%>uTtP6Xs4q1zym7>K7tM^iVr-dO5h{t zuA=zBW2*)}f*vZ04?Jz_z(;VEisAzcw+Va%x2PyS@ZxHLkKiE{#RuNDZQvt#Nk#F2 zW3~%?1fQuWK5*vtfsbIVisA!*+#&E0)UEDC@qu-B415G_RTLlCrbgf+xJ*Uyf!Edy zd<0LZC_Zppt-wc6s-pP7Wjh5vf?7L!QG8&-T>>9Ldlkh8Ubt)EBe+jR@qwdu3w#8h zs3<;gUG2a}P`{2B#Rs0gd*CCuRz>lF57rHQ1XENLAGmstz(-JLPwN*vwO-&OxKc%F z4}4;;z(??&isA#S>>clQbid!I5G7t$Ps*-`oOjqTYK`x0S&I!sk8^q34H_` zQXkm)lAt|;=_*Ql;5VVqf=hj}_$n#()M>I{2);;t;P;`A;PA_=J@6WplJ*FmN`2s` zmk0A91d~-1ANc!KfsbI%tF2!!b4}nQ7^tGO2hO@S z@DUtxowWxZ)Hm=EJfott2i|#o;3J?6RI*7^?WtugE5!s-^eI{R1Z}MXR0LA=NgnkE zDf;C01^9uT=^+BC10`Q+Kx#R;O!yD0{}hAcck_)UVVf@)|{GVD&DM9mkB>$ zwg{~Iwq=6*tK>4_Bh40pb>B%d74Ooi%Y+{{TLkVm%`(BpD!EL!h1nu-zjxD2#fNn2 zGT~8Xi@?LCTPAp{N-h&V*=!Mb*o-t&@kyP!On98xBCy#^%LGqU$z{Ur%oc&oW~G^m z&+F7>!f%=_0^7W2nc$f!xlFjL*&?vzY|8{+R>@_;)65out>3pyu)Rty6YgQQ2s~$w zWrE99a+z?I53ohx111%MB`Ud0c#hd3@Bw={Qz1C=L*Ks3gkMrkjtStwA9A689z1z-Ha zdIei7Ovej%R82C$r79)85^M}|;awNeMFbx7B~lDdP|1xK{=jSz*ln@TOnN1_UPYG+ z-=mt07#vw@y@E$B@si7gPg6}Y!7o%wdL{TJ$c4B6iY_9s{?|w`_<~BVS9qG)BCy~a zpPBSZaJh;u7rs?B88P_qQtK5w@LMmrOt__Lk_paJDe0A9Wsqz99bH5f6?a{R6oXHz z`$z{UFs3w`387jFIoILL&* zGg}0fHnTp#?#HHm!hKbfKEW!@Efd^DB{y350JBA4{o^bXd{QNs3BP8x2yENJGQmzN zxlFj1*&?vp@sl4hjN&AGaQBC>;E1qbXU@ev0XyFECi@-hGS|&I`C6@`mYPJY$ zeUfE@?NxG_a1XOZV0^M=f{RshneaNZMc}|wEE626lFNjjHd_P^Kh-k9Jx=qI%Y=_q zO_nV<(WDrh9c02^nk@o9INkaLyZs~W6Yj5?^a*ZvhGl~FRdS<+o0%;FOV1>;09(91KaFt3f6W(aH2)ywe%LIq0KKZgaTLj*krLh8VgGw$F-o6{Q2)xUr0&tj0E)#ynY!Nv4TpB9?|5C|i!Zo^Mi@>2K z6@ZVb;&Y)ucJ_{m~30UaFXVKFx$LRZTL%Atq(O zCxT4)MYBa<-7)l;0XwPWHY~WaX_r@kudvh(;Nxa%JOUnNwg{xQzSPbD^Sy4GGWu>H zFje&B+8fCGpq&lwHG$c(*Mm?j-`QYZ*1T1PLXh(L&IYHY^gB>W|J{k{ih<{=CMyQ4 zH;Hi+fJdt2I)J;GR#Y3l(o);qr8xG@v{QJBYSJm#;4N=Uwn2iURdn6Lr>Z6w6u}E7 zGvEw3KqZ$6KWerJoNiJE{5Hsh|1etwHlJdBf)w|cS(u#rT>t)yPTfG@?WU3&fsIYd zfakyCT`m*uubM14kaq+~RbP-d1tbF@m=-h#f15T3?l+yW#o)O!(t*HNsU`yfzfehf zU7sUp9=sv|KG)s{5P`fRKyoMK2%esu_6vWln)D0q`o4`AT%wX&bnqW$i@<~C`b_C{ zM(z|1dg#>U!b4P(UcvP3(=oUt$b@+_wPb?V&a?4?Cw-XCDcnUh$pkO`$i}-SM{tXZ zTUF?C=zRb8o*$>p!B?v$SJS~kfepStwSkoAcMAl5CAEQ6@OL&!`1kxW7>M%KI+cM8 zQlz}UONGBQTLz?-zpSohIRYy8yIlCv#lBnlovuicV*YZ}04e70GGSiSEC+dz`u@`E z%9i?fHp>1}@jq#gfa?CTP{4bZq{|K-rJC5l_X8VT?JJ)uU98U$ z@Uj3m7MQmMh;c%W;9xEF?~HIC)xN5G2!obk|ae3!hFIx!OPc4}vYd3%7&3Rtkz zhP@_7&{sv5%j*MpKY-KV-rrjCt0cj0fxq{5DATJw`@lLik5Ae?EWH}S?@@dxx{Pg!U zm;slV6ob6HKt7>>$Ju)fB9K=X$ld|+mIBu$%v%a%w!klbv{8V(qd>X@d1ZiW44$>t zGC|%bAep>SVB24C#b8&HvfxOQVvsj%OIu*;Uui1?@{R&=ft}WSmm4eGSvCJ^h5qhU z+eqEhKgp{Vl0P9`8MFlR1_U|ygNOWP!vgo;fRqJ!O@gc<@FR7(k@9|o&3*3y@8fp4 zy!U`Na61j=T?jJXYbsStuBGr|180NhR`!3B{Q~4&2eN2EUTctS@C3Z$K*aSqf={c` zUIg;~gTzO`>kiylU|v}u#$`DI-b>(&yqJKO5jYKws{4*5c}9+aHxxJ{{F)kN!GOHA zKvogROABO=0Y}wf)-vEmlVXrJ7Rb^AKdtE#-6+bwy+GRMyIcDpFFKI+!EtrX1@f8$ae)`;>kVWbgG2YUM3DCxNFrEG-(w(&Aa65};e))m zzzrWR);AW24dlHA(mr_K-Zl!5w-$&Ctg#QS2z+s0qymuF6G$T1yaBEVzf>iOBM3930Zusyw zZLKkodi~NExTn_Xm$8CW>lYWe)Laqxtkvj`LCW$=B1i>(87oM!eK%Hkuod2qL2B(w zW8lIwZH_=H?TZV1=PX2K z2C0KDF7QdMlP@bAJW)&C%P2q!-b*6*v$-OWa`%!5QrX@OAD(U1>tm3@_R>CBUklYs zV<2Vi#Rc{;R|M9vBK0vy{d!3RuQyi&QoUY!1SwSSh7T{dqV+LIoqA~>yxmIH#~@Ye z#RYz0t_YlYKAS}hQjT5{!JVu!eFRdBUWN}+cis&jo@F)YW011*(mpuQD$vIuMd!r@ z&No*C{$!=*W030dk_aAm5i=Qq)RvdwgOrhX!-tz&srVSAioCQBR90*Ik?uOEZBFTH3lv=DGS~{ zC~Y5JshYG8-gpa*Wx=g)MT)_JCS}2GZZj8ny-8Vcp-C}VbUTSz@OP79aL^s*0=FBC z6oa>$lm%Cs6obQtkeCJcx)Uh|Uot5RHoePS;8c^cV1v8O1%7E#7VKJVF7Qv2vfxek zmrINm;rE*h{KKReob!OWz|$W@ioq%mA!WhA zCdFX0VderKHYo=C4mTIL(WDsUg$uHmf~60W7=ye6#qDd=z>WWDvk(6C98wHkISMHQ@@5F>6y!A!$+{wF zG@8^1~j@av2)3)XuBDF%NtDGOdX(Oh7c zNl00+;agsEqk!9~CTBSCF_U6&<766(!1Jc2jlq3YlUV}ae4ETHSZ5ki1m0^>4Cda& zl?4}?6oX$*Hy3!$45S!rJrgMlPBbY7Uz}ww@Ywf|V(>YWvS5wb<^qSClm+*A-(28b zCS}2`=a>r|WKtH~?gMjy(@e^O2h24WSaTjy7QD-(80_|;xxlF=#o+TFnG38wA1MYa ze~gp`&o?OsdwyaraJoq`IO$V!fh`vx#bCY9kh0)$CdFV^l`2-q)qsaDv`nzdBBU5x zZ&DUK?@M!mr!7Xxf}fZagCk4L1y){y6oZw%Ldt>{nG}PWugwK6F)0Qoeq%1M?oy-} z-2YpoEO?|z5xCoTxMGku;kaWAJbv3s$t4>3NDeMEDGM$)DFS(gjwFIzYx%ZZ`|wcH zuB;7DR87u3V9lM_QjRw*uxNB>3 zfmf^K8iRSqfiwnQ+J?*+(R0FS+*NM^%##-Qf9mlNp1Q*>;)m^r6@yuwazVAB^;8~m+mVgpCKNC#PP=Mtns@KBSo;7KM$AVt5Wd2offVvv&GGM8ZP zC3=iO3Vw?V{PbmWfm6mIWx=0Jib0BfOIzUJS4oUPN_~q9qzboN)bK}dSSCmjZpj3% zwR+q!NC|Fnf%m;>ZGjZv78lrbvbjLYZ;K1;tre`@SmC=>lLG-rfol0cU6Lc9+Ovqu zas-q*b`8R*J;Nw;sGy_r&R9xUBs|=a}DF!MoaLIO+ z`AP{=3RGO+U)!4tq!6gM!2PS63#1IFxWLFNf@VO9fQk#e*6M*~KuUm$3w*w&^$1b` zR9xUPs|A_?DgP-ha8IiQngJ>PDK0R!I-nVl(x2i2M_3im3`pTmae-f24bTio*-vqS zjjRG_2BhexxWEBc|1$$p@>5*kY^(m60V((?F0g^s{>*@s`xF;gWR*WNAjLk#1%6?5 zKQkbuKE(w#v#OsNkgA{JqUPu4TKiLuU|@v?YyerXlSwg1eNbr&q!Oq*4#5Ktps@@% ztszntoMlo39(WM03|QRAORjx*hH7#+1b;o4%q&>>5Tpn^_fVu5Y;w4llG6jh(?@vG zbqZHKlH5XYr=yUv;FxAMG|kkov7|@xa%eKxPciY>AWwo3-|m%Y>h4gDnE9pP1U<8LG)= zEpW%SWM;twOp3snC*djtYn+Uf1@|;50(U}gU2?sW#PLa@lBEI8Pt2z>lZO9ZE#fN6@tCaH5WL*qzJt6JY0of!yZUk zu%$^6IJ76OLU7~xUUI{S_v(c$1D<;UQWkvCqzpK_x4FP?Oo~8iLd$_3JpCdPBan*F za(o3T{_MsI548f%F-YxaIiG<$UqbsaNabg7f#;bk0y}EaW*G%YiDyX!FEm#KQs7w< zL25a>;luN+u5$*Yl(V!Cw!MPkXFv)$iwk_NkGVj~IExFcewDdEia3i4>|phrGax0L z#Ra}>)toaR1)RkNesC>4Mj+*zWfK6Y)a;fHJi4FHOitqjOZ$7#8I5yv5m!`fP=u5P zTbLAsJqDNy>}^s6j=BL?47R$-OUcj(?!DQIZfJ0cYO*1KD+bYA7OZp&QVh1f6)6ke zYf=Q>avQD~JZ-R-lA#fd9pXhdGTJ zMPR+*v{eW;H7N_WH7No&m{bV9^>8|T_`*l5eeh{NcDGOd=QUor1%o4$M zCS}1&BXC9FT$2jHF^_wf+qd8zPmoy%-eFP}Z1tqMz$;D4f`d(pz*H-=>;;vjCedCo=|zukccGj3OvpnKlRa zRZWgj;J)9}Toydeq!?UjQWjieQUt!Xind~~+v;Fw1jnvPhX$XmnhXuB^CQh=!6QtH z!QV{Ef~WmNVgybzDFz?;IT#wjUB9G5gGZ|-Ljwn`qlYZ`m`O31`_)|FK$9Y{-+Ejz zIBf1Ap z7`)S@EI8Dp2yC>2C4zmb2SX#+W5;x8a5L3pXyAJ$Wx;Puib38WB3lCQ58=%pZr01b z@xy85U-^;Yl^?(Ai$RBc!9m^BLXLAQTb%gAoxQ? z*FIb$Eh`T;HYp3XRLNz+XP7MlsX;Hx0~{TcqlYJ@<>*0b&?n<1C6M^SP>>#Ooff1AsX;Hjf{TN4^zgd096d-4`lMHa zXS7DW8!efdfHRz>Ru*>)9x`D4yP1X%a4f>>4f_gzgdidzHAU#MGdg&E>Cn!h{ ze~}iX2dP3YUm?K$TBF|0DSW@xt&hMHe`F)cf`vb&a|&Oon#?J<%%m*1KFEZ(T}uZM z_`6A2F!yuXCw!l3(kEE|7aGfgja72<3AZ*|1U6r1ncyUqTqZo9}63E!uhTc3*c|Dv%h*jObuTDY~@BCz>J%LFH> z_L9qlJF4c^r(&r|S#V8|X!tw>Db@ zHs8iF!AUB)OnAQ8A~3FIncyWVxlDL~*&^`rZ7tJqJ1@D+t(5oFsmv!h+N3NvEy#qI zm@NV~Zf|{pOa77e32#tM`UIb{n(T#O=P1pDFH%i1!2u?<1JCL0Gn3O4!Bw}W&A~%e zljcC`49m#|JaTZF3Aa*BGQoz!f?f%FtLPRvoKsD5!6(C9f^k7EJSEKq#|;nqC20I` zI%c?qYSJ(Gj!MarBKRc8g}+X7!TFB_{Srivrv1XPYSJ(GjY>(s1nYuaxYA?3J;??C z4|V4qB~`WbZBUFDKmjoe0_K2<>538aRZn*_Tt{Yl%vsD4dH^G4#e|}QVn9q|#)P1P zV}dc`HDShp;uUoi!&kLWJ+=3`i^ZBd?^^Hs-G4k!{rpw!b9#oZIoLKU{@107cQD6x!@MJ=eaTm7`)FU&4izHTLx}=hi8I2 znxvUzvUrzVBp3WA@KTzHAQ7$O5#nUG5%m*74V!?hYu zwxf&-7Vq}lrV7EKCTcExnrV^?-r-UKWVvuTm8J^8f4+`(ZA;eC4wuWK+G8fhml?j_ zv|uE7#zgr$9%SY1@WXvPufx*YA(x=e{-@-EEW@q2ti%2Kv+-Quk4=-84_xgzf9Ypc z2wpc)K9&Q2FiD4iyF8!gN;#0#q2-KcRS0&N8czitVw&WF&zmH<%@u;Tl3e&(&m9P| zjC2^6V7nLMxNx0mGVW!D_a-*@xo895aB1LQhAT8Oz~Bz>1*XZr_!|r#aoeV2;FsN& zfh=b&i)_!e|GUhK46x}Kcr(-F3c!nA&TZk9Blz}}mr;cLm?XIqD+CS6+Sc&Q zm8!c%W*_?xV^)QLg`UH!{O>C~hmx%4Jj>GMw~y7FyMMyj3;_GMG;mi# zmUIq75G?g+d}(0Tc@9Q`{SqV0+RwpAa7|)_-#1N+6DtI)60NTd%p%dDA_1#Jw{24b zStVL?;rXBOD%60ReIBn4W-V#?n-^q-XsrgbK(xF)fGiI!nIOwUhYKTk<*PU<{GMr2 z4*c3A$!(|*uo|?U3e0lQVr;4qBnv^$@`a#T)LFA(mT;ErSrr0SXI3N3^31_Vz-r8D zgjtPQjLj7S)?rp73o)~Za;QkaO2le}S(P|c{P$&vgZSiM`D@x}#~`lIW|8pG!Gabh zW~pEu24fc;J%mV#VMEEe`zQGPzC1T)^VM&AvD=OZ}=5 zX06}wViB;~uNq<2_68 z@Jp8lg1@_zf&DrsC-;N}$x_123tCFJxx!My)4MQk31ns9@EQ=XPN;|t6#`Zq(^rrs z$5^gNHTXAQx~Ks5ywOj)sY3AbO}VJKFbfvRz)ckbRvuC#%)&$AWhI#7s}+?%79)~h zLGY+sc@Z*jh)X5bC1T|v9TeVloM(c&x>UomL|6Kb6hL~^zhD+KS~5w9P9A}&_c zTp?hAqL59%azT22@Fw?gel;Kq1?#jS7T&iJ_qMnb$`tb3l$pT4@vOrQ-;-^fPLBL-gjp;C} z8i@_;v|RqcoW4x(d8WyY2zc)DJXco>Ug%N={?Gwe9XNKySRa1cG^r1=ScjY$xNj#f z20q|YEjY=g4BWo6CxX*W(yN4*?cz4D>{2Z_!lgR!8<%RqT~?x21|IBE9r(?vxl7Li z?ig190a-#s{vk9}2wrzz4ag!Q@|uC$t+E|4`u!TTb-K9= z?Bh}`xUEYW_@qlU;3GT5mjj;d+R0tv6>N19xdM<+Zw|9`^)%wAE{tah|7e~q}xW`9{k>KE2 z(FnixMPejaXLdBgz2_uGf*rn#MtIVXiIL#5dC>^p@oQovSZ01S!vFdsF%m5EXD;$@ zkeJ8o;rfl4qFM(wZGuz_e&tdf z$b+nM%3#0VBxWFww#pwdAkVReQzO`L3sURAv-%*_g7aLe18cX;U3yLM5vIvsrr_5u z)q#6&9W&v(O_S3FdBj$(6I^>+&a4LH5nFMA`?xCudBj$FD9H1)dj9Znf1`dK$OE-f zALLQl@H!IktgM!UkJy278OX!3A(w#1U^N%!nYdsi;CV4M!aOAvj0AU_#mIFa4^GL2 zfD;Gf%0M2alAi;}6H#FR0v>?UGl5_5=cDStpN2C+Ex6p-NOd3&PRXf(``Uw5@|y(m zD3zQV$P-cF)ChP0N>2?Q=g&vgfnQz7dDMc7T!d5y^5B%58u$-;uu4u12J8Fs-pf!abe{-s(~LYK#?yyiGfhq(-0dNX)q*#G-yPIsvme8Z&-y#G;81h0B5m-Lqh{@OG-eem>&WY&VyU8)0*c-&p!GcIM|s3&mM zfxVwZss*=nDFfGk3RfN2>*-w5(}ydj$?1dLCy`kTp6OB@xc)Ql0=IH0123G6s}9_D z3Q{e&gG(8>_p`X_z`EyhNlzbs)HFGL@Z{&otOZ|ksSdnqs=L6kE@j}-FW{;J-*BlG zoas^q{@&<`;JPp6lAb<1)HFGLu>Z?s)`EAtR0m%2io3w;UCO{!r{k&ve|M=C>^}on z2CmbDR0kgOS}y77!_S%~rw`u$I+?ZL;%^|;fq%JF3oi2}t_-~6Eu=bd%-cw{;B78t zVDme;>cIZ*=8~R1e79+G`e4I9$*cvJcn_%#?D{@ZEqH=U8F`tSgMBC-yg=Ta@W?AHug2lA+-{8a+p>8=dq;Ym3QkY^ynUnK-Q@~Ec< zzwJ*%)`6FN$9dF(x4Tpa@~EVo8hG6IBxWEFPs*u*JOdd{jetiU_0-@`{E5gqu;E8W zs0CkisSe~(NjWv}u6ZP8AP-Nqff;=fHrv~!uV>mT})shDV;Z6NP!GSyz*yvIQ_F9GC zqJiKDlVpVE3c&;u_2S{Fo|}O;te%$(xdiu{C>I7UvWEL6RtQ@1$YRZ7@xcN3DAS}q z__RyK*@izRnQ)tlJSC8U{aq@4Z&>?y91}j;G#L||D6v$%NZKTM8Ywf6+@Ho>X6a2-cV$W%L=B9SkOt`OUk_levQgM?P^31Vz)J*tZ(}N;KgbQxVz}sCa z?(%Y8G%H4}c*G#L}zXu6NN zzu|Fq)J*tXw`JfbE)}nxkr&xMc}x&4#>WJ~Q(Y=9VNVRcm^|zU&-7;kGw=tOier{* z8wS05@BFA|3qNC;TqpQ}OGO@d>Azphgby}NGQpdU%55??=^?{;cGNN9Wsk;|ZDzQ$ z9n}W!7j57;mx?^dkv zY9@S;X)-4Gyi3Kl$LASc?5LUWMy5$7c(F^xeNV_UKeD4{!t+g&Ot5@nZkIQJ(S{9n z)J*sVw`E|@lRR^_;h87rl4io!m?mR_%`O%DoRVkkWk=0~4>C<(A;V`}DxQ66p1I;_ zaZGp<(GY>Z$Y)8$6 zN4hNo=eksU=&Za*zrp!YGvNbGlQF^PTq?F1l4o?bqh`VznkJdxMJ^ThspOd-+EFv% z-%OKCu(m$8%PVw);r({hOn92xGO))`&-~KxjA6N?nef%7$(Z0TE)};Jo@eZ7N6mx} zG)-S2!$~d`ho7Biu5eBq6W-V~$po)-sW{#6(in9&>NHXD$7jkMD zcAJmS*4$j5fnO!zy~WK3}9 z%Y4j1hG*JQGvV{ymVy6tsW|-dyvTezY9_qo6%3GpH7*q|H@v})nhD?OwhWx_Qt{R+ z^SY~z%#WH0uVF+Vb_zBY~tA8wkA2|nRcagJegk_j(%9Rp-wwM)fj!;W{vG2vBBlQF?< zTq@2pd}@5mgr}J%nc%lB6|cBE&uHn>aUK1^wF5w&l9L<$$rXYHJ(2d-Tk-7R&rOrR z!xnox|KB`8qrX}_Ky%htF%`bhG@V{<_;h0935hv>#?*hG?XN>H*?&P3@0tCsJ|@36 z*gSL9m~+ldan;}}S6U?eDJ!Q3)^tTGg2P-YfxE5jE^werC2+G<+y(CLQVCpRRd<1# zyHoN*L z?B*`8eRrfHxRy&LaOJh#1#aw83GCIwUEp3WmB79|-31n1DuDxfxeGkTr4o4jI_?6` zb*Thiy{@~!yId-PPps!IaE41I@T2wJ1unV)QVCpcL!=_Owo4^&hmG6?_IIfSp0KgI z!1G)xf%k6WF7R2GO5it}x(jU68>s}YyBSgu+|i{HShKmiz!P06fwynrF7OGLO5k^W z+yySWB~l68WhWaU3H)vwcY!Nxi&O%6szv@v1Q+yx3;S&A`y9`s zu&JhM%wT7;%;2-x>}--LLo8~O)S0xdHkc{u(yo|?zMy?Ad-Y4LkJ4z<_t4qbeIQb@HRQ zz`IS-Vjr!W|L}*~*I@wsnpJ zwn56kJ-5vzEw|v*&LfN1vhPbd?pNg!_`rZ%(lKZ3pY!{6 zlrh0CtH~_>en5_^*C1u!jwjMf$JPkVhLnVS#g04(FL-nthm5UPVibFPmYL-2S$!R*A3(*C#?X0-KW6t!m2ibO3T;Qs{18oU>%%vju zic2MsooJ;Nc=2E#5o9M?ae-S7aTmzmwBiE)6zz1$}7s#Vg;sU#laTmzLQsM$n9P2KS z%~Hh$zJ80lKsHMi7r6O2cY$n{DlYJ5-#4`cvRSIQz(wxxS|FRHiVHmUPIrN9mMSiA z#&~yuY@aGFaF+@00@*%QTp-VZ>Ccu2xbAy0&s2>)IoWkndL77PTxz@I**t~ExWopo z&={-1e|PQVu0`Vm?I11JXcY*9QDK3z0CAB`=LXKJ5GeP!(luR~!oVAR*Kz4Z)7s!^5TAwW$ zFYD-;;KM5*71?a@uN9FpkR2AKKFD^8TA%F@mtEO2LH0nDOg1{aZ&i1J>~1J7kgW{0 zK3fqk-_0{Yo|=+Oo|)p2D9!x$E&t>P%)?Rjeez;zgCBA2{>Mu%Ks<7W8xx z&kgZpkcG9zMW2hU_#a1F)SO z8^%d7@UXwfVq^Es`CdDU4V=0k^^0uo#`bOE0{1S(Vr;+mTosua$S!PhW^A>_W@=Il zoN_=c#%5?o)p{|IJ<+5X8=tYYnG^$GI5-w#YqEO|^I{-7lu5CJj?Dir8;waZkcX!9 z=fpl?>;xt@kmsnvFTx3VwU6y6HjwSLWK58~v^0~wu-NTNGTG88<(>($sgh)}bJBxXxC`9&N~9vlc1c>F?T!|^3R?!U>ygxFYa=!*^y%4z;Uq{+vM!xJLhB|yX8o+M?cRqm>Vv|z?MugoR&-!glGDE z!VLV@r2<%t8zoGx5On-5bV*rNNS5a_Ue}ItX5bbsRe{W;3E!;{Ota}VS`L2G7wOKx z&z8%-_>lXW`Gz|!AHNHMt4z}$p5a+`45JcUlH|hI$6Rn&hkS^TOYoD4ddBb)9XY)W zyx63WOK_8knhW0_bHV#pNX8}De8qUZ@Ls0L^@5+96vid^CCP=C>g4APcI=#tOK^>e zdd~1YrpdTq-!4fmL4Ol97e3rH$pw#EDaj?6W1{B5?YjCogV&f8u9x5*6Ezo}6m!8T zD<|U;?7B)WYA#%3nw&E@$D}YWLAzCBF5Ja5$pu$lEg6^KCKGjB_+ir|7uk})u)c|UD)3gONiNu{TarsK+C-G|2^bUOUMpc+5o2g1-el1p%~iJA)^Z<^$S<(^3{ z!5b!OF8sM^k_#T&E6F9OH&Jupi%pYU@T_%`T!QaS)Lgjjy17wu!ShTCzv2YfnW(w& zZ7~H6-VV4AsrQ*W>P3eF!F|YvG8rCNjdOomkJ;gIYK#tmd?#!?nOu@SkOd_kKT;u z2Y+vxT-#rU%iG+H@T+Is&5mIVf(6akSp3U42He>+83WuYvB8;XVGM%*t7#leDF`P+ zP(CRC2321fc$-smEf@(F^d;(LXT@arD%0e*1H5%uQjehB@R$pKbarAS=zDH7!o$x` zj09(25RLHlmn24l2QQ6Ac&DopBf&{mMdLM<2+-gTY78 z-j^IKflSy4J_4p>=+6jdPDU^iur{C?VZO8vMgrF0QzOh;dcjD*cdTlJ`KmJ*3HZ`e zjWA!l1S0_}yQvXoVYgr;NI%ktS=lWZ3HXFwE5iFuB;>&7|NXSpFU#7i7Jl;3If3`ao6;3O<6PeMO-X$SOj?M{w+YJ}$^QLcvGS z6n!8o2?Za)t@nF9@NW&d6nq4kiSqLWSzsvm2-bMO>wzpW6nq3zqYq@+q2MF<#@8S! zfh;@}d;|j@@^L|y9tu8!U40#*68N)8!AH>k5w8cbB2n-W{1km4YZ3(?!L&!c9>_XH z!AH=}mm?~HtW*?y1eZh~$XZ3gM{vR8J}$VEEnF0Q1OrTzpD)M~M!`q0|C3%1WD%p_ zBiP9oIVyoHY!rM1*ZC?(C6J|!f{$RUNj@&f;zs$nw!%@tj&dE~X13B%@Dc28qWD18 zJPJO7gQobnAgdk)AHl)CDpCn#C8XdZX!2!|N+4??1s}l(Ul^$bvKmtG5j^2bBbC61 zrsby`d<2aq%JqUQk`#OdzrEns3$jd7@DZ%|qWeIWP6|GP>tAvo$l^)CM{ty{q*MY~ zJ}LMJ9(u*=fzQ91OTkC*u8DHJAgd|`AHkY4ydKE9O2J34eUtk@)>;Zag7;r@AING; z!AJ1Cuf|jYS#K%$2zvSAOC@l>x0356IMhVBUXW#&LOp_Mz9v%%WFe;DBUpZ>UkAwI zOuuaqM3<^S zKE4enLQpEia`0iMNjdOLmkJ;s--dDo8=fD_!TXpd<-lWHDu8@^8_E&vm^^_A7vmF{ z;4v;0Kt8?=wEJ7~5lt3Lj>gQ)dDbHN_ zwRj?MZ`0bg=|9l$^4Fsce$g};0DQ%5CvQXJZ^{jYu zaKSV=6Y%K72D8Ck_-%d046l3cKz6%hTR45`V77$|zc~c#?50LGbYsUh)!3@7>*u^u z)$G*vfk|qE=bIK@J%YWzh}R3Vk6XA90(NrKifrM=Mrx{U@J(Lmx^H7anElk`1q9hm zO;h3i-*Fu^;KkqPQaERV(R1AgvJqSG5wH=PjsYL|FV6+pn=RxLus56L!ef3Uw-#jU zwvhYpd$(yWTeqG5i|2w{H|J8wB{<(i`G)`={Hv#ey?#ql3D^-%US+VQ-zY9<7r6Bn ziQk;SdzmJU9K6b;a22O5n&+HjM|rOSyS2;zm!yKnn-o$BhPW>S=eSe`*_KWQ0NGtm zUv>C3-+ZnXTyE+7Ji?#^e=|{DI&ehlBX}_Sz&Y)cdIUUZFZIq_Cjb9zYNw|Mzqc%} zNtP{_V}l*T?~XCs+{y0*$R>AcgRfYgYBeDH-i3=LXz3IG>@ufg>}>nU@#Md1Fi+FU zAWgn^+~Q~EC!%hvGwLNGP@K)!4ZK7zgd z8`Uz%m#x7^@OJcpeAya&1c&)IuVs)gTZ50_r|1LuvNiY!&hu|x%OGF21|LBi|K_y} z^2mJf5%6uRzNRo=wu(`9m0CUj29IxB)d=$ldoU94ZL1n#zHALf0={ikBg~hr!AQWj zt!jk%vNae9*q=;|@RR5I_oQIA^N|LE$B&5LQ^K=NlObkT2-vPn-YLN^E{VDDI+x~} z{EL{a|716_cvm~hzlg&O*_upGdef148V|{-2J;|TxMBjnUsfZ`*UMs@TOr{4Wi`Tl zy&Q}L?>6M8Ab%i$T^`IO@ikNkHZxItARCYcAHh=(c|CB-!%01YX(q~hA;@EHG6cxi z+IkuAvoAA34ahTS;Y;@Km1Q*TldLTQ51s}n`q7P(`u;3%8 zf6eQG>=Ksy?Eg1KAILso`T4z`*ZJ0t@`{4P-tZy7U;mj)`ijEYdu{{kO$s9rEb%_R z3}j0!EeG@6zT`Gl7WU=->Fe-GaRyFZHq7P)+K=2Wq z?sEvrAkzkdkD!~+4Jd<58wfsv7orbj+CcCT4DmSxWsqqD!AG#M&kZPpOdAM3f={9k zWZFRR5sdXY1Z9wE1Hngdu+JeVgG?I;K7ti}Za^7i+CcCTyc2yO(*}Z%;1-`lPzISc z5PSs3`5b~W$h3jrBiO~~5R^ft4Fn&->OME13^HvX_y~TCK9Fex!ACID=Ma=ZrVRui z!4tmmQ5j^~K=2XV>~jdpAkzkdk6?(;At-}P8wfsvBYh4*8D!c(@DU8~IRs^pX#>GW zQ1UqhWsqqD!AG!<&moY{uk$xFrVRui!Ja;cpbRE+2pTE``}rJ#GRU-nP>-P6=Ma=Z zrVRuiL7mSbD1%HJ2tI;Sd=5bwWZFRR5uERH2+APS27-^^2A@Mv2AMVxd;}AH4nY}Y z+CcCT{L|+UltHEq1Rp{33;7R0{v-mKHV}LSJ$(*A8D!c(@Dc3ia|p^H(*}Z%V6e|2 zD1%HJ2tI-bd=5bwWZFRR5q#rw2+APS27-^Elg}Y2gG?I;K7!2W5R^ft4Fn&-NS{Mc z2AMVxd<1X%9D*{)w1MCw=;3n+${^DQf{)-dpF>avnKlr71kd{%f-=aof#4(P=5q+j zAkzkdk6^IRAt-}P8wfsvcYF>(8D!c(@DXg}a|p^H(*}Z%-~yjRPzISc5PSq5`W%8X z$h3jrBRJ3J5R^ft4Fn&-l|F|c1DQ4;|71Wmn9)DO;7gZWEPRJ9<(eu4Gdt#@8sUvQ zxv`-_@PLVGgr77`{{9Bvaj6EJ-#ITQHN+2gCG|**C!(*Q$n4RRpD>PDXa94Os)8wZQUi~7rO~=4Zrpd5i zrW#Hu|h07xNEt$yxuV8Z(;8ThN5(~Fc*P&2$~DuZ8phmtPrFV72pA%Q?C|0)1;6~z>Ed?bpe^L zpyR^KR}dSR&QgGxtspk=pI>kyHDEfI0iOE}wpx%W4bl@prZniO!JmCgW(izk4$?p- zJaqdZmoyXZY1&e4hP2tdM}3>_Yj;K3B>u0V_P>y}O)9~eY4Yz7WOjoN2s67O{NxFk z*PuqGHGDIV3&_ClTq=PBf5J5oWHy2pgWrfV7$#Px%+GU}t`JV;-xsnEA}iT1Xu`rK z_GP~g0}t^D05u?U1LP+N@^!st@_qfM_PxFQ*6?*b-_ffLKFq$Omlql2D}2cW`PyDH z;Xh+0-{A8Nz1sHZn146xWKj6^$|g~0uUGYL3Dv^1t2c)nDxCD$W{R2 z0=L@0T_9TlhztC5LwA8}1t2bP?ndqc*$O~hU^idyzXoJ00C9moM;FLe0OA5~?Cm3h zYy}`Lua2KDvR0f%^q^U3ymgJ1V!+q{j4ajsQae>TM(qiz}xA2N&Ad{Kox*974 zapuydW8kWB-L>I`88R7zq-Mkj~q)TP+6PId1 zcHEF!;Nb3F3yhm@l)*XC1u~CGYJo%7_F5qOa)=9D!nWv;pB%`p9pVB9xhn&|aH$q# z;*`G9F!QFuI~@TNr_>0y^CkXkK=ufb69F%cE|5I}#09SG8v)dS>=7U?uozt+lefeL zGIvYQ6`pxAFKrFTz5$X6ZgPsdK=us~7ud#^{jUMpH$YtAHPHpKZ-BVKjeObv8jyVh z#08!kT_F1ghzl(H<^VMy`v!;$d_KBB_6-mhc$;qyPy@1WfVjXtd~<*rkbMKh1vW<) z$i4yM0{8RH0ct?@4Gima_6-mhI3c<~_6-mhIMcTfr~%nGKwRLuzBxb*$i4yM0#6_A*9fw2fVjZT z&vqBcz5(I_m+;L2YC!f45EpoMbb-v96c@;}N&Pnp-){3I<&9@ng`i;57u5)#Ynrq( z@Rcj_E0EmT6@ngD<)Y@oy-kx`@Y<`n`hg&mAvF{3eG9f4knIEH!oWedx(j6c0C9mc z#<>e*`v7r)Pu=D&knID+12xiizyl71=ox#~uVFu^3K7%s@ znY1b6g3O-Oabea63gZ&2GdsTwHNqR3CO<5&`&YRwV21l z$cW(2o!tc<-36%(uCWqQ4LHH2GFa~FE|AR|WJK`JmE8r#eH_Z*U#qwaWQzx>1@66? zyTI>VDuYk2?kX{?cfAt*(X7;bV70s;>F#T7JFtdMyk$~yHYJ}NyAiTK|FeO-xFtdNf*ia!D zc08w@f$yAvR0A>}Sj)jo2M*&BFn1=LH38FDG#lP=X`e?jw?Z(uLoTWje#A7na{-y{ zB0mst;>s}-?zM^!(Oe-Yny5p-CzvK3103N}37qUwEjZPs8t^TbO5hEv`*}>P5X@X7 z7v-|RIWA=&vtz`SPbi81egDCnUwa}y>IK1{nkE+n{^C*rOeV+7t|vI`>sSsRVw#i# z$GB7glgTl&>j^sj9LvEQm?q`Gel8V2=EKNu((HPIfqTSn!{C!llX76aOI0BAVL~~A ztQ5<^2b(74z(FomflQJKnK={65!78C%fTm_Cgs5UTq=P~ zrwQc<7P&Q+gFBff<-m(-|@$d0}&87WBP4-}dP*_rHJHryAe&E$G|1 zmOjJEcT!pp=5yX~(gb|at48?LL;M5C+4Teq`h=Iy#xxn`qp>gw0iTVj5#}?lU?ku} zE;YjJs~U_1d`6>2n2%_Jk$}%=)ClwWNH7xc0f`!6ZqkC0fZHH7!raaTBLR08YJ`(J zjoI}CJRhb;n461Gk%0RKHNxCB1S0|W4Qhlp{MK(6X4eyNlb}YJKQ2N=0{&o7BY!c_ z|5bx&{~?)x{;x)u_8*J{^nW$N>mHi7?qDRK|Em$E{Rblfon4JElW>EPfF`a+_^0;X z{oZGOW1U2j1lX764OGS{L z70MB8^GhrTXQoLx@F&G%fUlUlXBoyE)_s}RwzgCud%Tl-0qfK zlXBqdE)_s}Rwzf%iUu}p=zmKCy3Pu8&mKtGtRxlFKi_{3yih_}VUZh5tRuqf` z^ddFFw4z`npcknT-tYV5=NI)-ABTOp_Mgn?~8ev*dFcQ#<)Ck}5ujJ(+pcknT<^$(Yk)RcQX+%r= z(ujrjrKM~9erd!|0(z02H%u!E=S@H_QX|Ymn!!jwFH$4?^77u7MhqorQD3qyqs87c zp5sj@1Ald?3QYRaT>rpt!WXfTz*9_^*NG^4*f8clKudy6_g=ta_yvwBm zNGl5E2!8Gt-&^5jcg-~^2ljHQ0Md#=If8)$VmbIY)1(|Y+@%8Otw=AH;L)M69Q=-H zQV#sor7DnC6wZ#|!jZ8YJk~TR2R`gl0i+d$as;p69LvF- zZvB7D{Ss4L!xa3PGn zqHuu(^ddFFw4z`npcknTrWFMv0li3#Fs&#U3Ft*?glR>=NI)-ABTOp_Mgn?~8sTMr zPF@}YdXXAozIqK630l#Y=GM3Heray~!tR$g-QWAt+lXBo3mkJ;~E0iN>MFVU8uW4XB6%wwPfTpGYY~ihr@dnmh zPtb}6*4)wt*1XULR@&I#p_}UoXj*#SFg+_=AOTHFjW9hc7zt=vYJ}-o!AL;UQX@>y z3Pu8&mKtGtRxlFKwA2XGvx1R;rlm%h&F+GcfTpEJnAu9fNYIJ~*4)wt*1XULHl)9I zk>+{=nwFk7OwS7EO+eF9Bg|?)!AL;UQX{~1G%Yp4^sG>kphXSLI+GUr-1ryo zRvEbHWExl%m^84N-oQ5bEOs1tH`C;84m`@GBA7I=ncl!2pC8M?O{PgX@GF-JVA8;5 zdINiO=lCWJziOJ41HW*o0MfJM^_^KyP`7_92cKw~lmpLmsQ}WmLOFufDzO~g*EA^y z?&(q$NY4u82qs(|%fVAjlXBo&E)_s}RwzgC;Ek~y{Jd#W4*bBS0!Ysay3Pu99YgHqB>&MBFn;K!((+frd zx|$JJQmCvdtpu6dL!!);Wfdq6nHNrHvU?iZssS&2R1tS67O^qU2|LFZtfM?XxtF3|!WwDlqAEBfQf+{BbM?zigVkAA;YxR0NYwH^MvJuhzo!QsEAN z`q_c&xl{m?PB+3k-Dx|v4Y^tlzSJ~1JMa#d3SiRdMtG+?0i?Of zk86Z~t9JHTu^c?kG${w(?@|>=a|`7NrdbQqi-kY%ww8fExKsdXZlN5(x!1?DgGZVs zX9sS6XKs_mxwql9cGMGrC%7#GUpFa?O7LZp3(t$W;HTsBQ9~}liFd^_hR-og&KO)} zLXu0ciHUm7@J^;lE?B%f$t7q-6Cd#(H}S1M%tw~j8Qk3@J?8<&hb0<(s%hcHB6#Ji z_+r8DnI>a^|5pztu%uErX9E6S&#1o!*yIVF${bApecukVUe0@*Mp_y``0K9CJ_f{&oL?}}3blihPh)DzqtePFVC z&WL(~alU&_31rKhFfPHEH~e)02fvy8JP6i#%Y7h!>4tg)+s({<`ily)FHbNM@Hep< z;f^2rAYhM=l9M6$mx=Pr0UkUn@evF$QG6huFNJd4->@)uKP{mBiPwQ@qs)M6~-ml_glXXu=kv#9>MP>NbneiUR zB{<6F#ETC+W^PiC;8GLC2cGvs;v*PiqWC~&G=^~rp0hcR;sYoBnA9VIt}=)eDBXn+@kp!0oIW zVK#xuFK|j;p4(Y9!VNzrLlba2t45f+*-(+7CAYS}+C8flgWEsnH;>?&E)~G!)^?QN z+MYQpPt|hp6{gAW0r-$h1u(g_9p$&So&JjD;0;WZa$rA~3Se?;JIZfu*H}IN{SNmr zP0E2Kmx^G|HT)iCR6W7ZYsPZ$l56FflmolDR0PLun3N;fX8TwU&P8cefXR*bD8KRk=JZ$&UgnHklX75Jm#RSSwdHqnR6Ri}?*B&p z$M=8#S2tp;-y5!&fSWJhKnKKv3E7X zOo9zY0v>x;BfRb3lA#H>yHq30&1I-az}=-9VQwyik>G%n^I_Bob8{Jt1l(P!5$5JH z7zwz$R3pp>)4@p4iZ(f_rEPN5Lfd4A-Mv?hswbc|>UqO-#&F&Qv_>_;-ED8SU?iY5 zsu4c#=VWLCTB90aI%B9v(4sbJ{ZEViYTW+$ygA9cAGnfBRbbL4hk2Xa=A+ox;LJ3A zt2aE^r6QQL$zk3mw`mjKo8infEoXR?O9e1#lf%4C&RI2Q|y;B_14Lxfy{ zH8zRk!hKAWalsc&3b_QICb{r$F&FIAI~kW?n?7+|I5SOuj)pZZRe{N00K@z*fKv{Q z<>2#8lXBnjd>QM(7n>&a!2gXuG7jD~wo&+ieZAift0#DDzi5OPKQl2B zEa;DnA^r!2EOui&(vI>22JdvK3T$wxKX}%NWK@FbkHyo2&z_iT@{)pEJ)Yze^fOV; z1U%sB#78j9M5zZ(o|O0qJ~mN&;L1}I9|3>g=-U@ucsVypE_jzo;n#{_O7wv@ypoJT zu;r^>54_BzP>`M4I`{Js0YIVR;k3znGcKJZtQf{){*u%q z*uUB9fej{wdIX35>OSyIlY)=nyXXVk%}>T9m}sJ02iW)b#7FRhiQ)r~`y=rYTwtR3 zz`OoTd<19wm5bs7XPXqRgW$$C`Q3;3z#eULDfkGsH&J}xv5O==g0&X)df?M0g?a=h zwsRl2*kVaNf;CN)alz`v6Cc64OL#r7!K5%Q!J$jK59F>g_y{K2eW#2I9=dcgE&;cn z`kn}L_ZbQjaQmr7n7hwlB;fW_jqn~jCPNc&`>95lyU$ROVAkGwwi@BL_Dd=fJTM>{ z;iHdAj0D`!YDJj)*)TK#H?(SmSqeTF2|l?l4h`>jeXdCp2f6RndN8-Wp&kMEy=sKH z?F~kPR@?&*Yw11kFuw=pc2-XZ=598e4gt5bYJ}PLJQxYMomC@T|Eu5H4yz~Nc2DYJ};6;UyzzQA?Z_d)T7Jo$V;^bYM4^s=%Zr zPWF~K>HSy^e#{ZNEehJ*JN*rzy2+jgF9@OYf=te&!qxL7tG69 zOFXh1%fV-vCgs4(Tq=M`OPuU2v2bcE2cKk`lmqKsssibP;p_-n(Gn;B*R(`7ZVgvV zKpWJ5w(yJny$4OMC!h_g5vB`oq8K{dkMXa*wzZBUJH(h?`v6L15mMtG9lV9KvM_{2ZF z?@q2KpoMBKOa~2TLqH2vBTNSkMgm%>8euwUFcQ#0)d~YzJpnCLFA$#oNMa9Q}x{s*sVn*7>; zo4Zs1lXlwZ?ev`YVmbH*)1(~uv`YmrX{U|ePOn}xzK6qinnQ zEC-)wnv?^_xl{y`cG~Febk((EIe0VEq#U@LOGPkgr;XlDKioE!gMTtj$~jusZQG`* ztzptmrJS|X!|Gx=_;k~x9C(gPRbbLi8@-*jJ0+HbdzvQYz}_xZfpk#$-E91y%rR>G z|FWIZ8TDTyyyX7gmKy5`=!|NFX^i2eA!tRHY+PuUTzO=2Is|k^Jsp_F7*2?NfX=8!n8p~41aw9R3xAcsu5-n#b6|$4XP2Q3kD+rZBUIcT`(94TG0|4TiOyETiOyE7uphkzS$dC zV?6GEK^XU%6BOla|=zEwS%Pu^e1& znv?@ia;XR=EwRa4;>JBOWhUE*O4r1g&U^O$%*_H(ZmP4gqaYPY0$8hSMRS4XP35o9bXBpbe@KrV9om z0c}u?FkLVh321|Agz198NI)A@BTN?zMgrQP8sUS=-V&SY321|Agz18zA^~ksjW8P- z2O|M(P>nEMFc=AFgKC87g2718ik8^a(w5lN(w5k?(3W`ajo#^+>IrCrdV%o#hQvrf z8&o4qa|^EoK}$N_N-xIN1g~eByn%szT`GV{ryJ{?Zpn9JIe1Oeq#U@jO9e3LbYs2K zy}4L?dxgI-P0E4o7SC<6+$@-My0PBrx^#)<;Eha^a^T)B6~Uy_jrC5qRnJ%s-q$oK z2OjKF5llMWSnqT(d^ryJ{? z?&uR^Irw7Jq#SsiOI2Xf>Bjy~I^Ed+nojq9*;~uldIGwe{A*C%a5@BZH#Ne{1q((3x|~iSmUg&P?@NpXv_Un( zbiweF5wxf!z7%`dO2+HiQQqmmJ}y;(NlP5>EwS;PSPuTkG${uzGBdZeZBqo3mN?#9 z;;+{0^itstOXTm(QVv|tr2?3=#PQw|KkpRZ*5S6Dy&SlTOGPkgiQ~N`?$s-ngKJEa zvjb0csR$-5alE(0Gq;N6;44g%a^PJq6+pV6{Pd-qwZsz+j^*I9O_OrqwJsIFq$Q5` zmbm%}u^ha;X;Kc{%cUwXX^G?iCoOUO|CcS1M-h`q_+8g5ddIFlDo(?>9Mq(tO391ohQg%3R0-B&2VR~RN63_(I2-5?Dk$@(s zMwlKLj07}6HNy13U?iXksu3P_n76O-^#n9QHNy13P?3Nps7CmR!AV5|nxGnCdSIwX zKoe9WOb-l3f>t!d@hxqL<6GJg$1k)Y{xsa%*Z6t@nxI}Fyxge7NI(-*BYf*UiIIRN zs79C`7+x}hmNdj}FUJlBZ*H3Wdj@xRsQ@MovB4YSrEkY_@NK3^Iq(IS3SiO@8@wTQ zS~9*1!yA|;<-mR}6~Lq+Hh4pPe8pG}ZZb{Ef#11Q0F#E;;0>{~PAmr>ZJLw=>s=~> zNkeS#hFIP*mV-|8g~0+WW=;0>{9P%H=k zV49Qz|8S`aOd4Xt|D+){{MR(ZqxbUG(oj!88`OWcFkLYG;0RjL5*u3D5*rrU67P8< zId1~mpq@9JJS^2vPe2<~BTN?z7f3)GR3l6m3`PRlpc-MiU@#KU2Gt1D1%r`*HmF9J z$1sACfHtT`m@XKM1hhdl!UN9qme^2FKpRveOcx9l321|Agz198NYILw*wE6J*wE6J z*s#!+`1N_-z+`9(XoGrz@Y2^NMgrQP8sP~O5+ea^P>nEMFuY_0Eoq5syb^mDys2sO zP6ux1QWcoA#KsE2K5xZx@S&zjIq(9PieS2oz(-vwfJujKtPpfMI+laG znneh6iNhVk@DO?1>AxSQLLd*sKaY;Tz$R&8iMEz$6e`uPF z3m$Q4l1p%kiJA)!H%)TEL6;@D1fQCyx$sY>NiI12@+6nwDibvq9&4K9f|p;BT=>VB3x0M}GA_Y^H^*_|<4lur!FeWyaS0Y56LaAeO_N-(-PmMYf?+1= zKP~uD(^&~YCD_G8&4n}5Bp2NF zwj`Hef{B_7KW3Wbf?M34B?| zYto{?&L*j?r*WS|gLgG8{9+L-=<&j*ZSij{2(vJ_j0>_bxZ2>aEj5fm@W1i6V)wrJ z{gs{!eD?OaCObZVUqqO7LPA9X?m^WEa|;@b1l?B2Z`afa_ccv^ zmB4dX^}D*p3c;-=iVx(LHjF_qXtg|9eBdmTf{&ox>h1%%^9??N&DU}tIKiagBbXC? zV4rTubr4jWDCY-0nfeIciaxMk_oN=d028Gi*p&JRnxhZgZ|$TW!PO>8J@B2>NAPX* zfd}Jd~-lzQM7sgK}~=mQ7!OzIIlYNFHwe@%S^+xNIDg4|BMnxakd7Wfj zf+J0odf?rukKp&{19w8X!kn+<$iaEM7^T!PP|4`dtm;3L>!L$3$UGAZ~7_TR{T;AoSAkD!C?n=97=vU_gu z5gZ+T;7Xe$uM5EqCQ3cq^$6ZGQG6gD;)Z$ze2S|*8RkRW zU?f<5&wLa$!dsXogMgL2l9M6W%9ipGAIOS6VGM#p|DGp{5A3~9QjcH{6U7IfyKmwn z7;U2XKo$)O;}TS7J}$UfA*n~Or-@Pz99c|!1YJsA5B%PwFfPI3{oM!dSC!NwSkfOr zErEQf9_kVFv8Phy{6L;f4L*X`q7R(0e=;t?plUxq@Jo|IJ%VEna39D6K*2|_;z0L- ztJfss5(%-bC?%%(4#S5}aZ4u*C;nR+rQx*yun%KX8&sp&r4`2e}Vq z&Rg&iEOM~>z#fMr;}Se;qMRRCcWB}x_|!!4flMt3;}YC&lMloPesFkFk6_3Vetuxj zBNHFNb|y+akneB8xC9*r<;nUU0dH@b+;@RroSck7z*jYz3-e7)7=(bYYSakxO-(Qo zu=9@^;oeiY;tagxS)>xk{y>@uv&T;uf`AQp)CjYgO)wI$bB!8dc90210(Og0Bg_sh z!AQV%ENX<=+9VhW*vCYTFnfXoBLN$Ls1ar}jbJ2T=L|K%?2-|T1W*6!FDY!l!pkj06v_5RLH9 zT@xe0-m63-yjZuyNYILJ6&ovGZ<$xRcbhm0{LbH!Q3zPJExZ!P!hDe!exC?h@~z_9ug0$d;mu5w_aJa@ zm#X;!arHN2CcL3(k_qnTQZ?Td{(b5A*&KYJX_5)nyHw5Bf=6_Wneb_*NhWx;OVxY> zc*J^1rtxWZ)J(&xU8?5GzME{RZhg7o2TYSp@Ew<``Cf0s&ElBwmZnK2IBVbBChg)! z!!7oUneaZQN#;q0XD2rJ@@NA;b*XxAmKXlYj(Sn>&!))$;9dnzt@>2MVRqC^_)@oJ z;KwdipIXd|d}>F{gy)(jV}kukKITb=6+3Dse39ES@I#lX&+MNU`O=P>3C}Z4#sv4M z@-a^{9BxO=gfDYj27cmFb!9+a6!Z5jBZOVyXzL%_e=Q8VGC{IRJFtaYjSV#90gsG0CMw`Jfj zE>(}Tx#w+c%AIDy%bF&?L*PL!RbOs+Ly`&K>9!1=hNF{A_+GbV;Nm{Zq559K^^b^S!rPf9V}jSXR6W`7tt1ov&TScZ#!>kIZQE4e zWH{mII41m*X)-3*`54dK(NGpN4SiN$A^2doW#E%8RUdI|p3!Va&4fGoRty<!}p0KHKm* zJ8C9;pW8BUnbSOThT(yy=aOc^Lrjw~!H-<3UhRxLqqiM36W+r#eT59~aH;z6GxN+} z?5LUWif3_Z8F-pY)ejjq+EFv%kKC4leFsyly3LRrue76P!uOgcXA5?yc;-Ha2is9I z;WOQqf$z9feM5a-WP_pkQ8VG)O_MRf2`*KCY504R39mSeQ_H{;U8>$aH<+EK@Z zKQ>Lq1pA#$vFhQ5*V<7t;d|Ydf$h)n%;|=8=jM`T!h=ndF~JXAs$TKDJY!uuY9_pc zX_5)vT!k>?WmdX47X+AMk6RzJ=?IQ^9edmB=rE0 zSp{+{HF=>^4DNU<&(*VoA2Ch-mY-_)R$}|yctJAUJ7q{a66Th5Q$Q8oB| z)8uysWKxIxP{7S>&WE@_=6Q$<+|s6ehzn%qhq%DycI0GB;2t|6RfC_oR040`*H-prT>3{BZ2`if&o-ah!GR!h>CL6qX*XAbpuPz zIm0G1=A6BaSuub)=d4`3ie5}8=71Q$fRS(YbiHfl&N;68z0Y%>-}8O_E`QLU`fPP| zPj}BupP8zfar%uU={=A@K+ytrKMeCZ;9{dnfh~HP7I4eMp-O>I7?lGOXCW;D&(b&y z=@;<+US_qSCutG*!%L z_dv3gi!I=5u@>;YW6c)uIiqsG$8)9yEZ6j}(jt%~u+k#%%~%WgZXdH{uox=WOyP2) zN`dDbXIelK>Pd^hZ8hPZ^b5FEDHThByBn1Q9#&>rzz>be0m)Y+Edr+;PsJSYqH?HG z;QdDBfKOJK7O+w?Mo900;Ph%L=75WgDg`bz zDhC|ckBX(h(~Qaiml{#p{DhF&ifQqHS^^M8_FE^?bxWuR&aEF0r z3%H+AIpBPwN`c=Rl>?3%WVV1W8I=RJ8Ejg>Zbs#R_Zd|Re9ovGu>TOV1)OJ84%l|6 zX#qDeDhGVds8Zk;M&*EY!^{@&JEL;I?!!$BSY}iXxWcGXV5<>S%mE)ZsuZ~INYet= z8&wKC*QgvYJBo^>!0|@qfSZmsE#PfN<$&K9RSH~Z3>9<07mO+ezG+krc>P!^mIC)1 z2bBXh7*z^9&!`-5=y)oY0?#xm2RvqiX#tlSl>_cM(X@c&M&*E8PckiFccXH^4wFp_ zc(+kGVCyNS1>C@>91v$#xqbov%&)bO3oG8Ld^^zZ)M}m$9eDRSI+6vF1;DFydNcfa zl9rwWJLO~-iC5}@Z<{sXAVAz#ea-pn zg_n(QYbiYgR<6(c%2Iq=@hkN;3x!qUCwjN}iDrSghDty1{=~ae+63ar=^MZa6DLbi z!;ca_NuhwaMEaVzGj=vN#VimHM(GAliZ~&PF(Cei(Fm#I;M?X?m<8ej!W{9kKz#4S818lEK39|l;wk5i;pO(5y1q%9Kpfk|7`|)xrim61H#Bby z7qb55LY4*MH73Sz48!qDi~(`@^2YGbI>P+3vOrw2#29eY0W7o}@QwqaN`WsKl>>gJ zRP&g{tErXZ>2=vb7|Q`y8dVBh_h8ck;uR)+z5B56SDeD+!14P!U7f*%0^;f= z74hc6TT8TX$ok-DTFe6R!IFwV+^zh$;wn|H{!?NMhl zkg`BrkHi?>MR*U1F(8gY-WX0k-OR}+3&gKSjN!V2YmOKL;)Ual;b}8}SQsGBf%h0; zgXTsC_@0*1!1n5gLy)zv3I1#BqXS%fG{#D=P`LFNs4Q^h*g$z>Qzry`ww8W46t-If@aJ{36l1_UjVdMNyX7=92E0!xZ)~#};m=!XDaL?{j4CC^ zSaq!#19q(ols9%qeZco>DaL>&H&C;bY}I?72$co4y(l&Y-dH&?2Ap~^HFLm+FOO@2 zyIhG{7I@)Rv0C}8fUC8X27r%TP0i9y*9LgTbx>L0C)WqcANqqg1^k$nVhp(TY-*OC zeoKHjarv5se7A7Z`ZGV6LM|_jdAA&^UM})85csfBrNCE=$^j1<5qwkRWC4~Ll>^Q< zsucL4Q8{4gNV5f;XjBgPkx`|EpBMi8iI!3m*#CU13B=3C*ZjY6?%8#I?4kqishqS3 z9As1p&OPm4jcbB8RZeOGdwd(zWbquY@CGe?U%`)=TJ|G_-zC(*&6Z&;3+!W5$!7`& zE|0qgo~)d74fuDXN`6te`gd_na7X2&CUBBbC7XU9YFwqIKPd1V<)kLC)ejs%$=(Wk zY3XZ%D@-j5yw|9bzCQ*di?sAL!CxyUZ326)ur{YFJVQ%g6MU7aWr05!RWj?RV5H;E zq4YJuJ1Qq_0#7rll*&Wr6n^RnoU8ys%lMrLPJ8 zS~+PG*t1zsZ&p+?UEvv8`kLUYOf3ui!Kjj1&4ZDSE#j9&;2o8dHi4%ZRq~L+ml8F> zi%cyG+&yExU97NTmAFmtXyv3$;PXb6{GxF6mT^sRN9Cj@aFS6ao30vaT%~0+pNi*b zDK&wuT3K)RR@h6+Xg(EJm|7NiuTdoxt%H%bwDdK>Un(bU0uM1S#*#4#Pu9}c1Yc=t zS>Vq`mE5v=X!FoDLg{OQ`za@F0-rIeWTnCl){JX{cUDen0v~G=)MWL2r0~18aZPZu zcBo~6eT*upS9pe&zPI2@O)U%j(x{R%)(Uppt{t}t-b^{^EpVDqC36%$mZ%AS#niIE zuIq3BB_AsswQk%dxL!GF6Zoc4C2Or0YHX&ZKThy2%1KS&nMRfDyMCzotd_ne_zmTx zCa_z3>+Mj5Q?>Lp!DpCS7Wk1-B^PxFMmlW}N?#MalXB7~aHdfuPbhpPQ4{>3sbzut zY-qh*s&LXqahu@Nl#@1r?;BOJ!N#G+Hd^}Lg7;QVY634bs^pN4q2}yu<2J#MDkn98 z?;BNu$M2XO;+o((<)kKXmQf{m{BE^tTob&Ta#9m`lu;!l?HMsJt_hy5oYVwfXjBRL zdG;F-*90G@oYVwPG^&KmcmLf^5_8mF>|oU0bfq2y{9<)KztD3D&=Hz3HIYDgK{uoZv0F9~It(_px{3Ss*XK<;n}>J+`me*fZ$w zr-z5NUaz<&;0J5%0WNTPL#$TlQFX&9;qRwtDT@bq!l_s*nRZ%$wKJizz>`l8l<&u7 zX9oONEyWn{&a*nt-We5jUU3^?vWYL@UpmH8J#Wr3?)8XKE> zdBC+=iZLJ$>tzmrmAA$D0C}My9#`{N z+3WFymR| zRoxII9k48>Su53PROEBx4}36CzGl~l1K#QpQ|tU_fL$Lm3b^y*f$}wbJsEJ-Q>Hfl z=>RWy#wg%j&j!lZ{Pp>OyS!*>y$0*>iMS=1)H(MO=N$;E5XCDN3^hZVk@BKJXz9!H0ulo$O z9B|Lip-O<)8iT3Zd$;(MwI|xGAakW@;fS)03R_b2R!?G(*pk0s2uR*A5054 z%cvZ%=10>4{?(`)aQX_<0{&!F4p{q>X#p=YDhE8_XVU^+Yg7(+<}aoNywa!~@QPne z3wWwI z%ogwhqjJEF+nN?|JEL;Imy9X_eqvM($O~>+U%;j$vKaYt{4x-HigL0y1Kw;@8SlE+ zToBg;w^vST0(Ud2j6@bE=xZ5&F9% z2|nM{vcOM_Dm%GLFtSohUlY8>HZ+h0_BE>P424%{>1%>-Gqo(RWmk-q-K}sBeW~JW zf{##6juUvTQDqAhewL^S&TK~mS>VG)mA$X9RpPA;cs+YXlLZbns_YVlHzsO=A278n zaP1xGM%fDr`|T7cf1Kc{%E@s87aCQzZnscl8!dfJ@V?4PP2fbM%C1!S;LdTI;OCT+ zn!t^AvECl4@E9$9o8U@Q%L4B-s_YPbQT3#jz9#rJ<)lsE_Pbe|eHD(;($@r^U}{<5 z+eVe0yt^J>_xL!QD_&PiX%jfosIplK=W6NO1V3qNS>Q%{SZ|+Ec+j44o8aEcNt?ji zj4E5K@S8+U!+X&{wzwnE`ZEqzUJovCGkZx~f}LeF4irIx-Xc&)=}APXF3RN3VUXKU$ef*&@uEO5Oe zFjn@k!aaKh%GU(}M||fxN7j9VU=>_P!?Z=WTmfO&~Apr6!T(#E#2c z0|^xO#t8I&rk5E565TDv2;m-VA>3IYaoeH=BuLxaC&-#GYUu{C(iROZUqjLuX+ocU zO+uFmPL`TPAQNLO6p(;oUz31fLViV!xLzW6g#r?$>uVBbOCYVN5iLtRtWZFLU!&vH zpjEo1G5)w+#r>GIxN$jRjKms*=O#&?mr4%*dC5ea>3P|{)uSxhK z0g9qV6e2zzLIDef9G*QbtQT($ysx@|$e9MjD@0ZYaQzvqv>XtB5zzt;QWp}j1;m9! zw197$gGmn9sUGuX!2ONN0n3&0uRr@K9%E`{8TC@RLQCld5C<0N1@PPxXfg-HwMDdM zo*e#qnU-P;h_j1m0XH)zmmDzmdnp5UR{s~V1;iyrYynS?wSaiZh!$`?b(j%bKzwLK z3%KPOc8tK8MwJ0CGb#tf2S;oH_cY&|958mrDFYsRwzUYvQ%7t8UyZeZIPZuSaH9J0 z$T0$O?GY{DRp(iYzzxoaDg$m~R1S!1kk|sgZ(c${ttk zPmyQ=2VP>ffOs5<7Vvs?LXwdH?s*v%%YcU)l>_3jB({JXTtUSg5RWC%0?xlLX!$Dz z_-*CnA_MIH0LIFII4t>^xFwZ6f?D=*^-#hqN!mQ15f7woo}p$Ah*Of(1fHc~(K0?j z!lFeBIPQ6~1;nXIw1CH|pOe@E#x74~z`I|>Ru+gil-R-x%EgXRz_b5G#WG;hR|>r4 z%c$jmxKW9H;Ons#5YH;n0&Zr0S2-YlSE2W7E7I0m4 zYoLQhxLS4XenI-;;QFs;+uzGo~Qwv>Y_(Xw>O829+BIg0~5k6O#qXg ze8e1Is{zKoDwv>S*$;L2TK~SPMHrWDqcG{pN3?N!i#pB%i9VLI3Yd&K=2OrgToTX2 z(U%3>TT3|xAYrp&4S06K2@w30axLXU?=>wq@9=`k3$>K$OBEIhbH#Dcj|$F%JIu93 z0W1{xisPWKihJOo9e6LB1>zGZ9RcEI=WF6uhf|&B3OTY74g17!YXL|Ith7L!>w*!c z1thptw17mi`ZkF~#bHin0*JqySHsN-_Yu!EdMYUmT=Hf3 z`sR%q|nQ1LlIC{BJz?nvszw%x9>vAo{ z*74s5>MAXTn)^eb-qTX3Jyrzj6fLD+z;}%*-|FX}b%d5u5qO4C#ZUYawAT4Glwzy+ zw*c?aQmBVk2I_e&g__hN?1t{wQmCbwK&`S0d#Cb~*9h<$Ek*0uH3PLk%V>_WZ2~z> z%V=fHRbh#iQW@C2tu+ChXjJj+cHysYYbl4`bFDy)(^710y>_5>)iUY`!b~GuuXGLT z2F>TS6nj0^3)BcLg}P(?K#>f#MUhlZKdTbG!>0zl(OL?1(yTz8r)AWYUsTxW>hQ;i zEK^}xl6*^rRj)x)&Z}}2PSH}Dc}w9&*9JX*iJNg6Y-< z{j`h*=_(bLYU#~^SGyH+#RMb$J~vR2+MNNfd6%i>?hf!;Exj6eu5wYco81!>>+TI@ zMEAReWxsHi z?H8)@_X}0r%8?z*enEw<{()M?tXXhx*Erk<3XsV$3YBc7A>a{aqJ=mXAI3e`UAhx6;c_MF1G z$*EJAP2bG;JH4Kogj zAM;+5X!=60_WAYU^}s~a2a8C=)q71a&HzCZ34Z{u3C1@dXd>Yy;5ET~A0cQW@reYl z2|oOD8{m^O4vCK_g!)K)PQlj)Kk`rYk-kvYYl5HFA7)}xT0-KNnb!n!#T3ooG7jls zy?%O4Fc(tM{66E5xU70jFiTxDzs@)$uC`ti%w;!dB5@J+nqaQRK@*7!vDXBDt`}#~ z{5IpbKL10n&t4PE`6rrkL`d~|HhN7k*YBW-#MRtug1M}R){(f#drdG``=E)$wcl%k z7wG*!G=I#v^ew?_a(m!f5j2swQ+Q1`M{57elLsePZ@{AJyuxJMe3?zXP{-JHWy@WkY*1~~-#kot^Q!@?;XD(q+&p0G}w}hRUaY#65 z1-nSNYYBU<-2StnH5|5tJtyOkmKWRToSktoE4>}45;gxi&{mu4Iij#t87l5t2lS_yk`#v$QqCG15RhqUQvJGKim4hiQf z(Y-)ser(XenM&C6GY$!NDq+vdI3za7!pis}6>_R7(`~drhrtV#liG5%LRyy41h-a~ zEYXxJGtyQGM=dZ8TcX(^WA0nHO9?wD<4kG@N9_BATNI8@K@$m|Ct=5C91`wNK^F-} zrl5<2vyrf4nfVMk{i5>7k9j>+Na=8}v<;t`>+zhoQ|&j^K;I|dR@1cNS8^7$Z`=Y*mu_ZB1`6$-l|Y&f^{5*nrs3)3o*F@r}p0ILUNIci`^}*yK5>4qV5|8_YJu>5vcDf@T zSMXAO2pH-k@f=WC89^kT1p4;DJO~V$NLBa7ErEFu7&MWRj|IUvABpDpj6=fhNZ5Lr zYjr}x11abt{q?c9eQ^IL0~hKeksK-1N5U0J*dZDFP6O^j!Vb!{ zIKK#6ld+FK;Orvo47npL2`%H>BJ6ZwzX~kAEW%C`3(EqF>x!^bM$~lHaA}N24fJrJ9G?8##5q3bvA(3rL*!~&&mhS z5shF03D*{3rC&%VZ4@2`3wys@KUGS)zkvB9N6May4Q=pcj-ZRg zmpFu-pK(Zhi$mDIWgHUU-Vk=4Tx+)scKOtXurFmC5}(!(_Qi}t;!7IBz984|ZG#2A zoFVM<8HdD&GK76DvUEpOmZHzJVndn6OXCdORSoe5yiN*_$FI^M!$NPzstzxGD*Im0X1m4pxsmG?YOX z2^S_|UB(=m@Lm#D)(sNho)GpSSxrX;d*mq-_Q8y0Eh8V9un)*F6bD_t8zJoD@(ZXm zuzV&$*vB#siO)g^`)I}?@f8SRAIUf*zWN~S!?G7266}%(O<3tK65d$C%5@Wok3a}3 zvIo=8Iq<;- zVeia1B)-oe>>aYA^=l1$k3rbE8HdE@7lfT7YeYZBz{@vbZ_hX+-oFVeS4|||wh6mj z_UDbfd*g*$&_v>$Td<16JGP*Ulzig`=FOXE%H9x(S8t&{((<#yityKGFt5~tCK4Z+ z5LSLQBjGS7telZZIK>Go_ZTF;C?V{uj6>qv62i**LgKR$!pbjJBt9b{>@^vO#8)GP zy;`0=%nnDy2PA}*){v5Zc3^z#L~|oq;d4TLa`Xwiv-Cjy?w+_i{8iYc^88DsPWKx7 zrR+^qs=d!xnFplXA2Rk`Su-k)eAHO6fV9OE#)<``AD%K+u0cp`o;OzPBE77vpI`7< z^OBlKm%eQ5=NX4|!K=o8mT^dRuN(WR{DxI&pErzsCF78OddpZj2BfbS8T)m{A@y5q z?ECUOL8U!DGInvsA#MGcvG2*OtJGzQv7cld(*9o=`>{M%QR(Dwjr~Z@bd^5(&e#t# z4r$y9V?U5zaVp*Lld;lYq&0pqR^|t3!EeUO=pdc_dtm+ifV(yiub*X&i6+wSs~G!E z#vzrrGWKmbdsMn@bz|SkIHZl*8vAC(A>F;Uv2Vz;7L|srZ|p+3L#WhiLu3DuaY%=E zGWK=3ud9SxsvN~@8OM9}p<9}+Tt$%f+1l9lvT{@!7PD(gA5=PbThrZGp7yGQ!>hC= z=P(kkufpyoyD4>mC3~f?vVTP)e`T+Ocx!Ee?0Qssak8#cOg>RB7l%#_lNRyGqrU7`uaWu#vzg7QrK!aTV@A) zq_h;aue=+$C9ov56t*hkkVs-FY-PqFk;YQkii|@dZKbf~a@W@+mL#qe_IR23`$B6Z zsuZ>?(IoNq^1@gXKM2bmavvOC^gp(wh6!vKO z1*Rz{Nh&GqQF2Aq6qCdU2zzA4l1-9MQrJV}I;j~XN%<&j54pcC2|Xh%qp%0dn-k5~ zNa{pk56U^|~4MHAzZwocf+<;}Y0vm;HNuyTb#BH^5{a&JN+DV(r}XB-lV+l1{Y&tWuI z8_Cs#JxtClO`b*qG+__TI3&F4gq2Z8dSk8N5F_kw8Hcok`tb<+O~xTz9J8{MM8c=X z-ygv^>qz}?GY$!tJYl6i(qGg!&({ZUrJg&Y`GcH4D&g1THNkk|iRO>;mPq~aNY^Ip zij4bL9A{Q5YVm4zwWwy3+-H*dP4SpX>Nmx2CaM45={=LQ+Y}#~q<&L8X_ER)@ux}Z zH|AA?$4pWm4$m3CPQduhB=zC&pYi%&yl0a7aCp&peK0;WNqsncX}mrdPnx7Y93C}Z zAB;auQXdY#8m|w=t0t)rhj)$F2jg3l)Q7{z#_NOeuu1B};c4Ub!T8xE_2KZh@%muA zZIb$Mc-?q?Fg`a)eK>q?ygnGuo1{J*9ynefjQ>qi9}YhpuMfrxC#esIH;&f_q&^(pHC`W#pG;C8Zy9`El7EB4_r==+x1!s zN$SJl2jlg@_{1dj8}p38uO+FEcMEUmlYfKzzkO?;w9%Az_euT6-r)0gKB*7KTY5h} zVBT&g_2GES?e)RDp-$?<@uu4AgL%uG)Q973v)2dnRynB;$J=GE59Td$QXh`D$zC7K zTjQiY9B+@kKA3mMNqsopA$xr=Z;+GvaJ)(O`e5D-C-vcYN9^^%ym3wH!|~?T>w|d% znAC^kO`z8Y^A0Yl568PWuMg(!Pf{O_w?JMW%$tj(J{)f_ygr!c_DOv>VrRTQm?!c{ zeK?-XdwnoZ;FJ1rJc;-EV4h$n_2GDu?e)Pt0Z!_}@g&&mgLxvE)Q98Aq}K=Yd@rfb zQ$C)PCI1G;^D=J>%u}tTJ{(WCygry+eo`Nf-M-fcv#U?)!?C;f`e63_+B5( z&OWLCuk7#Tm%#_+jqdDo>MSpsFP0Z@jPKo)ZN5~#wcItf!9OE*q3=BKzuPf>lWNzL zO}+GT%b~6*+j-I4XSi$1MqV^?BVA)#_{?YK7~g7KA;7}LBC%MKp^POVH z_%_oV(s41nPpv~bH)cPmbx3Ue{YcGds%!m+4UM|iue#KZe{y|OUF)~4YpQE~*E-jf z4Zj@G_I0kYt$xC_{)W1yy4FvuZ>nqkgnHN5#y<0-jnYkZt|?o3Iil<9Tw|O0glqjb z^-XoHUsms$vVoV@zpi(UZQXIE7tKX-3Cee^zq7oMYyErWuCWb%!nJKqa-_QJkeXAbwT#%}mG)H|ddV>kS(>m3sA_+sITdUMWi zvs!S|5_WQ(Lpm*HN7p%|rK_9nNa>kM{A>{m!|Tkw|J~TV|Ko;2?)|xjLhk*yH8j<| zzjIwv-TOz>H|pNMFm~_%RIUlBKs|pW#Jzv5b?o?`sF$r>kZ|*t?*-p`LC(LJ@^@v|u5^nYKyE8z5hPrbwGpIAY$kgaz}IR6WKRK0})ly|VB zIBt19TGthVqxTX3yFBItLavZcSvovGxpf= z4vByXv2fUU3!fOXgXwl3?~rcW(b(O<&c{9u>Kx0$`S+>nh3z!jLS#s2ENq+64vCz` z!nPRgkO-g=cEu)X2hi9_x_Ejx22Z zu?~sA9AVcOYhgMQ`&%D=9pjM5r7XJNj>*fcEbJ#^ETm_Lfo9*gREEbL$V=mQ`D}hv3$*-NMp^pSl`F$0b2d~o3{pC#! zq{>uSAQhRerT(r%9TJ(Xg*{?u-Y3$9-G8VfueCkOm0xDVn;MGs>o8X!6zj`j7K*j+ zNj5LthdZR1CmY*sxI-czwe;)#VGfBvEn)vL%ps9)TG(fYIVAE+3;WP8heS}9uyco5 zh!^>zg`G9bA(1ay*o%hQ$J_}36ZZ6B77j)}Xkn)fb4cWW7IyS7heWWLumgr!=otB( zh3!4eA(78n*u#f8q;VJ8nC&;r!pz9mEV?@kb4cW87IyPt4v8Q%VLJ@7kTmiy3)^a# zLn7a@u)hs;NIbq5cG=KI!`EKA%6hw~)* z><$eMiG*6hZr0$Cc+DZ~`V9_=7ajf>z@*g@ z%@^t%5@C13&Z{dFgm-E~Q-kncYp@`^=Wesv?KaRM?L5cW9R@liUZhA5wj0=Jz}~eQ z#3!0hH#nqC<1oIv8ywO(F?&aYLn6peEX-+eNW7X6wnsx#L;i*~xW-=5kPu94j&E>C zyrdC!WP?NEHI1JwFrj~<*=x830+N$l*nT4&64}XxoiZ{nSGjL%WTBwJ9wS|2FM(D* zZnIT2(jgH%C{`;*I;2ORGToy_IwV30MYrcjhm;5~tRHFthU7LE-7!NQ61mKU9XQk> z5q>Ca+0a74i0h1W1S68cTy$HEbVy_@7k0%6heW8NuuDf+;37H7h5cZtLn0@+unUJe zB*Genoj25i9LYH@?88HyNw3?O-7(aWahwoH(Y;})1w@iVT-b|;IwW4n346xSM#Cic zdE46hZlpsZzqr)@O2+1$phFO)u&<4@kV+Dd3;Xm)heV=rVILUjkO;UG_V$q$ep&gU z_2I809TI8DMfZY{c}dEJJ#D0gYPSE>EG!z~kjP>#y04CKNQtn{=SEmqC+W>a_r4Jh zi45n$-a5h|5%ekS)gvqf^rJ7W59f_=NaRBo-BX0stmp)Y3OijaXt*d@(S;o@?AO5_ ziP44aJHjCmOe$<2If`XLcirXIheJj?R`|68Y4H zU3Y{-B1l!()*~!r^|ha@4?hieCTZ4n(fw+;-urr1` zB!X&%9Xs4YY%{H`57lzSDiLZcy2ZmS@Rmf6!rou!kO;sP_TD-R$0ZHCu-%3_B*Joq z-EpV|>7LZq`mk-aLn2sLbhoK46uP_q(58m&J~6}<2;IG7h=uNwdS2Q(V~9iAZ$0Z* z{Sb$g2=kpdq)?dez#$gqyF|l%#qJG591`Ka!d@}NA(84{*iDD#CB7GS!=Z&jf>%y$ zYDn06+cD${pIV3`Zr3WphIi%SdFf8mjQymfk!@{04)ge8!nc1B% z)gkrhZ0yjf4vFAmu~0eHLXD5!+;oqc>W~)3?7>qV5`oBKVUMX6mi);UW}(YehcrsV zlSQ}VREI>+vaoAUwGifpt;|C6sSatqt&RP0ibEp6SuA`x#loHU?_#>|OmRr>#q29n z91_9MV&T~-78>2Tt68{ribI+ov$srfNCZxcg;`T9jJnHqX5ri^4ry`Bo;<}N5o9eE zrcJSs>)Z}zVb~Oh)P6@}tEM<404d^i9mJGsPhh=q(mn$>?a<_w3!w!ivcb>HOV|T{_tz5fm;KKA3DF;sf_E z-B%|&q~bk|eQvTtB7j^hJUrRL$@kjZbZ?#Pkh|Qd-ArbH{x@S(Z@b}k` zHr*MM9MaCm7&~^7LrR3o51M45@?Ymnw|J66I=YXsy(T#%0_mj>2TZcC`Uj6Q-M*6@ z(#s{r_L=OE2)Y*wM@+U5{9nsVcdy9~sbjgZJ5F{;1n7%}EhbyIes!hkt~=Qwon2*Y z>&Xs@V1BXi`y>nPUs7$lUrlmITl6>f!$}T_z<;su#w1GvaOptPeSVTdS~SSmM(Ac%#w6D=J= z@l?}YIl&>doM!BI6C4uB62!vi6D)PY;OVCO<^+ednWj(>-T4z75{VUreQJWGS-7mm zEZjB0AywBJd(#AmL=pzEaMc7$$*`=>bkCaLknX5A_Jj!ziG&SeVe$k^-%xsj=?`G)8r1KyGp%7!cA1zpX-{M0OE7;Z#gaWhm;Re ze_@?NBJaAepVT=dTug=isLmnbWa^(Dfk^}*nhRKzhkCxqRr-jYyEz1S?QHOe88 zj6!tVj25#HA(75P zbUTkLl-y#@I7@EP=~}bk#yO-jt~2(+aSn;p7h-qjI7@_)z0q{1j&n#4-el~kaSn+z z8DgRTxI#%Ya^o6Jn(@l5X7!=I4v9}ziPa6O9TF)ugk87V5^V7ODq(Nw>ySvaA?&Qa zmUd(PJFT_bY8}$xyNtc2)*+FULo8fUTPQ`xskMbtbo8pV6djB1H@myea7eu#G`8Ce zheQGoX>G?Dmd<01M@(0~$ALsz578Z4Ye_!-_L%8b*E%GUeTZ&xt)>1r^GVZfKgl7H z0z`Dzn`8+=j(Wy)kC@?*<~(cc{xcjBj^Scq``Sj6hwSj8)$d;GkWPHb*lx8BiPR!u z_17AQbnf3w_sbfGbisUM->-2_ft;M9LDeFjwqq zI+OYZraP;~Ax(eH*o$f$66sCE!s#`Z?BvaVnC^zt91=-SM7P5{nw6VvhdW zba$w6NW;G|cJmsCMEV%9(4oeX$y~k6bX(Opq(_$<``ZkMM5-CFuxy4Uo>}7u)BRwE zLptC`V;9bFNTj6^3-e|aN>cOij6z9jHk@QhYR3L*b~{dUNQ8li-SuZQn!4tLl~#Y# z84hXtW+6CT>Tfv1A(7Zd*pH`Mnwu?KnC|P-9nv-#V_%%^kVt|f79N{!DRK5{X}WW! zJES94HTJsc4vB<0V&SssmOf`hYtx-M-65T}nz6Oh#p5?fB-arO3(LnH{EZiIiw#t82iaIheR?UvGDdZOAU0%MyC7HG>7!{#>PHA z%^{IENG#kl&C&>6y@}~wKg}VnvYD}$Pjg6wB#DJ{rdi4%zUCwBq4f@l)I-AVS8s`k zUf;^>epl|0NJu2Q%gQZ1Q7%qT^mMsHB2AI#K3Z-`i=OFXb_Z8Dq;0wyTVCOiNNFS% zj;Sb=;OM}LLJ5v~S6hN3zU3(vdQ>~4?%k}lJ*yoO>5oKrhw4JfklIzd0?Clp8R!}d z=;F(veiR1ScSL*bVLj+L&>@j3Np#x}bV&Q|WxBTya7goF_SyjsiL^>$;nD$xk}RDz zz>+K-wy)XUy}}`pY)LF^TTv+W(vRg$O}*5mqEPCkRVoUlUfQanQ0k?PE8^5khgffa zuXJryA_bH5cDb;J2Ay_?neK;`4r#-l#=cSMkVw}g7XDUg$(wdP!gL?0bVx_`GWO0& zheT>8v2bIhC3>no(sVDWbV##~GWN_$heR4EvCvRyNuj>Tn(o+2hqTeL#ty13rl zrjisrQT(58@dDjd?hp~jw2;gCq3B^D-ESRyUH3@q%- zu?~rZTEfS}LxAqpW8=#Y0#nz8);P`;N`~ zmawopkF~U23&)s+x@it+?{UUXnC6g3>LnJ2%AHA5eEl-PbW5i>q{>Og9yQG&kpN6A z96Zg^fpwi~y1PtsNTdZ5-7eECN!TsZO}Aq|heWb4(OtWrr4HMo)^wZqb4UZ~jQz3N zA(2>2EPPpQX~w>9Fx_{m9nyg(8v9DMLm~;8Sa`PDQj&dfvgzJi?T`*S)!19A9TEx4 z#KNp6;e9Q!T9*sW z!k&E{(hD)WLtlqP+BLDTd0$JyCZC_+8nsSehje$$w(9GUNYN%1eyg&CZEY?!3rnjU z(sMEUL6t)yots!#SY^rG_PE?EJXhtAeva9Ps~i%k-^9WlRh9_uq$|zB)m09u&sD}= zT;-5R6DJnVsIsJSKg6lzrdK(nzdN%qrph6aQcf%ktg-}ir(bQleX1PN_-l+kqRJtW zeoidxUuDVYdR%9^J61WQ-LE%xizHg?irheRSju`qnFrS+SCkLeyi z*dfii*Vyb}heXmpv2e&>O943fe$(A;utOUBfU#W%J0ubWiiJ%ETe`q*51DS;!49eG z!^UO?J0y|`iiMvBS!%(~kDBi1gB()V$BcbL5#RxZpX{ojk}P{rbGIBL+Dn zk{^nN>OqzYvG+@+d(0q*bmlx`4;|!?NR%iR_8w$u6Mvm=y4y-?DsBCDV>cb-kVvX1 z7Sw1EzZB#>gEW}u~n z{OkkM9XZe;9sQB9{p5&MB4MOhIBuY&kL>uV=^i%FAtjPZ?lZ7ZQpvmfTT;pIJ~s>3 z^>;{@e_`xp{T&i1C#4T(_qPO;n}2D#wf!B^l9(Oe-yxBnQY;MVZ^h&MSU3-OKwqq+5P7_8i%nt3;Ykv2ap9OWOI)O4FUt&mpZSvLu*8`#B_1 zdWwb0ewN_#z!s)^R6mC_G-K?+{TveMKgGfx{R$-m?b6SZf%aR~EYu8eNF)Un3*!b@ ziqNxKnQp%U4yjXXV~-o)kVqgZ7XC88(up3hn(6K{z#+|x*>3X8Mkn{9XRTp&SC^itL}F6WEgE2HO6P03QenU8?~ul|F$*8}cSs~L72UV`TT0WH z+M4c*{T&jiO-1*y{)G~qzSm%hPWM>HER;)j5tSZ@+2iUQ5@}Gy?lEZOQ6cPkA-b1Z}s&{$fQ>iHdEJVT2(%SE}ECt zJ0#LA343~dqsdnJda`J~RPT^Tx+?4o^_GH_@1YC3PJ=_@ljy=WZ*WL_6TG#vjkUwUymJ#VxcrQtkrHPLcN1A+8 zov#u{TvK2k7S|M* zhs8Ao=3#M7fq7V5Q(zuMGk+cy*A$qC#We-yVR21?d01RiU>+9N6qtv_H3jBjaZQ1F zSX@(J9v0UWn1{tRe?AZYIUi(<{>RUU&-LRYYy2MG&$cW&Z?1f4z8x~}WSbRLq^EG1 zRz*e5x4C)qy!G?J?q9TQUNpWP7;g}%cv@}R`i@%RZY`S?yJL@RCR zid#Ytp3;&dL?$hw93jq1xFr=h=nizk2Lb-%F7`D zahel*kLQhSk?JRuKFd>jR^1TEMJbIg_Ko5WxO`^lRDmOXIaO6UvABkMFIc@C5L1y} zdJ^W24DGz9rC$bVo%{7~eMZrz9NxN5s4uUK4bHilai*0v^yGozPoHU7sIiyyZ-*ab zX87vc^#>b;Fa1~QVP9Z*UA|G!ep*Z47?_NtG9=H}@L@n=dLlC2^=s71<{Mids5hyj zQ3MNp(#fc_p^ z<#6k32}~yFI3m-1cweneR%_Xf5TOeBPgv$OL*z zFTTk;p%2zd38m-rlqTFAS|DSvw6MarK&310qrWBTqnwedDxFwSL%j#JUPPvAK6*B|nFjNYa(Sv+v!Y}2 zYaNsB<{MW8gFkEO7caP8KgBHb4J1v4bUgp+y;yDRX7wsacJZF3z$mbyyVr*vlxtb& z%C^7$?QdF2kNCdzZznJ!IWnpop?OvctkX~L3Ze`#IR;+uE6M)-B5*1bFYsaa7U;C4zSwD(e~ zPpr+atWWjVmKXqjqg2AcAN7n;li9z&&?f)>n)J9un(2Xy$n?lXWP0c#GCg(?neO6p z9U+EeRo}&yn{Saf$|y2^Es7>?;Si|3W<2zTY<#Ybb<_ct%Ytt#@9w|3{vETc6^$(# zQ?zl9WVkl%34iptZqcGLb}tEFF!ES7oN zXV1NSPxz5d9%j$2^>E<$HR!o?0#(nYlR0?~*D`*0dG3$;HeLHB%km993+UpMcwGY< zluBsR(ZjXFvgCpEJ)!+a-C&5KMMno1qliooQbf`?Ek$H{m?APgP7#?NsEAB=@iIN; zt86&3z(WRVJdyZV>TxvbXImq)Y z&vC>&&hlLPDT?RP4^cdKZr*KarvkU7oeJERcCyjD zgo()X855BOHY9Hpdg}N_p{I^-*i%Q&n#gAQw28>{c@vT86DK0m6VpZ~WCJbz8TaQp z6Z5tp=?Rew=NpB#Drvn!?H!_hxz-j-6^q~=y-3RMTp-uW=VPHT;06^e(wxtJn?wdd_T>#E|Z@tiqE z5xctIT%%ZR)3)XStBCq|y^B$Ve4Ln8&$k=t31%E^1`RjK}PZ2=uSP1B1U18Lt;t;6gJUPj*{qv zO%F3ILKBAdG>RyN?uQ#iP(lw4RS;W5BvkY=ErJs!{>3O_5zf{K1*u3N!Z$~m7BLC0 z>j$evix7mLv!+G-!M4X5MJU4YIirX?IJ37=gdMajHi`&@7RMPyz`+3;h9I3F+F+)} zAP7a^!7F7}kvM}5%Z(z);MNMGh&Onm(kQ|U*4Ll|F;8s4pp+@19J@*`=_z3mp>Vqv^#R2=CnA%Hyv5(MFv~a|J zH>U8r9Lac&EqtqAjwxKJFTB#U@S`4h zl~K4<@Ag-t@Stw#jKY0-(^*F0N&QGn;W&M{x>HM6@tQvI8mou{^>F=;w`k!n-TOMz z!ddzhb)gn5{HFK5!L-u%f9@09shStns<_;W<}M1WM(T>ZC;dr3;jrMo!mm@ zHwBmBW9%~ACvADL*7{V-LLGcZ|MsKlbSn_Mmfxel+!}t(vq_X&!{VCsSA8RrA0YEz z3pFD0B6UA`>yrezK)+j+cue~5^@ZSrE>V}r&dwGxBKd*OHX$O(F*p z8^qDBticK>qjKNiP(lkBo1RZcts>1x#I~#M5Y%>{zSH3 znfDF17DYnlPo$9f6Def=L<*Vz^HRw4UN&kdz3Gq0^sYZ5+4jd1DK_&bQpo&?6f%Dz zh0LEwA@e6v$oz>EGJhh4%%4ah^Cwcs{D~AYe6uUA0+JWyQC_=G$5d1>}o|vR(P}<|=3|wq1ekcFX8@-s_J1e*cSxIJD>WX#Ix8l?rH(g(1~qoKV+wUjsb?X*AJSXc9geS&KL)28Ve-84}@x}U$O zMmVmBY-U8h@?EIL_bVgvlof&e^DP@6UgR@}QFZPU ze0n`1m$V5NiSBI^+bce{o^Uw+6Gzv0PvG6#^a0cVqRn0UJ`x=}HE-0P^lI|l|MtyqdJ*|Pr`M3@(o4v5=@sO;^aAqSf7Z`G-|PIC{Ad0A>+9!+$HIQ( zQ7vUBzSrY{I$X;FoAUvxJ=|&)FIV`ZQCT1cn-vxF)o;G=EmV3%=i9Epc5J93-%#F` z@W0Iv$FaT+h~J6R{)0b+!4f})^nvX1MEKKDTKb(h_&Mcd6Y_Y?dW(bN9$H3ZFMZHA zG=AXscnw!sKE@qsroSr|k?GFttql&*Qa0Y{W((}aH+nMk>@Y25FMf=6a+sC{9BhAk zI@C(+#V@Vf;Qc@*w%wQ3aR=jIrR$g0am0ze_@#A4OG5Qaz6@ogd7TRJCQ7QO?{<+U zx4Y5H6VDyjJrtfYyEwd|Hmj1reEkUJ#M#M9>kLzJWz#`VJP6>047orq^8lI*<)e{yGpce;o*! zzYhHVDQ_JJnZFK%%wGpW=C1=G^Vflp`RhQ){Bp;l-bs%K^IuJ5{9SE7f4us5K2SVnr10nxx9r$~8dKq{wy$U>+UId;?uK~}c zmw@NeE5LK<1>m{#{Ch4v{hmwDzUR`D@458cdoDfoo=eZX=h74Jx%9kyE{ND&$#E(6YjbH%y-z6@=(T)$^W0`yXx6+%N(zzY#6^(_)|=!SIPSN zr_D_zcay?fjmiQsC?PhS>L2OdUnt~l1b?f*yEv2nP z)WB0_sAA^Yp}#k1DOzi-6Q~`u6zbD;1Jz?aJ320}3uEe_^}}DQw3Lcu%s6es@N7}2 zXB4irkx}HwICf*B(hITI3*o^2X?M)={Q2&f$@}x&ar#yl?a{ceEzoUlL_YCL=+d9> zdAYTHxJDSDsQR;O27&8eMD|=OkPEepNamo% zBALR(!(RDek@}ZEJ+h<8pB^F8+m+~nXa4l~4N;*@YyR|zX8!aDnLj;3rZ*#@b)A-Y zdPFmSdW6iM9wGCmN67r?5i);zgv_5FA@iq4$o%OMGJkr6OwCSFdV2i5Ha$C@OHYpH z(sSdv^wfARJu{w5PmJf%^WwSmw0JIk(s(XCDV|HuiRaQ&;<@yUcrHC5o=eY%=hD;R zx%6y!E?bu=uw?$tCxVn)H%MHz-OgYG@Ms5lIVsSqtUBL<=kaKWKsB=&U0o z5iU_;0DAnA-c1WU5*$1)jLpef`Yj)L{l77kJx>NUT-1a3ta>jLGIo_eA zP{5yzs@(Rbpw(AP(E<{!U*N&t813M7TFR8?cPejdJV6g3v9(!Ivz;EyMOsF)%aJAa zJF*Vc!yxfAa77IlZ3ZB!p1x{FWco52k?HGfL~^lY1S66$d+^3EU=hg>C7!aas7YT} zBhB=MH6qhj)`(1>6HmMvW_g~L&5Opg1HWV3*ml3@YUrTD)U2p9ZR&-TDOrMPOOmA_ z-%wtbhE>#+puLu22)MaXeRzOzd%G}X;zE+{(YE@)^%yP15VyIbb!S-MJb6$(8Ww6P zDmXXnXU*sRGHRzj3)@?8Ocp=5Y)qwlc*btQVfh{{3#Eg&K>xPM?l?E+_y$L-?nd#+ zjgmc#N;j6>H2f|Yt)-0EsR|G7Y(E(e+g!D@l(X*=g$rYJcnA)LBFng$$ zV*ZZ?Yn%;MUN|Y^xtk7)za=wzSE=PfTbI)Od095PC7qgV9q{K1CG)Y(W`;)vy(Fie9WjU@F$~+fos?)oC9uVR56ef zUU~t1Qnh?9z;9d49PmSt_$8imt#Kl8xU!c7a=2a%%;Aa}ki+$A z;NNUCDmmfeTUzCtdUso9ce%>+2`2}@`Bqlo?WVJ$ia{gv!4fl`|+DzG!jSTw8e2lQRrn)vni7K<*22=>qN_YXN&0RRKKOs48H5DpdflR4sp$;9IO_7C6z)xGG@0 z@@%ik3Y0S%m|TqD>tbWTn~kafa*vU*2C|yPK9CdJ_aA(eE!ip{t64@77+(si(hGZ; zE@(DR-gy4@sEWN13tW2oh%R3CM80PJX6RUUJ_Ggo5(UE3 zBGbz@B3ZY$*!AmJc0iBY1-WXvUUgX$QEz7IBH%(3kqFFv)CdAo9%(YyOkG5#CoQVZ zta0t}hYe<~qS^>doLBs#nPW=44s*hwdk!2=fQ&1nwNOXPD{@Zr!_9LHAy;(IU87@o zot7<&YFf42d~q{m&dTVJAJ(yD=hm{QE>cEjm?LFIlJi0qKQJC#>3#l~37H-rejXf@ zxbTA6?YAnbE81m?nhq^H!?4ih9ss;QVF1hmmXi#~`t?HuzTI{y$Go7B=>FC&FBDT1zp(IWJP&3 zFiT4s0CIEiYGCdSVlBO*yxJcvmO}HhFfs68MpV9FF}9hFZ}L(P=8_*Yk&-h3W>|wJ zQs2ZNgW2>2O(Y%-_~Qd}JqVge-4f?Ln4bzk6Nynz&H#7opozrI#%qGP+XPJ{?mb=; z%yb1!q=WT@_nKg?3qcc!>wwq%ug)!3`PGVAyqaAtveu*-PU;t$=k(c?)NjgcC-s{$ z=Slsh%zRS6Df6GyZ^|l2>NjOAB=wuJB9i+5&UGOx@8gb+Rl;>vvTt!w;MDhv5zK;+ z%J+3FxDVul{F!a9d#6{7R6es~fh%(FrYs++d}>E~@W=(i_Yuq@5zQw%IwUR-UK7j( zS~M4RbVzI~gnhiDLt-fjJF}xbktlRw;d(Bb-*t3IEG=Qr@92=Y#Q0u;SyZBVVaL3O zk6x3@4R;CAe6VBQJww=)9ql(E7am_9%<>Y=IUOBRV;7;Gx;^L{Zxgujb+Nr#-n%Y- z48CViHVQlq&vDCNWcv+!nEa#NdkZ`!&U^AobNud&eJo}~&^mlfc zZ#(Y^>%Y@>MkjW2o8a1Z49eLy;MrAmptrK0G_~#M`TaHtd1vtX`atLgEhWq2{fk3t zT`r81ZF%$t&QL0$JyY8_*V@W^O-fsrXI2J+}%o?i1Sndh8BajB+Rp=ge4Yk|k! z>E^_vp%v|MxDpN5isOu}AA|MyVDf&x4bg*`6c1dz4jj~vcAR-{|77i_Z=OPNn;a2e z6*=^3n}i(wy)CA=7oB8-pW_hX0m{3a)@c72lqSyy{mfZEvq0W+$b10V3yOJ;CLZdh zOyq8QRK<35S$;F^WHXfMd6@7tfQo3-Iq+%2nwt zg~x1fTIpK@wh!(aRQz3hkYcKNE?w`oe`BApo$M2szR6?)o6^no6Nd-hRk?(z*$K55 z6u%p*eXg*@wv1;M*pyCusbl8HbGlC4d0KjZ8!*QzXC%i+$7E804_YU3Z!2U8NX7X& z^(+CQHqlkkl&-E~-P*~4*R{2l1+HadQw5~+$%RChkt|{fJm_^ zhY%@p5Ge$AP>r`8Q$2N9UtJ|4!EN2L(hj;@6 zo6`LOiSC0rYvl~?0RGhaUjb}vUgV*B)B0aALWliw8~zGlWBor``@^{UvkpwhWP0zf zOJ8riB3)w`BSkvGfJP+3N%{G|PjLvGZ_)T7aK?$|$<745 z)(Cl$<7%^WOrGcv{yPtuYj^VDQu@e~e{0GBB=tFD`kwq7+`r>^GcZ*%TUAoT1;}-Os*(4Ym+zC!v46X%{4bjVVADykQgLk zm#o>OB`{XcLM~>>tqB*6!dsK{xxPR*JfCSPKi7J`7k=E)t^Mr|*&EnXsf2dgFx%gx z;YI&!7%K(5u@|PgwT5&{Yq#9I6+Md$NyiR;{)7Ien0g@B|lIr6vyDxjIRkI> z4*PF2c%*ljz43m6iCkr$8aaPpcrB}@T&hY2@cyVCc%gA(%#460wW){g&(8)idRiyy z5xl(*zS!L$^BHYmt5@$UXA3M1wbbr0hOo$)k#A`V+TA|&Ed?;^CC4drj1q-HQEzqK zW!IQ{Tcd}ERRD&zYkAu>+TO$4E`XuC%=LE3=Q25;OFi$ePJf~C?7H_@8_Ib;q&YVl z{A!?56QN%PddwTjA`E@qV6CaIr7c(aAN3fRght>C8)G~GFawbY17x@?`(3yS)&<`5W*1*hHIt6wz z^@F0RgOB!U7C`Jn5~$QJbP%}})UX0(TRrpIXftOX(kZZ$DOD}Wu94w^zigbG%&r*M zqJ&xMc)|4EmZY>Q$AXsP<29;bWbxnN7@>|9>v+QE70a*AF^g7q=&7*kdO86S+_Gm> zMKcA7B0%h0D(}|g*3KM--KnQViCIc@;Ao39BX{+x*q9o;w4U3$kC%WYQb49KdhB8n zB9(5UG z8hQjWn3e4Dlu@T$V-V{_g8*+91_5NQvP%F*n>MYpbdsq7Px8hy58Ts++-INSQ_IZ* z>GV3U-3z?Ys7N|B1&laqc(VQ9cN(UZiVKCklVQnC8nwmK@&+=u+R8?_lMlWC_Bb^c z7!)*^&SRNLukc!Po-+8%4me|d>Kof|x_wHJtQov6P~&%MOKoYNA~nb0MS;55;EF)K zYv*>wBkWTuo?&olpnhWTkw86TugDOz<;kzx;7{)Ry>#mkeC6C*82Ddgl*P7sWx*HVu4+gGc;G^7}3n0d?VqmOa zh70Uu=EMqZYNzemPI#n!DhFO@oHP#{w>>`F04_92Yl2%YRsfef)c`&b)dau7<5vOv zuu}~n>!f|MD5zaIaENma;@tio!5Y9rjMAES877n|2PSYy(g-9OP_L!|?24~t|nXORFlBga9c%r%vYpG2f1t|A>iBC7(Q>&90AF~YJgg{e_Y0MB&u zD}b0`S(id=lLRbQMwJO>Y0AnJUTYc_R|B$cS{KY3mUSs$o+=2w(c(-gNP)dr1;OmR zr62_?Sp~r?aw$lmlePR#w3gr>hqVNPc|U87gR0VU&+KRU@laW5AVwg=0J7lP7?|}IF<|Vh;7xst=?CJg z+8X%kAO^%HR1C~YOQ%3~BozbW+#&|-#5R5r*#`KrU>m?qebIY>ciEbVIWBEdsB%G+ ztfK{^<+3sb)U1MF^jr#3K!Yj>MmMD(g-$f^naIY$OMJQokQvIk3y2BoFh;XMCS9cf zX|9v$ix`uiWM-qSf#2Y!Q~)1#ss=iixQS6?Chyo?3U`I>5v>)D(^qFMF}kmJ8P=v##p54 z2#h_7j1L|Qmz zYKs!toUlhtZBdFmn%`1(}e>#-PNZ<^{sX*By0$s4A&IF*oQ-dN`;?XZo4t3467TSl^aAN4lBTbpxSF#2JNiNqGHBrFI(czZ zqYwSA8<^?Jt3uIWR$|`p})4%0s5H^>^XYX3mBN=L8Da zy$4c_3k=SBt5e4sym^*Wzcct?k5gCF+VEEU6ob0g;C+Gmy}=`Uz2b2O=N#zN^UtQ2 z+3ex7=>=}+v#IB^spqq)Gn+s91nUgyL?35;vBBX$eaYa>f%=xgI|B71gFg+_Zwx*b zsJ|F|I#6rOX=~)A_9;vMN`q4awS~bq1nP|jcMa4&2G0uAhYWruP)iIh4b-;{hULj# z0mImiGsWv3iRP)MT)M1Jn31w@^3w^xf3M;H<28KD)`E~A55a){-J`?jEd*eGdJrGN z{x;jQ?L#HGqZI~Y@)#@JW?`L)xc@LUK~Md={GSeY~h zyf+d9uk+^iC`1gny;0g4czzHAUK)vk9|&T=e@0^9U3T?OfrCbAr{Go)1AZeC19$D_ ztpVR)l(q&wE{Fj?9T^dLxpATp;EG5L{CgKGfS94w1Xj7q-_3tT42Uc1aKV4}gr){O z=54`Zz!w;&25#_sPSt=9MK!@sxmW?*axd2;a95*rXy7?6Rshd-ss{W-R10$-&pH9_)XGVbne2E8& z0!R#zWd{;NbhO|D_ValH&vU8mY-a=&12>G*eX&X5NDtP7K!Uc`1%D@qapvGuA@@B%c1W!W4!dOmBwbfAFlo0u zxCD}8s~EW7bL0WwBBN9cOiC^52PCCdF)#^-m^1Lns5S7~mXC-SkQ7B*1AjV*0bh1N zu&oan{+x#F|1CF-opJBWB|FO?9SEEq3-B!qDLlkZf)_e8u@3kKJMS{f#IChZ>15Fmg>MCN@eqZd2Xc6b!k+`VWQf8` zLo&Q z@eqZV*q$Tg@DPRd1G!{~!s`OLe2Bsu1G#jF!rp;gHgtd$=Go_%u6e-s1i7U{#GAW4 zdd&k8cVvvqhSGpj4xI2Z&BMz);I84Iv}B0FVS!veMB#)`8F*HZTRcSJ(}5fwqQDVM zhO=mh!f6&|$}v*7Fp!IfC|nuH;UNkHE2+MCh{A0ixeor3K_Xb$Hw8kNkV}Rr5X8zB zD-MWDhBzP|VIfThZ^oa32i4Tz&_pMSEv=bk9Z0YB&5aZ|uMdh${ypCO5n z+dUu&i}paK!ueh~@(phAl*4;BH@8s^ulbp~Tn#uFr338!?BrS%jE~8l3&d_z42=26 z(f~)>bGiAeTKO$)t+aXY3}3$jxSvx!@3J*IJw)CoPv=lTim%PR!cy+NJoPSs`x>SH zjt@NG-0_pa27PDX-HQUSXeNT)-_n9j^i393}GL{avg89`95Q_`|3s z_-8Iw05|hQz6RXMC{+=7Ul%KY$2e63RviIw32hA=js-Q~Ms_?9MFKe;Xie}3++hZQ zIF5>e!=YdRC*mX^X*@9YD=_{gs|So-4a`-)tR9eieW?lL5?_Y~<|0?bfLzR}7#Lp` zeE`|3r6v%M)|%jJ-Mb6mT~76+xxUuC)tvt!4+6(c2IKfL4jlf4dh-4jPPI$$OFW(y zK;o(#p@BD6XzH`4p#cu84BdB6$0#vgF@@XV8Cm0U@Su>>kVJ)L{s5aBxsv1o_N;J0wruDaD{xU(N~Xub zl4Prn?kAQFRoqX=b&}l?a3xVzue^%j)`4SRDOquGuxu#3IN-r&H0>omZEh!}xg}LI zTryNK!zF$t6wPo+)eOVMNHp#xLlxs*l8u`uvC+7PecW8N%D9Jp++22+B$u4gat-@r zxOOWg(;NPhWDU81D#?nAr(wVPiDo!lHN)X-hCD=$X1LgA$PKe}ytrzHi-)+ciDtOC zYKDu4DrUHNsPYDn%erXVi>qe1xN3%rvl;UIJDTAlpCK3PGQ&kaLvFE4vSNmds%E&T zYKDval98LmvQ2L4qUBmtHJL@(WOz!ynLjW%80WyA{3W60u-81x`j&xIUSj9I#{+bp97xT@RoCCSP4fVq++1od z@|s)&v`Nd5qj}|4#U0(6(OWLyHyO8P*Ku8IZF*4Mig=S;x$t(-Yy7QHWy2 zCn~L2w?*0HM2>kfpRzp)teeOIS+!CwUAOdsK`E5JbJkH!xdch;3H5ya$vE>`nRTsY zPg&QuPjeD#*8N4K?3a9a)AC||B zi~-{dOE$fgk86-2GCu799L74h3ddSCFh)U-I*OI)@@%sStp~o$?W6!+m*`nFw@pj%U;>Ah0BiZ+O`G8?BgJhhpviH7TOQ0MN_ec&Nt^)4vebgDssMi z)E7J;^rYr3a>r*%!u?mpK;&xhkRJQ@v1#Y=-_nIzm1B^*sEg05&_-`MAQ3#}yi6T< zC>w_A8;rk6=wn;Jxg-;N@^p5A!Qgy&3lUtZ0{0CImFi<{JCt(DmG222`>XciIM`w(G?4d4E0h7cL00FDPDXZzFNxAp z&`Y)kdzls#ku=l% zSddPag}y45h5P5~W#R65RV)j$iq;^#hJL}z!UR#KE(`skGVzvNRoSw<-=!$o-%}Pzm8FyDVVns7b%Wj($*vD4hO+5;BFq$`rj#P&iuz50wt}(e?s)&Lj#) znx{=?1nE@a^i`p79-E1h(uZcNe+`%@vyvW}4R7uWl|DHWs)Lnc&gfTHD(|m{{(|u!Eog2O*I?+V zNfnNMP=>fhu7phCe7T*AS5YBb1U@|@s1W!@qatbCeP)nO6;5A#iTi)h_qo%d>woNF z8mLYe0iB^BS%h3M*&>WFYv(e&>Vk6vyV-x0eOAeQ$?n3xVxLtqZ?=aUyqdTYFBkK^ z0xzG)87W=j^wnj#0HC7_{axc44bAqmQH>X0LfhF-&2Ztt{v}7brA=PU;TzW_d6vD$ z%iB05$tyX$LsF9I_$&HYQq{+j=EZp*OPUpZENOPo$8c32!_6!5K8CCM7|#0GAbV5v z_=nPQbZwan{XP?VLoW1W7cZdlwE{`1c2-b8FfZ!K1tu?| z@oJq=H2#1$UgHhMLI1gd>|JT8m`;ZuhvEH7@sO%_EqM`;H<)A}NLxzZ+7wSuMZRK> zG7^Y zhH1O%4sS-IEnhQP>3?C9il2zdFI!=aLw%$Ro3pHNZcMhUFzsEDh~QC9d|O#aLYkHzH6k8D@l(>}|=A7O>P-xIYtXodI1MkG2)x{GfJCT|zKRE&jrSeZ$sB z#lWnWhyht36$5|O7EQ!}D~wVx@P3E22O?s?Ym8Dc@UkEVd@K?JZ)ip#tpTwUZ4LZL z5CiUOW~5?ZOiNn(o&EVK`xFXW8!(#_3W)h>V_>XM#DGn+Jrx6Eq#~A@s8CodhN?Be z7_Eo_|8AzMV&DzT9z_gzvYDoefiYJR1HRHiii&}EHBQ8U2SsAw4+SwGW~!}?WTm&g zGgv8jxp9(G0Esy=2;eU*3~B4&CykSuz`lOBKH!=Ip-=F7#z{@!(N5KXn+}GW;2FkA zP2f_eYQVolHNnrhSOLUQWuCwzBR~F<;Xg&(o94C0beestK5jPr?7?BYuQ5m8F>-kD z9>&QWfJArM@Y7HsgCi`gANf0YS_lh3V!noh)?TU;E@i1gej2%5|VVZ#G+{- zJOSBjRSe9&D?%>-oSzyxHe3Y_LacQB2^T9cqlAXE;#!h)i-1|;aI7?`LhV!$n<$Ob0ri5QSz zr>&8BeItr?;Gc(R2PDKvYd|8Lwgx7|i5QTiObiRy6Qxv~489m~-!y!0#1ZF+aoQ`G zQ-$=J$F_QUqL6`bp18pRr8Wlsm2<~U0sqqjY8^;G)2d*Cn~VcUj8if2^&ZITKmwW^ zVTogtJ){f*iD%M&8pgE!G-fGxinT%nQV#rg@1Xz^l~fE&Sdw0W2S*X=6vH2iIPe1= zwdz3PlJ)>5MoAAq!jX!N6pwC+V$VhvO!o5FGrjc%!(WfG(U+P3Z)Bfxz+2FKrxnh! zPwn&vhJO)p;6EBCmINf1l-mv9`cWDP-X^4hKw^#5tO_-0T+y)+Snjr1qa0_!BcjYI z&B;_QPs$nu8?r7L36PkhHNo5Gk8qWE*E;V(LO++;9O zN2(HR2q!`TIr(X)q*O19q6nDmNvZ+~Fj^Hn!Tr7f5_41x9O6%d`12=^BJwK` zKQsJa5eFU@yd1cvQ~f~PSG%q9-#k_5$E7)KX;oaA`y1tO-`Kmrc$p|*OLI7!ORM5t zT&5`3G_U%heM(gz&ZS~tyiCM^oMluDjOU3Mklj_q?ljwHC)ImfFcvRWb3^a1GIWfd zZBuFjZ@0}%JH_VNu9RcTV!Kj~ZR!VZ`x5sJ|JrT80EUFSA4uY@t%30Y85}Tn2QY3S zVk2#ES4Q3dUh0-#07kGhBqonzJhJR|Gr88`3o-q`8&DRb8DB{4sHBPoX;HKs? z(k-yc8Q82;MT53s9TRO_WW=%Mvx%|4Xk9QluXGE<8B`36SBTiY9XbeG(Fc6{ncf1k z4T=3u0pI10GyudabR=NhLPi24=~b~)ZF@R5+NMZ`*-ccABRc7BMSPEHI$GLDUAs03&;ALfX3N3TJQj!8YQQ0PiyMyGS<_as|rKKbV z+_mf|O)yJIJoS$7^y!>t>Z)aR{1&Gba$%DKTU^;@y2q6y8y>z~wu#%39hQ=$hg`Rn zBn9$BAs05u5P2d{O5(z}s*sDC6v!XT>J-Qp%j$SGUR_G!+PHN|;?KC9kc*lW@Vl~2 zQa)~=N=b6QDZZc0!_{!JvKxF22P#Plcu?651$?NKOr1x_McE_MDRyZddBDOZcKyR( z*9)5!hPlvfkgMpj;|gnf3FcO5L<^f0MzpYry>K~Oc7zqY*5Y(YR;=y9W`))k zX1chIs1Axj~>yW#x1f=4q3{9gTsv9(UU?hy5*}8JG3a^I9eMV zoM`-ZEefQOQhR&PDM=c&Hkkdd6r^y7&#foDAZj;gf4{;$wLx%L4jDIvTS9~1HF#g3 zawnInIQer?AK>8l<7c!eu=Miw0Puilw+0guWFj+K6fTMc!B@EniC!uEXCw%IBnWQX zqJYh*YQQ13$U0NtSXwHU0)eL-B!v)##&27hXylPe1PN255;`C-0ZO{r&Yy=~U@3tL zfjXy4k--r5bA_$@8&kmW`~ZrdWV z^Sq#xq`>(_n*MRJ!x3;wE3;D$ z@g|msBkrg?m>3kx!x4T|9!#K#<>3f8Di0>!#PV>&9hCi9WGB98pN+ z!9=839*$t7@?c_7EDuLaQh6}ZCzgjJ3aLDpAQa2P5sXwGOoWN$;fORU59Xj2%cm!{ z7aC{ei;^dIXBm^Q2X}XrGKu8hCuBL3u$y;}nly3MCX!op`(rgCkg&UT`^5q=NFEvi z2|XgXlXPSW4#7v22PP1S1IRNS@H$qC_Gk?0dUCt(s=xNZ9?lTa?JJgnfH=ixLTzuvbpV zUc3)GfK+=16BtGE4-+~{+(dHI?ol(hzgyZT zl6!TxC=nuseXH1tC2|Bw9TS*@P9&#vXBnNaUz^bCB!G(K4`lY%6X8;O0+Z8;WmiE?bmK*G4&X%LR&ZXpu;(-1Ch?e!^#QGaE^pO~=w^)6ulqbUbY~9Z{Q2 z$Mi?j&E)9yPw>9ZZPNmu;oOWC_}k8H>pCo4hugHkM>@A{3*2-r|G^;EZB1`qe*N3< z%j{F`=Yg+tssY@}sRDSAQ~kh0ohpDIcd7yWoKwZu4Ki^V1n@zZ@^_k;zC0fT4%)1x zVyXyv_KZ%jLwTE|k-Uo_RJ!UKMbp(qgWs@GsSKDAOH)8z?$C$$HbTatHNjzA4Gfa; zsTi26J87+ItZ8l{VlQy`Rbypf3_=H1HHwkC{Jr^w)&u{|Z#WC!b57NPYq|v#z}H0T z2V;+70>E9oWiUC0V7ylAf^m5N1e6BMp<~pMy zV$E>34Rf7QG1nP>B@*U3qhhWzD&{()Vy=1ilFn7$Zcmq0sC1@6rHd+5x~4*5Y)n(A zbVY?q7gVTpJ%vh_Q>b(`g-YExouJ0YbcV{MQ&cXUqjKpal}l%-TslqV(s?SEPE@&c zrpl#LRqpxc8omM<4EO&ZPD*-*WmWBGElUrB%<)^KI-6^`(YriH%D#~Cl)a3>gYc@Z zy6rt+WY&~_m$cTVlhfY#zFSooTWHwD@9=}niwmvk zXBV_+uBYJLK~L4*on9qW zd3V`wiE}I=&aPx;%sCmUyHU=a!b| zomE!wZ++%Jx3DVpDS@2egLw*-TBlHi9*k3{G|C8-nx;^xWeSys9ih^wBNRagvlJ?| zN}?RENr?N>nb@qH?Jkl}q)g zT&hUrQcWtCs#3XBm&&EeR4&z~a;Z9%dwzX}-7x6$-|qH3Yl?wN=y4X+`e`8e*2VP3f#wjdX{I4JKK|L z`DdX(e$^n7=Aq+(L3*UV*q`Oe;5q(^HU?LcsRx&2>cS<74^OknmSpO%C7F6`Nv1Aa zlBv&@Wa_jfnR;zW;Fw8ky+e7RNh9}vl*yckIwk?@jw|XDFz;7BANk3xLlR-LF6MY?NeaQ%c z{LYTN*}HQrRe%w7wXwwU^S-y>@T-bVw)+j;M_xAdf9s-T%R zbd>U9mWb85(`Qov?{%sUWTMg|FwD7=wLQ+hr_L`n$gek4{TLJ}CBKOvRzjLchA0#_ zCA?}X)Xt_zc8m)1+QNpghkc5BkT>(1{uaJL^#aMSB588JeS&nlQuOsNc{AV4n-;!F zdyfA)D-V#%RcghOS+2@D28*qV z6oX?VLNNmDR4APOQQz_FyjH%ZuR%RusX8mg@krXrSE`PF!%AiQR61wfrswq<5w{LoM5Kl+nKo6BvN z=a)W4_|*@-{=mgb#i?nTWmzjc+nNKsU{>E z3e?z>+7;HePig*@1~&@SmIkKj(;X9Vg3gI^ESa)ZAL)Z+&K6sU3U zYY%l3`;?*1F!+-|J#6p~fqKf|Gl3d^a=WdG_9<;`U~rQ_%`n&-s6!1d4^(OnEaI2&`ShLkS(39(XiGk7 zpC#FCuD-W@mL&eat$B7y{+AVS!ji=O@VS!2kM1!KDM{Ss9cJn!iTz&~lc@(_rp!=H z8NArzSRIJv%Vq`a#0g$&deqjz(~Xm+fCo4=8_nKdZ*AO|uGuX05s}z=hOZ1_Si*CG!X7sD-C*{%iHT^RSjJqB z{j=F2ZZ=BAz{_2%06y&0Y%Gi2LzD(&_t3_sTJUE3ka@Cgyu;)AY%KCJGd`^eUhE;e z0Di-%*_bOaUxoq1c(pMwL0`mx1br0)6ZJ(5hzqC~7*7x};0fjwDh6KQ8^vsVrW50S z$|AiswZpM(b3Md9mHUa|N1SU;2EWxUz6K0VFbMo^1klH+Xlq2w0eIUG z34q5qRR^9K)daJw;tQ-QK|<#QW_9KE1c>*m7?|x-#DG=y5Jv}W1Habh!1%Qc4v1e% z4?x^nYl87>5d-4a(irdrw;9<_41dIJrU2rb(iku{BQT~TV!%#J;n~O(z#IFr7eICz zIcWnQjdqxAY|CH^kz{gllLYJOXxll^jDUqNm(RGWfKQSXFY_JICcrwACdv44`>JIo zqHA;cnl{q(Ma5V^ykEKfY?bhIy%GSUd>KiaUkF9G9BpY95c5oLWoCYf6+UgB@>_kC zhYEJjBTPwUWweN+lq4#{MM@Iot?Sv~JamRzlycZG+fYfOBFwZT33JT6Bne<_6(u>+ z9#Lg0Z2Gzy;4qQ#yL#|{U9|0kNtWenmb-f9jJe3Y4MBm_LFC@tqQGvUJv+8dSOj;^ zvWBu3l!t|tk`xFV+9VhSmx2^di#B^OiGm2exkcfoNDv&BN@h*r=aC?oy{~MMLc9@z zS?^Mi0*kMc0b>KDAO*Zb$X#0$u#!?0wv%BjWo-(hIZ)LBmF)#%(GI{EPW&TII081K z@?h*ImQQUa{@ZA#LllbT*;=rV_-}C7NvSAXM9d_Xhr?V{9*nib@^Dy<%7ZbQSRM}J zQF$=76U)P4Ln;r(gkpI(OiAUz7|p-Po6(GBNU{9tv?uxE@?W|;ibNv$^0hq_VM}rm z2E>F!@Q&_|Vv$I`dhIM23H!J1EW;6Yv$ZQW#QxM0MR1d~Tcg<^+oedpc5UB0u|i>A zzjlifcBpF##{NX|_uU=EGm-pL_oxBwaq|z6{8o315|$|Jce*PR{?sl-^84L>48RIw zizFEn$zON3C=v05eXu*r`-PpfwjZrXAB3H-c6MnY?3!zL6f8yZf$ml(*3ISDEg`c= zcjEi)Ph5OO?x&bRwvg-z#eTYxck8yg(oZoM z6sIX^{`nN3FK#k(rYY|i&{CLQ_N4WPmfSsTpQ0SzuEO-M^f~ncxdDizS=#sbu`p95 zeLY}($=L(Q^^ct3NxR7yg-SO@p%@$^5sDEoYoSuTr6bU%)(im+jO{vpeBOEwt%vz# zx*WE7eI@9Ur`AwhV9BW{pJ$yE_^p1qT2HfGsmS2i>V#rf;@B1)x?b<=QD=W*FA^zc z6?B$8>HoUT20g9fRbv6Kbt@}?+%L&O0>hlMYtV}2{(&7Pxj)bsuD~1{rCNThui@IP zh)5A%iJlexeaQN|(mta|!$nWa4>G+#?tUWaVOzB8eep79qOUkE*};`NP6-@LZS;q? z4DP?%lUg>s{}#_+qj1dfEcNBdA~ef`DQJX7%`CV?Xj%#jokf+mm@yp~jEXnF$imJI zMg^oVF)E~)z-2z_%&5}7#&q@32Mr39H`JE~+O(muUGE#8x73rjluduEP5YH$`n;M& z#`JQ(r0NA?IWm2uS*+Veo<4m|u)ZYJ0SP7I^|%+lB@}5f2XLVtw|KUZ56+T7Qp#VHGrRsYJ$JwVg>LA zkr?>FAO`GY0Wd`!YoDnUHI@r!(?c7|4I6h$g*yHiao`PnxF=2lZ|lQt08xT=ak~8( zCCE|%QG$wrQG$p8Q9?P1#3eA~og*7M!Z0Q$kr?=4`;%-Oz^kL0;9Fd*0HR6Va!fIO z_9@gU1~D&f-zZE;N56*Y0@cYYzmvh}Osb+X6d)AvephxKhFpJfe zq{M_&63pn^l9X5`l?1aWZAnV2a@H(cd^6g~EMxi6=E~y5^7t?_kN*aT2CB3X%dbwI zh}Q4eztxF0MDknvw>r^-NDlAsCXFWK(G!qhCW5!^@1YH~2>aFjTa-pql1P4K|5hjJ z*~B8&4)!UD>F@0etjztB9f$PxxAbVMn`f6$yHQGMW`TF2R0`)fw#GG`+-40bzmnJS*4A5N~s~}z_5fp ze45i+V5Tcmp8`JHw>nYp$8CSS z-9F{4x6FRGi(#MQF{c-ZK}6DY_M0G`X0P;hh4m%*18^M=Pz{n55*69pStmk+Pz;Wd z2*n5ph!t5uIs!cgG6XcB$H2Vx9$F9c%Z`D2+q@1Ay4=EkUIL0NO%5OVJZpI#R>S=t z@Niwj>)CXqEfjRW??1kaV1y!-&&oHE+kMq)Of;x5J0~4s6GU|{W+8E>*ZBwvAgQ4& zBrwb-OV~TJfLW#?(vT6dG0X}llQb)}=E)ZLx3-DmK(fl9l7l{FBx4SdmUGwxBQ_LOx$`2+32iwPWUaK3$x>zeRf_Kb>Q?_~8g zdVzafCk5~OqHqs<9F0BT>G)xG1 zqf<2?bJUtlawA(Lv3cNj(Yk?IUlB`np{=18lp@9m>}1`l21d`?JeX0$DGbA@vNpyL z%d=iAR{S@(hApJ_4Q3%@dAQXvN69tL+;LQ2Vs;{V+Kw$s%uf!(K&B;vr|j6G#Kfv5 zDU$Eo(QS7%P4DutqfU=;%2-5_(({a3Bs*D@)FZ^*QtKBgH7%iN93K{{1J_NvD+6=d zVM(T4mSoy#Nv7SFWEwNlj&-fmew9nRRW9vSxwKQ|{yX$}j)kl%Jem~@{}l6O2}wdOXi4pchptE}gn!U$54&)c8AZl6`kJJWh#Tr%pknM+NCamt%f zsR(~!+;SnG{l4|>)=aSEteLxQ3wh8!^iYK(2mud&aH0sqN*>WV}R5?N$hNgIB< zbvj_5a?*Lye)5c1aDX)|@A&`;50Nwz{8^A5sV}xu84j_N28E&_oS=h2>zizhHnh}3 zOJPWv?n%?g0LOOC&vZZCw0M*&b`J2nPBoSrob^Ex#q8l64ISvUdVwEus{RLqPdU{K z{D)KZmsmHUyDXETJK9!90AJuO6~J#gRc9{02^5eaXk*|mpK<|YcoMjQjI_!h87gB? znRF1!F$#1fZU7vud9-}A%}31kefC&*QycqqpF=Njd!r)h-Hh5RNT)_lUue2Q144~d zixEl;7|+lcheV*f|IDHb8`=>*#5ur|&&D)sXBZrJj#GmM7X~UFzcp33l$96ALai8EbpT5w5zI)UcT(As{g{^OMMh|dJn3~7L-wZ z(Ark(1%KT8D}di}s=*L0@gX!A!XE;~5KgmERe2R-VDfTu2fk=iIL`+B8T%|1$~YhP zab{NqOq2oWxKTFMm1C;RQ#s~}+NW4E`uk zwEa||Qa{RT&3- zD{8*Fs^+V+n(2gOtABMmu2e=6mFE}9G>%n$!~J~D2Isb;<7xIOHgTE3#{-r2^^7$@ zZP}!*GwH8-t>Whfe;25 zq5iy~OqY2>zMP?+EZ^M>kqL)otSs$`&5EBvI%tn(pKn>oOJT5U>xsbfJi9VGQO@Or(#sNSLx>%GeB zWjPs5U;p8D|GIJAZkV>KHnSbhYs*tl#(hrnr&jUxAMwe^kD*)Pl9;^S3ayVtlGj_| zshIrp$J-LyT@p!dx2RpX-#*LU*S@q(zUuNwa<&!LzA_?@u>un;tEWnT))tEysusXE z*+eDk0#TZTR3Ob)>5taGWlN(n;JbXe3LxqhZwGdr-=0y~y5Vm7ltBP@yPz#5HGwOP z(we;&w*UMw`xG(Yh8Kknz*`w79RLq@ssVgBstNw9ixt4F7W&YDUo=XG2EN_J3gF+I zY5bWYFH-?z1!bNr6ILq}5Chg>fOj{O6)_;DtzzK8AO>t2rD9+lKw1Od5s85x z3atU3i^RYif7CU(o58_A0WUR5#{qsQhyni|iGe4XOUiJ8gGOm|5ZNM)WrDEVO2QlD(I@JJnS**~S;Ps4?4uFJ~avb*Ott_(0w16Km zO2xp}x>y1HQ6vU_G>8G;cv*0@w;3+%Q#u7c5s85ba3Tgg+hU%M4ZOrS5d(fV5(BUC z2{$C*G^4b&Jq*7mh@EZlY8N|gGWakQr! zsBaqlky8yIJAh6Ke75ZhG7R9AP8GmsjnbOnakhDj838wUssY^2D6I)*i;$Wl?LS*b zJH#=DFO9erhQDn)vNjLC%Q$HsxS?+mb>L~yPO{waPnJFo=WPiiYL>zc6-w_Jn;ZD_oml&nv__bkn1m)5#K{@t> zCw()i1D}re9B{Ws>^ks2qKFM>_OASyZAAnBn{>?iCYIxR5!iHNbC zygJ$^z-%kx4OiHo*&MXBKN`nQpxh?51H`++Oyk~VpZe>B;BOcwBOx7S#}Eq0hM_&& zZo2_tUpX*wU#bG%6>S0F%YCP)1KAz4HSk)#1r(&n><%i%7Vtn21F{vU7?^EA#s*|} zP_bSM{b8plfcN=MA+LKFe$aP{0?6(l9RLaY+5wojFN+E!*H^JuS-9RR3fn~Y$342& zfy8R93MN*|K!Aj86&opT_e3%J2E%`{PkEsh*oeaR<%X||IPk3@lmma^)Bvz5n5}$V z86chzOLU%KVu{QFh?}Yy7=KkU^Jd&t#lXRJ2Rd`z0lb)uP&zo&Johwr`sQRX9xkt? zll9@$LgCjtx-U;}f$?ea?<$^`;B2T6tM2uxBTVnC7#6$6u0h!}8Ilyi_c;MH0cZ{981 zoWX4Q(j1U2U#o)I@ zFoj5Psr^lQ0LEKAI7EjUkSL)80iW%Wpax{~S1~ZrK|1X$IMfIZ`$aJX{C+<=)_|NU zwbL;cFUTL10~2dxAV3lV6(b|y45=LWQqKr#K#~O&d(!?)W*}w`j57i-nSqD_Z-_Di z@DD;p0OSlQQvi|~=s3s-IQEGcfs<&cVqmfW5d;3x1LO1-_$d#J1(1j*HAmX~o6!#b zgyC&Hk_`eMjA9`8Q5P$Ky?&zV2i_8$#hx)dF*;>|U+qV#0=S1${XoKz>W6p~M-VWP zMD|>Q$rDka0Z;QoKtC}BH!oMf+#f%e7ZrhI57Gf}vmC-(!%)U^k2aNB+$xsHmF z@8G`5f$?9NJ&@}fF{GvD!K6C+tBK&?%GtxO^~`OLH}5JR5>WVp`H+wcn-p$w$C`Jl zB^u{?4l?hpmQ&33++yB3mQ!r(xy8JnTCP9_Q1;5E&P_qtD+SW~QW8gHdoM{YlX1_o zI)#nRS4&9>cx@>;Xzq#&mm~$ew5*P+vRRjsY|}VuN#d<|YFVAF72haHoP%w#BykJ& z#j;Hb@AOS_Ug{pD9FBoklr2)2Z!RL={O2tFZKFy#3b;?%A_X?gQj)?v-#zE0+hSRn zO^_|EBq_Yyv;28%bzG5_ouqf8C7Eu7WsCR}hlNrS2f__Xa-==&b!Oh`dEjl_&?FCcQ*1%!k7zAQ`Dh9^(#J7Q@g(`-@ofHLU@WmlG1BuAe8W022)>8WuF-(!z zsA6D(ql6+L3#?+`Z+c7|1QG{T49ucQr$ClU#YS4GDt+UdS`Qrjbo|1K47&$S;;mX2 z96WdYg}&i(CYOIDa6yX#d#ct3bJtc1QedMkr)CSaiG7xW6j&z}1hZx$cwx3^CCRcK z8SSZHvS|^#xJ4nprUTz@l}kYiaSje97Z<^gdSXsI(t(57uSIZSMYi6Phbx&N;p)t2 zM+XzPq`?ojC|n;2f{A4!cwvje1Cbz@_*M>)0w;#DHiaE5*y#kp1VRzKz|R!NMuK1t z6(aZ%zmDW|A>@a%qlSyCALB&u zf)<7NA_>e^Q3_HZ%PPB}z+I6J98AJCgai{;Y@7XPi2Ko-k)63=4!(ZU)* zE0%{Nc>}xFtI!wfkx%Q1f5uZRmC3pPU1f&R^&{* zqXi;zCaL`SiCNMl?D-Qr%9=#7Inke2R)r)kGez>_6I+xBO2RIj=+8FEpj35WvMG_g zd!naP+)4=h@Wd7+!jrHMO>9vjv(i?<1SXN(X40r>*0q*qiR4z3T9gP>!frXqpPZ6$ zX;0usL;b@hwI~s|r2Zk3I!ek!^0|o>Sy^uy(?oE1Vn=D2NWOJaM|qh@er94viJ3?~ zJu!RGE9_$vTiogp*@XT6M8EGPwyE;K#59q-eB!7X8_$nL@_-@JZ)ljO(*QnC$`d?I$^&yu{Bye=ZT|8-X`HQdHyKuw?|vr?$HXUP|O-I>g({Z-hREslBi^tlh zhEwo0&TZ2I|H`=;E%0Xk=y+S#_Qs~+v0dA=z&km&Z3|pDH)BLC9_D?@OL&HlvQN3L z0-o(u9eAEo1#p>D4dAz&Du91=st#N`JPd!8K_)JP0PgHk{?M4|%j=oIt!>s)F;#@V zGG%`qbg9}m3}UeI1TVD(UAc61vBTH+3Qcc;8L>14#FbU0lYb?3C6gkCh*5zvkrVbstJy4ABe5!JX2#)4&7q% zFWCCEF%|_ok{JLoDHTiCNyO6FsA3opM_T1l3tHJ2NJtplwQUQGTj{Qms$*5e#n66G zHx3zV?MoIslmnwax!0QS?s=aFoSsybB6obIB*M$87>Jy859#SHmmyon_;2Y#t;#V- zCU)_8724=cwIPD1oR_HsuVwd9eS`5q307=7Y%Jm#z*qS0;n9};K`H`SW2u;G<79hA z`w{z;-&r{JSFbOnc#OHBzemsuMU?|B{#iu7KUQ4IF)~4gr zQOZwC&~s2?_BF;Y*mL&f_9;v7Zd)*t&WT|OfHWLQGrO&WbUJeSs$4K$$t&l~k%9;C zCCMtTjs@cuw(O|loUx$Ef)TV!$%@lM{w35eB`RjY&@alA1T;18ye%D@@`I&vnVlB0wwBeAvW(b}@{63NbprKPXCtS?Db zfV=@GZ!GaL0V^pKk&!dJPz;Wd2*n6k8KF|+N=Kl-XUh=Kfc~@0y!9Sh5A(}(d4Cht|XVG8fp{=Cx1IB`yHP7Xu`@%ja3g^m)frqn?ohKjP z4ipL+A5O?zx*g){QO{>pXI4RHb)J~N*Iy^jPTR9=f~ZdH3b@h>$vEHQ<1B#tI8_6( z|4WbgY&x-k!|h$kQ|&XdV07@1ciRi(xnU&D0D~UbYFtR)8YrglXJ5Spip{rktsFO`9q|^&<)+YC!QN zRB^?8>NQ@7;u};V#rsf?xGC3i1!Z57l8Q`WcVD6!Q#dkEse(4MDWH_qziKStW0=_+#<&mCVeJqkHW@AiX3oWEJxw$AP2nLC{+n~!e@QD zz}Fa6PM5+#E>{E2cd8$FQC#)eVQc#H(KNoWgQ#IhOPW1!dZj|b&Vfc!O1Ai`51>WXV4ft486TIH_u65uhPSt?h8KvU@ zzs1G+fkzuvt`~)`2RR@fQOcz*h)ZDJ<=oB0v2Xc)1Mm*F{(d0VEmFXP+@|}n=|ygq zgFwtv)(MCy>L|dNornQ3I~4<;`P7MOT=2SoM7fuZVfA3Tu@GnNmN-k(pxc_rLe&7nH`hkCOY7qG9 z>!{cde1lViz&AP72i(W0LEr&S^#Lz&s^6h|@F4L3kJqIH?0cBEm{+dvq%R(oJGaJKX6|f1U~CjKky~C!%1Vn&7JB4&TwiF_!g)7fY&%R_(g+w zuQb0hzI%LdRNyN=$$B?{H~A*j4;*mcZQ#4DKmpl;#3_NhxraA^3!Ul*;^~rn0C99x zJs3|HF(8hvV&LH6{dhP&EH!}#x+nDm@nMky4h1P7J}gqetAi8}9~LR#y+I0yyNVR> zYwnZ%Kpat|fcTTB+M!#1qccBhbmm75{0QffK7sg7>__w58yZ0TNooRdr`WY{9+@X_ zlG}bi5a$so;3Yu{h^L4YFgQ*2M4+<`ug->dK*-t7X;NUHlXE1HbWTF^IZX-;cbq!D zL^@Z>QNV?yJz!z3Q_4}mV?+*!!^F-*?pD^NfE!6&AYN4EQDt3x3L`5?3PfwI4aUq$ zK?=lc6$E2dr67eW6T^r~K?+qC#gdnTBSp#wZ8dc$U{*#dE^JajYbppvZKWUux>doE zdcDw&9V+uf!;eKA`0vKa5f;elMBE8@cXW6GKVY2H1d`Cnc>#z`>o}I#{y-Kd_Z?l} zU;ExM2>klh?Y%>*{@5^^i1Yw_uWd0Z20qKTodWnLr)t1AMJofo$akk25O>oKSgVWN z%WA-{8l_@jJS#dtP4oR}kSz;W)0$w8R#Fp)`>7cCCU32uQ`Qqs)qt_XVnksZtKo9* zwCq$nAX8o2b`|B=+t|I71G86&H2~R#R1C~EB+~*OZab2SfsglHssMh@sT%MrQB5$L z+M4ncUGnY-MegU6T}@V>CsE@)CrN3szMJKF_|o zpoytn<~B43h{=hO0 zcz(41fUotN(*@yHe2EiwVs=z7}Wh2t%0&{kf@d79L{!j-_GfHcM z*_@;%kiAL8z-&&E;sKwCS_41poz7-6!cVj{++?)uPY6{;0>( zI*>z%m^2WV5ic6aVLs~4F}(#|;?7Y3mpj!9B<9Nb2e_8I%khMSisN?WUI{`j>veP~RD-iE96He8XgRb^+x*@IIqzrGvAW$-;7z6&5B zTizi#!15jpSB)9FB^WD5K>njg^qxs(!Bx=}o7Jjlm1wCP5fjT*ZYK+S1UTgga#*f% zU>;kDVFL*^Du$I33zQ=WV1mk}7Py}cV}JWxOWrBdRiu2b@nQ!{n-t=+LJY{4QAb>_M_u`<&KOlEx_!M zBKgR;%Bu{nHCXqyB&Au=r3aY3v)wzT`yxp&;ji5$C9Fy88i)buB*E;K?aGukwcx3e zVCm#wk0X?C{Ei1 z<8UG=MoVc6+vrsi%=5UmB&BmBNie?ImZXHIYMZOdQRCmq!FgBKUE?+gw>YYf6^zry z@^HAT%7by%SRM|iRe3Nj8_UDtx+)LGabx*TJU5o_#D8P?PP{ml@5Gm5dHfqM*7<_* z;aDCHUsicAw?wf#93HLmV0<)|hr?G@9*n2P@^E;p%7gLOSRM|)Re3O88_UDty($mJ zcVl@td|2hdcyKHahbOB%7(b5X;Z}!lOY}Hx?u*%kcbwblCcNR?PB-DHbNwj;eychH zlbXrc_nGU78V?+V-DYl!622|$w7Gut#k;jtFrF@wo6K!d!q?>sxj7?TR4GTN47DUX z=r(^XLTaAVq}!;EbDCVV&GoU&0Y=@Plbu^%ZMxwUsxMh{-S?8v7I1=5DmKkd1>pt0 zIUK?W8}dAc1L4zt>pKU?J7xMVbgGVxl5xp_f?+WRq4FX0FdBlWJYmX5)x)Ts@=^5w z$rLJH3!@eyW4rQS9opRv`*ZA5zL4+d6nLvdrjj?5y}6aws_H(S+UeHUB7cZ6GzI*5 z=W=Lx z4wtV$rpvrmC+oJC_3?J^s{n@X{iTXv0GTScvIh1D4FN+#^?V-L=DCfj5`P)t;a0^H zq}6HPf8>P+8=b_6T z!0Y%z0ojYiFS-BboqCZ1atHW7{`Go}6udq!a|E(nq6r|&BvRZk^RB#5K*GK#2gtkf zA_Y8vsMFP#yZRsp3LdISMO=bCUML`WiuCvvGncTz3}Q*VE+iGnxXG)90+M1&TR`4g z7bzeKwf1ONW7qgovrb-M$56+bpGb-|K38)OV-H@CZQ{JT$onF)UYI&|E))sht?qmk ztJ+U@K~-7!JlLMX^A?MS9Wc+}B?}HOB0Uw7R3ML=O1boiw@;be`|Qi$+>jj=Q~~7mzDSzG@0KI0g1#1q7kPnq+q@*zAiCb|Hj%v? zDpD-|8lJV)Na)w|@%p#fb`KP@VhYk0=l-!ibpNgyp+clmBT8qZUx{WqXj6YUB=4{% z*HyMIhnbE}59_kvq4o&`iWdwe>&bOi#~ipK5h+IUG1o?&ssA)k3~m?KMwV8bX@g?A zasUVZf4Y#Y>B&Bu0?3P~vXDSRg^V6Gtegdq=<`a8s2IqZR?Yx~r?5@cN&VQHq#}mK z;YX;{;67#9AWs$a+9hpCxwNUO>zTAI=`L-mvq9ZpgSyK;CDcy=|Ju{nTHbi(Pe?!P zwF)3Jmc>gaSK*k~Cqr6Ob{{!EFsjg)zquCH!M{Bk)*;*7#@hDC6Ylb@3uNSzv^98>%Plat@zOR` z%2D{3k<#9-Uv2;WS^E@f?VH=w6#EovV}recdZ)p|19hRn9|!8E1|JU8V+NlJ)ISZr z`D;G@IR@w1XF2|NS>e4gd6pGE8r;ij0p)e3jU;XN^VtQF3PNeWntw3x=dyUZxD3^ge5ZDwrxo|{2zM#4If z#;Z(`)*rK8R0jN4cZUMFr&+GJ!;&V2+LzkPt96es{3rV?1t~CW6=ZP#Y2z*hDLi4M z3WA@G1u4ujcThpROyvF%cj!gw4|O2m5E~n;KPx0RtUw}> z)=U>mCV#oDC1FU#z(gTw4M+@r1<&}k5K2q{`Kk0jZ(F}}We zw8G$R-4F`kfUna4@cd|Lxrv`v$L^Z+Z zxmW?jgrrZxP0KB40JtQwATU-XH8HASKm!<1*dqtnBlk56k%~ZUOIHbuZHX8VJBn>8 zSjzy`LSzut0x_Cu0~*K;XaECZqmsse*p!S6h-p=uS$2P)rZTdprCEzmXo5sQD4dTp zKqz7(Nq|u3=_c3oApS-IAX4}n+rLmKlg(c!lseABtWbC!8^2I!i#=W_w8aiDRH`kZ zM%v03MGp9V!@qRy^vPg0Q#p$OhiqS!`zql1(e?|z+{Fsux1Fj3e;m~W|Jub0;B-$@ z>%hH?Qj-ABaI*@SM6INWvltB8w+q(M18z z^O^-PM6Ehe>kgNy1Ih3uGyqBGrAr{0kLU-8W9uluc(ybKBE z3`~rZ4uJTh)C7Js%CNvBQ!;~*-1RH&n$ufgTvUD@dI}gHl|wo3>d3>uHv|s@uH}AG z1HLlyFz}`>RsaW`ssT@kYJ!JctN<=|ss?;4stNv!ixt4_JTa&N-)5Aq33#T96~N2g z>1sfnPHU!KryOpF6Nz$x>?$e-Ug2(613nSC9XPmMEqA*bZnwR;g?0cA-c!SSKJMOA z068USO)v*!nE?5PW*%?I)$j&Go0NEKu3dqhVQb3$dq=5LE zb_pgm5HTPQrD7v_RMn!N8=cU=ER(!=b@sT*a~o$kVqja6(mv4wf?2?}Bx}ebwOL98 zL!Aqlg=$MuBKoN$m;_KH&l=aF#G*=m0Ax``@SJhkxkK0wj`Kz42%;T6Mx`iX^XJ#*AxKyD8p2UE8U`mJz!>4?o+vlb*BzyJrXjg7PYB6a)tm6huJ;1mVRF zD$1gQ8$?Ax6l4(*R2JD61q2L=h@z11oZIJjs=lf_olYQbZ}Lw+_sOYSRcEVHb#M1H z$z0FaHc(^_+%+p3g*|%L>@-c-=iXkH&(_@4S2jFeWDnl8$rU~y`~OhLXD992wDe-AQ2o%)7jxRu#!JqMPDq$auB&-_zEkO zI5I0pyaM|dB;%p;g2W=M9tHV&8v_a~NVG`FP>^Y@aB!jyd2?Wa{*kG)Z+V3_pK$g- z`D80bPqj}~*Ilg#%24P+B01HBQ0U>EZh{7(aX_FL+_`~5Ex!*GKKopt(9_0lvj$ok z2o%n>PoS7Px-8kpl+67Sb1df0PFyxiOo1{&D5mfyAFpqzLburiTe?NB8Z)V4l|!?5 zm~!bLlw%b5mvX2L_fihMF*M~;=VENkU)*6&`y($1)`2SLU#Q&F$B>ultKk@&idW!!q)mQv~9q8@aJ6m%~MbENGyEJSAfoMby z!BdBb&f@V0q0(s!mCjbEbdo})a}z2ZXKE&OmvmIhrDjns9hY+Hz?4fzrd&ES<^H3_ zW(NZt6v!5EYg<4#0~3mEGbNQ!*(B{oJTej+x@ay@#>m)5Ii86ctbGtju zy8DiO>hJb5@U6qaL8=rEcR5U#-6D|aDIT5kbTp_uJ8UoH=(4jX{nV<`D@EzAeXK)N zr0pO66E7U_|3^LPCpbCsF9y%*%b|Zkrt5D(j%3YXy77zr!8WEV-i5)}ci zLXzDEwkk-h#YUhYu>=XVAW2=UrUjYise(iotfvLJxEX3TOMO$hbbiXE(^D>;opR~q zluPHPTsk%7(wQljPE5J~EAuKjv&IjHJi}J;LeAkNdvjvK8L3csAodZ8dJGkpr2TvZ zwR{A%d<13BN%9fY@)2YOYL^|vSN%Y~!`Y=ylHaJqL8doa)kZSIKJ|4%6h6xz3(ZQK zZDZow`$Q^0<|bRLONLW56=Zs|Rgy8-`-2RL8_GU|kp)+1q&<}EMz*wbUe0(s^On3- zCl=n%`Z~Zq<$xPV_k|8pXDL<8+w3NLg_{AnnM^mmRfz_E+}R^vo_vr-Wh3@a4v-^k zpr_fV?2@M0#*yQ*9xn?9fTZ(Cnx*4J-z{a|1EsI9M9Oxb2STJIvCD#CmJpIsLE?*H zi4;i|5sttL$#lgi$aKjlNY)GvZ3;3Cmk%d8;+O&jp$$2v$hD9iQxHl#=cPY~cP^@FrY!p1}=&PmrM_+O7lB&G%<@(@&j4`9srrcq&kNMk1~+jn*U>Vn zl`ZOuHnF{Yg4roWKEZy5zKM^smXEWaaqi)Rs^M9y_@MfMVVt$8HkjRfP+4TAgVOAQ z+Cx;-Pc|E}Q?FAEgTF)dKU-9~{T?%otA;_khHBJR!%6mfTT zpoqI)1&X-C6GYWOoI(`_4&gbXqu>utDrJR7j&BAE5hg0R1=H_d{rltuEe(OIV`eby5oD zMyz7Qy*&h~EHY6chY^<-a=8(!xe>F{d#=?8)C{HPk5jG6Tgys2O=8CyrtZ-16<%OB z`@VfD2fo3%o+kJ)=X#sqRV)c=AK+Ix*V_bd;9O4=yt8w?P4NEC$@ixWpWs|?6MTVl zJx%a+&h<9Ik2;r^OFCwJ^j>pY<-jCM)eDYG`J-}RDjSspdubzbU}_tc15>u>{lL^M zDhH-;Q8_S`i^_pAk*T_^%Py_rumc;c)v@xo;VMHsUrm z-`h3vNARA;$-)Pu9Fd}ymkS9x9&s$8n_kC|FOZ=a*O=B{QMoNAv!on~-;peC6%h;@;= z)~NgJQ>e{M2ix1HP-hwZa-g0wIK@>l7q{QROP0A*`$q=~r@uT<`23@R!j)%vRXrC^ z9u5?a{MA6E%1X--RVbdazKvZuFjkks_?=BIf(!TtY;n0F^#QrxUY z2xgNffZQJNFU zttWJp=R~q=LYC-+-D*NJ&2+-PV?vhdgxz~Wmg|IFcS1+WP9)zpp`&akk}sLiQMwb! z-6v%EPS{;0EOqs=e8aJP!=cGAPk5beIKFH3EJdu|t8C+Vs2%B@79Eq0vyB_)N!pf$ zkB1P-vA9ucDVLTe%B96-KDL=9W1HE`$2PN>k8Nhj*k+cDZDz^XW-fMYa_W<+O{jEa zLZt%}D%F`#s4O~hLu1jw`{ET=b_&p2qOjf)h4q#wtZX;lTcWUhXPX=I-^bBXn~d(t z4gRXk+2{47`oGPB=`Z#v@2tpQTiP!bOTD73yAzXmlUvE3C!UhtYV(rt{k!eMI1|#) zN_|tgvU3`S_U$Olc>wuH#N`?*4}G3NUKO43;M;LJU{PnMqT{3HV}nqZBJ%n7HS_uR zmCV1dWd3~~8Dai?&3yiSCDGDX5-okreExkUDW}hinlS&qlKJO9k)F<9Qb#&{p;GG$ zl^S2D)b>K9Qx__=yig_iE1kDUVfHAcVfFTp7x9Cu{a7M9U{BScM{B7bluH$%T&fA> zQdKCI>O#3x8Oo*FP%c%6a_A$3L2rp0gyY2!26=ML=igH@|Nq`JklQ8?m3u9Hg)}y= zJ58rGOQ(mmPvEE7t>P?^-s+-6rj@|6KhAKOojS(#SJ?r7?z!@Zfb4+%g6N<<_hvcj zN`|6|6pbyecEfWynAf(s=k}C%ZjbM?*zCtioqDw_spmQ=d+1Rf&ACp>BRtnhi1473 z_R$=4(s?vDVM5Dxm0J$rAku{tu1aj zKuIsufi&=Pos=&TxlYQf$6P1>-id~#fMs0mkmm74mOO*ZylJV-uPurH**-_8`%w?o zMOk<6weFBzHfE^4bgL$PA$B%Eg}0yOG&3zFMDQ(*M}5YzHD$V&3UtW zB@a77Exhzg$#Ok~eNY~CZW<4DpcxALZz-G)OF@*kJ_hDsUr!M z`jJZ6^RZ}o!Ha%v|0Pm5(GtJRNPd06i%_akjrLTh%B4zGF4d}Xsalmw^{QN|Smjd9 zDwnFZkTV6wixA2UAzJndMcL~TomDoup5)Qa@>G^BL~J%FGRi9FpW5mXWaec@MmyLd zwP*Xq3YTHgD(h|+>kgSQdPtQnRiCkUA--Ur@_n3&{cQ_gIG^nATlVvk%4v;c zAkm(_P9+qpAmJqx2Vz8*Q0e;zUcjFGCEH=Wf17E&D)3=EiSG?YBclb~+-hO60eEUiF?ExVA5#u4vsP`Y)c=Qz+?@r6`?ZdN8;4zYpEmdL` z;s*^zHb8?yC7#&DY|xzA0F{MN_2+uYY;e8l{+?ii1I-2u?f0G&27ruKY=HE^ru)N3 zwgG)bHYmx5ohga#+9-+cn3^hyIWYnGE+Tgd1J9H+-{y3;&u#V!zi7RG_*(mv*A)-D zy+wV{K7~r{mfvWAdv;yhYAx2j@n;C3>(>9toPk#u zRdm9|V@7IQ@Q-heI_9GLwic;^;O&en?#KnER6%S>)>RHn`YjrBK`vH7@MRV=g&?j_ ziBcf=FyjhAE>4dG!514R$^qh9+VM!fby?(F;2VQ)0VCgjx>L` z#F6F?cj!p-hf5r3{%|`-`m!0mFr8uSFG`(1%moghf?(`l2y(F$&M<$tLuZ&jj5Bm% zyvrlwfw7qQ0q~DExbM#&=Hg{uQti>P>84uj&-DDa$8y6-WEJkQB!=72ETX;!exq^n zCxWpNQ72_@n$Ly8Y&%C0mj;)JwX@K=mX>uKZ!}EamZk*T#r9u90dJ0S_O-uk`Bxlj zWl_~GfLIxIBrjBxs87D!1q|N4dzso$A&E*_=DxmrroC&ouX1G-R@wSVo|qby zLnGBWzql@xdf+>Zlf4X(@>*6;Amz1=4E!apkSaimCus>}{neJ>+d@kq3xKrT*4BVQ zUkfV0FF4fz{@5tJKloM`s{rv4tq5$p$`K=vHk68v&2J;m36WEB+ylU76w*gm6I$S_w%dl~Tc#>w4)W5SjmxQS6Z z4)D8NtO6{{0CVlQNt=S-?Wa){Ag6|+BOnKe+7iqzN`?z0?4>1;EtIwdZ|g@84In!# z6(dowf07P>os`)p+PSRW>UzUZMBJv9M|SocbI?Ta*`8yDzHX3s)Y}n|e~C`nHn9-9 zI106eh6y?OEn*;HrMDxlKIa8`KafN#Ez?NTmW0|K7HZ0Y_xA9s00}v{8;}x5Te7h3 z8pRs8VVs=16KV%U;rG9WZ)~%P*DhXSzD;<@NPs&qWt^kKththMp$)cn^jO@DEN60>?(n8hB;rj+zDz>*gS^EVN!3 zh0#uiXWQqfuHDnaK%FO%cSqC|Oe9J%4dj?Zn}R84MGROLs39r`iAqis^=>>A2y5aX zf%?@bP{BV8feIu#WgNh=Kph(eDwqXRekxMF^fQjjH6u}Cdhdt>AMbHqA@9CaujS}g0mH? z6S*Wlbu2g9!uoKu*n(f4vxTAe{9Mg9M}AE-h@8JJ2HT!%-BLh1WYRtXPQU zvHZlNjXTLhZWeLF^Jnb>yoWE36(F%9wg3_;+7kQ|Z&?EpKBKy30f`=M3Fb++*aArO zs2E{Wwu%xfDhJ-lPwZKk*P~Ec#X@PCeQG-}h3e?8gQkGr z<%@CyShljVOzQ2@=y|FNBo@S#fbBxz1T*d@>~n0_uzVx^ zzENEN#f@JDvi|8n82dZDM5&T%*|~_;fK({ja-`%~=J#a|UFN;<$iSp2c{k(UQ6*1O z`Z5J%){dMX%nC1(caCau_5Mf_OhmLKiHUgY4W?3P zNpkf|uMv8hV8Ws$$rS-2>|LWgT#k*30x-v3ElI9O=E90LxuUdh^+l4WpjYjIiM*C1 zSJd>ayK+UWX?rl?(`ruyeJ?8f!EEY9@;9TJTv2K0J;Br!ElIAZEL0LqY0;A8ijBNV zf(ZhV6ffcG{HSUN6B8{-f}KL7)e~2Qy|Cg@ToLBNicPs{7xcWnvaDh)ep#!NSc>I4 ziKtk|-h&YJ<5AI(X8xo~EOfOl72J&@ipk3_T z7uKP_b~m{qdZd@fyE|Q-4(#r9bvnM=D>hHZjrl~UTj zquaOhtdzo@+g-M9Uf7TDhyBk8=? z%4qpJ=0J|!BI(m@&vvfw-Lk(iMqgW5U$P4X(!Cr*(Jg%lmESx28+_@#M|T}KF1`8a zu7k(rckj>do_!Z*f{l2Mpr!8nT7P#LilYtCjOir#nI0xcd2WbKZm4>R2#={Cqbl)gBsl%Tr8p2%_BC=}gN7YN0@IWH}V zM()i#BteYhPK;KbP;;j+%FG)-Ynr$)XymW=w!D$Ddz>Hl3;@x-Xas4Vv|c*0M(FDt z>q|Tdh`Wf*IF}7d8e#);upJDD6tfL_8%np@BE=LKuTbbDXm^OAQ}c>c>Nx4pH6<{1 zR5x1Ah4K#jxqDDdW`qMwAx8uw9Bpn1#o4Q*gj_+@JdCR7jDr(th|Z327q6x#gd&xz zv6|1SnyazOM1vZ$yz~*9AgX&YJb)Tntj27v@rOSZATMNy6p&I{29eMC#dDoroAZvr zxIMNiQug2D1{nZy+A9%;G#>lOkt2-0Hn+ZHYCzs%kP?T-gCWBFWdNRVh!hUQ6LFz% zAOOeIe#%oRfW= z6(H|Sh`E6{hx7>iclQ&%h5K83Sxq8~BnyT4#B4kP;u*M5Y#(p%M;2A~iPw4UUZsX+ z6C(}NJ&aK4`trC9YMj5?QvveUk7O$(F`ZHsne6sWrjftqOu0p6Tit0J0g2r0Hu-e^8RuRP=>zWFElwYI@OUOShVB zz-T}V0jAD8r5elUmt`AX=Q`cppyXSd**7iUW)GlvP*wa@EiTTm|I{N0@MX^RHo-g$ z8r{|BNAw&(6gT98^9L0K^DIs~0ds0EFEpgy{%1>k@#D)>rfOAZ{FX&3!&ieZ_kDP# zn^dIi{9swh$hqpoS@wq}7dP}y#wGVVjz3(P-tS6VGw<@XbM^xUp9~c6lXthiPat30 zJ=Nfsoth2&?maGbkHJ;%b*k6kHv;ubgHHtN&jz0j)P480?(s+altCPLe~UWJK7~5Z z;MW56n8BAl;DeZKaIHYiH29`Kz1`rPK<#7jz(5^g@UwwB-{98+b&tVA9`r#RWAOMu zoni2tKwWC^hCtn6@S#9GWpL6%e*2M3{gm5v03%-DM$A$t4sxuCXsFWcCbO<`So*bQ zFy$~cgHmp!QQ=~8vISi3ZT|({7W)nOc=x3bbb;}y;#;L$#100=(PRw=#y$sL&;9TN zU10pN=!1(+ob&g0wW3NL82prRG7jL7htVMLexGVj^D`DM%tY$qg+?ukB8go2dQW|W zjP;B_0WbA=%EKPRBu^bKcn!~*gO?h-AyCg6e2Jw>+4xKZlVl~ie%Ah*Br7ujl4P~d zr%h}X%X!L?aX%e#-!l9o`;;DlH#jv2yu+zF$#g5rdfEYadryiLAcA**{>i%vXkT;yqQGdvh^;P(gb177RYAP`Se{SYj;oN~Bb znG@X~IacaK+BWqf=A(^4b=zu&1TeMUR=D}NNEckj^(&GFY<_Xsb&SwD-|5#A)|CGVDgLPnknGv z<}5N4AUQ{yg7GgA%iXJrd*M>r5{yepONunIkSHBU%F&i!a*nk8t7W1tPXz}~1Wz<> zta{GawI^~-s*vVDQib*c#)%69ae+6h;7Ik;yvU2eANPz<0g@Ty;Q(;^$T`6*U!oIy z_?*aJ!FZyGkzVjV9V>WEcd$z8h$@C3HiB5{hbo2}ekzEyTLke!ZHgOiZtkTVcwcw9 z3M(BxrD9;5N)!hq7pWMSErVzTNPd!*K>SQwg7GtH37qEsC2y`9-qb!t4ER4zHGnL0 zA_ZhglVJdHL>&egN0gSpPLk+Jk^6zq3GN5P=VWsaWVfh;D03n_rfiKWv+zaAU{IK~&tA>htYq5;3dSHTJp zzmd~M+=j(ahYuzPi5Q+la#1lbnMA~ZojTm>+_{E;c#rk~#(ks*;3|=!!C`@_0P!fj z8yJ@ohXax|R1CbKyTT9<^Q#z`g+|5(Y-i&&%o^QpmAS;wuq$KkNGlbKh7JJBT@;lT zVDvAq7M(oG_cjkll3>z+NPcRRC;OA4L;$96Xx)=5Ow?-6)dN12ejtWx337$$bV6Wk z*XoEXOx0@7RlFqvlM7nyxgx!5PheuVbx*DcRh0yj&s+E83WK-WbJfoL90@I{A>;Q& zsUI<+juVVIV|i9^45{*9s=`=4HEsNV?d*n4VtF`hqkV(1Oe_zFg;XAlePVey?4=DbuEejio7mQx3ZLqNy6v<1c`SAia6ZUu0+J+$363La;DyiuG1eZ7z!3EPw(rCS% z9f>$;yz*MvMpD@CPs?gHVSg|!ThfKSVp^7Wh5gaAW;@Sddm)l5tkvX-Wnb8FYk3hs zx)yf&TAsY|BVpHGtH~9f6nhmlo=842t;rSHUD*4ld9KIXguQcGlPml!_B}F$NKRcV z+o1@1+q7mUzPOq#`|I0h^z4okfU$nIGXNx$M$&ZltgmX>aW#Fd5lRgpM<;S*u+SDR ziUgt3gdr4zVo>{GPE(`YE_ zDA{S|^UQYmB1JAHvV}q$U-31tnvb_ikiE*SSDk5a^FUD}&k7V(%zFZbdoK(W{&$a? zyNZT_{o*i#5a z!nwtbTf?ZVYa*2f*SAeGzwm8C1;`nicyF$mDnczYpL7Y{|06GnE=a{NU`n& z%~VkXa~G+6HkqqlXS29F*qc`%xZ#Pe*8w1pbjjnBj-RCPP=&Ed?n;L$_ew`alIA2r z?6%kgQ0f*54GI)`5{k@#PJ~K3oo3Fxvpe~0;N!pJsdx4D54YgGk2v)QgI7G})XxoG z`nXf~8{Fgxr?xTpu0Xxd;3Z=BC3e;~5-W#aj8(bKuXALe2)XINojb~l^ z6wUM)d~2X;1`iL^u?9~F)M*AU3)EEx*Inq-9!c?gy5a|bUv#RD;=kpJucP>tALZWl zH4LsFs9g;1AE=`ZelAd5zi-{+0Q(fLJjvjVfm+q;Lb%eoh1PZr##Hj(`25!W9k3l?2Mvo`qK0@ITc!5yZ^%rij`mYVH=oZW3lTg7- zk}rXOa*Nfl*kKkjy55>9_i~liQ24QdLd#QKe>D`oZJ=^3_vc!!q20q=f3-6Vel<|J zmiy5%s+G~BH$p}z+&d^Mt0_`t=@!Vf<%y+%wnAcQ;NNIXj@E&1H*M+7z#;!M&<*aU zV&Kbt+6|`ta&sRQ18?Ep)xfLv4;0>YMxb!CuLO!b_3J>9r+ynK-16x_q3IRfEgL9( zgFum|`U8bO4+n}ob#kD{Q$Gk4hQ#|t*FbEm+5xZY!I6C>4SQoqZH6V+i_8Ybd}F%C zt>d=*yNyg6gXy~vIy%i97Njkf@Tf7`OV9J74w}Uh)w% zZn2(8arzftz$^F=vWPBmW6dJTzokw`C_YL(C25AqFHb3HbhNQWXEi6DB2`;%iz>E= z%1~_af3yrG_(Wg1EwU}aI##)`HWx3PC$ZD@5vzFqWNW!@18G39s%eHbfNE7aFlDQ@ z1yjPR9GF^G<-pXnDhH;(RXH%luF8RNAC<#@D9BU}Oew5#;2Wd03{2&wa$rg~y&ssO zS>?bK&?*Neuc#c(Ox>&;m?}@(f+?m|4oqRKa$t%el_NSR`ji7x1!-F_Wsu5&se@Dw zOo^j%U}_wd15>`J9GJ>P<-oYH%B6m+THoWVa8yxyo%KOjbt)5R4P+5Q++rx+3yU0Dl!@Ahn<(U z{fXtWm2Lm5+)jo+8F9B8j!lb6F{if0e7`9%Bk4fpFdreU9Ht84Ex*5IrXnm=4!skC z%CVZOwdUu>ovIu5!fj61iS)WN!txPGY^_d)a+n1Saib0CnG^HabDb! z3zRM7`tF6-N3FqlW+BK0=|afvEO!XGp*t~2M9B4;T*RIY#>0z#xQJ5^7@sKm=Hk#O zR={kPi}7%Q`v^Is$;CIL)?lKm5aeQM(;nWZ_5)8Kg>{X&g)f|u>f&@orL{PR#5p-F ziTAOcIBP85iG#-SI4! z;czvT2jf(+JRHuY@?d-`mWO*W{f*40FDQ&(=BZD5`Nz1D+*j?ywWRTO<2y=zBDrXs z7pr7ERWF!?Cz3mi_YxL|5_ZD)j`E*Kt~$P%CO~0dJwD5T!tORcOM${ZJFcS~D3U9W zZ+7C8BDuzRFRpRH*d0lHBH2H_$rTPM>?Y$o%7Y@g+4!ZdIhJoL<=6GC^r!6Ctqqv1 zq*@NlRzT&zaoq_f@v9t(p6!8hV78Ll2be8`%7Lk3R1Qq>qH=iz|95OF-tn4hRw?ttf*n%<3f~f55Bb;*t zW9H`^n7#p0(aNnN%+IP31Vn;UrNxPHf7;oYbpwsmm%yD&^scmq$iE|FR{b?38ioqbi-hq>j}5LZ#LhDxJJgsqKX# zSuu5?Qp*dKPFyJL9z8F@?9uaPtiEJfE}gS3&*`LNm}c!kZlX}GjUPCDXj%}K}NvUS#p@|CuEHFtK^dCP7-wLc0#53QmEAFgi3u*sJEN<<8nf!9w$`la6+a2CRCba zg(An|Z9?H}FUImh(c1pyqQ$#oZ^`4~@n%}OZ;8V4C**QZ#oxHmhtvmczZY6)zIQyFrGpwgK*{6K7XyW~? zpJL_2ep`PwJpklsQY1ae-nxCYzkQp14~f1=6|&x^1{5l_pHS(1g-SIpRBAk-uwC>< zGqZ|bOlIio`p~ntFc~^((qGT#PAEg(wC7Gi3E4N3K5j23pagX%-r(vp@5H1eHL z1RAMADCWxwCKMVc*$G9Uk?Vva(3beyF3i3C_gI)S8B%&&oPKq=;O1yizsPD@3);(; zi?3#HFqgfVTpm058^>jD7ni+BT=sak>``vn+rZ_^PyUFu>~U<_+q>mU7ut-MF4T!( z%9gI>`dl{p6TGB2oZ|3K(ZBz zw6K=1zxC7wMT(Or-f9$zvk?yVg~HcZt%btXSgnOhb3pECy`|qNNRy$a^;BQVp)fL} za;e6YLuI5*ltXXvixjEiRE|s>7i?%VL~dvA$>;i9o(VO> z<@)UK#pxuD%CaS2=_S@i%O*1Q^IL3%`h$IruxHI(HQz?_J!2BU7~Qj`{he(6H0?90 zMtGNJeShb=pX17(c{!6UvD`2!Q1TR3Ry_;q=jPd6)QsQSJcmHsz`$7{#|Fxxx%8`9jCCgN-kK?Vj;5 zin0;K^2>5uGV}ANHyP!iC%b`mgFMJoDUHvV-sFm53VZhS%%{tgiDQoOZX0j6L^{_K zY6W<{Q<-zgF9hI7TY6q>>|~IEl`L5K23}!G}Vu1J87-3cS~;25_NKl5ox+=HivM@<|6kSCh)& z84H8efMk{8eq2lqDF(QaQ&nJ;h=3%d;%=yZzrVNCRFGVpZ=?+Qtberr{|5Uk^PraFM$K2^SRu6D=YJBnngvOc00|5LZ&M)RUCM zkq86jz)yLFQUl^|Du%nAXhEVJm{^gK0P#u{8_6l3j+`=0_5WWi;fn>y#h#I4re0VG zmib|s)8S!1i9D>GJK-BTwI|JuZnErIaE5UX<;uJQ7r>q>_bJPAof@*tLY=67-cunT zfH8q6?@V8MH}|d592EbaNbz7YLechvmJ3euoG=GlG$I{?(SOmFi`W>BtxPEdN81HC zK(*JY)vzGeD{ja|Y)UY(-x4(Y64lx>7@HP?T*L+jZxWWXGl#j@%}Bi?7>_9K$i=dD zkEbH{0OKC=#~FZO1*zsMi0`&9iu?tPzsSwf*p*E=-f~3bEnpl(S^^)8#2kC&JoI9C z%FSLd4FT~N87~lbQTu^$9T_hWXDM?W5o_l*&v;=p1e|P6BjW(#PjWNhvi6t*{~Qtu zIJieWcaJ*hWMSkU;NTwh+&${J$BPmAvSI1WdiBn%SI2tGTH(Z?IuST1d@xt|APPsh z+A`PfU_0$Dt4T35_H8<}vZXpbn^Cz=>zt9QkY7F-JQsYIak9wtIC1*^F3_^h}z_Cz?-6$V79;_24n-Q9e@{k z2UQ@OVinuS;x%?7e1d2UCs4pII5nG+<7uOG7~l=Ocsz0ncqijz?m%it zZORhD{y;hKCw+~m0Ka6EisgIkDn-d9QT+jCYas&xmSuq_>`-5O06*gg{S{!?ombh5 z?CSfD3h+#$^k!hTDPkBP+Y}W8QxMB=*`0J!51$_;0r1a45&$lAY7lr*6!3Q#W``|{ z3vl~ruXBvy&qW;g%bpl2!26sU1eWEB=dDs#ZER&BTo$)%;$?8Vbri~jgfbafdmxmF zRpr10tMmY*gqPoS2gad%qlNGj_9@SHCxSWflBPi7Ry!q1!{&XESYu&VG4L)PSA)Rw zJpANEY{OJ<(kXD2XhYv?I1b5=8^ka1X;UykCt?nxSUcA6 z@ev39rgQVAfPZG3+zv=gYOiTfDo0fEWKNoge5sM_?bPy)E-x{ zXxuys-VYl-)wy{S!Gx@o#lRJOX|4fZ5d}1Onu}F{I~pbXvh#tL*7$*r7$kt920^Fjcj{kMUffpJlcLTo4 zj|%*W91oWZH?o{W(IS%va)K}808+G8E2##Mj4mAj z_l`0-_+U@?6(C7oCIBSKYoA~?d@?lP*k}zP_p{;CrsRHdymDZYyo?t}DOU7qO9Zu8 z;n5rd9qfDj3Xr29Z3|}2kP!oKj7qw8yC+`C(A%A3YXob?=&pGa!7LUs3)YITE(`%# zAM|eEFMFL=1F~eu&48hPtFTnCJm}3XveW0Qqf_XSHg*f6rDDLAgZ+J3kRL(Lmx?JY z73bRjjp~|pnZdG}t1L^Ag><;!ms&!Q+mVsVwohe2d6}0)JxwsBk-h@=6uTb}!C7p1 z2tgf5Co!mU`LmE&#Nd`ubb%Wox(Fp=MejzPR2C!bO;nD6z>$^1gT3nMssPJ2AXj;@ zBfsBj_;+6H_}1cZ_reMgm(x!1Is8mHe65px#Jv~;mXm<2%hc%R{^pd z7L(wj({HF^}sykljbo2Nz|*-brBN#@Z)- zjE^aYla+bTaO6E;yh7d_dT3OZorV4FD6f&o$t{*E{6)UIlX{B?{(h8id2tvWCK$gF z$={92DjsWZ4i^_aU=q7X%J8|u&9o;lekPI+kMifBAGbnESeYnS_@A~1Wk6?s-bX1coqC!~F z3s=O4u#b$&qD5Gl7vb{DsI&u9;)$f#g{zgKwGm9PiR6Q${181Z1Hl|Iv?RGI3rtqj zmLyjcfNE7RVcU}AiXatM=E)TyE3D|675ZNpwDFsYX<-%rADbLPHvYdfX5;@O>l3YU z=VN&| zd|&0k#6c|2BPAk0<-z!WEDzT%CSv(^k%70z^8XG#FVQz~M%hBuGs71ucJLzm<{3?{ z@P1*pol&yE7)V1w1h1OW>GJi?8D-1Y52SsYpx`W5dRjES)8*@2)*Ujj3`MP*U zvt;=iJ;P582pbvIoEe=iU$q&2!oZG7+P`u}lPiKt*wtqEPK)r0LycujBsUPPCRLuW zubGk6dBUDMqe-d9;wEf!M%hyLkr}?!agZUhpPA9*Dp~+PJ;N73_JSgN@QiF{DC_|< zI$ai@o8IZN_^auiE{nHLZ?;PT9H7fMpP25)=_CPRAD-UiiUm^b0%my>$%m$U#mn+2 z?0z%K7R#+>bhKDf&4#m#-jZkUy{UraZ%LJ&{}RDCi%p((>hm5ji(XN- z;|^r}f=my5uI}vVQMww-)-b&jr_a$hNqEq;k)6nvyaznqPPW&yPx%%ge?J=q_4`T0 z0FVVGlIHmAWZ%qW-x8y*iPo2H3=Qt;)F4ml7`#lCk??RxD7wSXN)(cIr+*on{+O=( zE$DIFok_{2gu92yWZ!n=dst7{v4N=K==)kf_yaZMld9&Esn$vXo@Z1P-M z&V32VeO=SlGy+8`b&o&WIMG1I%4eLM}Q*tgkS9}7zS>%A@KWW3wiE>^zt34F6r8r3FE z_g}CxYmpwQFO>Q((J$jfH=?G+jZ@PBV@6M-yN1W1AhaRrfV&4RWa(hCxza}VDLOpR z(gDTXsGxBmM-q`Vr?;1ltnsujIhm&qZYWfKqgkm+(i@HLI(S@ur~dp-+4PAdo{KLc=HtxPvUxVXPXvQpV!twoF3xoI z3;-FNm=9_CI>vR9<#qZ(5i&yH66=KSf(b^P8hvPb1~c8!U5AWgo=i&8Gj|V@$@0@W z_B^Z4J|jP-x+7SAM3AH`q95 z+ovcW$lG>W7u)#4I0qR4Z*Peda3dc<1-PkGgFuq6^q7w`+jQ(|m+kX`a%&eL??6?Ofcfq=uRCH%yf18z&x3hI3#xulgS+NX;WDI zY=&hjem29h$Oc09)@5(du%5-waMH6WZOg+GmU-oXD*pYQ%y}tyqw$84EJCV?m~dEXdT71-W=r%8yuC z#tAMeKVocOl?yJ~TjHX<&2)Bp2$N1uxpZ#IrBhQbotbj!#FSh7yuzdWFt7Z3zv}K- z60<3n&nvw9MLno;`Mh4-&|_@4R#|us*hvsFW7UnvuATiD)l{pix3bUiExEFv)6C7E zXNA$$EiN*q>)`wcsdz~wPKmrt5!;2am)U^t%jw*6-zv93?nfcjaVV_!OP_O=={KK4 zufL2L=Fr>B=Mdr}%%Su6$mbAZAIY)4LJor+X^EmB zx%iydQ~f}cQpll|BmBIwABeFFIU?@HAO}QwgTu2#!}+6R3D!+&;PPVKz8hw`gvJ*CtC~<04sJKRQAilyd4)jD7;1% zYoAdE59(>A-y>cY$uQMUKHffm?JbPAubGdxuVlP^B_7{b;_-bY9^Y5u@%hjCGu{>L zO~4|Ix!BC#80-gPheD3``F;>5IWBmyPxb*o6i_ryH6U^r?D3G#fJ9KyG))5qndX6l zOcOytrkS817jMYk5<|-0#j&vl$LlRIa-Jm0G_-B}Yw18$4%ar&67A zqd8++BAWEUNBN!V-05zkR1ExpbEj+r{2 zo3!2fNjpil3x?B%1(~)SWi8(rSrYsv=Cj7&pwZr-_9=V@6Y*e$nt{!H__V zr($JR!$fQl|y!w6n*PzQpynp%d;Xzr~y1DGQ=!k~^&^calGgk>9L8zgcz!x{j%F zOZURc1*XL-?Ni)5oeb_Ce@jd5Y2O7hJ}_l`1ee(!32?`nSU>_q=AGxRQ= zqAJ{bOi%##u8*vMyjAvGHx-fRy4eZOMmCNxp4n-$lHX^3G?|5D-+Wyt$W*r_ExSDw zv7EH*&O))I<+QSv)3TQ7gyi|rv~*mlOvxJ#xk#q*CrmGYv`A$n>|8BC+QZpth+3w{>dvb_VA-mBo2Ucl5k0y5rv0+4#k& zuI*wnYp=p&W&?+eD&!uwi+=>USJ=$DeTK7v8yZzKMH6oea==O~ml}=nE(={;Z#uxd zvU+T6V+l6Q78I1l%%$9Ba&64Kr>X3IS6u}yPH>fEeSJS`l`XOVVz{>%39_#THi*Cr;m{LW|oR&d2h2) zu`KURO~lI7IM!sCT4yqO-b?Q@Lf+fc-0%nPjJ*I74Pd3Uwb4Sq3DKQ|Z#mA$dUprY9Umuz-Sf${6Ua3ve? z9X1Z-(nR)E(+0hc={oG%E-rp#|5>C;F79ys)#)ruFgpN2kMDHlRem7krp`cwO7Hy+yXX7tvlsyFZtxDXB;K`ZD+tEfr&Q8g z8r;dL>YEMjAE<*2ej!lln7H?5E;0bz!l{1lJ>b;9I}E-%P;_@>piVG&MxfFW>}UUV zpo>&KZjja`8#l%s=>+(Kb;6BMKw+m`1+!7XyL{xcfoP>@n(JjYGdn9Z1%BSBQukzN zFL;hP5YrMB&$f=4mQY6-^)Vl27T1^9e_iV$vw=HKB6$zK#o%6nI>_KTuW+d=3_cvF zKNwucp76^XXqOngG*HhNT=kWHuU8t}Hc%fmcu}CfZ}8?o-D&WlK>gX^vw>P+jaE-9 z+oz1{l?Jy8)Gh|!7pM;zJT*|~7`!=9_ZxgTP=7Qy{#8E5)eLSCs2vTS5vZ>iyd+Rp z8oWJFj~M)GpwdXi)Hk`Q2Y~0T#-JLxsT-Jj>SUMN$l!H>nrEi|f?L0VLu}}#ZeaZ% z1`6x%;pS=VZSdegVf}9f3hQHXSu`->9j^EWwwUdjX`EuP87NeGU!Zc8X75C!(l=Nz z=mBV|K;_UN)=@4s&t+y7Y$9h5z~$yyI`g1XGMcQsz~#y9zbm<6>Npa?M5H_wICGc_ zmNE@RFkvc7C$L?_-ft1hE%gl#Ft;p^{`|2c<6mK7E5~ZPeGIStvcQ2iG){&J{FqZU z;KfnPi7#*6<)`+kJ%E2R`Y}<01b@bx)_`A##K2+I zsR3DibPC{Yd?l&@D@Lir9P{u<3@@a*(gEXz zxSm+>IP=0YB4;i0LR@Z($ZvA@s^e+rMPig#vCC0T<5MyTV3{v%68Q+_E&ihu1LG_* zF-l&XMJV7c(cRJlP46~RRkcgxOW*K|cvM5UQx!P<{?X|YQT7iGzFHK98+r3bn#OT`;tSH17lR_ z0@%qaaeFj*@Sl956(9j6o5XhUM4HusfkVn|0GHj|-M8_QXjj{bI?4uETeZbT}MQbkN6${MDRS0r%xUE_8{%qMY z#*)TzCT$lsxgfu&$-#Hp{fbVwz#>9E+2mrgDBXaG=As)e_KO6;)L3ecl?M|6u{<1+pz>g%B9@0EAXFYqJjC*F#D&U(35!@Bj_^=< zFo6)u!x0cF4<;UBdAMZ}Bl1&R8&B$JRS?N%SMO+95XptBXX}En&#&%f0gHjo9gN?L zfe+k?fw->?DLla`dE*))JANHp$CoLPd1~W;-X6lO{E}B5;I# z*`$uv7?FI*BtJ+XXtXCV!6K5YPHJ*RxTqwUg+(OSnbhQp;1PEFNgb^-BKeQiJ6dR7 z%wxXC?Z~jpb{6vPZsmd2o4%|ED|jh003;M5X`*6UkWP08^c5X-Q{gXvXvb=Cv+u43 z@$Y}DhjthdhtVIIz*BGwDSC5v$lkD?VlKB~?t0VBi8c++1SGdcu16OAM37EhkG`S@ zSGXPm_PsHJ|0$Q1qqA0nbG3^TgxsBugO^+)@fp!UqfSDR_?2qvCm+2tlX zce%?x<>?}jf>%t8G2wFL#H`_5Nrsx1yboMb5<9e4{@Y7ywe= zM$(kE3xjkzYWj+@3$9m^U4l0@a&K&xa8QJ#C0s9hYXR5$mb+dfcfEi1`v_;S=NV?li-JA(vs6O;_q;Ei13>mqVo#*mHmxzTJ?X0?m3+ZcibV0Fd3I@& zN`mnQvD7~=Nw9VOm%b#FMh#lVq8jU%61$0SAf1kyzDfd{2UAgC z^T0`{|G>chnyX!RXg8Ie8x!N-mpKhkTAU842J>OTY0U!qa3hifrYSmOBP1R;9sZ=~6vISn)VLqB4JTrZgowy-CFyV<8| z)qV?+$M&BI#Wj$JGm$h$)Yk;*bky_}g&B#EEmp@dwbZpTPLGzQM-FGAH&;g*I%-m< zM?WY-6rL*~Q+VAJ&BMLXT^nZ)FO?&;(2H_Rnj>xH()lRIgea+$OJ|ghL%zj6e>fXS zi%rMUV$;#I*mOKCHXTumO~-Vw>E<;1)blj(jn4Hp!DIcAYF`ul7UyQV4u9|OtjuhJ z7dhA01oI%Z>?e@W*9kt3o+kJdA%#03ULy0er-%3UCd7N?ZqS3{t1a+X}$ot@+yuXmCdxm0B0f zh~-wm3w`i){4dz2rAeL`Z+-xt%SI8aE; zd6+C|!Xy4icg<{qi6Kq=sEBY^IWY0AKL`XyGwqUKxPLG~XcsiOon;E0I~bM91N6f@ zJoonO(x0kVNXN(Z)bJAQ3#` z#7rGTGE0r>8%$hE{$h<`6_NA~d_$gXaS~|=#7Cqd5N(T8svt7>wQi)+cUPy{k`!vd zIyWWB%Zrsfw%H$O_9{ITwfx(RfwS&Q30ySW8 zk3j8j@Kb?0%is?Kb%VhN1NDT#wbpk{^cvhOP}>^ZJy7p5cw(SVH~4U%o-x?f?YEz3 zuscwj8+=QkQrE)NQ{B`9z^A8j??!Iw2Bv=hYh7yC;49twjcW}4DNs1Xk#7A4)_;KgJc`!1|b6A`Bx=cl|Z6#d(3c-{8VPq0%1LUn5s(_8l=)dV&Rm z=8#l@%ArB5qg-m9mCP*IM4sXRmz!tl%!5j!WsU5lloD-x1@2rA$K+ zOqfb_3Tzj#ER@_*t3NQeERX*DJ7SD~z_Nh0`;Os5)@QoK5C~CRq zYg%`Ch2?s^8+e-M{|fL3r)t3Mqbvvhs8UoW`eQ62LNFIxg}N%3J(LCkDn@WMY)OIEzrg z*IIq1Ez<%`xsj@>vm##tf5|v;OW+EgL#x2oMIQG_!#l>_Wq3FHl)C}Xcd81!IcnKs z{&>^0kl!~qN5k=SPVGF7WGaV%K$5981(Qrg3>f=mnnblJS(Gd(O;f)V3Kym7*OvHT zZFw}6Qk^K640m^w3E74{7ja z+;5rXf8-7__v2>D)7{E*-(eQr$391O&1I59z6Y91w0zJ;DpC|<7X*s2Pw;#?HytO5 z@`=cSz$7#Mju?1j&tgNsZyKd)pynYf=$u0Ta(fKU^$`1i?2LCxXv4xroymnDkcM zk&9PFYb%%pCxXwH7IYMM6n2Fm7x8KhX4NhPxnQ|grGZ(ui!pM+%H2{LSMfRyW<8hY z&n?m7zN9`Mf7PaJu}VEZmhU70V)=9n5dU8%;SkGr5*4w0Cy@}#uVT(f5X1q2x5x5u zc)iMlar#&u4(C^SFuotl!w~~24<-a+c{oC$7{7%GVG+y25fLg6CLm&YI08fE!Nf%@ z4@Z2cJeWX;<>3ejl?M|Xu{_)|S{DwT+|jxqf&IqG9W4wZxzXfoWf1mFlf5!vIncR- z@q3Y6f3okESr1ea%yJ--(tY z2NO0Tx#i@J7Md6Hq;E^xR8;I!-Us7rVyp)PUd#*t357_Ss5mf4ryB(NicY&J@|Qoi z!|m7d4b~w3y;-1e^?%)SJB*0K=zDZ{3T`1~Z|)A+dvyDm%N?1!-r?p%9}CU|B)3Mc zM;84}kWO8XzM^MWxE^~-+1ap{G~Y=YV|6Hl`9 ziRtz!M&pZLQ*Fz(p`Szy04aDQY3ke^gLGv^8LXhG1ofk9v1hL1%$^UM9seHe$rry^6nFJ?asbHwN$iO<+otyf>C~R|Rgy~n zNig0Zmip%<32O0w>3c#WX&H-ZtYb>-Cccr|EAx%j?96+8`;4r8 zh*|mQU~M3!ek4tu|Gz;x9W{NG#Cq_J2ENfg{M!^4!Ce}-OJ{-2mQ0caRxf$|2tA7w z8amJC+_>Lh^hVN1YCz>0*xU)lit%!VX2$!j8STbkJiaEz1a9|rasbG|ix>}SD(F84 z>2%ceRT9`do07E{$W;%*4Mn z)BY_tG0y#DsNI1aghVD@#pd*KpW8q>YWgaP&tT$q@fob%;abcTmN-5;2s37b<}}Rc z5B-P@a=m0WIME&gHtkcjYF`uM$^8TVO346_=QEKsN7R!?F2(693NsQRTda;_Y6CO% z64%N&JzAC?Ih=`JUQOMHp`#{sdh~-bMB%v-GKGKD6wUKJeUm@cf^wu5dQpx^a}uXq zIv?ej5G9pz>5S5Gw7$5Nj-PjSYOiaq`d~_;;u3z(r0~fE(Lj zWxWM%?oL-NfjaEI@}tZ>^^qyTo4c4h@Xk)vfpepl;K-?gAxq|OdFXJ_<3{eC9lABHgwpk9V0=dA4#a0v z42+#b4EG6%Ie%qLo8mwrG3Q~jqzRAs*ROwpi6Kq=sEBY^Iq+_#HvO6y7|paxg5mzb z1fgBfvYKg`4P+it)9RJ|gXe@%=ycrgYd4=ep^Vrl2`|BV!jFUA<; zDUWny>T6))Qt}sT46BHwci;&jL{o>6hN-_u!_-|wDpe2} zoHx7VEw8fISJRq9?u0KL?ru@zB$N;<>91l(ar^p_+-%?~8}O~5`t}>P;0g9AH#*7S z`(Ni$rx^T3pg#Hf*8g5&pVDxF!9N6Q-HlpOo7ksFZEtYrKn)n&BT#!8JTy?p8N47+ z-!}NYKwWL{@jyLe@VP*Z>uHT^L;I9*ZDw${K<#00&p^G`;70>>lEJSBDz!bfIK*u+ z0Nm6S-@q2TIW+)0(WwUJImvC&z&x{D@eRy#X`nFAp96(?wsp-kFwbs*!aREh3iBKt zD9m$lpfJysfx7?Vw4)mpfGjK4j&Qj$-wR^E>m#vy4gW3TR<(8L4PFXVfxAab6gU)g zRp5ucWrYy->O<{;3WTyl)JwT>sI^ov z>J5qvQ7^>>6@`j{$zyUiAoYWaQ8*lBg@bZw<)GY1OZzt>e+GZgIO!5N)_u1I?1_AL zAH#P=9Qe21v;v&rzFPwhL|%V_;pZZM2EW3+tpW`0Tq7;vuR3!u{wm+_0^+YK2F5o< zY^r$_zNunhd{e~m$xpZg*6>N3PFsTUHff2oQQ-;&#KE*BcwP6u8Zh=hFn%cJ!xizv z$R&Rlxg?H7u_EID?i~3QeuvM=-GJ@Zp9jsI{^)Ks_XFk=$GLCJUCE3-$$ew)*#<8N z6dF6*_X2Z?&N~7{h@IvNo68hm;RSZ~6(>?W{-mnMp)g)-NYaNKZQR%7B3ReAG8aav z1dN%b?OjbS9*G3OYr3$~_xL(KqoxJpGO;`yuA}l`JSUc4*Q|lN#IA!6#PV?Xg35z& zg;*XAmr!{y#*gLUZ~~PF;{&lg9KN9PU|b=Vhr=aQ9*if%@^CnT%7gKNSRQU!_=Ox8 zzI64HBvbFiNu==&t96uRMDotnO43Yy-8R0mz5Smw9>0241qplmYRv(Y!H0x>WVMbm zjYzJvx))9OkJ2&dbO< zB6;g-Sr!uZ+SNKrLn3+2Y8{n%KeeSZtZDL`+UgXF6n(rv#mq9M9C-ozDwoE)a>VVe zW@F{jax)!=JUPB(I2%ceO~=w=)6ulpbUZCK9Z`!-$8@{t=2`nxp90VH(zCY-KES!Y zCiv^l&2$~!Z2HwlG~h>^>uZ7+IhX%N3;J3ZjSc*aaZ-K(UuMIQ!VNgdsS0oxr|Q66 zovHwjcB%$E-Kok~3^H*U1n?&=Fb4YC?vZDnbsk(aEY_%vE1&kP&7L zgx-Ehy1XUwIq(C)=YWqoRR!XqVs0P@kva%4{wQL=_1t&rz#SsPfp>K=ch@1OYQPUf zEy0ls14B-fr_$!Ar+7^Ecs##gC)T-R6g))c4h%UrFWt3i>Op1pl-s2qw4|ww$kwz4 zCOR~w<7zj%ie7kn3-=G|Ce&iBy*%0(fl;5-3~GAm1F^)srVm+Xbd z3+<%lhxRF22qB0UO`H z^x6JMn!yTcPt=dDo9^_T|l2Aqp|@Y+hwsQ((HOq57OzV>8r$^ zoVrH#?96!oHScPmzt6k=vNv$hAGT7fVX(gKIr2Z z0CMONNi*8>f^=$i`YN${dlPe{vHT4kEc$iVa^@Ro8H=iKU`p&JzLDE2^NmZalb?HM zvw^E`-FhS`kDMrs2`%EW_MeOO5o_KeSt})EC-;UvHfJgctBg zrv`z)+_=?Jq=5f$stR1k#v)QchALY`MtX9P0$vwQ2)rnW0ax8Dj2}GBIQixRa6_kt zwlKJ@Q+42xn=_><@DolA0Z(?S3LN_e8V&(hbE*zJ!Kp#u>)+@Nftxs02kz|D5O9uD zb>Klx4FTslRR_Lt3-1y5HmB;qPdhaPJkzN<@Vib80dF=+eGdFw5Ccxwl2O!w=Q%Y5 zyv(UOaI>vwI0S4MrClCm_{bmz{D@O^;JHo>U1D&?n_BnRn}IhqPJ9@+g;RClK2b~X zX)ZPdygU*E-{xXa93EVmo z1Md>VfZvJ4z&~@b3h?(%)q!IpJAo&9CaVBTO!sb=8UhYSHv^M0Wm3S4y=5JEZ`2a} zWDo-`a;gR-uZnJgQ!II^q0$_yT$*H+yVKhIJtSVTEO}IV0B&f>Qd@%GWZX--PC0XU z?96rK?{V4 zK+>4hB0w^VRAlpqxge*=YXQLbSfm$nTpSi<3GnHj5-PyAdyq9q(?o7@J1*wCTop(- zONIwh9?2wt1bA^bE{JED1dw=^ra;2EXvzigEKPwFP0|!d?1~hSkSOlP1wkQAf%tkM z#|7Rl_XD!%7jj$#&#&S6$NSP=0kXu)-GKK;@d17;v;-0pGF~7tAvc?2{?4MW4h$wt zis5qcB@d7)@B*hAK*C7^5Xe$q+-;;dS~2o`FtMXQBMjckqhU_f-~}_oiuohMoBHxw z1rh-|Q7{Xvs0i2-#R8ZGR>Xj;dwMs5fz?jAVT%F0T{-X%JwE2(`M9Twf$`5#U32bC z79ka56?)tXd*!Iv*N9dI%5e&Al>@)aEA1+fid%XGvbMZ;5 zqf}5CFlB)x;xmWw9}-zXlF3-M3z8g#@e4AwenFCw-e9$AL2^O8D~C@&R@Ooe&7<0a zWMO3KE6873CP3k1y2dZ^@MnoDB+)erE=Vp|pNi&OkOB(HrBv>MGUYB9E>Z4+;S%L8 z7%oxnf?<>!DQ&@UiP9Dfmndz)@Uw~1#&#VdU*WiK6fPR+ZNYGf-WCj_HEDQa}bE@Yixi? zq0$48Y^q{la;S_ANC2rACXOosFcpFH03=;%Q*cO~gPo>M(kLlZ1_z9@DR}LWO@Y)1 z(vqA@Ruu}!F`Et-OjZ>!AlX#Kz&Ndl0poNE{;3xSgFw=Os110iE!Wxs80Qo*Afc>c zBl+a`$cw=Ep`4sg0pp0We*v!NOSimbYIqxWwhE9XTv`HgCLI`<^;*P$ojMkavorA{R zG`YInjnz*UC{sC`NgW#)oyrX_7*nF*ev&nz*%IXH*{Ea(quACMxrz&UFu~fAey_Y;4N?g?fW z(YhyBRA_onFm5E0Vj`{vqD=&t<+9Z~SDd!D+H-YL)E-Q2(vswg;zY*;X02`Y#1$)V zt36lj&s(xwk=yjHU`m&kBv(I+k|da#vL(sY3yrGymG`9$r1&0b?8N`qNd(36oy1Wr z-$^vZ@}0y~EZ<3F#qyoRS1jL2l*RHy9`U7q1tz*;c{rl1EaGDMc5z2c#qw~(mfjys zWX1AuM3~BhiJ4d)j@VIoFp(3>!x2F$4<>$MdAJuEQxc)Sm{qb;4J~Pa@d#ON`1q`n zm1-!BHW6GntJz7MiR8tzeBaLMq#6PfO(OZtS^tl^Gmo>gDE9s&Au%jU1k?#c0YfGT zE@ANsxCIc|$&;MP7~sq~M0SwPuoGqi2+E>iQxT8@$Sa^ILD?7C71;ua7(_1-6j@Zz zD+&VgR-LE5)qT6484eKc=id3}`E^Zob#--hb#*_>X;ETzQcf`QNI1`*;Ryw+lX8NY zLBe_aj20zUC*=e)cZBoY8J>NxIw>cZStFcx&B$_A<*Zn#_MFk_N_F#$RwwgDTL0^e zVOJ_njD>Tj8GhH8IV04kX0#|VYgBtMvqd zr-WLQu`?>ON~MC?ISS{2Gg_3GV?zDnj20zknbrq0yM*)P87)e~&9!svMC^xlU0NSl z88fka%*1i&mH<|A!1l4gqjm-s&OYR*A)PX9P9h=^Z-_$)ss36G>leDxc9oVktF*LL zr7?DlkJ4Vd%_$XahC^oJfsRJrW;lEeZRUF}ZdLJgj&2z(1t%pJ65Hy}`B`QoRsJ}u zb-5?-wUp%r+t+alASVJ<=c{bBXf)cJvy~DO!HKg+Apwa$a&pM_mqSJ20uo<@D^;{& zgP9)~^kII|8QBvN-Dp-wG()fw65hxTN=UD*K_l0|Z*T_<8o36IT!TigK{lS3*mmf7 ze?+NonjHk-YjPhT7u3fw)qxgsge&b`F1wM-_WN|fOpRQ2_O+#7nZA#>-UTppr9$sa z$?HwPFM=Ro5abUN1tqhG|LW%U+!E{9Pg1kxf;t@TRM6h0(Q$szGSCeUTKW@Q!J8`{ z*UGy4EfadSUFF~b7-ZM*)9HTjpAEq7iI$_g2F8tB}7m!R;LNt&k6om^&*pF5Ko=_AnU|0eCVa0#@ z0c#UGVl=6UJMx60kbpRsv3%5;-|Pl@^I^WM)Dlo%*K- z(~Z4@%nPpx-ni(|wc71r(B-}7y+GO$Z-ko; zyyP9pokU@W;13P-41=F7+$-44Mjp=4FM)!&>n$NHZZSYe{-{)*-2Ca@>E&G&Az2RwAZ9<;WadbRPmZz zTIMwmn8rbK_nKVb^ju)(H9Of|*SY?rpg)3ht9L4UD-QLX~KDc?jDfzoMm`QOGPOy9q3e+=$VQVQYuMEsh}H7sYQ0x+dSZ>-E=jCKk2um zGT(#y&t9tlj`Rsw11{^NS*c1_Cn}AWj6u>5w8DIn&7l?66H?ygEX8MyA{NLzVwOGZ zVPT0rw8Q#>auqW-SE?VS!rIlJ3+n%sIWqxDo{UHhI^S%~6SA+n!#w0#p?5CZ_5Q0H zv!7)+24R?5a1i!J#j8>=fGbWk0m%59J3tWpm+fYiFTdC4mNp<{Ei(jeHEU z#o^4PFQa7(E>4|yr!SY^mz%FIZ!+`qe6#m|VK))c@n6)JY5na!If;GiG~ z7z9;pn=?ytipWYNXWR$QT&6wEvdFxeW&JhJ{%3x{;678!M>Ay_0grJ~-_H!zHgT?W zA|rbTm)(o(_qd?O9D{>_wAkQ_fwbzzWiuPuRhG57!F>Yh9|m6uq)kn~pl4=y^gPd+ zYp-;MsaCbBeaQM1^$+;Js(fJjBAlXxM=lhl+SY7_Ay``7jPZ3|bMK z(er?49Kfhjp_L8|YTe*!HGrrm;Sq=qRfCF$(x4u|f@!7NLGpuII)pc9J@D$TX#r%G zNgsh#EiyZV4T!z90WdR0*nmtPWlLv|(wIr}eAo&gGfLUOOZ(I>fXp^&6gZr*G0=RQ zNhj7EWpctBi(KB;Nqyk=iI2OUY&#_)#;4vSBo=B5Xh`APoRJ z>G==5ms46`dMn%UZt(AoPaeR0$zWACaR^lw{1>;-bh=*U2y{fNf-i7Kn9iVg(y3>n zPJzd{76p(Ylsq3eT%UxEE_JFu>w#1S(hms-K*meBfSvTRO4ry~z$hEvYQ~Y~M9u}q z_%T1)qhI_#Xsg+D)ByxD31fa}Z$%&F=HA2=eVWiC)d)=QgmcP@?r8K+wnRWiM;O;z zF^f4u-EhTLCtVlLPp#PMq|k3}x+! z@;(+o86H9i5wl_)zt*Ndu}k7uRRm`>MxsPc#-4sv><$kx;V0TvPJxQWILf`6`y3G}6}a7NH-^rwWT82&G5L^V?{PY7*IVmGW~U({{dVJ@YeLl&SF! zc9j#XQ?@QiU$?7}(&T(66ENU{dVve9mOMtEKM+p6H?6=sH!F2q&8`xV_cwT;T}O5u z(ghwgnkcnk@Z`^yb`n2beH8#br!Umk` zx=m?;cM5F4`4L;o@W)JBk@gdVD{mfj`+(sMBN}*fqe)fZO%WRyR}ePfgXR_5t=}77 zc1!O)aAzYa8~8_o4fufWp08Yp z4km2^i@*iMzf=wI!GVogg3F0!m)d`qHJ8(x6AZ88Zq*0G<77Gl@h%YtTrct}JdOCH z4S*l@m{bSigdz=y6Kc)z=1n-EumN#GWdq}c!Un_%l?}YHIiaut@k_Bc@P){2Qy&$! z)J3%ce3XbQ4FGXbWgE&zuXKN$(gNd`dbSP5F=cIe*nIOZ9@gfL1LK&&20Y50uMRvV z@=@@m&Q<^yI;jSXVUAhezsEu>)9;+UTZiDSn9gZAS{78s|E`Ju&e6pZ`E{Ltdn9Q?dZhL|53 zZm*^Ww70_MvH?3{ye~OeUHl%1(N#$>10a=mAK#+H5J+Vpi7zpRU_!cEbK{>&{w-FJ}y~cai#h3_n-|;OYI^^_AFSyE(D!g|UH#&)GlN?1=h!C0x} zq=cQ66CBx0TBkIe&Did+laamQtlyS9NmQEY>r5|@%qHSy!4JEwY$utvB^xr@KwxLv zwp7r_u7k$rlBVY>Wjo2+I!lSC*h(?gm-#;SHmn4a^WZ^DR3R}0ECfPgB_-$!DP89( z5}v%dTHahOZ?2X%mpuiLH}{tIZYf)_*^){sQK5Hgle|`yano8WT3a9XjN#yJ@Fqr+ z-4pF^6n1f`B)B*8S_Lq4q#prcytAFz@`*~L<&h(~tBh7bSRJi`u>AJ7IV4NGWDbwm z%1`VP^H%r(-bbDx71JKyoyo4{va8%Vmz}xXXiE{6_PtjD40`wHdS}*r#(Fy<2m%H{ z^;}S9$>VKUzGK%Yv=MQ~xOemd3A_^CbH@i z^4i4TTa-qlHWAOE|7{|}voU89dcu_^?rl!ebOLFcNdH(>+Qig%zM5E59yGgJ-dY)p zDbZ5D<7##a_R6C4{U(jPUY|z>lh})!=ec_g`;qzz7d9ag7ZMf;lOc21yt!sByP3;w z=CZSimdjppdgqh)|3-lLhXtR1`HEWrL#)eAJ1W-F-OPlyw+GtLnDx>brN)_T|AJN4u9StgXh6UF zm-4)7s=-?!=4oT0H`3Qs${e%I@xek2@FzX-$Z8EHwPL^6Cc43pw)T`w{(st4ACpgc z_O$w68M^r$?O%HY7GRjF+0x7O=a5s*J%D6DvWBM#jBt^@U>G5#N-r{luqjuAAn7(6 zZ>6Q8swPh=OPWhXb*9vlrqn1)>GTX7jH2>vQ7*iZswrG)kKbiNyM0$*0E6tlTu>H4 zA5XNjN4|4KeP}SKj8-l`8+MKa9(6^l?w)LHgM=}}!s&r?#jqb{GC5(<;Y8BsqhU`) zRSkP8OPWhXb*9wurql&?)nNytsH|kU@V->diuLYF6MBtZC8Pj@?ChRo#f`-;C0g3B z=Ze;HMQgdD*|4*%c-uDIo}CHY)Jc7RF3SJ@&8~881YCAH6*HGb_6jbj7eUXuplr8B zt^KwO_j3mfzhI43ImY!CtY|$zCz(>HM301oDbP|#X*fX1ZKBSB_cWUL z3c`^zTz_9Q-IQl_6M;yjwTyOE)Z`}9O4}Z0SMlJd40id*^nK0Xd3IH4j~S+~!)dl? z+c1KEF^qghQjAV~x{| zCaM8r1A#AhwkGhV$b0WH+{p;PH?re&!@D`{$Z=q7Eb$LG%B|54T+v8s4e&b7Rsi>N zQXOx^>=LGc7)pb_b@({%cs~%E2p15Wh!yX)3b9Lpck}2{2VyzV0{Gj=uwV>Z5mT9j zA9owdNAGgGcIS3&U|0N8jhLE8Y1ju3mCOJb&qHvShmG7D8(0>jXaiuZA`JlPxw3T< zf6#yZXqteTE^;sAyiq=RcJi<>9o^!Y0%pdPl_@duLOpj>ixN&y@=_w&Xji}l+_FBU zx1!VW&C22WdAd1p%#WYbllXto=uuVgV*adysbw-LT<(UuG$GCs8{dY{*FONUxn@4snn{m7&J+-~q4Mw6UkeY1X$lyx8OyS!Eb z3>|4Q_y`o)=`fy}sANe!S_NVK2n$+ew%o#m;hOs8A~4I9EWG)O^aee5DQj=MUFBX3 zFVHh-f9okgFOXOlao=SYf6%TK9|3vAa$DMxgV}L3f<(#lb4l5w$72(%?L0LXHa!=X zojYw{YJI}4(y6h(DevM#B4?AZM;lMNRXlN7`}6`N(lD9*=zp6l+dzLpzHl*GLH{gh z(k%MR(mM6xaI}l_eUaqB>J*EmLYUyXrRzz$hv+ITzkY z)vU+~b}*s+c9nq#2HDMAP_`x$Inm6%K0q-D^P$0@GFrL(EQ)r`C=Wx{w5u#zE6*%R zQ|v0FrTa?K+wCf()Q=JL9v74yp~13qEgZn?Z+IP(Ts7p>TVgtH9w`9sH=2yp>(Pno zsyFxzih9H>r=tGL@cUe=2Jj=1@?csP<$+a3o*SeA=SR}O=Qvw&lfn1)h9O(q@XUyI zu;CHrGunrDCVr$eeCm_#TLo|@CpCcoj-=s&ojA$|BTMdN_#mepJPwSNB^&~m^1k;0 zSBgvo{;;zZKnyR!fWwbLA7g+ar6zVf6?=BofXlgk`hZwiDyEaR+Ss+!*vf{rFY^X! zK#VSHI`G}mLm8!t+MneY<)~@H) zu48SCQf;6*2BPQ6HdI8c(!VE~J7AiY^MlWiXiR2MMaC^;!DNv(+n z@ySppy2t#T^dRPcEBhgq+H*pSUIl0A%blffxPCG>Mcx-Ccr2u+Lak3|QDU^>kz=L` z=Rp%%l<2uo_n+W1cewGam{`mNIw=zdx%jn^Qg_Y;)p9|#Tu^qi>9;m1@q20Od<#9p zG@sY1<+ZZ5#@akv&f{qT49z!kLD_EY&!+TJK@czq>dOUXcOOr;K*(wz8K2q}#?NcH zr9-W(_usL$ZuHQy)kHvwFzdm@g1-&~wRcNknB+c&NQ_&s1L97tvlIvpeEuF%9{2mMo`j zz2U?>6{N38pe?G&(?_{V+4&OTj`Ty8dmzzHtj!!opm24NC;WhUW%kohh@?9sS}Lk) z;Z0?U2C1mdl)B!OT4YyERKTpoGFfxs^;FG@DgBrUeS)5M6%O5r8o8isZeE>eX|EFG ziu%xCP#LXUeilWhTE_Qa*!(U3xpF)3A-jrmUb%Nky4S8kdhFPe^as0E>>81Mxy$ZF z_5_#Ro6GJ+_ERo9n?cAv%VkdoKJTO&&HaZrHyyaMlWMsJ(|=?wcOO^wQjD1{nP~7Y zYfhb&_BJ!&N&`>W9#MV!n;F03=Il##(3)8L$-wsM14j+pur`31ySt zva8e_%B+t>W(8wvNsxXv!i~Mi)X_GhnX_u4A=9TmHw7b}JiPKbunii{CkNKCB z4$`B>q!t>z=)Ue#YdD3Z^7KiqPE`4rdGJ)9CdG4R=cRl+3*d@Q>H{+R6{n&rnoOqR z$gTs&ftf9G%$NFZ&7(;Ti1CFBOEP;ZChf92mJ@3mi&SFt zGX{71LP=a`*EaD{E4&&Lm*1!4M4vV%A@0;Kmj7%MS3j^U5cJwaA|GL|O`K)kx`$oc zL_*Oj7Ju4Af)V{|6H|}D?DSBlJD6}Tiv$q6D;tK#q)JO|sGMY>u;DJu60Z)u-f=_q00=U>oHQ+N*P4M5HtpMV*Vn^V& z&C69=@cr)j1@N*R%FZbp7@rhrz{TdK$_8GqURD)0;L`m;8hB@;2^;Y7MqmT~$!KCp z;D>hd27q@PN%eSXcKPp3KksY~cMc7VFg(t#(g5&KC)I$9qnc~%QcBs%uG;AFhR=y; z;0ui=EdXC|QVlq5*Pz=yh98e;;OC7d(tzvj<~;?zynB!aUS<#23g8}2ssZmdlJ;uc zo@I@V>?&hbGq{Ugl?}YFvlYO5om2zP*3(O)7c(#$0ZMA(% z+cfPeY``Ooq-@~%femFJfAWYO;*5LaBX`;am?W(GQw{^Axcyq)C z{%K$XKI5bs@YSd$c*TQJtpL8?NUF#BhBt|5dm8?BL<3)LG_euz;fM{q&7rhfd)(mm zhm|C475rS8d-@ZDciUBa`mQ6(e;+*%bOWDcG>MhKE1gsW-r=MI*k^lOZ2-KN?|Td25fR%7 zhRGPUD)`w@b?JGfn&a)NY~Xc`Ch7u@cT(*_gX`F4ThhlD2DY%mp)v6!E0CvZ8{iA= ze==O`+Gp8TUD@*Od%;fr(unO=!y6qFjJ}0ow)-mXR-@e?@o@|={!5`Qcs-+u1%Tg( z*ub|0wtIlb25IjzylzAThZBbykdp^h7)(|#iU1Fdq=8Q|nmU+44lPs~_(#rGBOzyp zAmadh#x|K+6a0=Zm)#OJ;D?Q*Y?~RLAJM*H_=8^w7U?zo?T7}x-DuJT@cD>s>ElZ= z^X#h4e$DWLh<2ypm2AtSd~AQV^<$VCkP{kZ1G7OAYXU!fV(7$7!^cImGY!AhU_H1O?46Lo>?kY(ipZW8S*jxyZc2-@yq_@Iae zKGtZ`0`OWVHG%u=5~N*a_>PDMUSu?p23&U6va09{B)`<&lVFlfDvfkI1KsUH%G^q;Q=+ICV99H-y@Y~Tc4Zh212Xup<@TI#6 zWF6K%fLVw|5#Vvrnhd_$X!7Be7Y5|#f+^qcYjqR2QnWCGKjiCo6Zn~k4LmEb0S|Oi zaf!kA4g^Di3!|YQ<$a7U-2?tQst*1yXDgPob^86jUN?a(`D#Bf%fB=LWW`rDj*A|R zmU{5ZzOENQ)^(8vWOY|*U{-oz1G2U&8;d%tvCG^q*XXi0hsyv)`^ zt@*0qci1tK7<19U)>f$7RT;s%8BLl1{>({r;Iuu0;lQ(uCN+VBdwREkovzHBcifN1`JeFvmI4 zDzGZK`l27>Olg5n^JAO>xWMzRI*=qw`v4}%l170XttcCq#7o$K9GNH^M1d)gJ(z5o;N(|un;r4 z4R0CIIPIBZG!X}UCSn6W7ubLt3W+I!oDHeIV9ti50pQV|f6A9@4U>nC>^fi^nDZiO zfpel?dIDJok~C_gV6sN32_$J$HZWPEumL$6Qa11>?Yv0XfZI8#03Ki@tqH!!+3LXY zQ9ikzVbV`aN5@g-xJeoYl7eb0B$^yIDGf|^DOG`ITZ*b|B%PcsDJ?xyYKH?(l|Jj) zXB~Kuk+d$Dyi%G4-gH#(MDVjt8|VgejwDrqoFi!qV6s$U`@AKZOLy z8i{;U&yB%;7SvS-aulSErn#rmNIFS4l?LXHt|)h?9pI2~3JLgHx#tDPl@>cQI-&vp z+-U>dV2)~}iNoy}<}1;0OnPdg3jfmn&#{bD1>Rz(GO{WIIj9jXAm=o~1tb?%`Ip=A z&E0;qGcXR!p^Qk|&CX&te-RR}lZ<*5%Z0VYtqk8~S5XYOPLwKt(eRN`UVMq+iTxx{ z4dC%c(iRpPemK50?PH8s*N<82*=C+j;EAEoqr zCPo4t;u&y1@ZGzI81gC0e2=lK?81PnTL!GEf!Fe^xB#B+q<-MIy+Z@wwTvdJ0m-Mu zZo?gP#d$J^Ufl9j-M}Y$iro)f7^Tx-@?~*pAgQxTBX?dkN{YeU8kMS?v`zCoxu3(e z!vhIO@~sVk$+V^SK+k(^mOnRGueB-c$K_eDh* z$u-%tkbvA4Rrz3&YhmNy@_5gq`+?jc)tcak0~>JJ=*Sbyy;5la$gNVD8@pSLFL})a z#(~Msr6yT9X}6Go+}l*uz+~mZ1|$<#Ht^>>x9$g$V=Ei@`oNZ^+sc;a+tMiMHhHqL zf%o-fxCtb8mYQF+|9;QY=)rMd&P;_3_=IJ&+5q?&&vFYOnXS|WlG$oaFqy543y_pm z*}&wiA`M7>s%)bM%4j&-u1W(RVKiw0NNy_9NKZ*kg#=u8Fof7VOYN`9QZKbC9E++R zU@})}0Z6W@Y+#aAQ5Q(As%+qJ)3hHr%5zjPh~cqz6=^^YUPTWe=dRiScy_1>YO-UaSk9LGE;lCO~d<3fE=EMG~zR z2Zw~Ze-BHPNtm@wFd4Hn0OVe!vVl1^mPUc!_Ow`@9n4eZ?mSiQ&r{|8bxta0)TiyL zjiz@kpSE;(1{crB zBfARM4=l&J&U3BVJ6US8zg^p{QXnO2>qj!gd170YYpohtQM)?%(DIhSw5wAf32IlT zKpNDpPJs-k&B^H@`AnNQKRE(y6DtnT<_)IDU~Nv8wZr^iX*Op~tTb&tj%wEQC1y5f z2}d1S8d;3X83KW~T{R88ZDJZ|+r)~E{=7k=W1nyIXY-T+bF5vN0v<2KlLsl_@?%zz8W?51yOLd%5&T~F z>jF5}Ne$p~(cTFBZlj5Ez+HVtG=QUb35(w9w$<6guA`G|R3k?VE-#i)i2*jV7G{uI$^Y29O6@RoavG?-%W=H1Ntk*9%~H-n9W_ z52ZDS+e8rrln+cmkl_cihfy{#(^=SnOloCI&;6CgWM{)7Re_I2w+z5+VuTII>Ay+? zv$1Ipb-JTbMz$?%MwA9-HzI8Sw~00;;Fi&Zjg1L$Nu`0=dI%ektw&oC+oW*TFKj?| zChbm8Aj%0}XM2-^y~&x;xj*<^--r}I_9)T-kS9A;Uod+V@n9f(6lDXmUupM&0{ahX z0>~qkS{F>97B(Q;4{3EZ+gk9bh8|#p*?vgPUm6?R4{ZR<3LtDi)&XS$b9^ssz}tO~ zF{K6my)PXFkn?$|3FLTQ8vt`IFKobX9nPXt07pg}7VvUm!vYM4_YEM2_}V6z2TR0~ zKz2sTc9sd|0TNEgDYF+6mDvJuk}sruyVGF1Q@7Pr8)1cww?Nn0|L=(SSauKaEl>l< zO043*EXbk=kf%kI4b1*XEWj4&Gq&#$5(_vFkZ4UXTPA4$7@zTjIqMfTAUh_N1||Uz zHXvIeWdol%&piV87bi7U6L z{n=qfKEd!=5e>Y+Xfg&*8$2RfK^Gcc9MQnfhgJ1MwoG=q=&@XB50A%dHq?Re*6F49)M?j$skcz#c?`B)D@!uiMq;0w4LrpK~q{_ zj)WvWcAsGXKf|sgx@KHrkQ=osj-b4y#ZIMx_wW;)f+$NkRkr*@rDiciHC}mP2xhm^ZB6w(hFp;9w`HyFEyn^UMN%4O?Jze&Q(ytr>*1>#}`HJPM=r!Q|>CCnfF(KBt@4A(Xk&h8WVXr=CWDRnp^?cdKbSl==7&Z;tNdWH*_a<1S*`Me$zEfAXk@W% zeJp1shmHB6k;^JSm`pb2hek%L{9y9gm>(K>t@4A(YGZzAWVgx>Cby0Gp^@XZelS^V%nyxhR{6o?vN1n2 za$4mFdq&$e>Vd*OFXpt0ESC&6mJf|gR^@}qSYv)@WUk5&CU1@Tp^?8TKbY(_=7;ur zGul{2CwXnm-$`~G^LLWt#{A^HWVdPqFu85a4~-mG`N3qkF+VgiUF8Rp=f?cd$aj?= zOtu^ILnG@|elR(2%nyy+SNXwYzA-;EGGOHglmEv2(8z<8A50b;^Ft#WR(>$KaLf;l zoLKq6WW+H)G%{o52a^}a{Lq$Ut{j~Ve`QjqC&NGM8TMqD8yJ$|U)_`4&JgOAJ=rZ~ zq2AxqTGnn%aGEUCyL$XiM|8Hl#^kEAG3ZGa1%tRf9uKKT@&h` zdi>@H8M=-Xn9N)_$4qWfA~#n~F!#8H^Q9iY<4vY6)PMH0D3PmceK6zHIM5G=Ri-368XJQkLYPpBEwg$z-0Eqd00=261lx{g1Jv5 zoL}$B?ivYoeoyx1olt+=)8aimb_GIR(9`Lu_Yb94wsT-dpjv_135d+^_p~Un7f?BgAV6uPVJg28ciTqzV!Q}nIdDP@iPrcWhJnX4Acg{rSiIZEDIQW3$1?-dGl&B-kuNI1|=-i5m2-XW&aX?nII28ZmcMd|^g77fs5(HzU*sCS{*=)B07PoT<38QR^A@ z&c?iOzhZh%ixPW4X??q%7A5X+XzO5hf5N$qWN#*odmPFMX5S~A8~1d2zvGiV{8hk z9iDK$GO5%19T!jP^nS-OJ*`gmbJBWuPpgxioN$iqX?3!PThCq};eLlaM|-k=MV)sz z+C*OD;B}2QkvB3vZBH4ui9DIi^F3`MH#s=?YZJMfO>AuwXW7k59tdm`nM3$Un}}2J zmO`7DJ|DPqf4Le&J)AdK(V2OJyfhMZX5L^$XXXu7bY|XQMQ7#>R&-|GAf4g8C((P} zV5;|L>~xGT8VvDu0|FL@Qu3yKD(N{}`8b0V7LFV_HteWYe_kv5b%giWy?8z(8nwld zrjR(neAu`vn$HD!^FdI5E-2He$J*G~pAtB-8yvK3(6=DGkqgg$DrXxLI?X#$0E6sW zE<5{Wm-i=H+Rw70DDB8sFLJFiVgE2;(dd5S_;MC7Rm9@=*sWDQ%ph;OrJj=u>dyuB z=Yld9T-_dhSi`RJ$RjW)ne}6galbdz0)|@InA~IT&TE!KymHB)1W8%#&v)g}sq31Qe*28|f zLa#5`gL%=DxBiwi?0*c%FgWqq#?D>j@$$5H4LjAfEzv08EqM@VVrE~NCpUP$R^VDd$7`U1!= zorqEATY3~aSVMI_i!EHhJ43hw^3iPJ0){?kKLLNgDf5S5{S6*ltF1cCUf^x?0=dN} zV+A*R!D|C|Y5>}z*Wzfv*KL5;l0C9(|FH`rBn1ketj_4Jp1**sk6$7)N5Di z_iB%pR>D1gV5#Vcu3jJ>6LI4?tJ*$GxYM4{7QbO5)h2FVnsyz#im|5rt~4zqKAI}pbAOs) z6cWz;S9iRuj~kfmUb~9p0Z(;ObE>^uKFzN3Q6Uz5K7}hJ;1S+j0X*7CO<>ToKu+ayptBf^ z1?2slv2>k&$}FbA(7((<7nu#82)4x4ARW3x>5bx7e835}5E4&okbw({Z3$Vckmxe! zT0-KJ8Y4VN)Y5Y*;bI+P5fTy`TefaON=NO_)|+Kq^#Zt+lj?bI>hy*W^2w5g>aVzy z6hJ<(CtSeL!6NTXJ?~9D?@hKyjxv?sW7jAgAaF}JVlNPjMclNtU*JwHM_ZUn{2lnZ zEw{uCfF?Qxz!+s@*W9sKgRaXI$h(|P0s6(SkVyuNZ}N>7Apz->WZdaP3KgmIJ~m{? z)-$=Zn$pr?Nb8B{v|2@LbFH;++Euo0-C#5jU(F?DE_a?uxWKOB2EZW5e}Up)d&aq9 zCK5bQW3+ruX3WH~6lq6lB8055Lf8sBmXT;RyGE`J=|cOL)aF}odv;Tr!g~Yy}M?8d-j^bofW>Z(H03PF{{#?&~l;RsW;%vE6{b<1V zZiEZCfjzk`;|AnwIKl zF3}M97FiCZIxqm5Xcz)xl#yLWj>Q^uUBVF3LzlBKM86ihXEZo%;(Mbq<$)Zx%X9|v zz0r!maJI=rcKarR%>^FYQW~O|Csm;-l_kxgC!&OuN~%!m`=-=S?W)lVjH1%LT)6ib zHH9m6p!-bdFYGD~1Prokx$JBX6Hw610vJWwk=dVjITN;#-7eU|uF<4`bf5i81b)Om z-o(MWkan~;Y50{QA@S|5zuCWp#GNEg`-Q|=|1a$(k&sq32iV=NLQ1VT&6N3qD^&n5 zaZ)|kvyM`Ho>xW)rT7%DkbpJ zOA&yfJ?$mXb{G3$llVdh9)o;&+U^C(Wah>v zAC(glkY`(Ep#kC!6;a@J#>Zr9$U!(y&?*g4%z&!Ul*)?qM3j(HNfk;xXi7b6R}D?z zV1#k9s+1YQDRm@I81)5oCqDVVZGuJAc>U){}54EezfHm#N z5z<3G{I#ZqCcZ2sZKSu^g~SKDxlvcqhe4Bhmdh@H&p4?+Z>~RYuAk=kMxr<%@CH9y zDuA~+sUOIlei;#9P(90sPB;B7va49^>i;ZHY0%^{Z=)B8MiDn{Ee_migrO~LBN_si zgqhHwgWl4tMi?*_(By}%(@%*oNDuwXA`Gte`(R7F4-&uEEKbCNh+7B=N902>LgKST z{Dh^Dc#w_9(S*bkW#L|t|B4_kCR{u%Lhpo>4iV$FfY@+j4#dh9oFA$9)ZrVC4aHlq*Ees)U z3w+%+p}8;wLw1ce)JMT|SACRz(kby#q=(LAKDuhN+)sH~k9NvjFlv zeetVY^?sE4qbt=9{EL$c;PX!E2coZd0FXP6(qgLTmZo37UDfOCgcn;p=56!>(J11k ztqE?E?A`)xVF=L>__}REa~*VzHq=MKbXR?pe$pxNQKW~?WIlS#PNg4x)2@+^LgJU~ zC4}(=Jx|LEi3i|&55pm|KzEMGzRs>u2KnIE6(2%*yPaZJfLgKBWr~K<_{@wVxTfCn) zMGg$4xdtx}r0WghJQdLbubb%JR{;6#JaLa_ZRHJm*3p0;j1n&3*Ik1Gc(#-3K$Mf= z1_nJdhn!&gO|h%SDO-8xn(X7fjb0!cMclM?Yv4|upSCcBXb61WHleu=x<(u7kYKv2 z4oN@hlsF{PLuWFF-0JgXSea$lD5^mku``jU_NuMCe1KM>8n2r16ZJykix0eMCL~@j z>VLR#BCdMyJz-+qgQZyyT@uiG<>DsL^lG8Y?W z1)`CL zLtEf!Yq=wt%2^IcTNpxo6!^MrLUUmVhU^+`s6&G3t~weF+erm*T_@Fmd@)E`1cpA>P<^(mo{jCd zOurx4RUOgRWt3aho9zXnWW-JLwZNU4iMFuKn=up3y|Lb+fqF6+3#cd4b^0luOoO3+ znJ3?CZu*#ABTt63p?}!A#z&|5$pKmScuV*IpZYak)8&X#xHyvJt=NhM^C{C{v^Q4( zw{ub>*T6sSKGQWQfPC*=Zh`=Vo<*)_BiA!~Ui{yt=L)8jSd6VS?@jl@2HhFVhqYZU6Fx{1#MPunFof22eJCnH@ezbWo92;*)FZ)2( zj<@fdGvMMeygW|lgv9&Z9DNH37vnXF3RlB+dwFvOkl#oVkKrdaf(8vVxYk{*0le8s z1@I0hHGsU;E&~Y+y=kOxhgaOY+u2k;Bp8uJ80D_;W_y7ssj<(NY?^;6aHrl!Ti8aF z2EJ}H(cByBEzPP!g0X-)BweSU;*c~L`j#FA zZ-NVnSNe87mL)q|zFH>pI+tAl`Ar=e_)9H2ywR>gLW2oDWCd`dlN!LFXTe+TJVGwA z(32+!D_rez)9((us`J<~OUJ)`6us;P(niEhTTQn~mL1X-h7eZ+4sVk;*EQNuzXH=; z^(*>Gr^K)F&SZY|@Sderc&T(`*ZM71Ox|WuTK*F{>-*;&I0R5W-W_G1uC#Qnrfn|O zb;`MeS*s;AZMURyi;$K}YT9;5Op@J&uzuf-3m zE@Q7hjO<#k1zy!@>$bpCoVL!8mKovlr?kLJ8%^8|IMGRU;AAHiz`B$Afjc>=0G{fk zI`Bd#71tP~q?$wblLD81Z!}0?yjFw(H}IPMz`m#^ zcqeCbr#`?*b>Q()O>pGsKpaE+nRAU_4GlJ;qC`g7F}!iUWlZ zoIln6dIKKwUxOQ%Iiw*Tb1>bPL=X(}gSnY~vDLP*NTD<^<{Q;D_8^~&`x>LHjH%g# zZ_bd>cu6QCpCsIQ`ZDcVm5o{azoF*clF&gurg6%N71roYts#tupO~40S<6zR_69Qt zC8n{)u!=}{2VNGYW9l$c5#M2bkcvQtUAR&MUHIj4o#2;oB^9drm0X_KMto0oT* zBp#2I#`0QO`+2SYyjJ#D#UHJ$4}PW8K5FavK;oM(JRe-q{albY9|ZO1f-;T%VH&;D znwKXZy1_xq27L>{8@cf89AbhAUDf+m0E6sWE<4+g@Mtxf+1Di~(vGa~xmKC5{G$-{ z{G$;6qhFWc0r0(!$1MtAaNMjP+ZgxGp%yUI%Esh-CzNgQOU^oRz`Wuj4#)R=c$K2U z2k$XSp;pyzL8lWpuhmIgf3mhd?63cLTYNQErZ%4z;$@+V*`5pX=7XSmE+`8CFPld1 zF^%NLWj8oz*}#rLcq12{4buBf=p^rM0SvNhx$MkGc&Q4_Mt9BCx4$UTj!c|ft4!Gc zzKO%zU@rwb0fXaa{rIhM|2@~Aki4f;z{Gl3uZD)Y8>$NUoh%C2JBQ%@;L z-?gidE;BglRIk`$aP2_)g296VX`aE$1L-=0PXKIe~K^s!-9(d!gF1l47jJ0Y9|@IJ&=G8IH?c#D<{=}i=EU5e8x#N;7d;G19kN512en7wZH*@D4seE(YQW)~kdegVDjj^Go3#OC6l5m_>_qx$<}WH8{C%Hh z1(1g23=`=`ySW++5DiwGbkdu>Bfp$y82=p6)dzegVgo;KH0dD_Hx?@&Zk~)A%XwoL z_*?GfeZY&2r2Pip;cNwPH8*q}$fOW$KVkpU7Xa1!3eEV5y&)AEtm@{yIt$R zFcfUeT^gcMW!}x5k{V_fPDGgxAZz2JK&v zK54bIJKGp$^^o>}t5~F0HkOU;BO2=li-hvAN~~5f*O*Px1aR+&4II2P`(6s(d3`h+ zo-;h!UGd;?;M3d{o4^a4ZAuIL6KCrKhKb~H^BQ-R8W6vbZ-w(qYsD!N}C(ne|HI7KwMI|fOw>M9gyHJT)@pk&1OGa5U@%TQvg_b(Frim=7(ha=&NlEEkBI%ig;C%HKkRG;aCvv?eju)| z4WuzqX=zXt-BRaQw%q&s@qXf^vVnv9_v8L}vo>I^itCC?0dYzd2F5F;CXlgLHZX%P zY(N5&vVj?WVFNP6%9duOS6Vb7lqe7Q5Fddiki~D5#OW3V#z1_JAt2@mDK)o{FzvEF zr#)oc5lEQv*MWo?{}M>~%x`X=tP-QTmVVW9sExxENbS?+dp!oC<0HEc=}LR9w6yC= zqwlzq(ukLMgwh6+PK=R9g~m)=JR%?aL%Qe)b6OlO?FMr>s2t|YShJ>%Js7jf@#m8x zTa-Q-g+DMpTXIsmAmRkG!7Di_5i7NIFhR5Aq!cgbU;<~!N$FEI$SM=e1SvTwVLIgm zGha&1H)}}-I{qOZ1{}M_|AU5oRWmTwjrpNrW#tEBNzfBsP+Ieb|Q2CsVz#3o^pa2HR1f?)D|ViO*z4gmvA0EwMB^$Q%*1= zC7c&c%@!QxWZVX9{t4$vQ(Kf6O`)D37D@g#x5d5bi+n+>`>4n4EUvKzvE7ov%J)>+ zIVE{VwACY_ptcA~L$#0+ox5^Dja*P87nB{OEipmM*rNRbPpJmR(f+H!v}s2wa=40| z=)D%zi8+#FRHP^P3Em)FuiacTZ?2g)*UX!1=FK(J<`!A^OD}%gZ?05RI`0i-C~xu4k6c1-V&+piXSKo@q4AuJU!qZtxC9 ztJo|HDIE>C8(ymbhVJ&|-OU7X#EcrFy9V_jpJEW^o59d!KQ0SinhnAqhuN*O!;y40 z-($R`&U}Gsb+ujPiM=Q7`95~6Et{wEATy99B;scMxH@pBLq%IyTDHP@Z~ZWzHiQe= z|3ioQ=!s4A!Fr4lw3?1qp~u-nfN$}xJ~i-f%=W8Tgwj>CYPDuv=3a;Ly_PJQdZ{QO zrIIQp=rg7igQuH(Fp7%b=feFQ12u&!)$$$I(-r(cqyPrlwOn>SI}8 zNo#|VmZup;WF+cd`eg1;st-lfayo2FoBRh;Y+=;gLo7q+V z7;AsL>oI2>n4U-i2MnF6VIO)T(F=IKDJ>OmHTY=MC-6+`htve#=A=51o(UK5Ls7@U zbX?em@`-1oeuL?&M80k?os}t`_o$B^F$!u$Fgi<3AbKg=P>Nwy<-x4GM+O7`+-R~B zIB`^qQtTRF6e>9>ogFz5`1?jHIVmkkt#RRaH;NJIL;OEz^hK=#rYA8!G9m#f~`(|1f)M|J@ z%l6=#CGFeuG`R{jgy9SoF>a!T20}$=Lz&m=WRSMDwpgcRIb&$A8M?dcS*@+?Dz$(? zX?O16e_1$x*}^z}D51M*$s%+If3I>16c6oXK1r5xkF_gXfpPX}Ktk28y-&SB7P*L< ztYcVX`LO?ShYz@MK{W|?9r;C)VNjQ>{o z-vPS{7jXYGsn`HMcQ&MK2BX23U4tzDhvgsEypA~SBe}{8`iJh^OWudSL8K-v?obgXVPnOJK?*X*@T(E4tr*=a45#J1WI@Lyfa0xfBOxc<(H?6kjOl#|^g zkXB-IqOh<5KW@4!8+dE)PXXN9NlhST)SBRhferX*)WEZbUkz-)y1A7~V>B*{X!jX@ zBBFuUIt%}60xva^io4zLhUTV918?uH+XUVavE5;~lW}R8KdSf#4L{|ygU5jxGYJ{M zW8D+_fVi1T!#id~rUdWkrYwLAhBN@YCaMW$fFyqaVsNR6y)kIpXlBS8+}?da>?t*Y z*i&nQ_i%I9ftXm-0RA!>0Wc#VY(vel8{F9P7GFL9-T46YGXPbS1*53`;Ah?1{XiU8 z*}%b${n!yFR5tMPZjF8*hN?DNKSskE%9fhr9CM~i+^J?WQJ%NSBe5&3RTZf4yIrF> z2WF1S&S#Sm*^HHtO2?OqW+Hfbqm`9$u?_zll~O#D!5FZtPpKzz8!+}1&d-c+HyqA< zZ`2U+K6SXh)32Bx8vWB@1=G8j9~!+>elR_b`JufP{T9m}y>f*E^bKc(<-<@PzjCX> z0S;QZ)rnE0@ncu^`Gg5#b8Ki%A)Mb4nO52|P|sPpMF}$r@3|{?_%x z`lwy?#Tf7w9?6=2F~X6^u)DL-feHVuM+K~P^VDC_;5`Ep#959Q13l5=Ku zAZM8>x?8s|#t^A~=iTfDvT{b;WGQ!B45`@L(-xa8*~kOQ>)zshSE_*?3ZMcO&|83X zoqo#O&Uyc`gMvdX#zmVdAQ@-H%LoK?az;tzfJ`7s9|?b`AzU5gfV~zMST%JCK+^Fx zP)bWhDJ=~}sVvbT71fziJDXAicGbItU=)=&kPGim)vQCtCCnA|p~0XsTDkme6(Q;9{x-X`naiA8!qx05^W#N>uLM#$E(m&?3(C$CV5yx` zHlV}1li}6R3$&p`FEJfI7AXMU)@U+PuSX}UYhS=`P}E&!ITiJ|;di)J4dAMg@?csP z<$+a3{z8xj9E_xazvgVk0)uaFh2dGn@MaNhH^YC8Xd@Co(thDnA96=3fQ6G9z`qzt zYvO{PILd^`l7-=2op$gzFjkgu5B$5aNelrl6`2V9zF;CCh8JPL;m4qlF~E>g6FVMl zb`%ouWheDHbd%N6Nn35~T54=%!`kNsX+VrF)&P!)CMuXQ5w@Y`?nZ9@DJ?L=pph5M zI7svY4rfKxA2Z^GDmY7D?ks)7 z^^@o)@_sp?MTwpY_4WxZN{m)Ka?DiW{Lcw3O7vW)4^Qx!JKT6yOe|&sosM%{ zsXOO_YPq0VE+{*zzsDveelKmEYN2PC=JQ&$yjIrM3)a@lAzlMR^Nn0kc5C^!CgATu z5HJYp%LQct@k%)_RR+%j~H(|J@EF@KHd%i%tLC+<(B@vZ<=gD>l znyI{sFQUCbW_QHRVjA-4ELl$5k}RAy5ZGB_o(j^_76wCOg+g02ywKy!ZoF(&TST;F7 z>?C$F{Nx3JHk9ZNT8~A8X+pPkucNh9BQ4i6jL1mTzVs!;MjeD-&r@ zTzoXOoRAQX`wA(YPPy!QF1wz~uII9|UBjmeZ@9{h9?k}v?({`0wz@W4{cksU~oS$uW!w>aAQg8^}bwYRW_bR7A@z7r8lVmCT zSi6##uV!gHq3UoS0(prcDrh7 z07lWM$LJ}fTzKY8cbm}P*;Qsi8khcG(!T9^a}_+t2rBgDDrE8dIWz3&|5v7#;!vv@ zJjhA4O)oD0`#HOcq3Q;|5=aMsujD$}t`+8_x#e7T=Jl}L_uW#O4)3FeSGq9JCK~>} zwN~W@$clOgd@Fkws}80MGRDBTH(+|z{{A9`PP%w*WG*mmM{RaR76iY;Xu?K|(;_x- zBe3mh@K+Jr;TM%-^A2+e9S`sZ?j!}Sgx@F|_^iMN+&vmyFn%Wb0z0wLB=b3KaVN9Z zL2k7p$AND&n#^HfFl0YQd!JjQAESNDNp)<7p+we$_TL_}lic~;!XTy-(kL?lW)c!` zyU4I#G>qk9E1u?7tOK#8NCRFFxN^JpACpXFm7j(tCf7K(p**W*`0H-NCJccK<0(Aff+twV?zAf=Sm&OAPN^So)|1k45Bsw9&IBgRe=nc%ugVzm(~O` zc)~W+EMPs+YGB4oA9({aV6r#@kBtTj-10#wfHyj+mX3)wnh#2i0U$6b8#q|IhPA7L z35F7Nffz%j4P}ig2f8ynca zj-WEZ%;J)h(vq|UK`cJZ=)@i|eco(w)T`Tq zA$!e5kFM38pkxcj_=?sGME8iBwg1Z=F0&k+B$~E#S41O7l$}H_DchQkGi{M1`X`6G#YM)>NAZ>{W;KtsE4{d^VleYBWfku!hCdegaCir9` z$+md8u<5z5%ml}nFqRuxdaBZfe6i?bVPJ`tRg#sNStcZWmc>9w=^8-OEN`-O{>26JMPJ4FFC!Bv-OF!N%Vf+ye0HD(~ENW zOM)O^5LC|vWqHg^<~ZX*mce*XTMUvmpVx8^3AM7`FSNFvwyQqG1@7|pn-7@vgQTqc zaF6m@1u%5P({}_`yb^F%qLSSRMXMmJo?9ieWuIw7hAr84)$TG)&m_BK@-aJvL_B3L zCnO+?O!c;o9Uck`S2}#Gl_b|98%Qouoh)~d7=OcZcM>>V-KzFXsVL=3^-N`no~bAy zrILh{3i_@ob+c~^=XQfpRC=5X@5_Z}Zv9IWy2!3FsewUuGZ&P3^?8Ywb~7MXw3aJc z%jIXYc7ZKx_xtjeElRK~a+WL!faR9&heNr=hWGekprvC#y$)KBMT2QVtPAXBA5s(edneU_^h~&b+eRG+)A5RR1fN*m z`#7Zqrmvc0g6XWx)x1Z2^oUVVD}vEkY68)#D)OKhR#hI%`sK)A;HQix8U87wT9jhf z0HaXJN$L8?iNJRmt>mP%B(=tcd$qA5ASMB!uI>LP|qyF1wz~uIIAr zx$JBS-NB|P0kvAmRHM9BRr6`By{xU{JS@!Z28Z?=c}KFl@?XoeE~qu&0WG`xwrkS9 zEyTGBHH6^|6)|p83k`&d&W19t)yW|3ZEdkm$#TZfK0I`HYgTJ7yGku!P}-e4_+OS_ zOfb9QheIq`gzn()RZfB8p}ou}$x{Ao%VxBdCsh5*`_v0$k&C!lzCL5iSH&x!q%E{1 zn|#_pppbGwS&H==Qx-vbS3Z|CJ(rYi`e~OXTAUAvU&=a<{SYWz9jweNo4f37R}I}r zdL^QzqLeS4&Z#WXAQjb_QXjB}H**E%bc0be>M?o>DOFQQsg~QA(AjpCS&*_!O4_$0 zn_LCYF@g$xxe8hQ-rwBs6nDeSdtf=kS+WEjmZL8XiRrn9*ZfhSrM;tG2d&4V!89Ru z19s9{GtzR7VMIoverW#^(v=1mMm3)>{HX<@f7=*d`?5gW$nY}}?M1_#XnUENUETZ% z!!J5*&NwhV5kCWlPSvmvJrVB*9&JiX#qSurG3pceqo%Xe1YY2zI*^_T7x3+o1Aytc zunpxC3%!r>?VP;d-Fd(J@*efkBSt~32u5dF9)ajp6;p6ltg1Yib@Rwz;ERnWncwN7 zT9jhf0HaXJNoj86FyIr7R&r8Wl3L@!aZ-&D=|lWKX!J#`0;VT1KQwxz{BLDH#8U4r zTJ$RTdM)jgFfJ{3N^H>RLREK!b9~`m6n6wnhs3>s!;MjeD-&r@TzoXOoRAQX`wA(Y zPPy!QF1wz~uII9|^=oAdfdtfQB~y*^T2;-bwbrt>KIfFJ! zi->yYCn2l-vtcS$jq%3T&elH;^}w6l=(@i!KwGGMd=(g#ijzMvP!O+-6KIMUVTU9$$HR+1i|I%d6ZH1YTeyk@e&N zh5xwD`G6lclJG4WpwJA&CkH6(7b*kqi}@&g@&<1N$cVNZp}@$9(m)1A&Ahh_*l~7k z*FE0~Yle|qG(h2_Miha-zL@XBx0Z@+ZP&I$3Xd64Dg*x%^HKQdZQeWJx<4yPBJaro z3Y!>FduMR>z_)0C!ij+oc-I|~JPJqu+}j0SVx)FIC_EbYfWMFVC~SA9%L5*2q_#W? z=LA0B9Wft;M*<)4UojtrOYZV^fe#p|-7bakcRL^O(?)9ZQP?%`0Z)keC|q!l%lnbR zJ?||^ZFv+%E_A;47~CR|fTtL#U6sNufe(0F%tzs|`@9L@D@JO|qwuj1V4fVHa9kiR z8lZ575yja$j97~XhKpFUEjWoh;BFy^Jvl&uVAfWf0?|w-G5FR{d(ps9k&S59u4s{M zr7N)2EFeKe8l5*tVWtP2S)aA#V>i2w=$e&=oOV@$4uK{PI!9QXk-EemLXWaNV*h?B zu;oE$7NLbH*KU=~CgRNa zQM-}Uf7(QxiFHmpJe;%O4DHHQPQc)^ys5y~;{)Ta#s})aNk)=3?;D_SXy5}b3JcVI z0~GKXNy>n~cVFpCeMPv2^Ay}ewpqZ~Q^2@~umM@4qyZqym2jntm5}hKPumjI?mUGZ zeO;;pPmB2|+!^?QELm-N6ncGKssmZFL=_;bQ@bjKx-UU>;Lc7efGk)d4S0of)qzYG z;R5dKGp7z@u@Wxe6@d%LQYBo#djl7cg-W=9clerB2eM2F7x1IL64ik$Qo;pflFO(w z#hJvy1q`cDor(KpUtQ`z79ObxJl5BiI`FGbDu66Iq69FC3-@J6%#ve%RIa%yY$MxovcDE# zFAPxVu|!Q7!Rs4Mjx>Pec4Beh+bp%ynqYD~sR{g`u}Q1*1}TicGN`wX;qC1zO#n~7 zDzJgSV>D?3$efp&z6?~-c z?F-=bPHF<#q-#y^pog6%kcgygU_w&64-_u-x((n>M$)=q_WZI@0Dk)VU~_QOXkuXC zRS_Hb(ZB|LHe!3#@bZ@Hw>^Tw2Ydt205V%tVJ696J;)X>+cD7?PvU0+mkZP8g#ivF zHg&!Rux=!60nBzn`U)f{D;t;@Ds0S4;wT-s7PtqES)Xwt`v2DOhT4{9GFuN_qZvniAQ0Qayo zP$i#d_#Kw?DUB3wY1^_X?LCHf^=(`OczDDHW*;a00iNl*y&~P%wHvUsaBsURjb!ku zh{oYVVcDSaH4Gmf(MS<*j%arne!-3zv@W|oRy?J#>OE#TozlR6_dKrv?)8h(jij@{ z!7m3k;5!}+4hY`ZXfj~HP8PcFL<=4GI-`y0I_2uYF%!Efzuy)@2|SAjC{#rm zk~QrHm~hjsOktHMfPjfNZAJ=&3zaxryzp#E_`u-^VTb$(VF$Jx@j!wZ(6%ZRI4wiE4ZC7m=e5%pJ&wv~k zwRNGet1Tf~7d+pWl>*3si#S#l#<(qx!VFtqR2+DBqmAg=0eEnHw}Jxxp>@IdN83~s z@DF8VRhsS#)%Gk(tU7H4@gEK%q$5BMBHDZuHt}=y2Fntg1*rcfIX# zJyQF2Rg!zs_coEjr~II^0Fu*-DnN4jcGXS}M5XR<2|lr|Esp|oMB)vQ8KQ#$Ce@cF zfRA`6ob~Qsl!0tLyJ}7FCPtG6fP_i;84RN1cb#iGkSN(!mjYo@TX;S3@s=n)f}b#& zX!fGPi+&s;GMH&Pvg^=p@QcRR){Vk`(M|w-rqd4Y29xQ_J7B=8qK&}EEVJLrv;Ki` z;C|2gXZ+0IB4?Y@0>9{N4d8Q@_KL=f2Pk|xN=w1hjMipsT49b|M|90N#^8BQ>Q572 z9h^t)-(sG|U z#eV0Nn5F{37kV7@G@OX0Y(zC8n$o}_x=jZX<=VPXs9G@zb8SWnRcSXtt<6Y*yjF;d z{XQRu7^)(eB(}{+fh<-T$yLcLmBzs(N0Un90P;vbfNTJdcG3*s*-mNzNmIrBp0xjN zZz=RgnJt)XRwf{D{V0nCZ|ccz0VL^_$VIN(a<1t>j(ysOV+~=IXlqA- z>{vn&@Pkpd3!Z8;Q5ZPUX0acLvgovRroge1)&{fe zNI!s8M@%d_ZEYy9?5I32YmCSPc9O3>7KLx{SWlY@;HpmQ1#a%7CUClk?kTNf4HLrk z1Lfc!+yCS~)@Ln@9~Fi3Ul<-0#p$_*7hV&Vn?D-fBRui&+yDihXiyu0r-g|A+yDhm zNR$ygKW3zGX~i)J(OxSP=D*>gdKO`Rp^=m=4f9GPq!U|}Mrb92QyQ2MC#NsubXCFZ zd-fcIR^>4UP6U(&<{(#`?70C7oC7E$m~((OBZc2a2Lk)L|A+iDY8`s$6BmzQb9Ar$Uwkw*5RcQX9<455HVq@Y2D-tA`p%#q`0i*C+S>3= zPCIxUm<39b5a7$kCbJg!PFudz4&WVn|!5oDP8<0g$8vwKDNdrKZJY@s3x@bR6SAT;hvh=qz$_P{8*sR2%_Q0-nnd8Q`h+QfmpiEs_;hryY)$iQJYCJ&esR`uHj%+c3xUg{Hx+HEw z0+NNPeDIGvZ|eiHSC$wK#P_u(80Qx@Ail3`;MbT3I6WDXsGBB6LLx01ZfZPczRod{ zDglm8iWUu|8v$AP7Y*PvJfGGk5-X#WXVCybkWp)MGIW@_O|mAuzpL1 zfsxo*w>b$BbiOUKViUY*fc2YwYMV1%e>=3#8G{w}Ib*QGK4(;=GG`1{*yoJF3j3Tf zI3uwS$pj|ikU~7H!WL%?R@mYU&t)Q8oRPf*K^R@%lLt8h%M*(3JfWzQP;Bj)f~<>% zcl4N90EwNl3;?G^Q4UP(6gFTS48cS|VFNCyD95l7?W74H>$%P-FwsuN2FR+cY+xpd zNCOh9lnqSK5;h?5L)pMg6JY}m7ZDicWg>%vS-9l&&ud3{4%ZW%7l1!)G~v8%REtuT z*{_f8KY_WIB(*Oa<#(2*5x5+!nAlDv|W(moL<7{@9(y%ZgBEM*vf zD>*4`6mfzHPQrP`D9;+>hbh3Ux1~%<@uL%9*4I)drCV&Z)iDOM#tP?^qx_(HyXaH| z%z<^uNr{(4R3?};y5ywvcqH@xv-jo!b`{mycajze$PmCG3d$%5dc{To6(nd{WVo2q zobF?U?lg!4iULMitW->=JkCT)K zqs|lQ9Z@6)j6V{l%vL1A6IxF&@teAIB=+XY1QVmK^F&%6l@4YRAWX3|NUyg?pPDBa z*CXML%0@S%85$UeENcTl$fqC94OlfB%!Yf)UFwaeECer#hgt#-9uvX1P zda9lv{;mPu0Ux0C1mgi>KDsCB72-Vb6y5p;0?%83sYts6fP^YI;c2yFu}{vqb0 z!%rw5jF*V{=;2kMhBIo|xZ_pNaY1c$=8tjn9es-FTju-;Mu?`Q3P- znBR>riuvPtBs@sWM~5fT{sQAiVm>y4`V{ zI`C9>9Q!q&%8uj00l(we+4dGv_b(6lFfh9eZ8c(RT^K}DNH@-rcuNm+gTRel_I~b23%tHn$Bz%H0!T17Uey`c>j^k|u{!ll5 zK=TA+|0U0#H+_5$51>pimS32EZFalk_+8TKQg?WF| zAGpEND-(=`7v?R^3JDvpOfa@xm_KQbyW=3HB+Ll|KClpW90U1|W1t&PAo)Gstj6;J zJi8R;SDM}KIPPuwv*qkE^uEE^c**mEfo^vkoo3aIt(QD68u0HSv&+!Z!B})*?$zve z$Fb=^X~%K?fIm>f9z$~d_hxpgQ?wTkRNeRnVIJ2UcgMj)OJN?-^iO$tgels&%?b%` zA=*!gRkg>Q_zP_nFn&UqCpWt~`FXA#6ujK7YuhRKHMg3Q263UX(Qtuc9^Y}k&MDKa zfK#TsN~fg3X;i0NUBQzk^!mq!l&iY5Sk5b*nEkJgN+3mLFB-W#%V@wb#-z zmszZk9i5z_NJHPET2-pQT55R;wU&hqH?^y%(p0?q#_O(jagu^3SS*^|29KG9!Z zWi8Yx&%N~%i%&m4R5Q*#qMkoAN-PAfc{<1roHTv%yE3l9m1*HaS-ShM|Rfg~z+oD?gnLO^`= z#SQ1h`A-*w;)e6$hV$aG|N1!I9*b}Quw3u7l6k69@oB10SXp28k7bUZ3J&GB@*By< z?Ds5(tL!R|DS%`ogKk-ytbT5xW~WT6H7BXo8uGs^@@G?|Sz>7mL*r0eH-Fo%!iY9xiKt-Hx_#u1$^`aAu8zwW7M$j@$m-AG@8IK0YnpQeLsrSV$`-PhzRoRpI0v zb>JACobyfVAPLh(JR&krAGb3b8(Hn5FORcxndJxJ0Pqk~MeL~-H{Q&yh0h@7Zete3 zpW)5Ae?>X?AOBiXusE}@y1~TG;zR_Mlfl9q3?_CK`y*zAu+k^MqDqGp^`x2PG}&a@ zCzRKpH$wK|#a~*3-(^>6!bSF{c--D&ey9xqd0jYSvp_$i`v#W*zPwEZXmY1yh|%ay ziC>{`r%W5(DQSAz*(uYOcFMG^oswHQ-QUU}aLiPWm-fo9leUz1JeRk{eA19qTwYY5 zh|pSD&+r`(jxmX4InRbA%_FKjZ~rBVGkx_llf*X$I0+!un)VNQ`={btS;RtE1RD16 zlW>S}cV^Gc^k z&g&5OAgbX?Cmg{IIVG-?r;bj^=ANy)Q{rK9X--*~73Y=Cpqy7agOY!U^RA?aWL}&n z?>wW^!jGOsp90an8bvYI%8vPv|e0wSr?S0AEV4`u?+@ef0svUYi8)>{t#rv?b^rL%M z_^tjh&C3ga!U9sP-2dDTWz(|4qkU)^QKj>SIz;bt72b$RQ{`*^(snal^Gh}V_isk- zw}Jnlp8ySD=$To0&tyx`Yb=9%Lq@=mQ7g|V+rVCJuj=vLB^d>bDZYRrDuxfeUl=Q7 zbZ>a~kBt7|7XX=MUSw=i=^N$XP^A_*g(|hE(xJWuvU_`$O~|$EDw}g)$a@wUg?r0d z`{zk5*O>5O-I!BR%8{)?UePSG<18~Kmu~$q@zJY=>8yHpF?nr76XH=S`TI@AM;QvQVKl*Y@x0XVc*u z->gp|@lget4pZ{imk%X7>A!{Gf{&FkEx-SZ6l^9-|g{~!BoMf4?$!lwz+o4P4W)g;wd{09xPecVBo z>Ug_KL$bW%!Pj+u7dQaqi9y8Xh{Jt>oz{@D`1ZcoGT>XRvt(4~tN(Xc-5^hzaO7k# z^=6?$rKzEe^t@(Si~q$wA+e5cs0Qy#HeLU(dfPe$-Sj_asqJ8akBM%FFZbrxC{}gip7! za<=iW^fiE?xDkrG#lHfTJy82|QgQnuj=b(eWESc^l-GSIZ>ucO^33uWqmWI5`4&0& zijN>PfXse*0GZFHtXogD3@!{A0YgTuJfmz0iFx9MQ5lOsf^o7ICb-EM5f(ul21H>H zA7z7=!>Ib0n4IQDuMebIl^!Rjc}a0;R^3(VM61-fc9qrXR4^5l=wY6@|K4=C<80`E z!!o_xuHqMftd=vrn2wKtB_^(dD~7b@Y{+8+lfB}Roa%EB3mQu zVfoUT6HB! zb*N7@i?VnpMam+hD||*-@mnUv>(>>iO31uL=KK1b{KxG>=9vYaVVQ@F8e}xXXOt~3 zUz}8F4SAX&#v!kj|9Vuo<>CC6v+?|l6JMnh-@?q^o4onUdS`-uD<_PXgiHHbSno^12uWT3*5k9q1C>qSbbN!VLen#Hd;?P{+O>e4ovTy)0 z{v@xl4g!O5;)DYWLvgkrin}cJ{WR7=*wd6!2rwG5W1TLC>{y2(%b?P>0!IUEtWy|Z zV;u(ArZ&LjUKm~vEsv^=u;t%<+W;APu5A!bkA@-mdeb=~!rc)O{E^3_k`d;ZQtuD^ znKk@a80#QBVoD`~8T77b1V+6Q!P~AK<%qDtl#Xba+2L|TV0tJK{2iMB(e$0mx<#+y5jheEEcFxM*1Nndl+Wy#aKBw;9}C>>j}Z@Hz&n{1@CdJ( z*^P^l62@~d%WYL7caeLNnarAlZNVa$0Z;d;nO`^fKVH=We(d4sroL>#f5*!8|5h`Y zi(+IJw-K0)QZDe@k3>0MVGAfGs7s81*HW_xW`a5*0$xjrU?!*|BH*=@2tIS7_cx2% z2sfBg>ixn=_3yje)n$mVOHciy@PK=G)yx|VKI&C1;Dl$9a3=5|uWA7=@T!@>-*{CE zxVgDo83I5&vD6EQBi4HdPhOK+w16|cY9{bqUeyAA+pA^*U$R!6munw{(@ZJ#0B#hP z!i(DodzeyqKv~u7d z*?L@P;~CGnev#1vj)n!r(&NWlP#kFs3Mm5knXtxK+(y9E3J=IqLu(8kv89O6fYC}M z|I^j+Rw9eMAsz-shIm=Q5WlTph?jXoj7^oUUe-pys!B{17!2&&x-+oD-5J=oT(G9g+68O6tX;6C%L>+XxL{3}wF}mCnctRTLAAHR7*N-u2v|@hf-#_u zh=2uEA{YbehzM(&>6AVySkq-~tm)6aogBt=e!-i&VIY=J{;mbs<1OGY5KAa5AeK<7 z0mKmMEr6$c+cpfu5=v&k^8*WrB@`AAJLsAN0ZSe`-Y5e~zps}+@@Nqlq8Kgg-(7!z)dDW_suAGPVG#;k;Z-BR zt!-T@CLKteLn;Bh&4Pu(>dt76jAt|ndq@F5f*(=uQUbB!ni7273Wnkc@P!lnvJrT$SB(Idc~uLz zonKau0FUsh7Vu858Uf-qq^`jE-dT(QaT>w`9_jtZ2oR?sEZ|*%1;l9x3y9N@HU#1` zw86kryk{5z;xr^P;NgJ<#Ayf%cvD~j@gl+ke$}tCM}UucRSVeg?qmdr50SipxDdS~ zFdjs195}u+85z%+%<|4;1c(QbdI0etQYH`wqE!Rm=$*+35T_!U0SR$yO7P|0zl;D` zXG=;TaXU>3#-&KrfUL45B@l-qEFg<)%?yk~5gL#Mw`BH2;vOHrg^Ah(etSu+l6AmX z8zH!xChq3f_WVZ9Uje6?yKzYoM!XMd0y{AeVTpGp&F-8@b3A7fd_ohS@S+F(y#fz? zD7sgKrGNE2Ag;jO7{dJ)#E=F6V&)wW;R+voZvrv&bsJl710yc^0Wso^hkzB=5dofW z@pwrKToA?W+X$F@;Q_JsnjIM1E;JyfU1?w}n$Un4G^K$t6G8)GC6ornOb87)zQt&c zXE87Uk{giuuZ4n{?Lq@G*_8%nY6}g>%vKthNh>rUb5?2KFj=z$X5%dbnS?SL=K9B| z%oV3Z;3=sV3TC!AA_9+`ln7?(I3kmW!RM3+j6O{bW>`5Q0^>@FU|9I>16=7`;lI7jSe%sFB=qs|eZh?9uM z-Gb7%ThQ&3`UUMS$K8U`)A9w~h9wrXyBv25+Fg#j1??`!-GXr+)HBqi2NtvuRx|Dv zw7VR43))?dy9Mno$K8TZuU!%{4tZO=vB5ozs{~s$ulK3>`qC1b0j=fn%hD6t|_&yKQ+8< zIODLmjlfw4C4xEZ;O-t_p&iyyVz-{B^L;zG!%-Yfe2P7f`f)gdv$&le!Etwpk0L;z zsq+Zy{+x@5T-jo8QrP`#S}@yxR|pF{cKb?9xB04Lfya|%)v>Z;1*f`_yDV9#k}+D- z_O)#8Tm{*~5ealkB7oQvr$pG$jtI$_P9SE*@en>}JgqkP0iSjR_;5IJw7BhsXV*J? zP1|F57rV+%1^97OxpEQi4?H$=f3Pi|W(R)Qbn8v{^ktnjU$wPOL~dI+8NxPE6R*nkUlo~P@PC_5Dh%AzEU}ciw2iQ7WPx`v ze6?Mr?}1xHM)@6vkFl$~f36w$z!hhmqvvGbUCDIzuO zu4S<7m~r8;AHhaD9ztxe!5CymMEK>SVQ~Py#dOleKn%A_i@@uQLAsTUrQ zRj=bAaJW^Ji`xjCZq+J+vHy;U@Po)1fESrgN(SB@(ZKi)p#k3=xrYxL#&u{_z_(E99^*sN0v&vw*L9|X@d%RH(l)~U$Yp@P?p;O$$a>zTMVJ)% z5%4Cai`LkvSei>7`8i;hF^gjs#*WE?nDwqxa$w-Juyj7JgK)knwG+TM`lDM7U}XLm z7x&I=ld;8`9~fioYJxfE{*OB4Cjn6M=QND9`gJE-}xJnc8B< zOjpmM%+Gs?a;$@eX8r7#sp-`l!VF`BUFvjI?Ud=V+9}ihyi;Nsv4)~t>a8G4X~)FA zVVAT<;K)Xebr3L1N(5t<#FGHAO0EzD?2@J}n4_^ym*!}!gE_*GXpUfvhP!D5%!aEE z3rrT1PPr=Euzxf~!7S};sW%mwrJiKCyp3?*Z-b9s$4&*k$e#}CKh)rV*;Q`^%*i2X zSl~TIlOmS25%#jZx29zu{#JX|?sSH~X;*pK4EU3X2EN|Y8o+;eRSUSaJ#x_kz}tn# zFu=V{B^6%KMi{v@w8=4s&$X)w)dbGIEffGg&2*9y_)Aks z<>s~#wzEaImI|I37UFZ;2&~SP2##Wm%l#`DJXca8c!huLGy>eg9w#XcJS{wR0?vqN z;F0hoYHs@o6V3=}ftSTRgsXybK^uWX6_X~zM`b*HAZ1}zQAW+lZZuqdj1|CoSILDzp z@Fst&c`_M*C!0#@H@A&&;_{FmxH6rj1zze^O`=I(`g=&p^TOBKBSNjon+<<7(tX_U z+V;pqdAPkPb{0c*FE)H(q~kQk5q9)KdB++i`lLEeT71_cQmW%z#btI_Pjx>qe59SV zP#q^L{u1dp!u)DGN1?o34Zkwl>7<@oc|^nh?2kIk0umc@qXl7_oovvw;Jy86hXyc; zr!8wEToibmiXhac*@0O*NV&`WLxA0)?GJcA(@6|VzTPA;tR*gng&NPRd4nS_yu6LT z;$4YgR`2fS5m?GAG4oAvD-nl$k&#{zq%EB|l%Q|yxuroj$v$B!HGeP$k4hT^nUDjcd$8#8$93d?BFf>PHmD0S_EPN8cTbP8Q7rRQC{ptIPzmY~L(6Fx9`&8?P9M5dS5vCk^&Z|I_) zUr_4#1^x}G9YSOSNYF!?SrX@O5-#X47@|&I&?$8Cf>I|-^1PE5bPAokV3qGQ-5Nb~ z+Wxn-1DR%5ozvhWy{IE@VfRCFl%8+3Ovm(i)R6^HI?SJk*$5Vjh4#bey{6H1s~?u z%0s|bv{nWm6V}SWFL>1u5X-6+0kZ&>Tfo--(U!VO1GDCptq5=fzg!*K+~5vD1!SeG znSqZ8G+<>arGZ)RO4Wd@Y?TJC{E~JE$kJ9$r2(%BEZ}vf(#*iOdRhy}f>mkY6@EQC z#5$HWtkf2W)6$eIXUAJY3iYfDWEW^E}n;9G2IDcu5OwJEH>+ONx_g(s)Y9*-8D zY3xJ`C5}x9MY033CRG}kwWiR3EEtsr{<19?rM^HSFOm|7ZPt`vmX$&SVy%@1W~C`K z;16xlDT4vX+EZ9SmY%}m1Te3JX#QYUo|@7YoV*dDG%$-%p#fQADvfm}>q*stf9cnj z4Is-&$qmRVQB#6hCJGIRg;yGwhj&7oZ4Q9QiqgO=-=wQj7ti5|b-h)8Wi@OVQ!Y+x zNt?LIE23Ztc&6#(TZ%wzkxPp;>a(fllnC)26U<)I5z~q4l<8D;%JC*^6+PPm6C-tr z5yqRx=@_m5zvpCckL|FlcMOh89OU5jgm-L@+bX5fO-iDiIv5m6vpT z9%@Oq&!m=&`%H>CYo=J z9kVdYW_JoRYIdhEduDeEGi7$CFe_%4wi&Za+l<+Mn}Jht^-SG~Q@-BD8zXC_Z6zL~ z{trPLOwkCMUD|QX?l3a;3WsT=J4|4N$N(?w3ukw59t;py%fiT*ooyMq92xUVBV&H2 zFf!(sM#lWo4sw2JWX$grM#lWo$e3Rm8S_gcV}5C5%rA|M`K6H|mA4IOG&1IQ3L|5F z=eT5Kuq(yhObW&Yh~1Gso8MvZMB`C7aOoi6FO7C7x>NC zFpw8j!YgIK!)kfg@fu0_=FzFt9R})&k7dO)3jyPo^|5n=+vR*^?;^%%)6e zz$d=T8fG=d&Pq!Fv$c{EfNZIh#-8ev{;i%7ATfPO32Z+Ug6a<#KHYX+GGu^6{v{<4 z52a;-S@H=Dh|f|Qm<6BEfOs*bf!UKuJ%H@VT%opAV^t`*0dapy1G7Ms+<;?`g_{TS zmXOeZyd$K!fr-Kj4ai1NX<&AOQa2zLRB2##fvJ;^>`y2KQRSkT5Bd!9O42K>Z(gZicK;Y(=5zIJrz>?Y!-}pu9--2Fb#b8 z!?pFR>xqPo)>Z~H{_8xEm;uTJGv4bwkub~31aJJPFa6g&71Enct4uHkT=Enq5;k0! zV2(ZsQ-&83Pgg|y(;ojiUi?HDjENTJ&wKoH;`o^`n4nzEL?T3|bpjKstC>jg^J6g2 zk%jrQ9{*JN>gcI5nDuteM2ep)gNYv0Or-wk$ugLrLd`__S;PeM27k>&TEmv}dhcM? z^EDIckcbIpv0pQhh$V_v`U8n*qLu_EoLDoFc8U)2g4s^gB_W+3F~LMKg!$h+SzJR) zC#=DvFJa0ELyC{{f;rY(=ZVC@UdNV`RMS~$_L}AV?H`O zw(`OF>zI!YzpZ>Q-a6)^!%r(8jL(kw=le`RMTP$_L}!SK`~z7reak!T9)?j}Bk2d@!Cq z=A*;oD<6!%kNN2E`^pF7-(x;H{JiqP`16>L4!^E^FkU_8qraZFRdV?`?IvD}QyXD(uRqx4PYx_qY7%X1uF;P&NL&8H#|7?fRY-i=Pq=rtDkRns zqWxp5+sMEsgQdv8TL-(14D__RjSQ^Ws=8TONbMgUth!lK=-m%?8yWcapg)Dq+Ch5{ z%$h;+ymHW=Lub{XOfahjVa^|{kXSD$6U;h6m|q&KkXR`w6U+)hm_HhFL?8y|6UmD z1x*hoLLlisIandFdJyfK2K|S`SU+fbFzW_k{-o7yykOnIZsP^-9;~`qIY{a67_7Qk zGu&fu3_Z&}Y_PWePt}@RO_h%~q>pEyvXys7B+_SQPKjZ}*g56uvYRxaxA0|_UTA51h@XEH=_JeUQ~q>ogUsF%-X>;g zvW@@NZT2^2SJ~quA}X#l-VftzLB%SN^2h!G)X*}6D}pL*2cFcu-=5gXckp;SkVibC zV%g~9LKB)ik*1=;N~AZG&7{Dph+i}V>tdY+4jkQ0pGL_?{H|~__tvh9U^V{2<@_bScNPs!VAP-unS!q0F z6crVqY*D3Q6;Y+--DS^9AGNEzXTSK?`dd~k9zSAF*5xnUfvh1THerr4?6I`4S67z2 zFzhT01(B=#g?pY`_80E=WHrZLP0lmy&oj*aP`ofU!lzOh=+bH7f9)9RPDz)Hgn=;D z?wD|@UFC@&kV)YZ7skd|o7-T;?U-qwIwgk=c(c$cxn)iQIAwYSz$w#?dbKqzCv#SD zN~dt_C4a&_%!-}0d0`OVY$t@4*;R(sA{&J4Av*TFPlgqcv%C?T^K-}8$?L)(q%2+w z5mT~(bq@C}cEz(|lp% zwHCH%d?MX0PbLG+@05kfu&|vDILBm$a2CfYSx6ARb;`oDS(trk*D>j|=(J}3cbs2M zx=oDULRnT#rqAdgu?%^~WP_k^%#KE8>dE{n9JVSPa!R+?l8_Th?2-#}HLt-?UW1{$ z219ubhVmK=Z6OPk=w5FnzBV!=1XqMRxwxq|1$jRZ-+n)Im+yAd^ z%%`oQ7ui+Z=iFOrXNy;Q&>vA901||a*et#-UG=g!b+%%IC>~cUD)uA%35=+KY~iF2 zfH+xU;bQs67f}K6x{?rsje8YV-k&Y}ZCJ}?f959%Q@1KAoGQmnMU{F_QKg63MU{?g zT8561W9yUY5t?6IY2NIaE8W|=Hrfg zylUtwTarGpjXFE#=$7V}ZfSm-P2!bdUjk(4$X(7a-R1nueeqs516hXC3OlFC;1gBa zlZBTJ3dhh3XOZVTo_XWd=RK6?-OBSG%Ja^aACv7JcRnd4UW1HytS>4uy4Wf!sm#_?^$`pGmo@!QcH6r zRFrbWm*us}GRs#?&#VFc%im9vHQ--u=>OeMfd()vq_dv=jjHcEeLZ#H36 z#4VIQXK|^SCEkG%d;Cwc3vH{y=j|$sfH7M#@OW&Z|2wMzASZ7kHjjDM_W#n9MbapX z^?}&xIsVN)Zq6yw+jB~+GydNx(-nYIrfUGFOjiL;$p)LPqf@3U0jEsY0#1nm;q;SJ zVhCs?r{tL$Ptlx`12=rP$tlwnhEt|%45v&@^NC4c%BFozM^?RbBo&gCM&4W5N`wEN z=KCwMtf7zS9#P$IW0TGi6~(>4j~oBbXuQHGEDl`p^0ug`)OvmhwbElj!by%83iHb&x_VK*3&F~Rc+EQt8GKiM6(*m6`Ez&6|ly~dpt#u&vaJ;l8PMOx_8CO^@ z2W5%*v<-)xVbP+``0pw-fR}hxW;YJApHBCb29RM=*!iDpp9E=Jm~14!^gIm)KQSs=$zUKN;=f zqu*J(r!|!);aXD-dr-6a-mJ|`=i`7CkB!h62Y98=x9|~_zx(IG`vds^l55>3ZdVu` z-FMDI_NB4OR(V;DEVYLVoSC`I-lmafD!|K46|p%tv#tM>N49vOEWTbQLy!CARz<}p zLnuR3^Qr{j&~Z!-7ewb27Pfi8fzXd*78ZUB zOMgkeuw7XAEiC>2_`-H!;kU3|SolfhZSfyI%pteQw--3vQalKx^yR~ zy3`)1F5L&JF0}@#OO1i*(ymio+H)Yln$^|2isNL z#F#`9vLls@EKI9@shc|J;!RY{GcgrqQZ;Z~lUSbMPS5EUkd z{}2=vy%=2H5H9Zkzvvla-ks(fYl!xv*(EPr8>UiJY28JY-g5ePjuR&wK>hacM=K9V zQ@y~VJkvtN4yQ}3;$*+hAD~%Z>33rTn4A~bFfKS<%7~oqV*g0yRtx!vonPE0o)QJ+ z7PkvQxy9|&61(K7DR#=#7CU8XjGZ#I#!i`o4(@wdn?x$e60OUD_$C zOZ!B1X_u%j?Ge?b9ilq=gT_}~+V-kT}sRB01_*8XhiPP@7akQJ|sIwkLSuqG;2HO(%n7nzAF&8kqZ3#>jr zu&aJg3rt<*@j_ZtQRSIu4LAz>b%|hG!XXnrSe|8Q4`R~q%&0lxk z8`$ZXp)8h^Vw6H4H@qz;$}|$=n2ZSi>d`4LvVYv+&$OKK52ob9Hcm+-hr`TH$%n*> zQPb$ZZx*)Mpz#8wOU_%AeDT03`NRQ#Jm{1(CN1Zbv>AU#=#<#nXmy^)S4Wa=lTo!$ z&&{XBNPLw-LdRr-p!lDqv?z@!m0Oy97ThVRJ~emBwDSvPtm6Of=?j)ylHKAqW$+i` zVsC&^vALak#s^`?p1#k2-(s%@^xIYX7RcKIg>}|8#@;8S0)|xC>yy9yb=@AD+5}o@ zRG)7LLY$IJqT#hPbAyHK7W+vOWw*Fp$SxnPORRQ}+SUByRAg!`i$!J$g@`IGLR9H2 zT-R=U1G`F714G^;dEVLTJFTfa1$G-9u|audhw==E^2%oG$CIrUFdh1$9hiSqcE*7} z`mN0Fi`4_-9~`e>(n4<)%}vz#d2hYi>bJLD#T#;_4cBp`kMIouKWM6m&A)^{64+_S zrDfSNVhRP3t1Kh(+_GiFYqFZVWrVK&^9=j*3^Nb1_=b8~MXr6R59CFzeX0NJ=jh4n z()Rc5)3cGoUfRZCM;F*g3?t{7PwEHlW+qxI$wHQYP}rblU4U#3u5WL$@zv32 zXfOUd4eEzBH7gA5JfjiDamdJzDu0!?m44Bo&@beD`d{hI z(tl&*#g*P1&Wp=>ZyhU!uf|5VGCho^JfmzapJy~eB|}Cdc}7`{USKtPwOw^QfkQ2a z^2~?w%(I@`$1>f|t}>y4!%%dSqDE~JmNOimA(0m)2mJk3f} zX-0f8kuM<1H%SlN-@YB5a(PpWe*_f^0OX^BQUZ|IM+%l}mlbt)@d0FA{E}?f=&$Y5 z3Z&^I>oi%Rv^}k~gYBySi3O$xQN5`^p|Os(9FDQ8*aTq6C_BOa#-#i;oqZOPoZHC5L zYdO`hU1cx;-{Vz-oPK$pe`hNTY7hc>z(-L=fJ88)0*l){&#nvH#jdi&0P^)_$3x&V zjD;BFm=$%WUA3FZp07l!j;t=RB1^*|%}a_)vl3OBQ=w8{w#xj_SE@4=OhsjS=b5+i z%(F$uuPoDF+f{lCNZ!(TOMN5L3Qn1J{RK%)&7J3!9m*>^lvg$z;nUWud-@2wN@e*T z_L=q{7@|sRl^%B$Q-08@OgYEpqj1#XQaCCP9&T!XcyVa-#}~x0_#n0p6Fy`4E{g`0 zhEAH78@_2~PDyV6?qf^)11Z4q(l&XS)pAd}5|~EjE@WJ#<%)_@DWc$9T9)zK>?-{N zByXwMa^JQ$8P6%x+HPw?H4B z7(DrTUbV{$YIw3;g?0KSwQ9{xJ?m(L-w&##FRFiCVOL4GXbV%>RaB2{RjYQ~+UK>K z!4Cx0IR?KUREu6xCs=zMpYWvyrv=sC20KA@^0sw?+w3ZpxXa+5gKCSH)~tQ)Dy+i| zc7p0-2G0+wD-B*BR4?7G&g*4%mAv*a*a)hF41O@Ep1pmYaC5s#!UtbgtJZvZeHB$Y zoapKcd{+<9)otI^&AfY>dG|DFtk5#eyaw6!ni_o1ic=%N(7MGcUNQ`)TaBZd0}l-~ z2Zoy&0sdEDQ64uXA#mWWe)x?5sZ}9RPNkxm1AJ!Y{O_7M45JHd7_Bqm3zL~$jHh#^ z))O!O4I9avihslWG5A*c%?9EIW_RM>m~l+E_%|j$qc;AH`f_FXa!)$%z}NceG6du{ z#i0Qyr8Hwx!=guNX$9_Fb=>_5yJOX*wncT^EqACo?u2Wp%okg)^x9RbU#iCEUtD+I z*X$~^J2tCT58G8#+gT-d^LC=qZT-(NOMSVw*p0^xKF=(-6woqwcuBd$`@*{BhuT$jml=LfG}stfZ;eJ4!-#RB zX~7H>DHix_o5xD)GmMv49hku*Nr4zA31a|9whT?)F??O5TVZ$uTgGY$n;B-&syY^~ zH`@YMb>J0#QQHE}u*I#?z(<-+Dh!mrn{Y-^X_p$lJJPW>USz9Z<$-VYE8-RqH>5O- z^99k|`lewfl+*-xi=S?@fJ`xA0hwabz!PnG%sN}k>@^*0Zq>1}o@A?H)v=y_iCI?F zjTpuNs}B6%-Wa!l!N17=rI~r%#+%s|@Gw(pZeXmk+!wGLlkxY+WPmXf8kz)SC*)H( zz>ZKb!N&{nfr37GXchks*CdC#L;*g|3q8+Xxl;#5&!&vXP9#J|CGdNZ zt^bwbC6Vq?!?FDbALniT@Fxti7T3Cg@dI)Tz-??Xt~4+Ub)f-SvnvgJhhN7J192)! z13%9@mXb5;<hxTHzWk^?o~s;w|G?xh#!{v1K$-`z{9<22zZKD zHGrS-sur;Fsv+Q|Uey9#;Z;MxMPAha;`g<|z&LrSK9KO9(!k#e&K-D_SG9mY@v0%< zOf{DoD;cr@Rx#X2Tt)mdlv9Rk!uHk%+ngc?|RiNAZ}cn0zW=G z+D(Gz`mJLF_#>~H1-v0j3BJYC8o<5$26Gm$v?f?9^6WDV-xxV5@SlQ{0&d}5%`D(C zk&^;{!qXbSpLx|R;H8oG!LQ&rB(MU!KZ-Pg*$ruc%YMdSYm0-i*g^whb(IEQ;Uh@1 zfEZ<^jc1iH#Zm$gORP!32YNf&0Aga5hE2tIst#)zTS)M}-lok0V(v647~3Y512TJ+ z27Zm7X|sS#Ri%N$?8{DwjXV3IMJ_X8G#by~^TK!rKFg2i7Vw49x);2)r!|0tV#TKt ziRBr;yK`GHPx0ZG29OCOHimdDM*%eDnKoYtrl=15BEM1{0`3?sXu*4US_9bjsv+PS z(MlB@*1ZkZxR*pU@a2B>+5oQQr}7YR(`d$nxA(LL@KCQB0wK{AYhtXY)? z{_n7)1#%ihQUZ^Q?ASSmr$mcTFiTsxE#M9j4ZMe6m<|DtjA&q@I#Ll}Smh33D6fiA zf)|AXfTu>wS5~J{LJWxgl{*EVAEgAd z0+y7(IOc;XW^Jp5a-ikdXq`Krd47#I&kZ0eRLu^InU63nVnQUX~V zDh+(BU&##tSujc?0a+bNWo3{2=pXh0r8C=JXa zQfNTDkpU zNE2QY4n9}x4c*3}% zm6{@92I^dqFbH)HNb%|ojG3sJNOwhs1pI6>8g=cAIvO|`RJJK$_F#oV?Mek zI{)K5#zI#jyty9p$D8rY(3p>onX2^xGf!haI_9hL z!OYf}kB(WZd@yr1=A&coDj&=Yi}~o7Y03vPJ7PX_gX@!>BQoQj-`A}dd}z8~hBFtm zo?zyHFWS0Uk!MY~6zcg}kRN4~VLLc&Q4_pZJQiRmud z(LTSTXTs~C1QV_n=I8q=B&NS;&+hZV84Q4?2lG%@n7j8?NSFiB?$%c!VGuMum@R`a z_vx#U_6^H}z4|I7jD~Rc?DI#5FdLdH80Rm{ulD%^Ma0rYyG~ygSr_eEGTE$T_9&vA z)#qbO_lA1Cy{|%I^CH}X`h1L?MTKbJ*;gU4sS)j(Z_2hfqFv`r6}z04Z9+sl`AroP z`yJ6f*5`LWELKGONS|N2u*DJW*ZV3YHaVibw9jvO*wl#j>b?qz2jil>s;@%A9Ejl-jy<1N15 zkiD6)W_O2Gc_vMaPPVG~S)f^|sg{5#Zj$S@cIxd$yUKTiUTXiNNPPHn{^(#oqv0{X zY0lo~B*W;o^UC@+J$Q&KjYDzx6;V+f{=e|@2gO})^_P#rlhHh1?*TG;*w;JzuI4S) z@a&4!$WS}hz^WsnAIH^pv#{4tArv;=LtxEshJ~XDY^jd8RQyD?6marQ73~|@i^i@E zBZQMP`EzRPEW3#WbCHHNmS`*5>+~wL`7JYu_UUSlSr$m(vc*p zbRen9f|CR*MU@UCQKh3uROuiRRXT=5l@1|MF><)(BS^lWZej2+(|QXtt+z@WM_)fl zTSs+i^QbOuAJwG|W}?ZY*1r)Mlu$s*B*@xgl9 zkn62xWdrA^sr<&Z$DW;UX4f?)95s2(tq$d9uK5tmjpY7`L+F`s)YSUZ8ss9^ms>ec z#^dB;K0jilZIzFC`Bw{TiznkuMHS5y2h(OylbN=I z>e7Z#UD^_=OPfM<`E-$g;mW4V(|2g-l+W9wylBnaC@qoWS)8_($Af8Ssw$hp*{QKj?cmmS{s32lj9%nV z4P>vX@??NRCOVin2f;xE)s0vdo#;v73d0;HP#%$eBKE2qvdSN4SJlxfH%Gc7t%Evt zRo|*+75{|oAL9`bCIxIz%j!IFbgHlxKm=sky zBt?~uNKvH&QdFxSkG+NYE&qa*&2MqE+5GM;%bvJE|^iNY$k+ zsk*c&RhPD<>e9wkUD}$eOPf=5t8dR|?B!Fjm%MWj+w!!{r?+zq4brRaEJdCQ(rX-rN%v@FriW25^a24Fh@hBj=K+I{s4fN~?aA zRrz|mO7kqVe*~f?|KrOT08*ofO<5=TX3B!NlttS}4T1lRW}*gN+%3iG7xBTgz@!Ps zPv+LSPx%@?xrh79g6n*yVRcKi++3HJW2uAFIgp#?@t0mqTTPpr=5VwzUV8CNkXwE# zW+QKtvRljBr0l}-HhJRiDzr)W?kaDSC-0ilHj&jpVX2h1h^{Q`{2gm{QKju6s&t5m zDs|qX!gtdcqDseys8Y`@sNMb64kA~P0Fj5yiNZ1nvhc8r0uqutvndblP2UL zgE!f`9`CU0Dpnq)VU!kky={is6t5y=!23`*1X(&Tz7 z5jrMIoR^uAS>-ni=0J6BzL>#9rdU3KZrt1i8J)up$uy4BzR z|66lD?}ywjjF=4y_9@@;e#4CKFYLMs$CD3_yts|bTw*qhTV6iugss-Fw7o&d>wuz4 zN2sV6jJyFRs&q`e(OzDh5nf^>@5%ms!UlPNWz`Oa_Z;KzNAZ3kE=mn?#~jI3kwYPl zO)<)&MRtoE%5jFziF7!Z8By$-ICd53=ujq}mVv`r6gi$-4YOKQo_9jFb5ChBaIxQa_QdH@X6jeGRMU@UnQLTPF_WEz+g!$cDnBNlPHnS1t zcW+^S_f}~msuN3FQFUoEsxECu)uj!oy0j%#mo}y9(zaAx+L)?KTT^vubEnt+lC-_hLEZgwp?_iL=2f0p0O z=g=z)b4bRO`Nr5s(k}ljAIYoE|0*Aux7|~-NqO6KZ-4T(dusM4Z@Yi4{Yl$SO#YMh zhiSV>Ua8p@RXXBCl{T8FQkyNR)MSe)wb-Ic8%$KGy%tq!u0@qvYf+_!BW)}-=xJ-I zE?qvTuH^jE22)e7Z&UD|T0OPfx0t8crf z=IHXa``>HeN`0NSZ)Hv`80|b%dZ#&=9@{pq!l~s=n|J4#$sTMKq0;$Q5^hbxn@ku! znJ6me#wY#0vh;<&bY@7xv=P2##a(SziFi_6BYen);*R#kWpU9Z_6F5?{}#R&y#6a{ zJo%MD_gcgKuM0Zx`%EX50M7NQ7VwKvO7QnRtpU8vt6IPZqmDOfagRh!54d419-bvwSa5w7Fr1W9Mef{f%|z?3wU&t5`2=UHGrS> zsuu8)C?)t?p4I@a^LiSs1>C_@+Ct#nJ*@$p;Z-f*yP}lfBRs7E{IOTHfPacof*1UEgc0epv7wSXUuQi4C`X$|0Sy{ZLV5v2sLzb92|05|ih z7I0@%X>GyNJgosd%d1+z??frV*Lqq5IN{AyqXj&{R9YtZbWdvlulK59;4M)~@V%ba z0B*gPFB7=0skBV+0iM2-n1mEas4d7#5)dU_JEjqxT^(%}9@H<}B1nv|q0KhZ6w{HMH=v7VNU!s)Yb%Qeo z?&wub;8!Cz4!+jY8o>L!stJ5={7(;SV{@I0jtQ6g0J)Twh3Gj(ZD$EdXC- zDyZ6LB3ERK2!^Rs!ntdKfNV-X_#p)haIPandh=F0Cqdq zp5tds3)syad?t!~fkQN`w;~$$5{rsyYn+lr$a*UxWOwh(_>i}I4G-^9>v|?k-n>F! zIVZ|JD};Ub38}%?o6Zpt?lh%-9%xc^uSx%ilK0p;@Hu|D*js@&F`dg2;pL{RvqXAT zOhxDm)LA_h(uJngusHaVI5`5VRw+r6BmF3*B81-W^_KS0n25l7RtpDz*G#gzO$2PS z6n-#PMZjhY^^l$liP0smqX2iXvF8dxm}bg4HPW6j6#-9BQ;}xHRD>f!uBT0^ zkUkVs5l&f&iu9?NickgWv`H1xmtrcy6@j|@qzdT=F%{vum8eL+iKz&G3{G5$<1! ziu7Mf!G3MYuNPDiuKbMNCCtQ6{rbTY3sUBJ5*IDQCj7Dy06HitzS8l`0{m%}U!$H7QxS+Lm6~fzsa?c9ky+L_=h43Fixo3rNqA4d$*t-Is8WRyd z7ZJhd$3%p0c;a3a_{x}w@Y9G0{$)%=xIH3*?~aKGk3>Z9L<^s}{z2Htl#?dxRe@g+ z6A_5GDG|IlCL-MJbCgA};YVU3!n19IB|~Glr$XAuw62y2TLtCi6~gvGxo3s2Yfyfr zLU?0P?pYx;gK~a_a6nM*Ss}1-lq!AR?;<}CGZ9WQrQDL(MWoYWD#GUjRje)27h@^{ zJ5tG2s7T+5sR%y{xk?3)eic&@?pTS6bWco0cr;L@0!Wi=|LS@QVPjKDU2mFLA-yoB zBD^e67f-B^c8sYA?5rhMp(5=QQxOgfxk?3)-X2pCj#`O|bZksTI6Y9M0!W{UsR(TE z>$)QSXG}%-Zpc;YiuA*nig10PUOTZu`fW@_xHnL*nOGtHC8m18q5)D@q4t=xj$K{H zB5V?mtNr2S(m0)dXYu1N2VsR$npxk_D;PK>DtX9nuk z6Dy?8#Z-h#0(IfU3h5g$6@h4r)K#cRKaHsfzYDoa1(0r!sR$3QL`8ZerXoDsLOOK? zkTx=HZCgzs42DuK%_=0AkCkN-e)In=f^OIFn@@)hzaE!|4)-3{6CGYYPKWNWLV4&IwsE>AGk9g#A3JZ{P~+cr zs5@Gi?RgavNAyH{-aH?IyysOh7wIoS`{j8)H2DGxO-c?|&a04!QHu7v^RkGgXs?>* zLzYYs(Mrvbm?NV7;=Jm0HhBnXiuPOcDx|~g*E(OM!E)^x2^O`Me5= zSZSRv60=scznGUrPDT6Cc@;C2c&TWQo0mmT>wF90(?#>DG<;ff3-Qxm&GYfoeJ!pj zTxm(9p`blwUWIf>&KRb)>)?5O-9AXgdu4h+BgnC6Q^+h7qTjzj8tXH%Tk7beH znp+6{-Z@qX{SIM)cL>o)8IVZRg7%MN6%ygzx+o;Vy`sHwtU@B*TXT_)2>JeeEQ|iu z+(P*Gr(;zb{;j!%`0rI?S^T%=76QQE8_NQ~HMbA}zGAFOBfvGc5CZ<{SQY}VxrG?; z7sskJ23&L3v>4;_Lj~&1b!ulxno%vxX!l_2R?Z$ ziv!o(LLm6Wu`Cc=a|@B+5HSC2;o|%L2kR zw-6DYK9)si}n>`SxmU*7J|Yr8_R;iHMbBI-e#;yqrx?} z5EkBaEDHnprPVPO+n_w@qk1;S+qNzokf@HeAD=HokO}D7VTa0vJi94eXT8-i7Jcs=6P9+ zx#kvv%s0);g3L9y5M}<&ye!IGb5F23e8#S#-Qnyk%v^H|apvvMuF^Pj%`F6)H$OWI zG}qihr1`mLS81fV=H6!YB)BZvjn2+O%{8|WYhLf{Y8{JfZfMtbUb-2bq$PYiXKGMWXQYwoGWA<`_` z^+zitLd`W7iD0v6pEa6=o@;Izdlv1a(JGBT*W5JxEZPa9RT_Y1pc zp#IKil?JG5ZXrT_#b_3xuDOK}^*2VVG(=r<3o+{Xqgjl)<`#m~=ZY7`KQh#nV zi&EFzLYVrj(JV||bJwvj=q4dZdirP?nM8s}AkJA2e0u6te3$~Z$JHZ3_EKbl3V z>wF8L>JN`rX{fs97Gl+hk7lvznp+4~A2ON+t84D(toFpGMSIX_7Ok$ig>dzOqglAR z<`&}B{i9jDy5<%F)_aatX~4SX79!TuN2@eqU2}zuO7`} z)-|^fwBBws3tHFQLezTO(JX3xsD?cY6z*}qfG+RQ8>fa5r))p1ZZ5G;3>td(eTsIc?ae%+ILGI&IL6wGG zpOrMzVWD~amx&?P5Ymn^cYH1_We(p#dU!>CcA zOP)T((t_N_z5dn)xsN?p-6gwP+t5}kcS)XSf1YR7CA9a)Lzm39znDaIQRtG5t-c5Q zdN&U@NN-8|(_z%8&?QfwV(Aj@<2Zk7gWSiBL6y#u4_MpKRx5W&o@alaXVxXO_xD4W z>|urr)y<(xE^O6?>o0bd#$I8N-VzlZMvV$x^7JW|F5y1b3+>N+92!(tJJtOlExVJo|4E@s<{G58ghhu@qe7QFeTt<^xQ{RR zTN~s){vK3mmn^Ynqpeo%l047;JkP94Xz!OCcAOP)T((k0x-LVs(6+{Y%X?vl6cRF6^GYUM7;^X$*_ z%({g3KHKt^S@P0b>lGKO1@@D)?9zd{20QzDH>Vq z$5(gcJwL$LV7eSTIk_W9zXseaGB+s)y z&ok>1+I#oVB?noTpc)Qc@<}_Yb-O>Z)x6&zy(R5Whf$+KmppxnrAxSv$Na4gavvkB z?vm}TZD^~NyCl!EKhHDk659KNp-WzAU4rVfp-Y}^_2v1cH1heE_wPC zOP6pTr-UxyKJE^xbe0@!Z9`kF+$DLQ{dt~Qm(bo{30<<(qCTj;vrBE$q-8l%#Kt(`Opu-JVd@+0Djhf7;CqAW7=tGT)yE886jYZO{CZHO zEp?pzG=4^Ds$DJB_?1jk?U#R}U`qatf+0>6azeZCj}v_02lP}?R42Rb30u&&D>6xO*6N% zs-|J`=%}F;b}&1pIxy2kp4ZAJ8jv&vA|H}K8mi=sRMJv3;d$NIU8bK1D&|7tL`@%e~ zx9aA`g?VysW&ulG%{+b3+^~E`=Go?BxADHV0mPgOE1hMcN(Y>%(vg)HH}pMQLEt(k zO*ncAIFvV(PJdb48cl!iLd%m?-feb30Ut`Z#65d(G_>Jk{JzIt*R% zw3P}~T!jZJRB?H`P{rl#LKT;{3sqd+E>to14pi}>cSY+5gy+4xR!*ES0>o50FO02Z zG&m)K?})3iJBPkAv@Cdu>0|~1@9?Sykm)YjFKZ(( zImBc$^G~*&hU5nPf~h2$GWm`=M1tx<&mIEa>{TN`rkfO#PBu|7)y^zG*-#fn% zAhSq0_0mOiBfwVJg=b z2-pSTrB*>ysZ9_S&V0Vfw4zIORbTp#z3n-OK?VqSvfMD=M1>8L{Y2de*PH4b`A{zL}Km(p1(ZD|rG~kVms`c4n}Sy zHFBRz}#qBFs8>5Q{&^5 zm>Wg%Q#$!B`Qdt) zC3ItYgw~DW5gKM^GqW68D0l~NOyFhal?J}=Y@Ztt1EMtWHRpI5aIvYB2EOuKPXqqmR7wNi zA7~y%OP`5`FV7VzZEOtU*P)5OelYd^03P~B)+Gcblktm2#w0#Onrf-xoX01ddo?2sRLJJY%R z5N1R~@K0hQ!geQw9KmOs&gF=3YeWQNP#h5fi=wvz{;*jbM?|QZjO&_ z^_>~|0DPtCT+s-dd^Qlldz#J>5ipPLt}Wn$QFKIv??t8$e52_c5dnjzIfC~yH3)|5&FV?`Yi0W+#Z@NdH2aZU%}9#bk2jKOs|B4BZq z2wvaJsv{z79@$^;TVo=^dm85#etU5sWE!LLIYxEl?KMj3Jr+uR2mr5DKsFKQ)ytVsL-&XKQm)1 zcQu|3{Y}`l0{BKuoQs1doN3KrFGO zWZ8=C)s)~<%nnO!fnW5hnLrG*uz=&4V4-zmfQ8nL`4t+*7dxtV0Di5lM}-D#deuze zm{*MeFZZgM!27&v1c;TEb_8OiwHDy_`xWpA@N}=530&k=BS4J1u#%%}wcw zt?j|2>cFq^4=WqMcbdwz2?7r{H7%Inzat{>BtWXn3hZmq1B3evKOX78lPzQ?4FKHI zt7Z-v{6FlSd0=HlmH*RWvB9NrRBRPZBLd=xy`ED8p6hE`O9I`;3Jd(Y=oO;shlrg65P`R9J` z_nlg9)u~hGRMovHMcgOuUq5xFvfO;bNUies4c}!~*&113yAF%(Dim;qQJNCm2x9vf zTJ8l{|r4xqVVpl2S;?8I6=AuXte5rBLo`uJyC`O zlXd2kcGW^w8(t8_G}{?wNlE3vtL!%^w`-7iN3;S+xT7h-t88gW#O4Zp?h0a$v85wI zAV~>i$w>>CYo%$eWg$r)b4300E9@#%Z$VR&pow!#^6Ya3O*ebc)C3YKNlGArl0E@= z;K;g)QZ*ovlB5I@C}~RYL`VrFQj(NF0wqleK0Txa;`B&Le4d3z1-;~8)I2Vo zY8=RkEy)b{)M$^BGaaWz9QYHy@7VydB`UcAZw*pxgbw-vkp_^1BKqhZ`}r2TD#xJ_ zPK783=2(b4D3B9kDz^Q5>$Z8NU6tF@@ELZM38-{_>nl>$BPohgy==p7fy2z%1Fy(*s#u(4^p}o#g6upuzXsRmH9{d~3w9WH9{UP+{=y z#z}?GHh5_y#%cg7y;=mAg+u6=WOwzpVNbh2HgA2{srbE7mr@U)9HfZOg(KQw`3Mrq0m4PUZP zC=`6XaiSx@t>5ao0k1VmbK7#?`sZiZRXOkrjFa4eCpgsvemzP#V5>lJL`d+*QT3|j zi2nMb2y21i5Z5({(}*4^MgX=zyrofO5nGgY6CAlIHUw$Z=80u!KZo{)&`yvg8yLDHHe|r`o_cYyz`bS2blCOKA~=QioaOBfSMAqN>tz zQ;Lu{kt1nWSb)Uo8=-)gM{yMK6S0%l1iZomrK(s0seL?HYv>xOpqmF zz?&j5Fmabu7`Wn{q4&WD8z;E|&yK{dF?^GYHGxEGS~oBuo8$&uY$2G6feGV83`j&L z)ddpRiRJ^lmYGNaFOTxS!!WU)mI)@o|-_S zsH!5|5K_q){^lGJ6=(0Y2r!XVl^-{yn2PvG6B8IsS;(UtkrA^qRB*@ZraXK?Ww8sLJJra6;;QqovvSxR7?l@UamG z{)BN-Eb#l082C;XYXa{ws;UV$1Tp$#-~&CNX#ZnyIKQ&$ z`1)z9{0_4l!lH^K9%9R-BGZUSvm_+qU8hQrn{7|1%aMkDw!uq1{*k>I!`ItYo&-o7 zBo+ur7^J0wx3gGBObd`Gsj3J!I|Vr)JF}G>H~R%SAfZ+z#|;~{QZA5CORLAOEc>p? zfj@0AmLvrdepN+qL;NLjK*BH04*ZpqY2t>%D0rG@m>pVaVjxkP<_3PXiA$kCg1D-3 z+z`5HTJRMiEs)5rO3Mv#oTddIY*Cw(3na#?(sFaM%S`|Y{3MU8=n_||b7$fmEB$w^O+qASNq&)cFflaP`_nkonWP?w%<0y(!?Ju5e# zH91WS{#Hl}yxFKKZF-tW)25+jC71@A(gehs1e2PUHxLOXm76V!9Nn#cE|mcv?%e(h z!9SW#9>z&-z%dIi3MKTp9`Z%_uYQjUhAOy-u}( zM@PZ<_YL0}ao`!_qT!GnIO4&08~B?j7+=0$-7`Dc zReJ_JZk*H&c&<}zAZIo-C3r*MuWcP+kO*JJz(o7feL!M<=>*_SmV>4QvkV|&i!IbA zT_Gj=ysM%$0`Q(;jR459fIKJgS5e9*+seSO zU9}!yc8#SEfXADdy)|6nPX%QoqX6I1Fz{JQR24pi)#lRtKZUYIQr6qxc&zf>_ zvevBCc9jCU2G0)E9R?RfVJ^Y-&K^g%fkeex0GOy)3IHy!kXFTrkk5`dF!8P?wVw%E zH7S^=Rh|@hl!c>`5=hjlDZyt4F#=d3R22hroKtcG&K1Cl7%%T|Bwi>WTY_2um@PpO z1C}CMB32Ot?the9dmvkaB1LFR1S=Gf2v)1nIJ(Z{jdtztd;4Z!;#ElsWZzGdf(c<| zAOJ&@+6Er{9H&=7WH9lvhylOgJBSTJ=MCTQ4FqH-QECh1&3MTR$eZ!{oM84F zB_*)`1EDzx)4LG|{+w~rl0brX$qmT6XIdzjm|ju>3E5Q)Ow2C10SVbv49xzZo zS26IV7R8GgFb?RSbX@(^``T5Lf(h)UA_VjV=PCx?z=QGzN0;MZ`)>PryW>Oqropz9 zK-_&@BnH0OIC%yj5xJxUvOlSH0~4c5%3dOL$&L7YGYiT!H*kpA+rZ-@u}>I&sKxA> zG~EJKF5Lr_QrQljw4_pB;OCrb0}1;zGs68+jLi$hDhK9;VktC@lU0mBnY~L91G0@N zbpsN&YD)GcxA9oA0c2-U#RxfxDU|~gR7#=16D^ojG4NR-z~oJoDM`v#jJmh;#u&99=tYy9Ojj!HQ?htc3sjPF-#2G-?#r}V1igl3gi=D zvM>PLAqrFvF}&^};{+k&3!*3wOi(Bl0ml24L^Z@H+P>fg9w$ry2aHm&#fI6oR1Um4 zBn6g&le?nq2t@{>fC9X|aWWWyVWV>bNT8q(j3^xeB#2NkFj0iG9B_d- z`6>n;FiymPL<}kh4$(ssNXVdK;I$z)AkMprf$`p@P$1h+Dh9@*7ct=6?)U_|Npm^X zS^{2maG@t~p`YWvu^igU{pE%D%SYO8QaK>oHd+E0k66TjxU4FMtBNnG960!;4gAt0 zq62Vj+~ACAQckqtj4B7l8x<`C;+U!!o+-YkR2aCuIjbs``GZvW zR)RlcoQxtMhkWMst(+a zmAk=y-8DKr1KvHHo&oY6grt15osfCxA)&Ltn;R!(0(qA~o7aB5J4y-uOGpXiy#-16 zg+uGIN>g?>nq)b?@^haSSF*siPqfem?)XC6%J&%TMq=qgo3<`1ZT}vUve34(t)!_K z=T1IgoIJzX2EP%BU1NA{#DO2?OK2;Z##vp{5-zu&e;&l{Fu2yPDh7Vo5!l|9k1@E| zt}4cYTxq%wFIKN)y642dCgr4m$ptvjW+RmYpX4)CgPDm%2^Gudlm>GOixMivDg>(x z%5g@3r3KMKRu{InWds#tdEthz@&J6T%}^=^KE}EI7lKdmnQY~k3^IFZQl_oFZ6;F= z%=9H1G1s)k3V|lw`GmUf+ICg$K*QZ=dINvmr?LjIK5@P#W$T`;d1)r#Rklm7Vw`qn z%U#5P9B@`KFuU*~24sam#qx>KmjT#GSFzGIILicVX{#KV?Q1C&$gZ)95%UwRE5~j! zp}BJBSzv#8w1doUGEuk6F(DH>D+j)z>mzJkXW#oft^VLmb&*;P@a@LQhs$5opPkH| z*Ehmsdrvf>f!V*3#INk1^8;fgOT0xVR0qt_Mal7{{eF;fw@4EFR^vo+tl!@ho7*6b zV36MUuDWPRyit1<7Hg-@g&Y-h!~L{_HzE!mjG?Vhk~a z!tT=VW|6aX!oH?IJ838EtNQ(wCw47_-K{^{!w`1Yet*dcb1Urb{eCp>Nw#aD8UZHu z63HFqe~q7>W_TnYP%{w{ayG}O6r_hH+2&|JanHq?^b zvEiVSV8XXrlDl~S0ZedL*NHo}A~a7hFFlE*j1umC676Y#2@XYaxZguX;={U5+{Mu% zn0KUVN$&b=heBBC6Yh9-s+Q&M`O)48m>9H{^xSc9 zR7(QmJ&L5-UCWDYs=6fZHgVTcRyPcDdbF10ZgC_DW}8bS+x^)IQ(?#ZeQ723KEZgQ zwIp}=q54c<)=g?jR!-QrQb{mwsYr^JaK{nUIz4x+K&h}YmvR@s)(6JvttGj`{ne7d?2?J3%;ntS6$>kx&mDfTrU&B~ zi=^ldcbrQVR=f%B;x`7t99OL+xtp|us#+2l*IOjT^Wl!AC}BmTxMMp`SgAjEc;&)M zUAg0JLt&)_xZ|Lz)&PvxE|T(8-0>Qsuu=o=*!B$xm}BxT;@j!;1*!7Sd1q|8R#v3#eJV1f#flu^!I zud8_vWIXYpH`f+C{tr-dg%GTE#q#VLl~%phHIRt&CAc7j&=v$AZs9~M4;Kd&L=gDX zu{By> zRUV9w9LvMuE2}&hpE#C>!#7rWFy3w~4~N&Q@?d=4SRM}FSLMNYzOg(U9s}6?^Wf&_^z=$96qedgYjTvc{n^-l?UUo#`17@t||}4LyhI(@KjYEjGr3I!{M*0 zJQ!~^mWRV@Re3PpX)F(im#Xq$eAHMT4qsK}!T6-HJRH8M%7gJtV|h3{RFwy_$rsDR z;gMGP+nOl;Xe9ING?s_M8`b>5_@c2q96qVagYigXc{n^%l?UU2 z#`17@qACx@4~^yF@JCf1jNci{!{L9bJQzPSmWRXNRCzGoW-Jef*QxSge8X5C4j)nF z!T5r)JRClu%7gL!VtF`xK$QpM>&5bL_HC^~-x*Xa3bvUuWjTkF?nQWnJ#@l!blRvN>0uIR`J2Us;x&iWm0$WxgiO z86aUlDN10g&a6!fd)hKzseY6FD(qvI`S-K%zIEh*PYaR@mv!gz!G9Yh|FYD-zlF!G zd4ln@rSxN#`Jp6yZIuM$V~ga|mi4+)ef3gbspe3Vq~Bthf7lDJTT23;VP~C0@*&H* z+_7RU?4Oo)xnspz*q_KJU2TOLe_h!AWnJ#@*tIM$p1Mf(E%Vpl@zqrlJQY^TXO?DX zt0et~%lwsjj#ml$$YovbIA|s8W}-osAHKh^iGxD zt!1Tk@#icnt&2ZoFnf1Fa(K>Quj}HQ4tD2?BREeWd2TnDoh}e|tHJJEaRuw+B6;Uh zUoGcl2w@Kx>~crEA?*Hxy{@6}JLrcQh(9F#(SyCNp}%{u+e;iGdA??_*ERIl4QB6W zNcx=z=UhYQjD<*!4|cgDCJ}aG(7#SkRHFI==JN|8x!dwCcYJ|C(=YFG$GW?gC9{&P z!gGv6*q0A>xg*LE_N9Ye?uc`=24LbFk$mx>f9HV+MbnPUcb9nKN?w%kW0se87=AI>>kh;1gWbXo!-D1AxgtvT z6r}vkmv^}%rWCec?3KOFL{zEu2NO+-`$Y2;nKke zbcf*p+sovzoWAD*W+kZl1O~>8rJaf-rVYobMt~fvs^rp-V7$V-EWYuorGi;QtrDgS zj1|dCPFJ5=YpR^i19Bd^Sn7-O7Zyq{_@;+uQ{}p^biI}Kdn;`-e~V-PgD!ML3T>+61z&pIV;N>>q2pGi+9Y0D!it7qP=Dq zy@8n4o#H-Z#mT>Lf9tLFzi=nR2|wLA3grFINSd-uAi0C_S}r=?tP2luD#8Z{1n_S26; ziAI4e_eatk1pW6@Tza;$qNbeba9W#V+0qs>om6=$ve3RWosF$>)Tok7o2VjjMsPSP zGTq&;NSZV1o|z8Mcc(w!7?7_hRf*GwzAzwNuen2&ECV!^i6t^+Qp2(UTzGURO%A%>})=yQtt?gwWpa>%6PDy zRGQZ}3M5bx#X_3mU+cwZibYwGVogob1d$z>#m=TJBmFovS_woOg)IMlsL zUQofQ$$|<_W&dQdO3p*m<`r4c%c)7aB2vPs$$}D2O{Pk?oAnGmghfxEN0gB2tnxk> z0n#m`PD}Z`z0~zxyGA|By3O>lZsCD!7e~@O;Ek?xnI2G9qz5w{UI5~YJJOUhoq}@A zGD#GaW2R(^W;*zb)V(UGpfNKYTA1a4O0u9aGbN)nQ!-jJ9l9ven3<9#n{i8ak2Pdf zdfIJYOuCI(hCbsVMLF`0$t=_%mfMGNC19cAykHD~{Dav@3D~MT!{7SIlz_4#C73QL z!E{LpW|?{lN-)cOgc3v+V!G7d(;Xh1r<873@0qKh1ottWMM^N;p>^5(tg4i1#$?i$ z%w6g8h-Q#q=&ejMmRfE**;OJyj%!@%v(idl8v3k{{gr98(u_oDUS;zQ8Ggev90gKF zB%PO)sTgHNDmFEl{wpGBymgs`($`t4|+XsWG8*~`+W*)`HXP9HteR@cQl0&)l`lAdQ}Z|Zf(w3V_VZJp`xLM?C6 zin`5o3M#xVQ)NMgXF3HHzK{7cGMzJ>W36la-2$yAO+ zHq$RX#@CIidZJ2^ZqJm=@k|ysYyl<88z83vBIzM3`(<8-Ot~p5 zQf^rSw(pSexh`qVnNC6D*W2SMX#7m4pz-&|4T_X|ro&MS8mW4s-kqC*#{U<3JOz!P z=@c}6rbCA}t;4IwEDVDleWSe-MHGdtd?U1w)|82al7p&c6Uh#i+eog~H=1uW9TqWw zG<~Gj53{M_(LQBlYE4;@TFX*-uGZ5fwO((Bsi4-=CAGdkUR0#k)2`N>0FwS*7l(;v z|2J>;F(5udm1DuSuZzP(e?7wcYYe!^sH&KCcdVj0V7fFSrb{DYeO#*-Bswf3qH?Wh zNwif)1Wz5bG#e58_W}MDpllZKeaKY@u%_GOb-}lGoLXU;yt7>;VP1nKHF%u2d$!B) zAbXxi+EsisihH#emw8{Czoo7Tqf7VYsW{)WSB|U>x2%-ogOXHTIR<9@f+J&y7aUdY z86T+2cer<#hRPJAfGF|}XYaW&5q#VmY3@GKcw*ZBgY?OP5eZz=DQOa=$s`M#gJ_4+A=>(x1^8-_Xa?Aw$mr~`@ zZ~7_6!JS@T(BPParsY4r%=I#Fsz00doie|6g4V1^^(g)=)u;HkRIlRSQvHg5OZ6=N zE!DU9w^Z-q-%|aHe@pc+{w>wV__tIqn)H;!X59^&89aS{KP1^|qY zCz_oV-{*XbZd28o*Efbnon%%|C?Nm6JIa81gn#clHe2zS_qeKmAD(@Eye}NL%io7* zUmxCB+%EqYhbP1GnKnG<_3i$a#N!a^^G03n!*aKDpj}`esra5g=fM+_j3ds9P zQdJ&s-8%9R`^e*&b}jVvQ|zZf7ij=VC9&d~&K-x`Vu>iA*%44*Ype`K`!QNzx~g zxHzqgP-#tsO6wt1S_`4lItX=NHK?kY)}bP)1^?7qh9~fE*+f5lcReEbvXDH(KKAM; zAD8LvNz;s~hsv{>NE@x#aU0nw`uTR1#sE@LNjEiF$SgniaJxO?TDwYSKr)jlAtwaBp;=Cq#4YL#8UEkvWiUO zvx;PXV|}e6&$92R|H7^n$p<4?b*uBVu|$hjB>yjvHmyhuEmKNG@+n$g!mmi)y~l;D zNSw%<&G)FtG_tD5bj710ue7B&24qEI=2^?CliT}J7uvNV)9Ae-dB=tsu_F1;Px!1A znfC4ui6*gBj2fXc;-%)gl1;aJS#F(NFJEcOHxcv_xM!}HuQz?%dv?8~tVl2A%uueE zGo6B7%7I~1(nv37It9I)aVIX)OF0Id>*Y+RpqG+ou9q{Nf?m#a3VJ!yK`-eL=|$Pp zvle@;H|7{H(qB17^uBsn^Sy^EF&}-1lzOI9Q0kdZL8-$5XqK6)JPS%44nU(gl_Wj; zM(^1%V5Iy~Os@Phor3bubPCEp(h8lG<~{L(Ddn&rc0IVT@O~B@BLH-@zI~6si)^FNxJ{P$Nm>a#r-k%C~oyctn) zV;L&B`esAre9P^7VW{wa8y$JD&)B2DBaD)vf;3awRQLi)1AWjxj%CS-{h(aqS-s%>|?EEtWR=}uwv z{O_An23)VkfYE@O?l7Rx`Km1oE>%AFT$Bs}<{ml%WtRb!D|t4cZnxa}URP^tG(_mJ z@i6xQF@cdZ|8MW<{@|HQMOo2+T9>(}Fre0Z?kNnY5IRHyYNk^dP&1_gB|g0^_D0Uv zeN0HvfST#h?6k3H#!P9T%#;Soe_@!hp3@Ba5{-(P(x~Whnz=L4W2Tw3HDy##a?sRl zRGes|;p{Lf_>KiO^g8=kqIhJ$9~mX10%=C{Nwbd%%8EwCx=b_t58?-MnjvR435dq{Iq|u0YkHu`q`RYVAPf%7gBGzS| zD2#~po+k<;B1{R#`-6`GdGN}37nFZpCWM0W|1Y=w1?8W`_Mc|MB+~SJk?E>LH?jRF zCY>Rgo@-yG=|{c3_JoeHt8DfFBZXY!3!zcayr#4ex~8)_j|A3~)`G%rcC-+>rnDBc z#+QBgI<;#(4O6xXjItBGvQ*s^FbPDRTCVTUn|RYP%LTh;BCN^WRX5 z${7ZZH=o#XiW3N&rx7W>z&(v)@e?A{G!ZN5j{Ce_SM1948H zBGaa-$VoeYwA!u}Nel9Y;)+b$up)UJ>RyqwBOm;&NLrHrie8aCA8lEYX=`p^tw?J! z&!%OI^&!8|UYYfIiRJb>yXuh$@GZv4e>qPZOQ^J|L}$~65~=h#g-RbNFRq>E-OlrF z=XqzR8S=azxO%7O2mWUqL|~YI%!hje7>-9|Lv+%lPY9`iAysy~;GL!*m%F0$(kFSU zUbN&GE90|v?eFU>1c&mQxlUxY#)4ktwQc}IMyoJ!4A6pIdtXwejruxzCLpiXcwVdQ z#KP|_v!dbpj9d7Xz%Lk8v=NUt>-Ud#6&uRgLa5K!Pcm#zGk@Vcy9$N>d5C{qvWZvu zEI)46BqADit!eTN*6}WLQZt=C3zOS2tISSbsRrf1@p?{BPnJW(;!w|R zyq*o<_D)Rzu{7d{~o=Ld@aaq})8Gp%%6TplQ0!4(R3^YgAUEnEiz7?Dcn+s9h#ZtJbw zq)C6fAFZ5O&4x+uX;;x)4k*#CcYC{z0`D~{lBUw1_DW{~Ib}uh&rF9G_wWtG@X1=8 z`DxwYuZ2S!ykb>JQb}qgD@Q<-ppxUTadZ}Fro)SMyqr`?@@5@xB~>J^*6})0Me=SP z(?CTsvG8(IMe@cSZzWYEuO{(2QbqF811~yMBx|Hm^fS}ptvlX4swDGXSV@QAHCA$| z@{A^GKt+xuIZE&Y5LS8O%Q4N)MP=^rzUBcNYke# zspMj>Z+WoKgPZVUA0Ep2M#YCEB{+5r6%mhZqY6K1d~boAO0?v zVq_oZA6;lMF!%E1oYs}55{y8xkBq7(cRjE45vkO}tx}P$QN}-e8Kc108Wl-X{Ef3~ zCS^sMIW&HUS#LLQu_6o&)IKYgt1PSFtN?XZ$2p=YYZ>uDR)e*BXu z7yXDO;#u0>i6cOsslRW(`PBM)@4XQqwO6sU)aRPkG=lbUYzC!0+Ld+`h#rgfAdRLz z$u%{zYm^mfkL-=uz=^bH7Q4oHinQlG?ArUi=3~J7=|wV1Bkh^#6triiQ_u=AwE2t~ ze8WZFVq?JnK8TB+Hb(Q|gi^xX(EtcC>Z*;#R)ovM87z!vin}*g12TMqf53ATxNZ1EDr!Jk*V#X-DjepgtVj)JaYxd}tA-i%*~aTL z2Hf7L|1=!0^qPzTqXmTg{leR<31|vN4&`p?<&FR;Uqc%(Z9{Sz=4!9b2#~fyG##US zcIqwm`6(H7ELcN*CVZKSf3>%t&#g^9opO**WZ4SV+bn})JfjBibf;F5_s*X8N?^;W zM%y6sovg%CgMGXP*|*N$W5rOMJmop|-35w$nU^sNr1(fWFDtV|l*J?Jv4W&{u`U!# z8S123{d;&0GSpRIFwdrrUY`3%o_l5&uD5FP(s6&^(k@?wTx-*wato$vyTJz{mE*Ih zAAV>3n{qc9e(B+XTV}xU&os0IS^AHq8#%Rk?c% z<5Vh#qsrEka(q^v6CcW@2R@Wb?NF|JOA5LtUz5vpZ%IM-mK1bvNjKL$DI?Q8`Ipv5 z)H)S(Prm+UzHiXIB?aAEQqa961>IXx(7h!E-79}}F4w*Ag}I=6@>Ms}!=QWNt8+p3 zmK1a^e2FgT-jaguEh*^Ul7j9nDd?VjWiQjcB?aAEQqaBfSL|}#lQNRSM*79N`_es` z;*Xh34PQm3+E8r@p_Elu6fEAf)U`3`XSdpm?R%B`bD>Ai!6`7jAicD=_MW#lu zB2z0^k*O+HWNHU1GF8TkOf6wWrlznWQ(IV(sWGg`)EZV~Y7Q$hwTBg%DrH5c7O^5z zlUR|dO{~aNF)K3F%!-^%HUDH&v$!Jje^GC8Z~dX#O6_P@@%>+6@b!V>f06#touh2p z|K$O7Mt`-dnrAX6$CAnZHD|`%qo5d>{tM z!^Glgn@n4If3&N(wpFQQ`()3yktR)BgQT;`#j{u{^WC@Cwf~`ABhMM?PY3dVO)STD zHh;-kjGYbc6DSPCK{hLi6k~Du@t#*YlthZ*agr~LG{0i-!ayCD{Fh=$$Ui6kf&C=Z zw84!%nrQM*gO3Ol|1tRNK=BWQpJR4i@=8aOQ0WK}Ds9@IS(DytS8<_%!``Iryh+ne&G#t`s z;b&Y6vxcKAq8hQY@J~*r#pq|dAd`WiKjb-nRvRxq>ElvkGYMtKZc?r>6}k`=Zpaf zUn;r6j6L09#>S{rl6%?sAcCpL!sI;NDNN3@d@&$3KDQ;hDRV^i#cvc7Efh`X0fY8s zn*Q8_YO_6N*GPBIwk_j}!`3nIQllbi8tE2q%uLfME7Ek?VlhpBk6oq7Oa#d zsK5N%t6cr%GcHNcROMMv|Cvrf{bx$*KT}fwnUea?l+<4evPu8fcCD&ZQ2&{d`p=Zq zf5z3H-l+0K{ZWUCL?@y#G1GZoJ|<>5UotWp05cu>mH@uWvoHW=I)wo+(LV909cWztPFtapFp6mG=~fTDjt+F8vwUhZqGZ|{TCE%h3S@f0O-lhzQxo85^>8p z-~(+=pzS3gjl8Q5i)PxyB1Kzn@AGTsb5PH}%Cj*0OidPMpQ*{h>@zi4n0=(6eE3aG z7KY!{WMTH1nk>vdQTu8YRw z)Fe6-O-NIdh4DBwSs0H~lZ6RsYO)Xm7B&q`BhgG5kJWi7p8A!pXd^(LUe|(o=!=3F zkcTgw4S14`*Js;RG@MgR48x;?iw0z5M$)v~c0Ts9iHowL@i5)NIz;1Py}hx5>i>^+ zydu>Pju&k#DlKHLs=;^K+M9d~7-{cxX*QWI%_i&PPCYr%Bit#Jh^LX+B-fN|HtASy zAIr7!s*~yo=4W=5-9g~3MnzhAh&9c7yooZcq^w9QXIv`}wz*3>VZEKCf>!=d@rP)+ z>M;ujdB($m*O)P=Bnw*kU*o$Rp6Ca@3(CRsh_>Y#kZIeq-chU6@pctYf(iMq;JeU$ z1GW_) ztPQ-ZY*bKIG%D8HO`!#8F43X?29JdH5bpu_N^7F3LO3btQbiWVg!m6ExrH$?i&KIB zfHGEj&gnmdu2~6WPp(SblS{FKDGCaMOM$iwxweb|X%h7nP?NQO9%lqdok}jnAy(=! zK}|V8$msaq39hCrBbk?rl3Q0k!)_dIp zW#K7BgTiV?q%2|fj+AAl^OxMG46}En8MCZB6f~p9m4_cEeaY-iNAf(P8F_DInsLY> zwJo{Pt}?wc*4Kvp721Cy%-%rGkI3wencw}x*rz6~w2A9WGktO?F%A8x)CpFp$f^xn z-c2uK6gX~FBu!b5ntiIKtVmtgW$}QPp&6>_Wj&V!XvatiXPGW(-pD-75?SXhv64oK zj8l)n_N4U-{lm;i=d`?YMu2nQ$N@ziuU8A2fr5kF?seyzo&V^%BiM znwHzh6*HS1DJ#;9=?;T}V_4O^Q&?77?>Udhd7eMc7?8)Q%HG|6kCY`u!I8z9c8fL7 zA9)NI>CY@PS;1q0vSea&S;4gLJV|5~fd7u>92E-|{{u!+-UY3!}i> zjEef4vc7yOkCOE{Wkr2H%L*}1%;Qx?p88O@L`1+}hy9gcQA15u0;7MlkgsU|(3*gz zz;aUVP2LV8K+0FkNdtVr8(;)T@g)QMHVbN2+qJ*%pv}M>k(1u#Cb~3ukZA_35M({ z$9sTReYyTgwCtS8)HNdAQcsuZH6jbns`Js)d`~b;-lY?Md!1R!|LRj-{--8M_y)^B zD)p&JZr)_1{9ixdX|de*?Pjx2M>*bPH+Ov|A_qQO-#pu{RWYxzn|)&PqR-WmSK76b zyyWvWx!{~A&*gS=!xtm+U(T&>?y+l?e9@O`a4awm3ixuT8fh1Zc}+V&s1I55FR&__F}!!gfj@7Y zBn6@!niTxev+EWYG2qvYQZeu!f*26BQZevmU+~<3`x>QU;P(eH;B+JgMq#CHK-5-q z1Eazs21Jon42)8X7!cJ~G4OGw(IN)?SEE!6jN*$J5cO9vFhfDafD8x~1D|MvL&Sh{ zSty1J7D}@MZxRLq!=;z3?zIu9Sv~xWx)+~qSE&{7cSflg_%ANj0AfNVCGeDJXoEj# zoD3i!qh3-1e-WhwZ~O@qtpR+TQ*Gb}&4O!f!5=eD$^_DM@@Y7lY_YYXrUXYO28gLq zG4NNs1KO$CQ8Db!XU+b|g90x$O2xp;5+Vk?D-r`^xkL;&V1`Ye3V2gw>%bT|5d$u8 zyVe9^^0aE;$o%bWDKL3b4Im~@zq@BrvGoIg!^>=A5Z`TvQOg7$W1RFJ5L+o_0+O*_1Y-l`p@84DSypQczScOY2k=i$wSg~)OdoiqTgV3R%Qk&$ z0pLrFlLCOhiNwGg*d#Avz&9ABxnW4Ll*)lIm68hiX&b@szFosM1)gW*iH%=|!s>p_&X84MT1K;RL8^F!XHIxE?Pl>D(c!yxu zfFE>f9Juh4wGGqe25)JcG!XC&PK^WCMk&Eh2zCwlMyJMsm^v*JTZh3?t{01?a+s$T zkwpQ&#tqLnaBU<8##M($o;65g$DW?o$Wt79r9N=bP z9EdqkF)*ex}>w!P@6t@iHKrDocfv*W- zz?Vdp0o-*1G7iMHhzbI4h*E;FE%FFJY>U(9F))To#DIhDt~G$4G)hx~33(*tYyr>f+=?yfg0W`( zeQ#d~#+=E713V%!S+^M8+U-*dc$QIGu{#Z~jX3aDZlD?%s4tsGrAhy2_+^nx1s-)f z(*R;`q`trh+VouG4pa+>holw8Gg=&(9xN30M&-a59H}u7d!u4t433BaF*st#fU%u< zhS`^w+f}-CGw>O1d)mNHIn@H<)<~H^tddqOH%DzEz8^<{;qMIpG2*~my4iaBLhuXS zY_)-Bx>$$|zY}q(d!)6)KVnHj%nESt$mD@fbZ*~;;4cK935f5cC8R!+a%rTg9AV{O z-88m=I8Q1D##~9O12Ii11}5Z`=K^A`Bqb21NK=BbO(F)wG^yByX4tSzB8D4u=e3)_asKDz0K-@-oshu0x|v$J zuR%N{Rhqe0ras~;Q!7h$>LF%OutRDu!HeA{t;BD_FVa%MTlol|0OBjj?gS7Up((*E zM@jnvkG0HH4Ezn}_Fo9b&64ji1F<-o6jSpk_qZBBoG}#xkGoh4_&TRn0#A0T1;mY$ z2mP}Bip!??Ctp)h=!9W4m)fQ=X7^9NUv>@0D;6P+juwR%P%?^yYksbx&6sZ_^pAfXx77*K|Nx@husRt*o1#0D)x ztJ(@nS4=80T{5XiB9gmo*i>X1S5#y=A}TUn6|G407~j7l(M&Y3B2h#7sv@!S7}|=& zKP8&3$V05<>79ziq|z4^iA|;DD-!3CX0FII0Dii8fEYyW7w|jXJ8T14_ZJteqW z&fK8IDu{o%?nZc3$q3{9u|KIrq|v7|3pN_Nt77jm+e>uW-?#5(V8Tji7W4_jE4cyD zE6oiYZ15@|wphi`I*hDxUryXJDU<=rSXD8`E2C056qemc&afJ6n_N?>9D5d-4;s~8xSlIj9+$W;uCmWdd! zmyR!W--*%QDHyx7Vc(|jn&-O=_ePRn&d7-5d*-9}voSc_Mwl%xA#k3)|9YL*_p|x-@YjKiT9+JDyMG6SUz=`A$ z^ZYo*HIXD3^H=A|9Trg7qvvIdadocv4qHWP491lZNqKngUL8q-v9Wde++jxb>A~31 zx^(Waq$&xOUVtF{Mlgfj!O|d*2HcI8eSg2SY4oju-VC+;Z4~M-{c`$Y`yEYhaFORFjgp*hr=4FJQ({D%fmg8HYak0&K~I1720@FuddJ*1MA}oeSV-j zm;GSrK`ioX2eP9P!oGN*Bwdx;K~%i<-i|YQVQm zFqpzl4D{;IZ8uPI=(b$coy(jOm`O_DtT_Q$QL0npehN*u@lMRMZQOkV<+tBK*`Pf~U{`rh>r?h$ zXju?=urFVZ0vZ32H0v~n`o>lE_6ucQW@X7T0g&x=ITx_l+Gd5fQ5)0C*$|PUa@0g9 zYQQRyP-z>bHPEkuQUzK-zY3b?K0@x{`LcKPPO#@XGqmN@&GpBQp*T_?{fDDTSS(at zY>VYIv{0apq7N*fvp;$*jSB0W-)I=z1 zaH7{B>$|iDs-ska7LWr7^Yh$C$UQt?rlU`>=XzFXOLP>9gTHb{kmn3zF*{Z&QfNr% z`*A8q^deHZI*c=Yv!*CgxrU76@xH>_Y@EemHhCl=dK6kVvvn)%nQ6@jxNqs^5!b~A zkPTPS0AOgDM*cJndNMpsrYCpU)(tP4$kPBB{$c@Hz{bTFYJnNnpuE}fLXpb#xt({a zA0}gJmxTG#wDYIQEc1V4Pt)S3eaMn{Ag!N8V3WTC^)I=y8E>Iq!c+k*{*>D=O2c+p9;Etr~ zn|sw8Kwd_Xz6CNLNhR{CXBtp=Z=rC4o@kow4jJR=ilI>HBA-yH!sW${=f(M}*$g zHekp&D|?Aazc{1)) zXIB}-BVVhjlkF6W;W@zqa^?aw-vq^Ce@!~R5O?M4hN9ZawopZ~N>sl(8R`aJ;J?bW32nWs& z)dYr`PXLz%Dd5wcY5=!%{g?p0)Tt&Fy~~tB=4)Wkk0$W3m(%DIz{8zt0&lp+rGQb3 z0%=((5g0WxkOmZ~+1ih>A*LSq_hCYl&M{2TKeR%16#O#RkQNY45&s4FR+G|{;Qc~M zAbnUG1e<)N))jPG|Fd5@GL=h*rgA(Zx>EYDfTjFT`D$I}7wjre^p^{3YQaUQZsTb- zB8GfqG)fiwkXg}ByESb*;+u6Q+t^j|?|!SMzGzpWw!fsNUSLUIV+uK#B*+%%z=3Z-J;Z@ZGUf!}kg1-#Cw zF(4`_`2*Lw)C6#WDW?{RE#K1&w{lo+R7yGUt*&NmAXB`Gfl)zeaNs32ovPS%hJP1v z;EjB`Z2;#o8Q86Vj5J}D;kP;W_RYX(iTG?lCRJ%Q;IXD1Rb>s|5pm$VU5gsPozJhe zS8@X$Yn0}8Ge1YlhGy+$c1PvF2OB3X3H-cME#M_lO7PV#)&MSYgVq8rGfK+@zsSWJ zz&)L60VkuB;P<##1Gw1T&o=OD(a->2=3))ty-xXP!5h)qf>CQ}a3ESOoeX@QTjUmS zWi$@JZ*s8)@cmA;fNP?Z;6J%o1Nclg`QyNs8l?{aZo60mIO$XictVsCe5#8zfPZkR z1$>50Gg>BiMVNYkCpxtXxF$*o{*#L}fY19jDnAZfX_S@;-rdC-z!RNn0ndt3f-i8f z25^m2E#Rg$cWRm7M~3+nIO0?b_}VBX_&^tH06*+h3wTbH68u#cYXJY@Qd+15{Hjq} zTks_=)&M@pXa6>E3!^k8cpDdM0FQ901?-yNpeey;1z!UAXQ$f0hkmzy08I(r(l{|q zz<+kC1^h^q5`3nMHGqG1YL!C|CR+0h5@*Q3W|mrH(W=%A`~u_D1{+)ziGkl5#8w-; zBv8OpE#}n%z~AsVxDEV%BnH0A#ah4xHi2qx;6*;Ewt!0_F)$IgJQWb{Pjdq^FU#Ty zaMAZd?|~N^C!P&(=SU3vRu^jn&xypqe|51I@S#_u^KIbcjne9ZpXy>Q;0{i;fiHKe z1^j2H+Q2tDH4c1-QCcMUQ!ds5-r&?K;B8K|fg5=&y9&6qQ!U^Nof-#@8Kt!VU+Q8l zAOW(9fq(B}t5WYu#c;1!RgsYa#C;Nd0d8f^m8M)~m=Ii2o@ms^BQcg~cJ#HG7RxpJ z8l}0t+wiFo2R`4EHh?=@(4k4w*hD$v6oM3a2H=_~DR_Pqofv$)T{SoGi(IS)Y&+Ee z?h~a16B&uE0}>=@0pJiNwSYg3asv}VNp8RpOtpa9dN9=nKEtUNaD`Ljz@40G0rzyO z0X)notv{GJPMRBdT_gsc@!VR#m;5l881TWyiDm&Wh{V8Gx>y5vy;E)AtxmOo_c~Pw zEoE-Jv98imyGm;Vi8|#ufgf|JabSo^TfmDMvxU+-cKAmO%(fuHQ5cN-X@@fL7}Noh)O%TqRhZ;8af z?+RkT6CyG2wJz2I5)2mh--rcY`jw!IVB$a799Re@0F-*G1fBwwiQ^T{SKE$gt7`{FYN~;18md;At0Y05|n0uLayP3I@Ud=wc1vO-{9e zw?-k|D=hkA`#_)IN5&DEDaS$vdkV^dSNlFg1NcLy#(}>!N>hS2^ks_%a2uyuz@v=P zl;C4stN~;ZMf&;vEuLupd2HDxw%jiY2f>Gia1eN*Q{%wzM=8N~xL5=D;1JXSUl)ag z;Jsa}0sMkfwfDiFN zvIX2K3PHi!yI2Fbw^J?P5m8F;NiNm^UgJ~?_~a-A1wYH<%?5BEr^bQric*4)cd-WW za;I9rUqmUv9@zFZfFYo56VQIk!`^Y=Wlpt$4~gR0G{%*Xj?i{85+lYPk0RAW4X+N7 zDv(%Las%EJr34e$iWqQhBnBqd6&nmB)>Z2YCa@JT;D@77IE`^NDM9W%9!0l-n|V|^ z4kY}o3bmhCxL6BF_$&1Qc7qg<=vSnG7n_vk55CJ&wt+;%Dh4L}m6ik&>#A59d>=aiMX|5U?OfQ5=g`?DS<@Xnv%Gh$XQYXcMV}L zkYHLe0}@M1Lf}!Jun9cYsW$Lrr<%a9pV|fzgKJ&Ew|mM4khomMz?+768OScJih;w9 zZ5y~Mqy)avsTPnRUm64W&L9Om#;G=tl>lin;2u$+4L&49)j;BMtv{H!Tyg_m<|)U4 z*E-b(61_`8;7W^^HUBjFR*vxdy(TBN8%P)~tpWU`OErLJJJkZ-=~Nr|7pEG)4MS)Q zBzl(;frRQ>S1_TvJSOnPAu}M+yJQBO2vR`ed65Dh5Tt;F_#y@Tj7v3uUo%SU3MT58 zx&m1MP_fz01)Ot!2+zS^HBPc}ctI^Dy+#oK2ctB1@LCsZ0AJ*hcnkRIC}0P_&BYqP z6P#)R?}}1_?{%>Ta0d_A$ALRVp+0zb7i$1N>{Jt23gLeeMTX#ChR6`Ovxi?z;9gP0 z1l})1Ou(NyH4eNdihIEGJXC1_U*}X4NED+z1%AJajRU(zsTlZN7i$1-aH<9TO_UP+ zM;B`VpXqVWIPeuwcm&?f#TvkqoEiuIHcAQpvx_x=&-Wl_9N3J)BXHZr8o;kQH4a=6 zg(~2edPLIze#xmOkSIpm7QCUyDt-izm_^0F4+W2F7CHBfq2o961abm0^(SU6c8_39sr2TtVM!xnMDkUN2_AsJ>5xd z0&!`jOyKDzr76Lm_LMCk`&E(>cxR9T-s{vj5RX>#2Y=E1)+P`ySMmqq(#m53aaA=l zFpjB+0dY*LGR^H|_ejKmm%B&W1hSzd)d1qZNh<6w#y@HBH7 zB{Lx2q-ZD*XHukqy*QDjJ)Wt^;R3(My{iWB_fCxiUm5MKfOiSU<$xzUH4Z#GN(sKe z#TvlBI@JU|()Me#6~RyNQ*{j>=kla|cxhz!Xiw%;!w-&jTfmPByDh+#PK^Wih*E;5 zT&w{+%c*f7UWGmZICvQ2teLU`s$!h(VQEu2@M@pO$AOzglO>o%LTL~nbF1bCW+D|a zAd{wwfmyf{F(9*{ih)_B6U7BGA*mQM601_m{nl2fm|v6wGrvfwK#aJGfwAH;sDM~( z6$Ae=Od`O$ooWH&brdk`DN+D%)5vUsS$q&NAd3%L4=_gyekS{7d#KUi342ktnag%w@o4!69P!<&?wARMm1pCQc~M*8ftncOuk!XX7sm3;kIaHvFEDdpEDy(A zsPbUu#aJGW8ByiI%!jc&++1^HEYG~j?5O#Jud_KZmhWZ0jOBZoHDmc+=FV8Yml-sc z?`0m1<$IY;WBIw}ROZWA9*%ia+aJuV8Oy^ld#XGbs~F3}VI5T-jBSkN;job^55{K2 z@^IKLl?P+FVtF_$n9740JYzXsOS(g@Nf6^%~7IB#=2B}yP-LKWJbP7K6=RC;AHH}=L&$h%G!-!hP)(x>`<3G zTxFF6GuTCP(;+|6fvc>NV1~I!zGSFZxA|2=-MNN4FF8n_V?$l;81TZb9O`nnZ*+VF z%upA}R}b~{PJ~GQYN*R=5jfSt-ZtbeHm6R6ecFy)?l2R=K6S@A9dA~tMe-BFUG6X& z!k#(Yt2^Ev$`%+T{quIrma~ODZ>Yuv5eSN(k%U!gfU8%;}HZ{6mM_&F378$i8y8%N_2%urD8W z=l`e>K5RGKdo-^zr0ShmZ!>z+z?pR9~_Kx9fWnI{x4*T*9VT7=^4|`BC-xkh= zT_x>ccLW#0?l#=zE($dsv|}mMXbk(ZJqz=a!`Fto+!1mJd*P4=Agsj;J2u?qjzC1% z=5Uug0ujx3xD=M`D~89Of^#k+`}?6Tcbs$)_IE?sxffv{G+YW{UbJH=gn8#sw(KN1 zyky5NAq<-Z!ai%*w+;>tVaf7g4{TV564~eO*yWA@N7!fY=vxREgd8p$_Hc)HV?_4g zp)Pl9C^8$)?g*TO-D0>DMm>1g!>EfwAhvASU$wb5uumKAaz~IQ`95{H%N;?Mu;&hyLazQD zdkwiZ+;PssKLlA)(xJm1a~TX~?xH~KcH&UC z5T5;L*x%zJAd?(UAIc5@348T$_U4YTn+$t+#!ic{#}9S6;}nmu-Jvdb1aHEAY^ci} zyD-AOdbrCSA)TgOJ^kDBaE1{Z|GOXS3Ytq$Gv)Pr(l z&jTvQId3*Ul;ey8Ppw>fE7aK)e>^MlQC8``T z3hR5yrK@_%F>x~~E0?Z%DVKJia_P#Ha+p`lqH?LxP>x~EkX4Q$$*@x{T?|_R@mgURto*OAB^;X~AwU?WP^9UrS4SSh=)|l}r0rxwMm&OM6+l zw40Sn`&qfPqm@g0TDi2Vl}r0txwNyDOM6?nw7ZqN@BR)4P(y$JeV*1iFYoXFee*OX zlb6p*bNSi!@>!7SEKK!gU-R$YZ`Y0bI`cQ)YR^wloZ+S#?X9WBdu>9Uwm#D>rE^AFj_|0&~GD|qPVdfG>9txYH@#R{}gvpqNmxHj!OWqvKQW<@&V#=mjIn3~7GrPFf!TRK0- zzwzkwRQy{yW5>UxQ+NCuZHIFn|CUbX@o%ZokAF*zfBak8G4XHd1QGw1P89KP>4Xvg zmQEb;Z>d3ve@iEl__uUIiGNEcmiV_+-QwTU$tV6TorL1w(#a_PEuEC&-_pq`{w*B? z4EpVSVD5IE4fZuY=y%)3##I<{yQLYC!S*4eR0JcycvFj&jx*)b@ugfku9Qp1lXB@e zQZ5}o%BAB*xpcfJmyQ$V(($2OIxdt;$Afa|I8ZLtf8|oWS1#3ev=__tJt;@?tTihoOWD*i3i zt@yW8$Ku~oU5kH9buRub)xG$)R0reVQeBLHOLa2-E!EBVw^T>t-%?$Te@k^X{w>wr z__tJtM63gqK#ku=}Be#Gn!8fBefWy$I!kdN4k2lWE;)i_5j6g8n(q0;?Op{N1d2|~^G zv=poVoe4|}=>I&-3mhT$@O;^St=P|=YbvxQ|D6enX-Uq_VqtjAO(+aYc=Tp!Peckc zGVM-nGqoNfl^PA9Qd=PuCgKYJU_~>v3?hX=;LR+dXra%$ax@wK3*13&;>a%z6dm`% zKw%pW3>3~bYqU}#R$|0od1|ty`@TS76BhZ2aDT06d7!WW-wvAK+DA+iYjDz!cp13KX3ggUguN*fN4oakXgxKkifuh(<|?s0}9`dK>S{tm=$RX%>#6 zzv%*R;{6Qr*0MDQEEh94L<2G2kU3W1ayo z)M^{x7lnb&o(cnAqz<+Cn*lErJ1Pu#p?JHK0WTCG8v|Y_wo`bkL?~Vp;dM))c+HXz zmI_6;FqDO2=zb!MYL1p%7${Ded_PbeD!DaKzcu*qFwi+VvQ40#ZV*c$m0&;T4MB=C z9ajX3)7Q5Iijx!v1f#(rh^qp{X@SoMJHm$D4+6!BfI9-k;ebB}isQ@=4R(Z6%g+wf z!3HM-#RmQd19iH=PX&tY@V$byVK2NBD7MABfx6b<^?~vor(iVL-CYtW&f2~(P^oF* z8~6N^4e2rdSpc6@7b;Cv_+}#iM}QG2Uw7a*8HdG$;y@RZmr(be_o_VaRe9d4^1N52 zd3WrMngbYWJuzk(gr3h@=#-@Vjru0_KlD)@%8^YM zYDK1neVCSIhN|lS0R!LdHC>f|$nk!v)}t-YZS5+K`IGG*6m!Dyv7rs`{bAj$8~BjU znw1O-BQuP#`}u#V$a^bqh*2uJxmR+OO8&(vD~rJCfI7w|ZeAMIAfMTmsa3fhY>H&o zR4)A}f^tlfyGEaRW0vGQZYsw#iC?T7rw*7el}lfzRF2crOj61*|M0$#avaa&IGu9o z0XgNEf^cb-!~9=hO{W~bD2}LdtXnfTD92GHPCYBfsRJBO<(LETJe6Y-!162C%fXqy z_v8P~eiXx)4o9KV(I`|p7==p5qEP8j6e=BwLZt&ysB|0(l@3Fp(orZ>ItYbI$DmN@ z5ELpMfkLGNP^fhL36%~%q0-SOR66*CO2?j1>ChAEzAfm|f(2b#u%Jr|7IbOBf-cQI zimCh9X}>9#cARo)&ncI7opNd4DVKJha%t}=mv*0WY5ysgcA#=;4=R^-p>k;-DwlSm za%nFrmv*Ca_uY?wp9yvL$@}qt_Dq;sJ$;6>uXi@@BzP(L{{9!uGrHQYv+VDurnpob z|7R8Fskpz-H|F`+oGi~^`T3-lP?&i>#9LUQ-NL>#w_W(=92xz_*H5zJs+ZaKMy|7K zbi9B!z_#+mveEP~@GjN}Jc0?Y@%1&qGFOS!o-oKBaA=T-qkerEQ^H z+6Ky{&#v5k)gx}7v_A1~X}#j#()z`}rS*(|OY0l|mexC6cC6aPzQNCafpUCThQ&hV zSS@6GK)Ed}@L`-Q$KoJ^QMrT7q_8@u90AW}(GhFDK*N%u%AxbLopKzv=50Ua(j`LW zSR-T=P`OiV5soQcIRYbA_m$%aHq*Rv1WWXla=cB%j-Yb9AH>wJ91C}>!zstxHLSWR zN3g{5y>g5i*6)=g2x1*xxf9I1pcBgdT?gvLh`;MV(1g?ui096#3uZv5)Cvfd8UdkF z8z59_0)$E}fKaIc5Go!2LZ!oBsC4uTl@5NP(y=d8I`oA~N4`+$z!xeV_d=z^UZ`}` z3zZIfq0%ugR668^N=Lj<>3|n19q&SgPOeef)#}}+eXU&D*~+E8tz6pO%BB6ST-xEv zr9G}(+U3fneXd;E>B^h!btsn_n7==N?PG?s8xv{w%ha6qzEElB3zhc0P-)i- zmG-<)X~zqd_PbDNw+of_x=?AS3w7UpzOccvGYO(<(DkRSd@ zZCK{@jRCK`%Qn~hjy+~F9h7;xQPN%HS&d(BaE()=@4Uk-m|bPf@+^aQIW_)`J8P-O z{hDfxFSY8t*{;$A-!w=~3$2pZb0n{4Gq2|eRlet^)S$WPEj7H@u6m;9mo@c7y9(7c zctN19G5G61<;^gXH$!ugHN$J|D%sOAyLihquQm9qKt1j^b-kWuS4sE+gKrPi(FRWn z)F%yoEl>yid!5&jc9p!Il=Ve3?~ClX6Mcb#=*UW2UOAecHrk-?*i$FDK}l2)Oq*1K z+@Lxt2u6o0L2ghe6$JA%l^{2$nF`J}9!k&l2h)B{2Y#5Tl@xIPB#O1QE7ll_wV|ub zSg8d{4_kV!b$NsnqUwTqEcvp?jT?BUk*hu!m`184XKN<%)s*0mSh?|M=}-@HFO?L_ z-=FfNrX#y_DgBGVRP|E0Bp%)+(}r`*l3n5!tpP-5rY zp;Ic--?uDl?p!AKqH>vh5T`PtSx;q_v z>Yq`ZtQHfOABZ6oDd1af4VfKi zc=unBvI#uTsR51-&vXkr0bJ!&6Ufx9DZvYFqZ$*y=NhGA;LD~FYXTqd zc3}cY=Sywr7G{5GARyYH`O{HM`^tg;==P%teC)r4h6FRUOQAq!dCd)cTA2BPS2;BS z+{mnirUc_CNC7}}SH)1PqobtYv)%qo05Lk+qsd<{x+kM$ri1ov>Dt!LVKHZNCMSWMGXY#KAPBf1C}g-GA}9(d z8aGZ<)B$A^H*i5k#06O{mrJ+;VG(fw0TBfe`BwE)@9KVaKN(I~e&3(>>-_V4x=!_8 zU0qe(&ojS9EL*_6Oj1KjNHkr1TR_A(@R2}}rCJ~|9r#MAZarJ64(0VC*MYGY$qtOA zY`1!m?T~jxr8|mpv2Ttg%0G5BIt={voy=n!xP=L_C=TF%IH`>ozai1AU_@K`^zb4Q zs9o_5fg8IRw}Ble4Fi`ssSQNFHO^yN7Okto2}ZufqXQz|^`hRc6ZHd48~@N1bsJG1 zyx&I+c!!gQf%iG74Sd{5!@!UF3TXo`chWGBMIl`RPKnz9kR>Br<$`HH+XW+~jkR39 zY+Hj&3UI*ndmG3)5-uPcgw6?=B_nkL*$tEpyjE22K-Q4t1opaF#N||cN|5DrOd{@J zRCN${63AekJO)N2lDSewCaZ3PuImI1*1XwP)<=uCHXl)W!226bE{65pTYYy1(&DHa zfLLF$VY2UC;QL;4d(#PQb)j=4qQV$PVN6U$a1+BQ4iO3&zX9MZH+Oi!>y3RkH@hQDPS=dHehHlH%3 zz@8~(0ogO9ta7JxQ*Va(NZM9#4Ei*HNS73b_4iS;^fc#XhOq*b#=5`X13JS%tUzVU zSG3enF6br;`VrR-!$8)x7S_w^l?t%*KJTia31oRl5OaB}gTS0t2!4?-fd=puPHF;K z6+zxfOty8Q#ep#lr4_)PjZN}CzKFybNnY01Ikqipd0#Nh{w)4F@KwvIeMs3lhTrD2 zV<&;HHJW4v-tMFpkQJ?^fmzU!6Uf>Q1HkG|mo3Y64PSg6AltoG0p7;hTEN|$)B&=h zH76KfEet1#8!WFfE;IaaLIa}@#Nq^|x*OGSnyH4+TM{gFtpgmFeKTM7AuqPWr)=SC zUX;NM(*R1tpul91_5o28G8w>4%v8{vxzY&LqCrkd7{S;ZQXcTagbj_eG@*eXG@1xE za1FCZv?*Y0mDT&se*egXZC`QrNh1?B-E1=C?cIdw0PD6z6quF_Mwx|9qRtkWno>qE zVQOh9knps!fl+J1223>^7z;;c1$brR8vmE!O-;pV4O<(=5>gr%#VN%B@gtNC`~}yT z4Ir8`^q<67wnAWBo;qwM#=?gTf7YH8`gGPdn?(8&qp#FAe-~4abL^>Y2A^oOP%jB| zh!9U2A#t#K7xPgkgBHuy0#7ykNv9n<3H)V`dC%Y8jD&p>I|JNw1EK-M-U!Vjk!mrF zk9V8y2u&t|2GaI{(ISD71m3qYf>ARvfM}UxqLw*n1QX<9w@T(?fp8WST211v$cI_- zbXpz>Y!z+Ghs{{I(4Cw4C@9oO=m!bZh_o5VN)3Eiu=p5S#|~ze40#B*1!NUValn%k zBL;l7=WGBkbJAR3q6$v(0OWQa!uY}@@R7uP0k7}o%ZZc0m@zB$Ed9)#3AohulC>X;;YCwhQzc0FEg630a^1}8jGIwt28hRSh4~!ER-#`EVLnJ zPhd+335eaGIl&kX!UklGD;t$qHnVDI1uz zCTzeu;YZRn>+%HsTZy29|Jwz+0esj=LqKeQSw{~qB7yC%Re~>fe_Ao6*_QPWFd$lYJv41>Lq~& zP+`gf4%!rg5BqsIvIE5ZketAuB;E;X1U;dpfl(BpB_s|@oQKlyXyA9?5omc}l#Fa> zz^HGA$I>_K_%e1t)Q(mFM(;>pfv6p21EY7O9YDMWWdq-DRza8@5|{D3kHVP7B%dbIQP3W1_u(B;UDuoQBc5X&4=;nTFB2X&4=;nTF93rXd;L zQ9txghIe#ii489X`GmfA%4gK?T8T8n{-Vm048P@TP)2HWq-OL-M`}iYv>1I6hnle; z9jO`S(PEehnV+2On&8jHT@y$MP1YBX-BZ^In02yJ-yAm0x}A@mN3()iO;Q7p?M2y` zShfJAF@-2-rGYW@WRQTY9c2S=;nA2j5WOpX03r^Wlf}jaD-D}(MO6-yu%Q_sp=E{{ zQn@d+tltMX#tjC?8sOEFJs8YBE(PA+@4GrfQYwZ`d!%4<^b`agwT&+s`CNB4Cb2 zs@$Zo8MK{XLI)KmDWV8MmB}D=a1yNqV_;OAq%bkGCNLI8#YyVQ#JB)sJ_x4>A}RJS zEfb6dQI$!mZY85vD^602E$*OYg7M5M&U}aKW!0xwG@tE4Ps^xV+r2F0v-(;W|tp&wu@g1JbqryEue z3Ft(DS^QGwi{^JpvHX=2j4BY$>*m$$@ykn<2=&2vT~h4#S~(b< zAe?`l*CoY%ADU@)0NOw}C&|nj^;zuwo%wZp|Bmx}-TPj{`0$}&=5jBb>5hJKk)|PJZD}JeGuxo^SZt058?dOylyX=LpXms zuUCuUi}O6fFqXEEGS8RRn&pavY!+zDHxYt3f>JE=+ z)m_6|&#WWDE)rWIkb=W6q+DlFHhZ`n)|Lge%7Ti!nQikD@DL=(xTjg0NSk0k0b@b!vY=uB4mbJ0R+H&wE??(myHHSIjZl;YxlqJ{Tqt5e#TXrLE&8at zd&f=&$5wjuFc$7tD`VkBcQ3R;FS4gh05F!l5YdeV6%+8ztd-;COV09H=(3@mayUI$ z8Otv|INn=Cnz<%MDuGZShL21YkZuWAE>C~8m6%?5WD12mK5ON8 zIqDLDDI4mSh8g!{1{roCl?^TQ^a(W=MYl=Bm%RTIW`7U~bN#BS|VFMV=hT?z}G3+>@z@ zQj?oov9v;SuU)h}Xzs~sQdx^*frDl93eC-paE`5HMV2G)?@=)W!i95#87d@NaFLH) z8>8!oFW%#A(mCJuM?>)V}=Ntvsz`aIX5)pdm52wF559P4kD9VwRW$yUOt_7sl* z7z^^-*u#D#Sm??9vnI(0aa6t0D(aDCOCfPKi^Be&+tc4?4#*kylxYCQ=s>5G!eZo( zumVnw1p#A0t+Jp(F#c}$)L2F7-L$xXhu5%$yRk3e7j%(*-CA{nJri@A(B>OmO$`A# z$4t0UQ|m8Z#pfHUTuFF*5e?upKM=X0#ts^Y=o(J!12NY&frzt9WH%7$4sp~#WD{iR z1Y$m!fr#ZzJSY&+(U|^$nCq4+vLTk8?eRsjl4%fwDQCvzAQl_ZVOH9E$2|U5cv1O8$qRE-%QOjzt4U0fkn$-K5)(uuT}X7CnGjMw4?@ak zK}h)=2#MbCCWnynNfA;$C3y!m6p{B(X?YiwmiJLY_flzjH%BQ)`ZQ%FoZdD_c}zWU_K5`N}Db%(q*vciVGZ-`gkUqtC3d+Uj`Dv6To< z%|At;7{t7;^L(a-jYd2X%s}6B1)C@QI=M$k6ntEyAxIxI9L`~?0sBjc^02%%O!3lYa2z0eaPu|{LWhg zQzL%ot%$>NMUN{}ayb9$<$aavMpI#{Kg{PX=3cVK#L%>#+EYgM-zHV0ZR{zey!B;4 zLzMZrm)+X!?^QMD+fxMkZC1@aUR|rts_A%jh4hxy4VGm$>B@h4*@M74oYX9;{w2N^{w>2JHprR}%)rZ$ z?Zf?DQkz;$$_Zx9D^5~-y`++a=c6s}wf3c#M|x>d%Kt*POM3pR1G=>GJQvxaUK%Nx zZ#$sdOY;z#y}W|X%_bmAU1k~x>4v^08haR=9!bFYPU-;TVk#6y*@E`vRx`^*Lw#Um zRKq`3Pb|EM2-Pf;-j+nJVGgr(hNz2YGdhB-(}h4}epqLLNULdbAkuEcIuP@U>A{=+ z7}ps1aHEN`1|Ib1icQK|GD6}yBkH>OmEk|zQ>+i*OKs_fy!36G$78+V4NO=9BMAmU zD`5=2n=(FRi5EYeG;w1~9Mu<>Hh9Enp&Ak&N*KWxrHmwgoG^m-7+2L2O8jMimDqme zgh*n4BWiEJOH)P?>y3{M2OqOaQX+|yjHo4o@0pk|lIUACmI&VA#R(&ceT=9jf^Sb5 zN&G%x1kbZI7KVZZ8-bRXi>%U+*d=Qw%^~qMBPt^}5$z=-%M~Qe>079j|QQwcOEa0(;f>XlgAE{7X~#(gz^ARoTFZn6Lq#t+XX}(_*)qkTIW|{S zw188Mq|JS|;SW3Q*h%1Z%xV$G9EejSn^B1$eTPTEJV99dy;dRi$iXPYqFluP~a- zAnq;+$t$h}#Gokg$zb3P$nE-~#8n-O&QF69^aZBIDA+ zz(0;T$C;(VexYn&_6}(pI|m-KkboF2niI_aA#6C$qlvA9r~K-~umMjq+G@T`Uag(12C?;umMkTXTR|=gS)Jb zq1OTq8%YZTALDEd;Hxa=CNmGj5fLpzMBtpr1;i@U^1-XPh1dYHN6Q)o;=pLmw^@!} zH$S2Un)mM(MA$ru9DqOQ#$^k8^JXVCaCu&p`1QCvxH(z__yYI!TRqxxDfjX0~xq5$qptMFS81K%D43?-Et3K$R0i` ziBEtDH;6TKmdEc;Otx6?SsuS{0533-R6-1QX2(j3n4b!f4r6f@35D1H3qi z@3PI{wM%(&qF{T<_V$##K(?b$FNt>K1LD#LJ`%W8QXUYWKJbxf`M%Wv9_>3)2gqh6 z7aD<|j9fsxvrqvEb}$_%@U*y10ol|-UJ{oZpXLQ$9rFVJVx*9l#Cpjl2i_uXa=^2V z6!MaId2-qWX6p-#BnZN31HtTgfsw@OzWsH8?0JEY#F56Q1&*}=KJ4W+fXTt^k`a!% z-fbJ9mIr>XN7x&{Z#$_2WIGMbBasFS!2}KiBMEj^trz?Q-(@>Myy}pb#EHq)3tsHo zYy(IXDC8xl;0Xj7|O47Lv|S3_M4H!>i)Hp8m!sveJu_jZtIBk624o=LOI># ze;84}E0W5isNwS1X&3=UT0;f7ymH~b{vr0MSx3}`b7x(vV8SX=9FPc$vVl355;owJ#P$OpXf!dEe}Henn1Xc8;|6Clx{0uv#Tnt^peJWj^7(HM#tcuHfzW6LQGj4dZs0ErVQ8yE#4 zY(Tf}v<8b6#F#-Fhykail>vfwu4a_2wCUQt*mTl1EV?MC4T!o?HZXce*nn6x$_B=17d9Zqi?V?+ zUW5(!TwG!tT&*J4IZ8w6u%jvs%$6!m$rX{Z<$7qWO%g32yZ7P|wm-b9K+OHCKt%eH z*FZ!%5x+oW8${Rwk&O_^3Pfaz9W4;^JuMLPT`dst1Tgsnk>VyKcq##&nB^bb~WPuEA<`lDhs*qnuO!Qhs1C^@N_4&fxT{#tau$k@I!7B zx3{uAZ7+|5ACT{cnv?DDqt4bWcf$^0544Ns%y&bjp>UqC3uxjN1KAZt22e+6BFza# zD+wF$oSNP6S~tZTKvb8^6%Ylc6@WkG7JC!OrYLm+QF&4r5XGm3fr*X?8}KzrU<1uJ zHQ6%3#2Hqp^v~o85Z<0JgBKf3d>tU$u*e*6o<$zCg>1tk9*t-Kzv`qm5FbHC0EkZ3 z!U#{WK?@rYEv;-g3>Uf&F<9=^9fIv&N#YRTAH+BWkT8SP31kz{I>BrR!Uo(t2^p|8 z^lBiW^tB2UKRRD&M8Q${N<;1Af+%fyioVXqKgtx8<^wNw{nbE~p_`NqjB*N_3yE_R zMfXzEGrcO8iKY&;l3YcEO3)Y2q!C!_EJ-a8{D3dw`9M}_sDlKCgyv;Qz0}-brQsSA z;#1mvxXH0-7U_q*b4?)q zN&CUMnW$GFi(A>2x41YTQ64Z?8RYeul~(pUCHE(9H-R59nsD~5+~r)Q*M*awl7l(b zs7fS7uu5AAW;F@tsw?{rds!0T2eUZ}=Y*BJq|&1RFs6M~JE_#g1QYtI$|RL;zhIow zijx%aG3^nUwO(V=63q~ynrwkmaZzg*&7&lfpS6;bG3b#b4 z{VV%T@>I!yQ8ragq~4vVBkp+tLPws(J)n+q)tiH6qv2P;v|Ju(lWv9 z;}s{VbXNzXzp8eUN;h^e8+^q{3SFnQgW2ROPEzR_2jkvVoTSiXS|%7pR&kR0s_8oA z1fwJ>PExpuLX|ltMX*w+A~~d{B(?(>8=@+e)L3d&I7QiT?uDq6uk0-QST`~G}OHEgHiG+KQxrR@`F+JDSt1zKIQL43uYO z$`1|QuI&e-*;9UKXn5rZqu*10Xy|$62czXverRZW>jysH2K}W6`lTg|c})4dR;i13*41Qv&&~$fEe+b z8H_@g%(EBx`4mRHa)MFi!g=R{UJd%c9$074|MI{w4SLSnrKTGebV;G=g?iHhk1(L@ zwWVM#!V2f&1-+X2zgW=iMcGT4cgr}LBY(jB6mA-(65#R1)fK2i7?Xk1pudQ8;`-x0g*q zYWl%}y*dhOE~s-99yqX9N8$bhyS;1_(x!hC*)#K>Z9zv5jB6mA_la^V9fczn^y(-) zbzpIpsx`4$;2KCxzdg_|E3t(Lb&Umuqfm1Tfinn#l5$*2Y!Q7Uq>CbCw1WMJPAO^IWg9qdJc4q^pcS+l-LP!7k>u zENHkasFzvW&sy~Feu%heGB~!a zt+dba(u805mBS(@*YsEn%XxJwKZukoX)okjxxfxWuC=FpDDF3RRNwaI$lxxH3;KqD zoFF9JE14LsWlyno^0A{XZfr>CI=`70QG2?GT4KuCE|Oh~!17ZQSib{5j|hJhiM%L^0BRt?gsIH1Lc@Q$=e`(T{B<81P9 z-`9+j2gHk)$%C80crINS(=!kmH0CW3 z^O+08eC`4*}iU9_0Q0yx>P zAIt@wZX{S4mUsC4%_Y9_{YV1-+(>$BhOr~`QuCF;N3-_HkeoF_<2dUKM4ExwFTzhV zm@6Ss<(94~nm}3+O3Oz*FKS%hw8F4?owb!aE;2xRW3%qgOU+e|-mYli77ziFWA)sQ z7gFB(i|uC4wf2|1>po4IQ&#S_AOt>3-(FNO5EoHQAZ zIM_{wBMx@4sn4=uV1WPsB2DypBkywq$Q>XN9pJ3U1;j-cuIEiM@3a>(pNwBK;Ckt? z<|)hgqHxOXX}{Gy|f@+g~- zSSxSyWz@`LM8fqL?K487dHS@&PpJ%GG?mZMnPV<5pMF~5}1tHFS89n6$ zb4|43B=wKbxAat|mma44|499mnfaG^g2TKmXAXt)`Rv-w5f&N5w}mr|qa`K~!_SS9HCxAkob;qTTs(IYMU(8IG->H6i6MLJEmED^V{Y5lX;o6B1Dpyfz_~ zvh43AL|N{XvfRn1UCLs%`A&h5xG8vF{5}B^kC!1_rNno*!hr`UTsVPvfI`9vBvL3O zg1zJY3ju{QUL$EIW#Yq|*K+PsiccHy`KyahyA&V)ZdufP?RU?!(GX>%PB8TvzVr5y{E=S z`n>L`Wz!2cg8%q(lx?K4?EfkzlARDl+}&~^G;;KfD?e7WsL)A+=i%w%aBxe3p$ap9sujtYg8mwlo2?K|G> z29W9`2zJ&871I4cWItWz`)LD6D*|6$=_6JdHOPyya?CYhv!khHXD_e_+&^Y{SM~Ry z8+opAeaB4BtNeSGO->UgQv}VB!^6C&n)Adfvc}7lP3e*^4v!G?Hq_+YqAuqaz2w}a zF6Smi&L3s1WvCCzTU-;_`>*BXJ(Rq0n&#wvU0&W^rZ^YCm4kTXl~&Ze-UG5WFMoCr z-YBUxQ&v;la;B`NxN;tAid)V+))ZGx?i;PMD5&ugZke#zLHU>*UCVYTxeyVNfV|ck zp?F7aVMph6wlg+alQ~P@-p0eI^u}}Sl)Rw4obj?E&F3y2pAm&2;pbh(@ zKK%Z#MDF$xE1a(nnTN%P@HN(l2g)~um6q2=z8_kCi8=S#zwsvfnr`eATX~*aZo7m} z`BECK5iLY%G^R!|QQG&sEmdi9eFhQ*i*HGRv3bRT?I&vnB_9BENo;CiVclxQ{NCHu zKk@GB?33P1^D!C%@-C2!DBRraesko`n?qgv*8*ACH6LoHTIvuk%8n7HRvAue5l(u& zUpHtGJK`F5jfqL47y!LrQ#N6cCdBR)0`oHakl)t!)FX~NtD&T|YkAX#fW*TRZaT70 zmEcY(cxMu3c8wE~{&o)fK~8 zR`-JT?qVBrJ|Ql1{_NUa7W6E~`@7bnrS=@xw`ejrwz5^WvQ>_5q0%0-LLauL=u==U zdtq77!hDfkk+ssUqn8bBmJMx|pP)5>@qLeCG~aF9XUAN? zn5!70GkW_NUCjsIYCi6kTS$6RQM|iSoGz5#zH66dx688IW!Z%$D9i4YWjD*RdujJS ztaw>?WwD1@8bJQfiQJ;(#h{h_WVhIB-fab(9SZ`+x0jj}6yIJdgz(2Eg#3dfQJ~B% zxrLOgk206fTFg~Q+bvet!}gR*q?4)a>;4J3qOaraTZ$9?n~Du!Z1vzTtbm)AU(iii z{p0&ioFupJX-+JxNvmRKih<)_M#V2Z*8FeVLR0WLZvGpT{2NKW-uMZ>noz`a9;D~? z3CYAZ-NnB5wZDJ&YY502%Lz9Jvp;poD(-;uxy;zF7S(gQD5fS(9*q}Lxw!p*_~5n) z7wzShXCd)&Gk%U-<-$eTaYTxBNvRGuxLD9siY?f15ETxy)lI4wdb$BUhnhl)N@}lY-UNA4VL+k8=|?RlwF$~(2O zobnoW>Eu+ud@>if=Gy!lujXb3-x5h*eQEXUP4*NSIAi^a^l^I%X=tO0w9uYH`sphx z(yjIs(owIiNUQ8nJ%u#7V+F6br;s+-wIXe0Pa)kfRFRh2Q%Gyitw?*@Q%L!|(dW;2 zpND|4&mH=_oA-H$c7EL2D{rX+W79ij(>rC;J7v>5Wz!3lQ8stt3tMY+x2o75*;8tqzh^}{ z$DTsE%HS=L^sea@*CqB8uB~QPqV=aQ;4L>1AHK>Okm609?21S1`RkpzlE8NtkRU?hP$QARKw42&dDGRg>M$p%Ie zs2*hm_qD1~42;WDNOdDK%hZn+20q?sQrNdfNH9V|9PM?uMn`%auF;Vmhii1C$Ke_s z>2bJ5N0v8SkG!NBQym&GLnyBwY}oJOwUbGua)Ozeijx%cq?{{K@1LzLve*76do99E zjdiuB{Lfb#q(^5=@6w`4asTS2L6Z4B(+jb!8;RwJSc}k143565ltX z<_2Su21XLtr^*P%Pz{VESU1XupdM}pX<#JLXC|pKf-zSEBZ(zul`10`i#0HkztnqeClNxaI;QDp>Uss=_9g9#(}Sfd3-66@_B z+X&ugFcAO}?=_-U4c^gA;i_s&U>_?Z`0SLC#E*=qjNsc-MiS>VV;jMk-l1v|tJ(gf zC4$#CT3{q`Rl*2nlM9Tw($x~tx!Cba17BxWRLD%?*NJHb#)t}x%hOrke_8A>7&RqM zJMgwwL^kkmHm_*H2He>6m9`g*juJND&UWfN#+8%ubxOXc7FAi7U)9oH84!fnt0Y-48PQ-Q%vm})byqnRaG~mL74Sck-b%396QX6=KlRCg;O?`1u7J~>G#~g5C$)hm zIB7oc3@5dLpLWuG;KfdA16ND-EAaY8)0JV6C9LBEzTVk7zJ+)^)Fno7H13zgrX$lb0 z)2vUMlp=acL*_o21VzB3Mw2E3iI+$Xz>WSbcJ@TWA5CcBA2{uV$>3iaO^O4um1*O^ z-6>TSVW2Lt#8viG#v2S1xltMzn@;KgvNb9jd*Vvdsyc)XNGK;r1qqG|HSZ;shp3Ix zz!S|hl=6VPCDtMsA57SQHzsW0yJBfi8?4(7bv0r8%c4UCm36#%ixl8>*XbhrScKOPb9Qc%=Wm(o?^NI_e>&$ zA2R&uga-bi(PS)v1QaDU^RH%g&akHr2>2MINlxHroYVo<*+PeI5c>~)r_rP|;O{qN zVw%98Z4z^WZ#SCc1pbQ~M}xqrMhfFg;zLH%ZrxybSwaK<*=SM)@G!Tcn!wN37(#Ec z2&}j!rx>g=geF-8RwfWgAXeM9qy1cGFa6nmQ@&mPwHluN?5Q;H0Y;NP0FT(x2N;Mg zr8%FrpNV6MJOH0eLczP3>9o+En)NG&F|Xv->?H687H5zl0Zw&N8@Q*Dv^4O(&ei~a z&q;0IMX!!B@}%L-w}~|HETc&~fFp?|2ksh8dJnuRVap9ZDXq@9!_bQ{kWOyz1vRUj6l z$S;s6q;LU0XJu*mVC+iC35+IY2NRRnkmlUR;y1)|lm^BWmC^{~V16pwA!cu$=yvA` zlfc-Y(%x-%tfU3|Q?r8KYQG6vX^M6*MLB`coZy{zVzo7Z$2h42ywXUT6MSD}t2@Uy z*^E~VSIr8>a+T%+f91y=jn~?#EB664CwA@c>^G4QAoi^k2IL4Od~2I_}fO4 zaRYweNgd#?oYVyV(McWPoA<0L)$;ShFs0?k-ZC*9dcVpYkS6fePU-+pbW#)e0Vj2U zxGP#Ecpvv>n!x!^>Htr4QWN+ACv|||bW#(DXCyrWUX?gT|6}+;ryVm1jN>C&|6&di zevftljN>D0Yno4kk0buhB=ENG?=*qY1?tSVUvY)B0`O;IP9V2srB2{d=V}0d>!c>I z-+iYJaAx9lf#2e64d8E_)C6)tS6TtY(bD#VSN3bTP2j3d>Hzm~QWMB+Unw8RZC^2q zfM2(aS|#}ESQzjQCv||_6P6VQ7J#Lly@4YH%}a4&PF)>(3a$997@A^<`hF|IL{nZDh-Si zE!6@!#!xo!ntm|R26A#KIf3UV-Zz*75D{J=Clp!%7%yB(1LB1%8<_j+B3!vc9`+Vo z^6Si**Sy@odBA9r7sz3$vgL=QO2bVbG&eoeK>~+e8NoR3fssUd%z!7~tNVU}yYFov zZoCZD`SvSU7PKkX8I8+2N?YDth3~Etw@B~}Mw1Bx?&s$iP2h3s#hl>Nj3zmOT!0W` z7g*k5)$_(ClugEVqV~Zn^9{A`07{0TEVY1nzR=fz4sNE znv@2-*hy{RcbqgIc(s$-Ko0VxEFcj96+kf20g(p|Q`S!c0VkU~kBc9MlEn2}$8Ldd zH=0xn8)+>N z7d~{J1pd4%dLVASjxTtb*U$vw)+-x0y7+Bee2#3C4LsYtd8ri0V0k2qVCn7}1Q zQZ_L00MWm7PCp(#UcF`o_jV7`R{JE3bHyeyTejA8iuN8o!kKYF3>nj^L9ziv7 zzh63v+kbN6(1SnV4t)cNuP@^P#IM&n!T9ykPas#Ql@0vv=)40*oYV&5_KVN}@&2_i zFur~e5E3~1$_U1_m&O6{?3E4Aocq*D!vV&bRT_8?cRQOv+*=tX;QJ#N5QkT|@K-0B zzbah?zS2o;VADxW;Cv^wf%v=HRxlTTr0YOjU}Xd20}I<1%$xm|J>?6MlfbyL(gA$T z|8`Hb0ptu$D*(T7dbJ=$0D;^gm%@No8<*w;HymMC#yhWLf9n;F@T?VB8eZdca=JCwb3Zivk}KJr^MEik$rdk4p|G!6zF{ zh7uUBRt*C`IyuS=_&lRYPT(U>8U}8hoN5jmerG}hFEW~x28<`2E#Rt&?{$b_jyGjq z9$qw-t9ADVu@jq{JGE=#YJvBQt`_inPHF*vn&brE>}(C-mhNY@fX8ke+wmjAwVFBM1DrlZJsGHkV49)-{Z~r8F@9mdqazcT3s8(e)a}_2NKP z*}%A9GU7noEoH;y!naZy_$qhDTDV*fMbgs-If~Vs;EnBYRVuCX&^VSoJ+k4nagk3; z1LM5OfaETlka|0C9p=E5Q`XR2bHYXvXAF$*CN%)@-83s0KTg=ja^o&Dr%bbgzil*G z9zYy588;w)n&t%Ks7X#B{+Y7n4w}+-FfWXIf#dq#HVKRmCVk+@6&Fmif;m$aHsCTp zUTp#6iR&>JWIU3bko4ZxN za}KIB@MHFyOaqXEP^kg9#qQn?AP1qs1w1Ws0r3Nc3-~GH(pG>u9MyY&;ALLgFc1$? zvx4_`Kd}YGg_KHxoPvrN;X1z5J-`+ae^D|5aSkOT5T{RD0gevfFejZKb_Z}u7mOpQ z&KUSk#}9Ayd{5T8$n4E&fMYqo&+fl?dq87K*YJzyx^buIbaLOd7$(Q_}9n< z#03;CAikZJ59Ux$*nl_eA5{$a38#%r26Ol)S%G+kS_AIjpAxST%+*sFU?47_W(B{~ zPt_Vg+(Kmo;}%LofcSvQ2FBqNHXz4g%66SOda3gVe!zYcxdGw?N@>8?nLj98K-@y% z0^$^EomX3qo9wAH&fGX}QyS-N9HS`>%qf~w0j%>kIare+2iCcu2hEL>4~_?F4Il?= z+7J%cdT~p)Oy1=I@93vz4InpZSL#~`98Gd^x3=!6>>KOH4m@UfeB#rA*D{)n2awY- zsTKISfE<`OC!a9<^@Ik#+Gx@^;9s4z5V%I- zoPaknn&brHkw~|IS0pY5P63BO!Uo*@)p0D}X!wkT_EW=mB{cBwj3x~M9_G%&LLgSZ z4jedo01NQ|{y4R2h_ub2o9rEYg46-1J7^ipw8x&88ZhIJax;D*7Cq*?Z~-|+(H^W} z2KUDH)WQrdj3gkow&onm$lf-~)WU{EeXv>4$_9Rq z(PaLB(V$)k#E90MV612zBr~Kr(@-{!DX@i=c9hw^C)!hK7{Bpe;6jXG3|eIaW0*>< zuQzM5omiij8ph((TUcPsOUa7ehmEH-fVr?HY`|Y6b|3fwxA7XlP25sj2*lLW3c%QB zQUNf%mIhwk&8vk#qWD@G7;8*Q17dP1TU{`{w7C|JWpiOwNew_OD6IjE2_kf^w_fiaeZ4S1LvCo!arF(Yhu+t1i7fmeAwilqfy%Sj8l%EY}SDXhGX zw2*5^TtSi*18mNY3Y3UC@o()EhE9xoF9c%TC>vG{VQi&=iCIhAfZY61HZYcsumLe{ zlntw9T{mGGz|>y3%znlm(X8NC+8rR-7J=9!QYmmO(?m<#du}yi*V$8PD-!oUW9>NN zOAY@fp@APWnoJgO);h?-9Ae=ZAKHqsjE>t9qvLND-X)MLzmSyAvAtcW#?B zfY>O~UgE2VCFaUk4gWNufp3l`43KcFl(x6UP-ojy`v5+`XwrM&N1QZ=i0n;CEEW7G zqe;#UwyuWtG<#|V;4d3Z*nrnMY0d)%2NH9LH&tHkw$B{C!tt1qv;y$c&ei~OVMhCI z;Z@?NnzOezRpwwxVJm4?FacDNRA6dKjhLl{Nu^o4M!UqGO1sMN_4bqo6JI5Os%)57 zuXpomPS@bYk%W0g7*um&YGG!D(#)=!ZBM0PVDU{6r4j7B#Q3CfW7%97NtzWaDK%mU z^bzD!zWfS>()idiK|ZCGhD`&*hF6G{4b1DrB6C1&9%TcMHv>o5FokY0lCpt+71@AK zIB5>IE{L0HPB2k2si4kE+S|;YIf+SxnMC+Y2K^rU8JkCI02A1f8nAy(O+r=JKNvWg z6^n)ll4J!QX4eapjmrcWI7+LtY&M)#t$nTrsFeub-F}l!)R{4LHVXy{SHHDdLN@n# z$YxI634YyieHpW9VCG<{Xbs1h0mB7r{SR#5Xvxgsn=@E6niYJv+dy;bE?e_fGH)Mi z*7YsS!->DrFm+y*+AP14_!ir}`uk2?)E(>POYURJk-B{KI@_8;&D)r=MInbGN!(yRhU~=Fms+4c zWXDCh*DngS|6-80WOO=s*WwsoQEgTaFFPn3_=Edbvlbe|4VaInMAq45MwES#bw;35 z3uMi)rj!Q$rY)dQNxsqok)_7^(%fJ?ionQ%VljpB!XrTb195q`*z3Y%mzdCKwO~%) zI}ozCGjKhAx4wj`}cQAtz(g!&^^NhdW7@!{WW2qL5vknNHsHOyS(Oze{SK1zD66OyH&BB*nX;LY>~h17|=RVqox135*&RzNo*FdN;+Z;6$>#TT5 z5$#lI0plkKr)V)!>+Ta*JD9t}!YLy~>YWKEn1g8H6dgqBzY|U{fmPuYsU)>wazG89 zZ8YJO-jm{8TA}XT-zCLiwos){q`1>ul|Ty1OveO_FC?5Yd!+D+s!~be7-@bmhuOj@ zQcVhjPpHj)f9>@sGvG8o7>iFh8~uI*8v9PDv-`WGb~YO?5k=b zg>9#tV8X=}C#eIH;4%2qMyohU;g4yVV7?YrwUgAr$zeSB6r%~Jj2)@;C?Cv`zHo~D zK?(y^YX{#O%N*=?Kk%e0s-2`b?iZ@eGAUx?S`!#Yv1&aj?Bl9bQrrX(sm*>Tg|Q2Qo&p;s5nUxz*kN%{;Y6{J|b1;-Ex^gI7J_kN_}2J`uM(D519J|l3Ofq zQoYZ;BT{~7_!G(x#zRQ?q2VbgKNvqD<%fp9 zp!{HL{gfXXHox+NvF%fSXxRA555|^H`JrLcD?b>EKIMmoWv~2TZ1j{L8rHe;gR#O> zerQ1hlT~L{9x?glph*)u=0bkf>VBISi{N>#uiTbp*OVU` zcC7M)v0hVtXxOdF55_)C`JrK_DnA%2HRXqfwW|DJY}J$>8aAu)gRxjserQ;($`8hF zP5Gf=zbZc%>ow(vh83&)U~Jfw9~!o-@`JHtQ+{Yzw8{^@*X-Do9~yS8@`JHoQ+{aJ zvC0p|+D!SOVRb4$7@ITYhlcH`{9r84lph)vsPcocDN}xE*p|u<#6v2&)%jew)V}gSmlOu4P*)o0lEUOv@d0CM3g`L*T~ZjE$_d8s6wY-9{9vE(x^jZ~ zUZZe+X`o9Aqf@Bo4~!Xr=Q5;ler~|8M)JJ}p?-Iu_`su3zd6t)SkG%lLfv+tOKJ^! z=}4$k2D+p$ZiTw_K(B%Q<7f05*niv1y1@SYfnEdqa|gOLf&Jgl=ryqa+Zq0O$t19U z|Ma@R{=^x*2KKias0-{rFtaYO|IV3pf&JgkEIvyqGte05@{vl6aG~x$&}+DV-+^vT zxc}Pe9`5I=hm`u@^e!n3c%lAodas87_e~%3^Bsi!rOeS8b%y}w&hSG3Ub_ z!4ZMAT?FQcK&TH-uRAbUZAO;^13ncZyoU{RN#TwN_1_12Jw`Zopzavqh=Fb| z&WhA@^vqt55iXwDtvN>c)XchLg!j*^J4QG`*0CKF;Oa;V4i+iw?HJ)*GyK-it(HUb zzj20Ne8wRX>S+VL9wQt#&>hP$N{$g;HnZ*+;b+t9juAGP+3m%Bl9p~Wv)5yUg)@3R zM!0`wug3^?Oz-s=VeOf9#|SIUtUE^d!;HFPgqP0r52fH%>HZAn;Gmj4QoJ=M)Y&ur z9Xebuq0XA=7qD=?v{W$13Bq~(%(}ycQ)l&hxbW&(ez?GW5-D|)S;d=oLS1K8uSX8| z4UBp11Sd_(oHDCR3O7xA3dTJX&K+iTN#UR=C-{VTc=43n$crW)(N%g!-mge!#)2 z0z#cL%U>MephKuLXVo2h>^h^@V~-!r?Dg1VhZ%kq59d<~^)cV2P@{=;ZH=|36`+h?G$&BLmpHP1|qt_#nhh{#PBa$@- zdO9N6rniqG;G*Dg$P1+T4KgmAbJb67!sRU7X6NgV@_i(3_;LSQNO`Vv?ULaI_FT2E zfAL*g1}-$q1*SJv>Kg*0QW9>ipsrGWn;TR#+^kWq3ftt zNL07JSGVw)svFmL^hD~TyYdRsMEV&^AEflynZdktZf71J2ks;rI7k>zG0P`enRKM*F{B0ic?%jqUXGGs1v27NJTMMVFM~hD+PQZep51MD*bRUB z`s(_HND7d1YfN~Ko)Ysy_IoIi`@AfP}fJTE}382|Il`UQ?(iYcc$x+bqDOe{+pq@>vJQf95e>%~EOd|9=LU|#;oMQ;d5T{1{;qs=$< zRu_wXg4MCQ4^jh&Y{)b+ZhVbNNQ~QM-jWVO7{{$c3*xwSI8b=X8&zoKyiuwWXcdDZ zudqyHH0b(DeS=gOyIc(K?RKI2clMM4LnT1s-*w8&b2EOg*SpA+)wZbimENgBJ|3~^ z=!mRY;MgNg3%2qWG=Thn0+|mW=U-C%3pqufwcdO^4&qW<$QZES^A}KtfP5E3h8%7_ z2eOvGbW+GDb&XnG(lsF8j1wCV9kqsUNdEbjIX-g3jLFq5w!?_+&m)N$j*>jg3`a>G zMw0pZi!=h4X}Y}`BqXjg(RU%yXUuaU<;pAXvn~NT&6tntTQrfuj-?M$dK}SW3B1cj z^3*tcECEQY5?KPQ`Z%&JI`wg%;}$KsJ(6fi>}RnmK4>kVZ~yRf%S8OlhoJ$y$w|XN zP7kHq(i zQoX!JMzz!-q_XTexp3!Yt8nLq%NOq^mZcAtr5D1zkF|Jy93_Ms5}(8r;iiuF_`tQO z;{+d_LTndW*|fUn(P5zW_39eDSxUHF%Ay5veu^=Clf9dMygifI<-}x`zW_S~X+^e@5=0l8f)8VPR9&c5Y4UDP$v>XLo{<6hW7Bk>^=aYRdv z)IlTtz}1ic!_+@T5|=~naE;{u&vcTjAOGj2M@AAF>0H-H{vShs5=o2@!y!#YNsV`n ztf0|Ecp0k%UJ2NF;G;e&GP>x`Tqa(`BerN{9a^ydgKqI;Gy~ptqig zT=`{3=_7mei0{!IW*?73xN;4W&%P==rXT6k2uwMsgOna+t5A5izOovS`|K%_iNb@# zzYdpw55e`BH@j#z^X5Ka1<}NRcwwc_3%$<`U>t@HkT;8^+vSA(gG)IU=;}Ag2Pr-F zuTTvKTPKc+V~J{jbgTEXS@yHZJ<&a<)6XVdpXig&r0aV{QrTYrN7r#QnzKyfyxuiW z^V=r82(efuxr7{RO=g^Wo;7;2y7#65T-!-4AfL>T;_34WPj}gyLf*$&Z}{kzUMRZ6 zBrg3@Bi~k>ZBYs3Zz)1=Zcys^5KM#s6RtF&89bde~fAyQ0{(()^lN<#;sew3DX zRcZOm{lD1P&-()FFs&>!@d)x+6;eK_LSp{5b1Cg0o&1kS;Q}(tvgee`u)`d0=W5aa zHF;cfg{M-^+_V}gomTvB+i`u9iUtomL~I)1FaE zWeZ$9!rZYW1CiOAWouGS#(^x;z{ix{x+7|I5XjOEeEHf9L?)kU4a9u)1|n0-@(sj% z{RU#bfCDjK!GZY9OL%IHAWW?hgsC-xFttVyrq&3;)EYsUS|bQkYXo6xjUY^|5rnCQ zATYhmr3!OC9-G*OWnB{$;R7N)fiD-IK+MM~5OV`F&Cjg%w;GLb0G@EXO^O=HBuCnYm}m?HBwZsa2YPfW?Wyr63$0P`SO8LT0SmH z%ZEj2`KTx@9~7lM^O(ec6d706l$w<#Uy#_g+He22X`8ZN<;L`1S>GpAJI)sQ_m1Kw{PmwlEa7yjd_kcjG_w}g}rgOKtG5z<7v{JOqhg6-r>Pq_I0 z>CgSYL3a4;&ua0^hVOr_>ci3D9btw;%HrkDN8{NDBf}wvaOLx#kBmkj7#e0q&mfqR zSm7Y0$8j$r5J%Z~pBU$u2n3`L`IIy%`(578!iagVanr>AjT6Z*9PPu<0LGE&06EZ; zk*JXX0{VRHL%5i>F@$1h<7!16X-`>fT!G`uR%f}y4gvYVRl-}0^gLixcZgTl;NKkZ%~TbSV#lr^zw}nKEepkPA(B@6V!y}2863>YwKAFS+T9UF51^$JSke+FJbcHcLh=-nSm5m>y z@p1Bt6}HeO{m3Y2tT0H6TrQdn%$k1eUu+-mFm9UoPibP%WNv{k^6_f`Rl-=7E;%vR;P>! zkpJE#x8lnGm^93do^8xp7cK(wC-`Z~@KS?!MiO6qxYqUTFke%q3sM$Mf4Mh(n2#Nt z5J`OZ;LDN3M-TY4ft1Bt*01ry!r}s7J`Ac17zd_7FYqz`v898wG!Am141Q>Xd!s#N zickiS?)LF-aWjm6sa$jTcB^sI#Q!U^Mms0DEH;3#>BGR;k*l}qX6A9zrH?P91pL7M zmEA4&O!j&{S$eqpHA6uDfoH)JJ#qay`WotAGc0?Ar2hE4e3x9?q=DkCY{>Xhqp;f zMk9&uuz$(rs7d2u*Na{AE7mBw`&>qvVL8?t)d2GUTV?Qp+-Z~=%XSu1boqLfs^{y@ z5@Z`4;d9O0=aBdyFuBJuIx=~yD)V;s6h0t9fKVQH7?OJ&qa!uH4 z#KS_F9Hb`qI7UY}j!W)wjE>aY;}{*`9!GL%V{|0Hv=J)Gh59BNv0Lpa<6Mqcqa2#z z82gczRiiiF3X-M#6T37^q;c1sD;9AHfO{D!;r^N}_-`+N;ZxV+R;M%?IK%tV+1PF? z?r2YmedHhF6B3Q1B|@SFKk^n7L6f`%stafWBcMT(vh+bpkNqoj!L`<}TkI*LgD!w{ zi1)Kq_Or!F%BDLp;w`>RcvB=X8V^Pi?R|?+Rg3oG3)JkRw_7_If#-QXn3{dOQ4Qdr zlR7}YOCpV+>B&R_V{Zyc-qL!rYaD$(F2aWr2Xkqg1$Q6@#Ky9HS9S zAEfly?mxr`XLs^uBOSGL?yH z5mFf%A7)p)%Fcc@qXk%qy$GocjSmwVe~E|2hx3y?$yi3qhl!S7?dxxtX!%4pCx(fZ z_wR;)3==JXbtDnb{%j<1tEw_Nu z-*O2^f6GN7{SBGmB5e8_|7>E?j#Ycp-}s6z-{wt!L#R+t>2HV<|9Bz&4Vl8EPJd$w zvpCb=5IiFC>2J9$nEsZZOsBsglU#5}f6I?!)8Fv-h{L46<;Sz>ZGWmsvs>?$pnS*7K& zsw%aHdm!f09*DWP2VySoftU+?Am$Puh`GoIVlMN6mc0w_GOE-*VARf6FB_{Vf;N^tW7I)8BHjO@GU!H~lRa;`Fy%meb#I zkxqZhB|H5s7x47AT+Y+qa&b?8%cVa3Ef@auw|otxzvW9I{ViV+>2LYMNPo-MNBUd7 zOw!--)sp^}FPikXeC-U_w$XMc;NWuGIQV_VwsCM?(B11+_VQ!)lnsKI9RCnwZ!1M& zazMm4;pRyA$9`H|L^7!BH&&N8t-v>UKU(x-kvlUj91~W)#Fw!1X^D`^O|nI!_!lq2 z#lG3~O|r$nKN(5O8z$PT@eVLUr|)1fX0cg=v>^^m5%2h>4ahZd5{P#|y4DA%$pA(B zpveH?l#2t%fA^d14s?@$;J3#P)tn0#I%+ka<0d1!P9)K*!y<{nJ~NW&XdLV&;=ag7 zw#oPtn~+8@{_GYt?(20nGK~3i5gmr%#XbxT;5trf0U05wk&%g$`+~~clP|5NX^kiq zya3I)dfQLohkysi8#HipzCPe*x5d(=u5nhE^cJ{_lUiL1-Ec=nmQ()E$c04XXo-+$ z0V-Tb`3lQhpeu|fFao;5%F+iZJ@&6yVK>=WF0-d7E>;+%i@cxBvY$<^2eaXejQ;*L z)%>jaT3=3h{GaehU6TR2Et2TM`96D1x)2AbxzrTt)2>j9=;W`hH;mKsJZntgq2A60 z@F*v>fP7Fx8d3J9nC^4et_JO5d&-1xv6pa5pNH#)fS5Q5_ui&j8m?jr;ij%nTV2vZ zAl1uNL8_$=A(dqp*WB{5Rc!OZ_4Z&{`e0dlA+~R^79Sr+39*Ir-F000&a&l+_==2j z6>^D3Lz`twn&+8p{y54gv82m9T-oIRv;T31*GL!8^EI0LBx^c@((~Zcf<@kf#;FGR zPnJ>^Er`=!Owj?R)K9dhepwmJ|D%;7J+wMIn~-p~2^(`N*Kwbrxl6JC#ZeH@Pk)O5g^3pVW zYT?{Gy3aSXV$zpd$xql*Ze2_Qui_t}Z2{MEQgLD6Q2XgLd&(v>3CyRyMOW}K^t-*J zqD|O0>$X@xbK3^*pAV_I|8W((`gkWD{k{tR)}AsocY2G;%eDOz| zw4cGxMAF9RR=>`)rxbs~Co0mmpY)7h_;dxA*;Bag_)JB5+MYuC#(5R#x~^xO^7#s$ zYER+XyPCwmHM>n~NL>Gl-T^#*?(NmpN3ac%kK>M2||Tv5T-T}t^FxpB=1I{sRrEFj{n6Lqtd^)xbjB=8F6}XEj zB`pm_b(v`=rGe2{5~Ex^LSp|Vu@3M(pRH)p6jU1eOUna47IoS+U#xN5i$tfck`3a09*uj($yuIyafsq7ToHByh>jEQ*I_deHNmO7Yv7v2rS|S)p z35>nSN?^>TMN33n*uDZIiFJM!g%mvF*A*==lK8OgU0NcTeJwDOnES_ABKY5p78psq zCt(C%lQNQ6Vq2Y74gT5RlQxp*_QjnGe3{XzHd>+=Vc%_D><4&1qlsPuB9K!4=m?2A z=|oht7hohMWF}E3Hs}w{3{E6ubfiZK8681F_A!G%SfYeA9y(3pd^62;^udT(U?hQ@ zDI*v$3ydU?Gi3xLW`U6ea;A)6#4Iq9K+cpAjF<&R63Ce{f)TU8NCG)iMlfPlwQ&X1 z*BjR8N`Ij~JZ! zO(y|a(A6MbVOeb@YjFpBr=qcX10xBRuQGyJy@8Pg%U2n}tlq##g5|4>U{-HnB*F4k zMlh>4Fp^;TDkHcPE$5|+j*B&`Se; z$w*q--weOxpo&dt;FlXsdJ0^0u$KnB-bk8rvqP$%ce1C_zyn5;(tuxhgO>(;%t)GZ zpEp)NA8b#hfsZnplm@)_Oy^=Hp)0Y=dZ6t??7puPdr-C2KFLR@iz`w8GYlniaOO zlxQrH3>+8-E&TxEpS39X3TA@R+B1K9Rsj?5aHjPkhp=0k?lDp;QgL_gt?AJk}^xTXkOY z-)uuN9YA&=RRgmLi5ieSNY%h>L81m^2U0cgMV7}AH6Z(ss)1kszz+fV72AAN4a_bj zwE>Td)WB?Fq6TCu)7rr7WTFOSBU3dn`oY*Pw8KYc%2rHF>CGBPS@Q4E+Z=BQzyw@mKAHtJSS@27tED#^> z$|B@Be8OF~6z1J$*wq!r<m+Z?&85dkkRi+XxTQU)h46wo_#wL=8rXk8aD4&1eYfCpDa@RVDV#+)Ml z{19{Ts@UKBIS$(?BH*!A5&V|rt)1f3dz0$-{#$aDu>cP?O3Q9KGx=}apeu`jA5=v! zj?gJ0;0aX`j4O1C2>3!(1QVD$MFhN|DuQu`PO+ysyC`&@Tt>hnYH2VY(Um^eO5+n9 ziGWko(qO!zQ$)Zmsv;P_=oAsEagy6aPUCFDS4SN9=HN(xgy+&`M;T#+#o*exiwxfs zao{_Q69WOR*y2sIql_@nNUiTThA)UX@Ri0%eZbd^a{WW-*_t$>^?_G4PRauDi>@p} zo|DA)X??i9#latTlnH`~d|i!0iFwU0Iueh$wDGJfT&0ujs5W`fQEl>|quS&_M;VWa zW7IhV;}>NOfVfCEK7@Z+B&=n@M8!^#xVU8Tu`1#@NjE45elcVtfcVd3RV+%zfofUs zqFcO|1L8hiv*t<(hh2RLw?^^u*Z-2#gPV1V2>4m85ghs4jxxeZ=6h8Ur;DRi4ve35 ztsvlNRS}Gzb&3c$T2%z&XPqJfj#d@H_*tijfTLB#8$L*8B67MNWdxkBDiV<5dtHqP zIA2u+M~=9ojDSN{MKJ!@)rf#YRz)!W*eN35kW~?kKX!@;)i~#t$kE+w_@RgcKW&`c zJV3G?(&qFsLR;kgx(xp#;=nH(C-ngbST@Afhp>l{I@muNz9Ztm4;Ux)0oSs;iK`D` z(E%!0oTpct*_~dkbDmzU zbDmzUbDr*sL_0-?4u?94dH<8KRGj+2~TuF^?P z_f8TgsKW#A_F&SA>mowQNL3_(K=wd6Fb>oeM!)7z=NtH_x%T+qg>E$XN=k%q@W}gr_p{ETmia78J z!MOlQ?8;nqmJu$G9Mb~By`n5Hc(st_1&%Pv)rT-PDm&Zo%Mk~D*EqTHfZJJ$*wu$H zEXo^$TYY-D0K`|ivIu#O6Mv|-F#~rPd}L>Nt_i&@E$eFRo66BT@)J1D&T1WJXSI&A zvs%a5S*_#j^o|q%q;m$wJ-L}cAc#{%Ffp7{M8H3(BKZ0T{2kg^##gOv2~Jh)&R4DS zSX3BcT_d$HY0*)SM~Wm!SAQZQRgnZ~uO}l#1X879wZQwIiuA~l;w{~v5pb8<3K(zc z6cKQjstCqgIz4J{1V{d~vy4EXsfu9S zrK=HvKvNaLxJ##qK%l9LVB$=th)_+?c~#_xRxls3VdP)H{eyo2@)}Fp>?$M7jLLq+ z-dk-Ez0(5Mg?C!OHltj92$Q0+9~fT8UViBWfWPHmh!uc`8|CUl7#EcVpA*UgahI+v zLZ0tjY_3uJf=A>M_9NrKL_4% zU2hO3n?F@W-Y!MHv#Wg3yrjuN|46Q?2*!oF8WHfJstCq~Iz(BSGA#NSGA#N*HVR|k3{Zju(_2Hk;?)9EVvvX z@9||`CbS{E5tRkkgqQk2Jd`Vokms)OLb^z8Stm5%lbj};Q0-~L3Duq^oKWp)!U^4; zCL|N-W(R?wO=kieIiU${2#1^pkPf)#e#z>|o&@9; zmipVfJ0M ztq;sIt*Z|q@3qZK7lbyz{Jho`M&Oqu+6p-ORmnUb&GEBaR~li;B}p?v%HORuVTN6` zN-)3Fb&3d^T;@x+ml62=o0bOiTR15_uiB`wz1pa;z1pa;z1pa;y^O==DO(2v#vi+h zMBph~6~P=ya*7BXKvG3;Z+{r60K}KOvIzKSEenqPb$b~BAFYaDT(qkZVby;IGy9$4 z)&+qBSB#Te63B0)wGHqJ3zMRv2K<4iMgohTDx7YRy+SJkvsJhbBi#2|=p1-JcqE_L zhQOwxHGj04E#=gK0?h&DLz zEaRLaJK*A&OmBrwv&zkI;U~#hEX?e2YSlSg+`@8|Tin7jTO2!>)(DPvvxU{}W(%v` z%@$U>n=Pz%H(OZkZnm)790(hjTUG?NE1e$j>a!Ee6DtF>|k0J%m(HZ5!k`p z8d&y%4a_MbjCmp0{B?#meI;<#Z@CXn6Jl|}e=v_tM>m@QT71GA&L!U$}sst9IBb&3dV zsj3KOM|Fw_Y^kaUW=D032yCgU2xdohiU@3}st8{6ezJH@5rNOFs3MrH*C`^f_o^b8 zt=B0cu=lDWn61|-BCz+WBABh$DI&1RkBhK&^Xfl)Gsv26&wqm2~&f5u7wfb4ayEJ9bb@qr%> z8y}Fp&Xq-Av(rfi&kcLr*fuskwl!B8frmUT4dxloDI(-O@bT=Xg~8Et+*qFwV_#E6 zFx#4I1%XF5H<(M31!r4xiU{m$stAtuxUtoy*v3|yVjEj+ifwFLl_|EdKE=jUnhplc zLz){k0#9kG2xePziU{mYst9Ila*7Bavrmm}W1m`aDfcNc`Mh0<9gE#c)PU?bu73z@ zIXVz9JC0LCV9QZOFx!h$M2PnqFnf+uL}1g=8o}&2P7#4kM-{>BIZhFQO-B{M>^V*` zXR{gGR^?_hw%cbpKJw+7L12T?{(#rF*AucZK(-uL7J)rS%YxZ*oFW2yjw*uLa-1Rp zdyXoC*>apB0(*`sg4uGMA_9AkDuUT^oFYOs`_Gxt{sXRr{RbHBKjXUHf6B*({p<&~$R>3%JENX&19$j;BADIDDI%~vsUn!&$tfbRJ*gs?-N`8;usx|FnBB=KBCtKF zBADIDDI%~vsUn!&$tfaKvsJCPf3SD(rpAfA1EZ~KqTj0CJ0g??_c}7+q%4q^>(aOI zEx)zLhO$Q(o)B^13yqWdfScIP=juZk7Hx+Y8@@H-!1o#_^#NB4TV#6~;cL+r2_6u( zNFckS>kC5flfu}*eEiWVA}oyd(#BJgLVMU%R~NjWanfnvHAYE&v&#sNL}fQPHK}iq zU9~>&4#r7+z;Q;o`Vf8}l?6`>wD zd#*jW@=z-^&h9pgJIe|<#ktwX-r3crcH4bwceP2$pk;tSzP6`h0rT5nH~k2FZBG@! z{5IGrBJhbcRRr_!>l6_{GTg)gbB~t z)eSHkv$U6qS?arwS=!50#w_jSDr1)Ra$d|r{PKQC7Xyi0-1zpaE{vI2Z5T7VJiuPV z@-(h929BQ0C$=H*gzox-K#U{g#BLwgUwXr@*6ebxHxpsacO!B$6Mk=3?GSjI_aem> z6aHXVxzT~w#CorquyuIrJG+dqQ}ovNbi>49GML$A1OhSb4*1Eq#zB_MCODJs0Ex}C zY?UF|#A**dO>C<&B%9dQT}Z}@W4C|^gl29c5Qxo$oL5HR&9T!&;LWkC6Jg!(8hLiP z-h^H4suOgU;Y(sgV!vCAl*t7y_Eamdnh5c-C_)5Z7a~Mp6d}&<_O0~7w!}1b2#prq z?GZ(O;Qd162fW58nWy<>gwCiecxEUIBsgs2~U$;2O)rZjV z+c37X3||p(;OmW(`hd@$=I_|~WrP8zhx$%7+#Ye@D~yx+fKQK)>OD?Luv~oz4@cn^mVkQ zU;;U(h(IK#ir_Ab>SSerQJ^O)V}V{A)q#obTq6i%+_Vue2{)&RK*miK!9;gX5rK@G zDuRjboFW1lH&p}^$T>v>0y$L#N1@vMG6Lb5DuSa>ZGIV{njmb*FM>6kW_WVMfu|ZL zO9K4BC>h1jy^x??nGvlRxevlQOT2K;)~X!34f;IS`0^RS`_!>l6`)d{q%l;Oi6-hJ$-(UR4o%^TUZLIK{6%k_i3ms)|<`z9r%gdNk3y-L9^1 zm0|Gg@~QShlh9Wz4)}NfuCp2Vo>9`q#5RP1FC-n1I}BJb%IP7T9rS?2)=m#$*(lHk zf8RJ!Y%e1WGgA5toZ_iw;LK2TVjIG$FZn(L$(OpmwAlZXFxANiKNiXY3G`iAgtcDw zZ2+UZ>%=yMJ%S#PX9QOt0uKq=7w{^t_%?u>8s*9&>>l)hqhdXT(}EuG%2*G9=Me1+ z_>fn9Ux2*Pc6~v(KIj4OH_GWDyb<((oKkjr2wVQsw+rM5v(rO3Am{-(!tC@A?hAUr zSB!Fc2w(HR6lwB0gvFACtr-2+1aAgsA{u4c5{3r zT~`ozn$)sj^6#z@1oH3F8J;|Oz|^wf5B$SsD{zC5h@aSozyqf2hrsse`ICJ8KK39f zYUu|}p?J)kY)_9u0eOgYgGJ!sQS^Z0|Ako;fUCR>)w-*}<2_XXF7i|>u)&@Op>kbzo`dH> zx6}wc5UL`W=Rv24zyqNwf_WZviU>Rqsv?-wzf(k5ezBi>;D$zt-o!S9oq`_lm{<>i zhfbM&;D^3w0r-RP_v0qEA@FRfeFpQsL8=4tw!sYp;bE&#^nfdcmkblz5O~xTJs?lI z+ANp{T~Pz_nnKmU-?l&MDqU$WBUJNnyuUr+YGrpCo*QxCSB(=x18)DzWWjWG$_T$T zQtNxx@S=zVFM9y1T>v&57}bYxvXNTfKMcPUaUPHM_0<|2d{9&$!bwJIeNP&GGvdG> z7$@TeZayZe58)^ywZ2(~pN}~30^_7U;AV$L^&ymv)cPJX{943;KQvD20}eerst3z9wuDlS51x z9h2itm=%)hdj7=+&tIwtj-SQ+%LksIR1tjoxyCTO(BwO!VPuL?HZ7MKIBaQ$!&AP(?7&hf_qTX5-v_RMKay>|(<=MjZGq<77#I z?3F!giopG%E%Iu^cSaoeA>*Vr;8*-kS_BR@O8fR}!)Hev_(ET_0G#WoB5*-e68xc8 zD*(w)%cy{Po6nlR4)eC3;bS5We4=qOQs8psq^Pt2{FYHV(lLfljX3amzGwmXgr|zY zm!p#4_qtAcvQrJk1|eb1K#YZ zBJdwk$qmORHP_iy=MB7raZ(%bcuy69XGbN$mw2@TkhHUm3b^>JFsi<1CwQn`MJ=0u zE|PyH9?{;CYMyJciIiMyu&;#}LTy0^V&Q^N1Pecp($V0qm3IM)Hqo|8d*vLiCnZKm?%cns`)E6qE=1fSk$@;Rfsx7 z4M?I``vzt|7d0T;xvGKRvaMazfNbWf24*i8HQ*Yy^QszKa^8l!^FLUH0`N>v6@l$W zX>IJvS3E<>;v$26o`os^*4M@IB)xg9l+NgypCD(p4X|$hRmAk+&2`}Zq9Fve1I3zJLB(;F#yF?4f=?SfjoEHf%<-laT zr08vLCw-e`S5@O|#gE=e{!fe-c(SL8J>E_Jm&B8n1e14?27m;Gss<+16Ez@_o~nTf z^h6CvoTqAF(m|pIB+H{}VA3+81|%z^YGBebq6Q=@qiW#&Ekh$}z-q$G)&r8s)2gNz zz9Ztm_ZcTk03?OdqoxGh=fF_g6^3t*IPm?(No~L{k7kWaz&fL}Z$}$GGvdJK`=SNl z6P_voUye$G-}7n(AhD&43YZsWzHv+#=~fm>?iPia;9>|ff#-Uv1e_F=1mED*3P7Sk z=^L=;_|T8xhWC#+@FB*@i~~7%DzyQ7O$fCOHT?6410Qaj)CQdHsS@z1sO0)*BsFhi zS6x%^cE(95~ z6>5S(LO-E^FZ@2tB=}9^WSl@kKPd@Z`Y5nO6qpy@5!30YIxN(i>qEX0=Vp6fmh@LT zQeDVbsxIU!RTuJ=@lawS0wXdfNKmtV3 z0umo;{a^w_Q3Dbmsv4L8QPhBOTu8*XW|VUw;`?>Pk%tLUU9if@j1|%}mqF_QZQ3JLv2zC#y7$<5#A~UTGOlT%*Kq50$0~4Bw z8gSHWq0wxVRw7^{TGQIP3)6_rqy-?MnHB{Tn~55b&`j099EcS)!nDopb)>8eaCc9Y zh}?+6v@%Y(9@EWXR&BtdGom#u+FeXWn524O;v}gKNSLH*VB#cE0}>{w8kjgq)PRIZ zszyfa-4Ag;1t9O)q$Ke8@O}+A)l((l9Y$&W-Nj!A`8R0=ATQaZ&AgDTyZDP>ON!Q{ z{}q$LjT{}!^h(2>5eL4w-+E(@Ll_&vIZ|8MtQ% zb%3jRY8Y@=qoi;1$_V=!snvnU__75c;gTzhaM>Ti>VS!-oZ^!gBntOj7!<+lRuaxB zB7DqizS;gY-;_&2jo=x^xf&6OxO9Br8XtW%6MgYbYgGf2cysk3kcAU+wttt%u}v)v zo-irtp)4?Px>2qy0uh_&0eKy%)q&sf)fIrF?Pa8t1oF<(wZO~DW&cP|3cxl`wE{0R z$`wVp%1G@A?>tww*PU{&0eJ%|J?Sp8%)hMTjFe&H(c{Xr*2s|9<3W0a@N##~xi&3sD!s$T|$lGP7hwyOF1HKj4hrknv z_65AxOg~=Wp+>nj5N-~7zz1SIgbnWV^#P-|-m}XHzX*Cjo`zhz2t2=NpTRt>h~mUH zgkko$B4m3R;ZP&x&Ij^X;|e1@78fRo&6ADOL|E(9WPIA6^ka@wtmZ+-DOU5S;}olT z*l~(^k2^g2@QmXW5qQYa!GNE5jRh*)+mgbeyPX{&jcu+hznBK*Pr$rpN(>R$)Ag9H8)U*JHj|sI+ zG<v;ch2Q!T(}qLSc+UabJ+=|V;d zyx^=bsu_j}`bBN7QAG4Y0g2kx02f=>-rK*YZsANE$Ka&oQ2SpZdZB>Cj%p0K}p`Gf13FD+XA~j+s zRRjOc$590!p@ftK_OfU}OLi9-uv1G>ARDz71+$5Y8nD6drv)HesAvJ%LA5gQ%vX{L z5jEfwMyXnQlM}USwm4C%W`h&8j)h7457Dr0A3pVAS4*``E|x2o(? zss=v#bw3|KHXl_3v-?PGKsFy$t8Uk6Vb@^;(4tH7|KBqYs5*Zzd|kwWZ#GUQ63FS^ z+L|M3z{3v>H^N1RZ;m+d-Ns3Ez%Ly}(IaZWTY0X3U#0Ke|3CLmjZjuo7@Ej)7+gOD4`T>lQywgBEOYzx5gUhRk)aJ%Q^^GAlS z4n=`?da4PCN7oL6WA8rYtfZs(Z`A|iq}3)`%}bBAtLn8Gu0-4v!?-MB58T%tDOHchM;;GVk4He9ta9MPs&u$(`$wk&5XY<4fpNUr74WwH ziKqbNVM&XEk25tbinGS`DhI}?YFTjWf?%RxysGMfuZi^1fA31$NWVeRvbbFwt8(dw z1?9T)sJKzp1LH=uT`+!B^}zU1)x&`jmMgb3p0N};i>nRa9&zB=#)?aM8aE}+fp{tY2CB{hc#YsKfK8ri29my!%7CN1Rsl%zMn(_3B4`0|K%xc2 z|7gc>GOtzXWN;2{-VpE(S|OOb-YFswNU0*2+ukW6aNnyUnET!-B2*Lhs>8>+_g@Q3@(Y&|T8~DnW`qxf_*$zeXky`(Jv#-4fP)#t#Cz==4R*<3} z{7m;Bci>q^i-URYk=dD^`S^m=`E+e1{q=>UC6f0o(NhwbguQ6qSX)8j8A_W6ld~7i zOKN=vpT{U+r`J}HF0~}SmIsr4Pc)IPi*oT`67Pv7Qv6T`=HV>SMB*1o!d_aN`F)bG z(`x-A9M5gS%J`9fdQD;x!cMBKAl)>@vy*EpNRJz5kO{785!6fjR#)+m_ zFA~R=v`#SZeG*Ni&gd-=n72WqDfccC;dW9UiGW*JxlfQbj>2y+Z+k@ZrrHWp{L4Eq z0ehl}M97}BghbGu=pub73gN-LeM!nA#lb$9EK8z^#9zG-_S)JC5?`Pe_PW{%65mb~ z_IlY*x{`J0ONqkXP+LKY|9Co>pg}aRs?CHD!pbg16hQ*5qzS`iZeR zTi~7##hOTK8>^b&>p!B2#CL+EeenTE{CZQ^Kh;){Hh&~(OKSz6VqBt$^p{8z%*TWh zO(cHlsda+)o8!kMbAt41V^tHp%44x6(niLrCis@1d1Y+{>48WS-17-vr)VOrZLHP_ zp863@q(>r6aIYtQowA-t69X$PAzfpvwgle(DPLY@1ZnTNo|W=Q#~Q2U!K=>mno=H# zL!GiBQXYxpox)BPUvEF_xjg!L54eXN_DnR9;$xv;j)x|iNXJEoMZwR8I%TIp;wY(( z3Cvm2q)sG$=PRsOE)u`$O>~j?wNavrbntV@Txnb2hmA|hBgH=l29qpFG?8w4-p~K- z61$o7USRL4tswPzA+!(Xdsk9xS8WApOr#0E&bUMqDgIRynAg&x`4`#!?fo+ErG@RR ztswDgTG-oaD@fz4jLsC8_ti~8FzpkVFKZ<&A@OZ3VP&q7UVb^W z1m4tMY>4Kaviq4dDzLKtNLL0{bdh*PA~npASuve|*j4)qUglLl)3Vk`@%aHTuUMo` z(L`#p@>(bOj8Lca35oA&NqOl%5?{v>_U_sW(pCQqvjXP(ScxW5?Sh~QCNU|R(moQY zNn!t7oB8csQY)#-8=_jlj~FMKGN(wSCv^N^(i5V2Z>>*O{J`EEB`qOwY(m&u<>}RQ zc(s(Yh4k&${94JlkT?>dJpl7lJt;340VJ{^!v0O-N_&IE32!YA=0|y=`A}_z1K-EI z;oBD$>2hPWJeaQ{OZf+6uX{5ox4B(a6U_IkMDxMg3ZJmz=X|OO<{)`eClW`>RTIoN zlao4;e)Cqa6fobt5=|Kq5@*em@<{v|Flir&-vuVRNc=KT*!ye!?*y;39|a~gAUz!Y zR1nO!v65Pm_#vT=70k~DlRA<3amTyQ4J4^0LV>xJ}JpgltMl|)FSe%sS5Wlcu)kyc)|GM&q zIoh9;N8%G(!ah}7LE@Z_uybVxu!H}6XDg`ziQfQdTVT%iB$`M~_T4Sj1oNv+(Uet1 z;vA4_g84fiqWNfT1&MEK3HyY2D*I6%);T)%wBYOJjXF@}{Z} zCO;bM!;vRdeK1+lSRamTsp^BtmB#vTFha;D%`e1UFu|6EROVtOHxs3JU z$Y82InEYj|4@VwT^}%EtV|_TXj;aqP=NRk5k$Y5qFgeCpAC6q3>VwHN#`EjL8?BO3}mbiM%heK_)wst+a`8SBH5 zl~jE&dB#{Dj(nr)gUL3=`fy|&RUb?qG1iA8pQ!p^vWc-i99c!x2b24Y_2I|?sy>+f zU91mB9#8ebWbtBsII?-F4<>6D>%)<~Q++VGyI3EN9G>cf$&Q`d~6-u|6D`GSvr@5sUTV$c(8zm|Rz^4@b^R z^}%GkVtqI=U#br#?-lFAk^fSCFxjtIAC4@T>VwH(#rkk$vQ!^T9xK*|BcG-EU@}y( zJ{*}U)d!QOiuK{hSE)XjY*nleN7hR9!Q`Q0eK_(_st+cY6zjv0Q&N2}8Kqbsj?9wk zgUKMp`fy~DR3A(pDb|N0pQQR=@f9Qh;F2b24W_2I|?sXmwtP^=F}CP?+c%)=hQGGCZo>(7_e2?mb$>7BLaAa~+A50!6)`ugXqxxX7F0now*%#FZ zlVyqZ;mEeAKA5aZtPe+aMfJhtR$_fPaxAJ3Cc_fz!;xuGeK2{JSRamji|T{Pw#52y zWL;DrOco^8ha(%J`e1S)u|6C*5!DBi5sCHT$c(5ym<&j)4@V|M^}%F3VtqI=AF2-~ z?-A?6k^fMAFxih-AC4@D>VwHud_=#S`~|s*SRXDgUqOB$)`ug{p#1@pWr+3R$Tp}x zm|R1w4@b^H^}%EhV*Mo@O<&p^f@CE28(dZPKs3M9SnV0DrXkgy(Ry~<3i*TRjMgpH zp3%C+pV3-vQj(XFe)it3g0xv+m)|b$7wg=4U_6BNMv=S2N%^xd;~&%h0+tM&}s&UMwEf%{XPKLa=AR^Qh>>ncd(q-0z_s;eN8mD2kIOg2h1 z52>s6WZcZUYEQ=9TUYJLxGUXlr3KFO3gx#+`^TQTl|5{(|*}5m{t36xy zWPRqRG1Ags>MQ(EhBJ1;&Zw^-@l^z2pQ*1PksT9uUVR0L{Fu%Qn7o*1-c(;fA~U9% zU{2nN<}LO9w~w5>6L!*|ymNTB4$3=+_u!zsb9gTfs`eaS|3P`@@b(?-&*5=iU;6c0 zeFcg0c*6d(KJRqi@`JlQoj27^>`D2tbrmFXdBPr7SM8a-a$Vk;y_f6#F9FEz=^B8^ z>Pbt_*H@6p>!~J~Q+lE~zux~`iBo#Q-cX-+W^d@Ayfb_I4$3>Tcl4mVGka$Y@@Mwe zx!-%iO$Swwt_*CyK^3Ge9`L$#gDOaz^OOE=Jt*(g-xIRy*=awrl{yPxvXoN(k-7>J zc}mp;bIwmR=hRh@IOiwqrFH()AAi6>*yZahNMtyL?NMLtS-{1ED&1u|`Si5Zxng|< ziH}eVyK=q%BsCdOVS7qU^=LAmczx$T{QCC6YRH2lAsxI%0;VOfw zJ!81hAb-a2{&4be#X%J$vZ&Hl&q39mJluGYKY4gjIFGpepb8Qv5T(||b$RCz>t%nli{OO*1B^%W$(hAwRH z`U(=K6@^``-k)9M&yxtdrR;>yCarLWQP}?V6(q8~!md$YK_cI);{ucC70pfSD@bH| zRTIn^M$z1?-v1bsPp}KSTtfxvrf{Nhg@(Lyj=yTC_MGE{hHB3_p4m|8E=$bEM5U)s z53V3_-ci`+2IrlAykT(O>BoBpS9|(#-eCWIQoh|IZCyLKg2X9EVXqnNze~?4NMToQ z$U76cVMDcNBDZa*_DtlUhP*S8%QRG~$zDrOdo)zK%Ui!4PEYR8P(j+pPCrWd?HVdb zM+CM(MrzXKfqi*!1&Q3Z)G&W=wWligXvjNNd45CQsmi?@@=jHrHMrVSm46&u?WxKu z2UmNla<2w|s`CDD*7BT&3KFL)WmYCO__LNxcB)d?>l-RaWZ#9I+EDEY%xfDe-DTl9 zb18NHv?1>V=9s~GCopeps8o}yms-aSuJ#1x%8hv^FmGw7=dpNE6 zUSkD`cL}2Vc4M_?I43uDdxmp_o$Hi3A8PFO4Ch@z^Rh<&2O4;HpgRtDh@IAyI`40+ zAn_(a*!vnQNW4qX@?g$#isoC5{$wX#78Z7{%+$YLE`;~&LKEDF}hb{-igslW2L)yBhiV`3mPjqCq_?d?DoVcf4)_ET5hZ$ z@wPE)tGnYbVuoJH}7ot(3{k{(vS+@dgJV=u)T)lokab6 zW3?wyYliqwPILBDYJF=+?n%@kc_&eq9a5?0t&r4OJH&r;j(0%1GGN~Qh~~kK)t*GX zVMyLd)C-5?okSfsB=02Zm?4>ysM{TuSi=aru28c~=RY=a@0v(fJTo&<=}|KrINzv9 zo9~BIKJ?n@H&(R8Cp+|$Bz&A=)_F-W<<__-!JN=iF8yms<>(;2=}|KbNHRs$vOOC{ zC;8Bcs-^#ZH#IZMiq3Ky^~yHdlx?6XUD+B|*+yZS`^`(H8Hx|7$mb?FIyTYId^63y z5-6Iz#Lswhy4g*wIX)02Unv28l0^vL)j6UD{5#*V0x)k8x|{KR4o%kmNV`VX#bLv7 z_QPngMIdJmBW=EKGuzyaXs2g}w&H0RZ8jL&A`SB^YPA$HxnyaT>&|B5d7x{2b|*H_ zYUbt_HaE332lWCoUuL0nnThF9(?qLbLNXTmZL9b@Ve+w1D2!Mvl&RwO6{?Rd&A0s$ zHPe$n1d6#k;!fN|Gb!-SK+#`jNvcmT;Pu9wv^P0gC%YOp`%zQwYTisYm=LDw{Ee=e(UX^P*_;VEOozb^W?DGlb&<#Sp>- zW$ur4tm{ll)$2hIdidrFKt81@>j7LRXaSdQAzQ~J26%{FBdg;i#@&;=jRN`MN2JXc zAU9jGjndZ7tSy-n;I*D=>20>zH`pjWp;?)L^ic(&=mD#fW47rYsM*p5WNc_s!)#*9P?)>eA0x%4h2pzf@A;)}<}lW7 zc0^0GIA68=AMr8G9HY7|Pz>Q%KWohlAxu!lmcMCTXHu$OBzka}??C~`-`J4#0L}{?d(sMIt(}3>2aa?~(X@f5`=AC+Czt~@aGGSKV&K#sMwl`19c*MxVKy;v zDDDBVQ$~uR3q`Yc`jIwsO7NH7B$_dWuLRTO)XgkAw%c3%GR4J^H|89*?tYWUjpT zf9q+cdN`1uTSeOZUB=5_^V(@QNn3|oTQW^R{-&@Djlb6VWACa<>63z@Md#>=Q1pP` zo(T1EJy7GO3(SBTceeH>Y7gVf825K=T*Ja#V%$*JzgRNk#K?u><{c1%V^(vXU+89L zW7}ZK{Dkgizf{fHAv80DFhLnh-ov`iqs~u;G_-Y;wIy=`ywg*~1?MIeEVipy zA3fpJlTb9rccOD_G~JxqDD5#^wNYwkP-3Ih9tM-K(Os;^#V~Q$C=_Na*2kc*RiQXo zcD@}R6N+q`zS{G6p%)`pFDbJ^A$Dr@jXT;3!WOfropl z09?9N8!#$a{_oi}GBJ*sK4iyDCAI}VZd9br$HI?avO&@o>2&vWHN)&~mgUeKNs5L{ ziz9hV|48GK+fJeJ$xa{ z;7B|e8?PhNR^-U+G!A1%PqUeIdg=EbjwI7Sve%Kk{NtUGBhxXhBh!yUj!b)%tx^WF zoaTV!ZD)3VnzCcb+}1s?;wbf=-fo-e94jSS z97F92`wVALw+sG&L#3Pe`>dH!u^duYdXCny(QIs2x%q)#blYb>ulMs=0N!GhGYf>f zf*vsUwqfR7;ZNxvVFg^B|FIil*Iy(qWFNamK9S@9=le+-4!p>yNc#qR2Yu_3-$m2b zN33Z47te$8+X{X+;Z}&*VCdpOfuFf`WaoAm)6AP=*T>JpgAPp@3?4K)KTX+gXFTY7 zR@=9N`QbsKaI)g5uoXP1P^{I|hZ8#%il4oF+1qV1E4f>s=r1lq3Uce89$YU&;Qkb? zw7cBOx<16N;x2*zEr#CDro|Z%!j^un3c%0J&_8#pp7ztkd}i7;a%_BWYxLb%*l-}9 z-HNp7`Lj!QgR~V{M_0Ku>jt~ZIe}zXIVX_pD(3`}U1b7E{z`x>Z&x`dknAcGNb*g4 zr^yfC_^F#Cx!?GumLqd^#IABq)Yw(di5k1g>6paT$({GQO{61p99&m9Cq(Qj=Y)t| z<(v?)EAyvtS)M|R81oRP*QH@2wt*qY(_q#BGEVPAtNH9;Y&bnA{G#|9ECc5! z6i)`rc43mu{Mz-%K%H-JTA=s~6MJ}DZe|E~28zdth4=aD`EvBGg^`4#l zZ_%#ORgCC^`+Y%vLV4^1p2D$gHOEsJ*sMS?wU|VXGrqv4bdp`g83V5}${7*@3oClS z|LWWF2%9Z8NQ6}$V^$0QQ+MiP`y}If&90Ff=I4!L>`y7k(?9S?qay9=?b-B}B|rVs z)<>*ki!X%J&h^i%xibW2gP}|83gjn7@BAWkvY*?4&hi z$CB~wS6OX01)IdTL*f3#ePKZOc%j&WpA0^f-=`lCd?+7HT;nNj?PmJ>pf~wu`pZP; zILzCvpEK<$ju7}?Y3fW&8*OYCDGLXZ|273-Gc zZV$K7jJ2z{9pDK@xrIewPDKy+-*WG)YxC~LgTM;Nc!2-^cB-klZtuhe-ecFutMVC< zyX}b{(*9Y^(6=z4x21A!f7Ra|%oF2Dz^d9Tq@xajz z-C6#RIoqiz>%g&QC!;C5{u#%5g4K3bur(Yj6uws+7>0p^6^a}7YxcPuq4-wLt$||M zj`eoiOn+G^Daf|@M)0BxfelZz(ka(JSl2JNt9TROe~VSGZqwqd6@dwo@c@~t|2?bT z|Hp~XYqM+Q#rPc78V@BZ;`4xf6)Vyv&Kb7kbE&iyS;zEpCF}F1=f$1V^Wx6wd2#3T zyts3EUfem|$DMp6Ocr>0nSt|_FGmuLM!sx%UNkv9FPfb0qshpZP0#aX(|zDL(k9Zi zo|9djo)06hTILKCA14l5HApUK-29C@IYc7FfcC9o1ZCk5(r(jq3 zHz-`7xE5~&W(-2{B(Us*SYI=XbVH!%+%LV2Hgm7`v#)zeU3}W>wm>liW;w^d4YjWC zVOQ}7z!swt%P@fn6g}V<(9%mbd9LdSOrvxi_`hrXr?w^*b%|XgC&qVGx1WL04F~RQ zRHS{d-J!o)vdg2bj~K$}&%ovJOz0?{(07T`fc$+TrSO%n7sxuYt1yfO zIqoxbq2p6lguBenc~iEB8F$%Ywf)krVr95XC_JkAGczFErckW^lhd)>WHJ-RZUHFVmOf8xOO7w%Ju22k<{@>a{iuXV(b)aV_cP|AeWtFm8~aa%k|K zmc$N5*fsKZ{LQhp+c1^kK>qYtq}^_>jQ?m?2_Ms82yI0s(@`Fh^^P5R0bxg8K-iHN z5O$RLo_ORPJIefdxJ9=l!;#tSD07EkGLB^6(JTCpym+$1$CHtN?C^QaD0J+|3mrT1 zLdTB0(6OV;?D7`Y^^+I#1T~IK-_4H9F`ACNc(Nlep6tjZB3a1qnbBxG3C57bL3U_7 z$z)GOiU@930xvJINH<%?35(*zG?g|^iQ3{0#oHq^QZRUIO^}%Oi6IYr|NI@)N z4R7_$4B?SLF$B^RIX<(Wb$y^+#Tx;)G0LqC0uv~Dz%Ss9a%*t79c2V2NV*RE|MyN! zja%Nd6a4AO#2}BcYve-v+>rd&26hz}3jBsqk#^4y6YW*(n&WV3>mzp5`!jI3{8M;T`IF!mi?chNs@sJ$&YZFr{=^Ivn5X{<>;0MM^?TpuWVMMZgZ`n2S8c;YExnWrbyoXTu@ppsQ;1A{g z(BBQs{FU6*g4a0U=A`A9>?(C-htSLrZt@0`Ih^;Qb-kBOl6V8)Dn_{(M_>X)5BQne z8iPI554HgOwNb8*2+V}^5%>i*(*ea~DZhGTa;>cySlQk1H5UZ#NyGdlan<7|$NXh> z<c3NFFwB`F=^&Hl$n>l^GToC=HUUh;^4i978+|P^ zzbG}*0gJF&0&4O>v-;v%y^idX*RCf znkDPJdt%a~WolMfT6i;z#q2W?c`msBiY~B+LAi$kS6!HBhyB~Br-wzCw9 zWzzz-8x?8qc2-isv33=0-~~oS+EXt~wC}O2Xs4}}o;_KW^bYi#iXhGj+`No^Cd?oqcTkR@Z{5jD( z7x;pY7z*Ed^S*f+81(1*;NXrXW%g#%`3^@=XqNv~GQr}4c>6-rFZg8`4x~4cHWU35Khc@DFSPYZrVDe?vCu(!quggPH!QQJ z0>I3d{hhLOS0odVosdi>U?p+Vr=y&g^X0$e5{cbzk9d;95pS+O+k3o12`YakRxm zNT-3_&j~&G_l8CrYPn#BtACn_+8LCXZFVpjv&AN#HrtHM7HXBUH%QF2|Jk1655YhB zf~WY4@5=>)Jk;R1f#NTXpZKybc)7tp1qxq(w0A`rpZ}tDeYsy#Q31G{r%H6akMDYk zuG3%H`RV7;zMlo)Z#-23PViI#$o(mGWxJkvYF=zz|FZQnGDJFeyPwzLz%HXAZQ2^+ zrzzvHX^XiLvjr~oG|^mGl_d_1Hq>mv3|Ig50pny)Vz$&C29q&cY;qm5&B$z__G-f% znlaZ_zxK^+<3D`fYn^KF_kmjW#pHiix2t%_EnZ5fM!O2tV({2NU1V@tpxD*9DRaE- zhBlf;f5#Por+TV5)J73TQ>0V$L_U}f+}HP@0Q{w=ia`1+Mga_6FJ`-*39PrV{_Sel z$Tq3)I^XPYAZ>$$KQu0f@qu5!r3mvd42XeOzdALxDy)t?gU^>|@Lt)eXv)ri=6>d8 z9bz|abU#C_cbvbUxsPXr`l4MYpm z{sAyFEjGUhqRX&``>+- zSO7j}lxrCw%uxZz963E^i79bpj%R2u=Xi$pGSkOgx#BrapgnV{A-w*JjI|6)!YhNSy1n8}oTwq5U8W|C=>05dyXnR}KS@>_Oe zM)xe#*yH^@%e}fF+_T)PSgzbb%;BhT&vIj~`cGe1+H!Jky{)WML%i200Hfs{+eWvd zTWV|@9qZvAEDFFCjS>qU+lKJfpa*13PA@$wM=~zFjU#hzsj+Q2x764+JP`}!il-;W zk?DPPSDTW3!n%ALz2PSNo!ukYl-wBD$@bpwWkT3< zt%8euMFrsHMu{OUEF(-0dcbIX7nZrjqkC#$ncMer>ta%)39tBjy8vVePA})SSeUod zEG#qJ=(bpx*;KBz0o-NR$fjxj1K*?JKzbBu(^`X{+{~szTh-4Hi|9s9e`x%(oDLRK zw+b**Bv!mow~BOsWUI(dLdJ@D0r!oQ5+9y-gaI919J<%|+4pgBu7US)yfjRX23(j_ z{qd(2$e-g@lS2fyf;@XVGW$MGTF<_Z6Egj3)fG>BhV%&aoqT$L%B9Dr94|&0o^t6| zkjkY8ryMUJ8JlwHp(&RhnJb%m(WuD$-uxjt6aG*PQqH^lZ5GOj1<9y*$+fWDUgswU^V2;K=k{ zNv_43@ft-i$2sn#v4uM zh5V7Jes=dle%8s!%s**YF*sfzLjCC!%(I!kPw|a6&oDSEP&Y413asNne2!$W$JodmdHM%Qv2fB(>SQl?cX3qbC^Pb0%iq=J!PSYdho77Rkoj_Y=^1<9 zW@>d?Mp z*dnkPqzhOHrd?vd>~v>hK<>=j!_so|LcM!xGC^{8afdDrcj_u{C;z*?T}5k6Gjc3n zDCYHGn_r=>F?d^`UN!iBptiOf^)I~j+xY8{&CR4dKR^_JQSeBM(9;H#c$1=jd}7J%H_J!)FB zU2jcyeIx7NHg=6}jJvJ5$9=QIfpjv`rmahSk1`1m+G1|RLjsq2nrJSp$`Xf08)}qb zhFe?H){Aj6C^1NC4}-}Vn?-bNJ6E(fl%p%o@@PFWLKGd;1J)>*1l$=p`Wev^E}_r0qd=x7(x$C*{HB(%QQBf|s-C7#HZ+=3 z8wE35wNb{&pwwyFAi`iWHi`i*3KNHoLjC1*Z=<7a?JL1)_IWG$-vjL`cC~>y%R+FP zSDLx58*H?}Am*E6khRwGdcFq*;3!WO$7ecK%=Vy24{q}}P7&DUsRD48r;5O*JyigP zu4kUZ*R=j^YS+lb=*caF-Y2CZp0vgpT;!NgDOT#vudMYWI?X0B47}#73cB9Pe$E4INt*yTV*&1hXaf9TE2W(+m;@NWmA(sIe!Z zFlr(Lp&m3l=b1yOW9&(Is$GRjd)r5CG;i2dRt;F^M^ns>rbyS<_FXRmH}F&e*w0f% z;MSfh0K+sCv(r$_4lrZyuh=MRtm}~l)893Gv%`V(JJP24vx9be=4gxQ`Xn<)b79e! zX0-G`?H$YvsJ%0E#wqqrgJFCbd&ijH4s(gUL(Q1r?H!|D7>t`7&w|&z)&{oevQ>*g zerPj{2Nwz_ers^%>B;}lI<=1PK>_%4PnG6cXF{h+yJvb(%J!f{4-WG^C;*S~R0%lV zQw1QmY|hV)R=583vuk8^$5`i1^RdZrATt(e)9+<{^BJE^Tg;8vDDcymru3?$n^S|N zJ%+2NgBd4-5`)YRCS#CT+srU=7$j8f8Q#?Jd1M2{u2!-P63_5LkyN_S=iD+L@*!*P zHM`0j0=Mzam3rG-1Ck)J@butT?|lovJ3LhaKH#YWFm$~{u0C|VMAu0^Ud$lFM=Ox8Y&fID8?kT+H(HFIrKqryzG|6p|9(N=LL(FgN# z=Zqn|mu4;W-Ewve{d309KW7Zt_tLML!C_ST{x-V~`R{78V;Gn-hJiW#9hlSKfjRxn z{`Q*wZu$Gf?!{+Jo|n9`x}cg~S%BXMNf(jA#Lbw{Rc{bifMfBMNS z09Q5_B)@q`mzrzZ^Ft}%HojD51AH=dE?|kjlSYw+bFXC)m^XPXi-qL9mi?x!4F)C2 zSob?=>R!>?N9MI`ANwy_>h85{du{S^^hvv_0evH(*0ZZnEt@6O-geC~vus7fsq?$b zB&B5`M)pbIL3S0YW3_}@{mWj99(=?1U^uYeQ^gYuP6*Vm`XzN-Vppl2uJ7x+J{&mS zQ^f&wNx{ACDg`$llu%pQRj9NXWyjo<9Zhp~G);_VYv1+eY(JZ_{cO(mGh?OcPN`>R zC64kd(Y$x>WO%pPRboIE=RjK#q0+NijLW>VSZc9qIjuvKTmg#uy_ zTK|LnlaepmRn)#UAfX-^m|TV0Y0CtjVOOCxFcV^_gaTq+T7TBOn%m9NW_XKho@a3N zdf(*ggA@1zyGs2_vdd?CC92xqzYH(1#Z?Z>iuSBoag|!XzCW^os3w>ZB$`O~Y#-YB zqS-{ketDXK!9|sTxECqNC>VlJ%o;-w zicw(qLZxSq(QME&+!|m;C;`pHHpYlQb|eDMS#1ftmTjF*5tm)D=}<*5^WhYk5uCOv zg7Mx?5rN53MKC_yDI(zDRq-x!_IP@yh=AKyMKJ!~DI%~Ls3MqM!6_oJMW`Yxhx1o% zE%W+Y+SL_CU`tR%FnfbjM8FnQ5o2I?aEb_Q6{-kk&v1$eY#^!#W+!oq2y82=2;RVM zS*M7AajGKLxt#4CP7&ctMyev1t;i`N5ca4dm<`G)BCuPjBA9KBc1 zBHS1$g4y+)A_7~W)(GaFbc##5D=%9%+?C*iZG#lo1ms4Q(2v{njFm%4Fn4Q@nie28 zsrHO}l>1S+?rz8N-f0zq&wnMf3chr$gp>XP7aFB4fM>1k)qrpQU#Jbt-7G@|=H1u} zEOgTrz^_;gCmjKf|5|7P+-aQ55^!;(2Hs+0`db7}@l*>C4gNo&x~EFO zex510&eB0B5)T^m4L0DDgqDpR0(*Rr;5M}JXHc->!~8} z4o{VU4|u8we8y8H;Cr4b0$19KVV8g#da4NQ@2L{-yPhfnf8?nW@MoSX0uS|62{_JE zMc{>=Dgiq@RRrGVsS@xhPZfdhd8!1wY3pRzYGB|yjT4s(e9BWrU~$_}5)iLKx{Akf23M0*m%|tR=yd{UdV` zc&(>efSsNy0`K-z3-IU$%&Z7J)l)6Ni#=5Yc6h1<*yX7r@DWe70H5V}Dgq}PrAq`}6x4uU84~Oh ze4KHz;J|iIwE(Ahst6=J)HatC9TNVj4wz6-!paH$neC>PLeD!G?6*=B`w{4^ z`+uR~?!vVhQMg8IHpNnHI=WegiP4l>+IT8&w>xn2(7%%nuen9wN`@bcIG&H!%ooqpFza1@UiNM_vk-bXmkLHoR)&lDd1Y!d+>*d5=|iAf9nlZ$EpaIU;(r z;co@zOK)A4Bs9loW5m` zxrff!EgzvjndBDg!G3`*>>D9tIDztJVhojaMrGJ3ZA3 zoE0S#z$6u9N`N=|{6Y)xIis{q@atZ!09<_?22cWi(oO2RRX>rm1JMNJlbEuQ;ZX<1d=?F=>UFx-LO*NZH<$Xz%iaG0gsDHf`9AP3cwTl z`dI_!C2IOwQbuPIyroan3_Hr;_(%=>N3YfjBzDl+z+`J>@FZyoCsb{&g%M}~M{Vqf1tiy_wSfsvq)}jA-iMciT9g-ruh`2AHwMEi_oLMUa2HRNfD??;lIfJP za%7a*illQu5=^QFp5Ze~EkH6%Qj)~d2|mr!0wkLxTEHuU7LaU`XaQ#iEg;z>(E|Q6 zXaUJ4i575OpNDAyl1&mV;NYMIB%35!z#j)KAlW3*0v;Q*fMkzlqNd!ghWCiL-xyvLabUuAi9Ue@>oN!+FE>Ps z5T4AFHVQ8I)J`jq)RR;OEC($hsVC6_PV!m>AgL$m1^J~%gBFmal6=t$$YX`}75vL> znA;L?iczXI%kVQ12j=NSdJD`8r}vK@PIv&hIO4!0PNX^@c@ymkczvHkDFAtFk&?g; z)6$aZS39D{p#&mTRRi;iMy7XT3uMW{s2Z3wjMN64W9q5~zO2E|FYqQ$708*)3ls?w zQXpCxxSvlklz>yCOaz!zgLDnJk;`_xI0*rO?|7;N+-Li6?}7I> zPD%o=_EZb7yQeLl7QPWZEr16YC$$3)_S8sVP4r9w{*rN063F{)_v#IyAu07KHE5{4fu?wioo}xlHf0e=Re>g zqr@oN+Yor3)6s)(^G|>yfzNuX0DRw5B_I!lvdX;b{gpij3I*IYdL#sY$2b`%@UNa4 z2^_Lom?H2l#z{$FNT&D`F(*YO!JH0pHz@+ors~w~(UeD2ogy%gt1>K}R>|9lp9k^) zE0qCxj@8P*YpKvo zKI7B^obIWSz?o4=@FQNW0OWnWOb2jLR1(~KO{Sv&+{IHZz&{(MGX#FXs}+DD5zq=e zE=mM|&-YLLg$E5j8>xZ+8PtG_J=L_kN!hKO$@N=Q;hU+CZwxwOQ3GiU!qzT|| zo@(kY)xh~Ktqr_|PtcA8a^y?Zz(4kCEx@rxsTw$>ds~6=n~m94WUjBR1YF>$k-*+j z$^%S>M2r%+L&$;vNt$Ta$c+5it2NzikOYZT1`N59B9NSk*bH#IrA)MbaJzBhJ%Cdp zwONK2MjW{B*YGGsAQ>2K0o)qYfTN94HSl<^)(V^(seu=IwIXn_r$z$T-#EByFlirW z&q(i-?J7TDOQ(QjE_qGydzZwP8Y5=U;*5J(}p<=Z6b({Jo5-35|Ea%B-F z1wG)6Mmar%dx9R2Jd)ExAZ?_50dM5fD{Rm!(0lA^3#DHH3sTPnMYKq7;v;{lG2nFKx)3n32cT$qV zkB6tu3I@I<#3q5b>Qpe`1LDTiB#^6Mk^(+4q*_3(f@vB8xzS~%0KY3@P5`;mrSySU zCMh6Sx+Ddh4yhK9`wePD;HoFkh;1P5NGlllFCo?fZnAU41mcafnBd!!7;uwa1~IGk zjKCwE)N%mClc`Fz{V6vuEC(>RFccH`8y7dRyL&MMAE?E}`N;(hl?2Fbb`t|X**%?_ zWWWQ0>H?1rss(&YP#xg8L3M#RPc2LEcS5WMoC>N9+;}(oss+UDswx2=pQM1?K2eQ; z&kCstAoo&~7I2kISy{QFa(%{ue-){C%L2^^wdHBJnKs>G{R=Qk`U{I65*JUxmCxloFh?h@F0l4cHskGqNIVUk- zKNGv$@gA9n3;f*V;R3!ds7c_bvY6nnhgb_Z_mP9LRVy}uw>fD|4*sxnYF^;YL3M$D z%3^{y+iH-7Vgm86Y03b(*K2u}?^PQ26nAay?Z3u>ai(d-0OrmsFdi!nI3OM?bpsHO zm1O{)>;5Li1a22p3;5WeI>6j{b(KHfJM$xfS2|a%Tm&x81i`#Zrm6zhgu`h9cymyb zz&o?Vz{%Y-3H*k;s?;+;JW*0Hz`flmRds@6yi?UkB9Px!;+E2dk4e)3{KMdmoe%zR z=hQbqoK}`^`S}Cma82P>G7iigB_)T4Dfb-V>G^(mdRjo7JKC%Pam-i-;Fl!t3J_+zME&Fogzz>R@b_dADT!lNvpPu2r z`g-6zFt=hP2K`TWcI1=5{X?q7CjCXey|gUByna;8T>@W@eP{>B7FFc{vT?NJ z*f~!6mQXVs$O}k{2|OmGTEOFjngE^_R13&vRLKLmm2IWqZR&h;3BG7o7V-(;wLwh+ zZwzVz$nI3-2eLc0Jh`RA_R%=*;;?;GR3Ljr69fP5i4?63WV5K4K=yYQlQ*ro!DAda z-R5Zn*`Apgn0;Ec;t^nnrfh+?r+pl7Xm`px0ep;8mIHX#5bFY$1vLpgG^o~w_Jr)^ zR5IY{PmW>$+1*JB$Q2W;<)3#vTA^@3#!v|_|8NDxx=LN zfnNxz7BKDWYX2^YeckQZwV%Lg4>#=aN&c%gJ830>6;4{k!3UH%I5JDe8qaHpz#2{dhc@_hFre_b?KNG&pW^RU)hK+cb<^ayMohcT+2<0t#C zRu>@WGgVvyoYYvpU`)bFkig5rvK#AzvG8Q=%?EQYx{6GIgBZ&Nj4fCR62QzeK`;hf zB}ibmWTpYJ>MA(`oTgZUU``h*K>}D$CI~(_SwBF`rz$Ri#cr`!Thmo-i zh)q(ZM*vg6;)1aSDnSC=`0e2fZ2?iS zRlWqCk-0Cy2ZgV)1w@@zaS5PLEnhGSwGt$Nsx!gDg*k+-`_k+*zixB+A=wDJy@S~hlOyKi_>H=Sp#RMM{VlCjO zg6aT&nZ@LF{IedK$^quGsLBE4VyJePKyHDmDS;2oEFkcslLZ8PK~R&xS7tH6$Anl5 zh`FQz4a6C1-2&$NrNn?3RVKE%J7GusS95+>hm-zmV&K<>SlrHB71Sh#*>yp6fp=ty zfoE?yXm7PG@C8A2f$ww5iUIyeh_!&c=c#%E_k4Kj&l4Q~`Vol(-|3vn0ZjKKCx8b% zGQ|X+=$v8#zZujd@cHf>wiHKVXw>jNjPGao9G4 z+N|+d^ytcxO;u;8t;&auSFIuATzom$vlrN58>c$;N@XFRA4p zh{xH)xH@^KM^z5MdE2Gl1CKc;G2m!s!-My5PE!L@|96=f7{9T~2E;?GegQVw{=Cj= zRk-FcgL3}Re}{*Tod?Dv{KzK8JwfgP8V7!6@+kvxH>=5k2ZvM_$Ynvb2M`amr4RmO#B2et52_1f zi=@PW?2s%m@G}+;`bW(HWY46Sz!!y73&@wmG}wUWxs;_3z9Pj0a#c_r6JoJ(Rz9C5gxmhPE;5A7K$Xz>00jH7_kh^x00?v6n zGoTCPuAQWST%uEp0Y4BCCxPs26%qKYkZJ+BM5j3iqiGjHZr}6{2&t_tu^KJK4{%aif+_>Xr9Qc88V9*8TJ91tH<~3l83O*^Kwt%Mw zH39r^P?Nx`f@*PY!6}5L59ZC_Y7aqxOLQg(9)BV&*8*~jPCWyBgG*IaaC~CKoCI9GJUr>KfpR-J)nf?!IZ|;0sM0eN>70c?GxCj05A(P}zVSV3-(q z^K>Ku+##q*AO{#q4A@ChK+ZHI1w1pPT0m~TRb9pV(0@&GxKg%oABh&V?H%H=unOR* z_)F&b0CVR`_pj!IpY~K*cLIo4-;x94<4_&e=i)dj+vS7boOb!Z?*`Qd{vwMBzAeOB zz(>T!f7y->pOg6qz$-$m1x)^d_{`S7Wc~s0W5XHH0=^`u3E*F|nBe=SyIjDRI;H+R zeIAJg=uY6)PFbGd9YU-Hd|6Nv!1rV^c`5iA z_a9_nse!qIrXdOBBAI3=@R}?p_}`sVOyDMQa?%Ap!YRuWydcC{K>RCOJAl0NYcaVQ zHd8;y;SWhQ1;5@ol^6H}r>cG?@ZVWn@TTsSP+Z{Cf|>xn$tf!___Ppf0dZ?oxe{2M z`8bYpe0}C{0RJjE9JZZ5sN`<`YuSRI?VJh>#2Ha7QUpG?d1@#y?g*_HK->$K1^DtU z22ph{35ZicY6p0sZ@Vof`17$9Zvoko>*F7f@O|{o*&Z9*N_%V|cepfifM;Ye!5>dC zfo#bY6WFvn=RM1+y9jV2%&G-m<-6=kkU-x_69iuz+wlqDRe4-?@@&j4E-ywt-}miR zFP4|fDw4fB*T5_`m@8pb5ecxzHo-l7>&?lV#sH9WH#HZK`(0WofNah!G4RE)QSY)T z-}KQ8p5<)Hn|9zcJ$?J+V@a+JWK*oIDv%fNtZd*7 zObqjK%-R9O&U+hWOqIgnLjvV-9YmWhG)Oxp<{`xYrpAUhF@3BD*| zc7YuDs^x&!Cn+F18A$=BlN6B6jii8^#XhGCWWS>x1@4%nfSfNYE#UK$6p+(pNdZqv zQo#2H)dF4+R0qhZv^5x*6KM4a@UlIavJ*hAfTRS&;Xa``TPH~{rre;E-0J^JCJDx-ljQcp@mYdaSL_E3*Z%#UShYKc6C6HR4}m#_7{n)Z`t~U& zFb38jO)fZbIw4m5Mu-E7L8^o}qOknI7+jLvVz^HzKb`<{Od-jK49B4bClrJDgg9{! zJAXKCzH=xbcJtvrA-)|T_F=>EB>}9tK?;O0S!B|;?Gzsx8fLP5xLKE)d7pu`u==aWAs$e|-14%-Y z*?R(DUf>@{63X8w0Au?NBne^ZiB(AnampZ8y-z5eIkbSBJq!d1UC&X*@Vz(Ra6XKt%h~0L$Pl%V_2k8>Z4OK7(t0W&g zyg~C7({mt62vbw+qTx6;z~e7=r{VDb=imASU*|^$14%->TW>=J`~*K17)TPrtQGsX z;hK>vR;4QK+<`2nE^jjoWC?x6bF&hFzne<%_~AaGnVQPH4WWE?9_|yuL>9ZtaGwxX zve?~*<0XAg7pzQR4i_Z3aJcs0QcaSh225p1YWX9S9}s}2+~}61CIumm3dCws6XLW$ ztkfML4hqC-sU!4mH@>Y@U|y||r23B#=DJCO!#J--Dk07nOcIQBt~7U*vh`C5Y<00C z!|};fP6ot2ak%zsyjZm=#yIA-SdA(|+q+>Zc5Jv$2oqSWawBx`-^mg>DY2u&eL@!` zRxLy5&xzG|A@oo;UX`0hCLvyv5Gz?iSjuA6I)u(jDX6@JFrg)@8WX}87OORb5QeVx z1Q+29Hz3#gE5qIdAOMx<ve8gLlM zmM0kVIG2aROg4EiCUY*2;fzt7KZCG6X9*nV= z%fn$bnmibjF_(wKbToM|#$YaAT7&ts4cUZPV7WXTmYC%Y#wyF@;czFKJQ#Z`mxsgB zGI=m|RxS^Ry=C%XtfE{V4(rI|!PrK*Jlss}C2XKP4LGbH%M*+xl*_|m1DQM+3n-U| z!xA!iFjh=14~I2l@?dP4TpkXa#^k|RG`Tz+mW|1S(Yv`k9QxPf!D!T69uCcF@?f-V zE`M+7T50Y#FPf?Q>CQ#>w)^R;BQteBeR5HJR05ZiwGkNosrr0;bf)g74~@o|9=g-g z1fw&R=Jg|SOLwLkG;=?FZ&8!`>4ZfybwAy>D87||{Ivh@7|F)=4 z=*51(H4Cc0LV$B%5#DYcKE2}*MANS{#Vs=EJ3xT-iulajM8s zqS#lD^ak=lh^vCkceE4i5qZ10h9fpN)JvImaz331I<>_H=O z>6XuNik%pVk8|QS6Z^uECMVicN1B{yOGe^=6t|gDIAx?yh=WnF9~|iu!kH%a{E=|2 zann}pl_PQQ_G&*F6?^qae8UsRo7gXnG`ZmxjD#DGuW(uli~5AHq%5~ZGj+~wGSc6W z^@KZ4X>L9m&bd#xlTPe^j`Rs}1S@v!NF2y=(BYi?xU}AqdGE?{7pGW#LvBZ?- zf2m#FRfyeXa}>U~D-_p1LT$_lY%Ul3-kdlKjM?I4Z^^DE5NU zCI{i8M;aW2D@v14(YGGyZ^#(LB`C>Ni{b+$d>T~jsiS>DncMKB(I&Uyk)z=@pvFT;=EOlKk>$pAb$^vDb{ozmv{fqMM|f)ZCSp?3>2=gdUUJpKsJw(L-FK zmh5q3eL@)YVteUQH732)3ydi*$yFQvw@Tc@mgL)1DtB<=TorrrSf5blYW?15ldJXq zV@{fairta>2MEVa|+|rQj-_osf?rDhqW4g7$y$rE`8tW6v9LDSF-%^$A z0qOPzE@H7u(wq9+#}NA@{pU}=mBIZBu}`f36E3k&(c4|_{KcItcH8t~|G}ASc&tz8 zq{NQsJIo%sAhACm4d*f+=~23C(kFZPD3911)RG<(*R$B~=%WqJ;(8YQ`TD1O#NL=b z+{&j}#r{HS+#S$3q{aR$UF*OhEq2SXCinEb`p14G`^C{d_dD1ci@joWrcUc~(p?R1 zV<`S_M*Dws8)=$lcqD|C#!&f3X+W?|i(<&r$jG#(F-w z#@8qCU+5NNxqbgnHyydjH}lWBnq1ImO*;EySxQl#u>Q@CaS8dvtKablr`t`_sk5^pPsq9kN1s(cYdROwh0MWNmj zg{pmdk_Mn8W|@F#6q$!}>Sb6)>Z!^#%j7{`)vZ(WVwphkt#=s(RGs&)L~(-t>Ue*q zO-Y^={nDm2j*XX5+PGKGNfd9kd?iu%++Ma5z1GIz_Rd7%d;46XaJ>CEQTW+5iq}xu zIN2VTDEw_p6UEKIS0)Ni+dC44W9^DW;Z?gOQRtpz{I|LI^_&<4ZF(+^i*`9!ALBj7 zShy#Hm2taM^jHhX8&4Xnz~xB_h{yfj9QarL%b?4@>%W=xMRrF+tHk}F3}S?PTFE$f~?E1MvHR<=a`tZb0{S=lc6v$A>eXJsqp&&tNi zpV4MCQ2wlJCkEb+eE`brI?4y!88Pqcr~+&1b&hdD)TD)#LSSgFN`buz__yQ zjVs&SxU#K{E8Ez(vTcnk+tj$SEseXYdgbk1)-Qin)-!)r);E7v);oVz)<1t%wnP4` zY>)g|*)I9BvVHPrWjmeokilBhxDfHObTymHmZ?bY7IOcgBKacO#lDZMNE+|&Rwu5J zaX48?md#a>Wjj@5*+3OpwoFBqO;V9%TYS#j;!FN3D}(yAV@q7qhrjagjLzC<(2|+D z;AY{vcw2e}AGkR(w#qf#K!Qj3w>ebScdz8b0M~61y5Zd`(FuGhu9D=cBiAS@lDib# z1gJ<3^?84$A~|p8i&+&}`ui%f^!Qa|y?)E6Dm#Hn4hJV^9~H^s_>d=Ml`MOyY@U2{ zm#vgPD;q0+R<>FGtZcgcS=oa5v$7%cXJvcl&&p=apV7KBW&W&e(fnE2u=%sHePbN^ zc$W70v5()M#yCFU4u=nm*ZFJO=YF2RW+|aEud**~B`^EXxU%nzEBnm2vagIQ`^dPm zZ;UJZ#JI9Aj4S)VxU%hyE8E<-yQ+WQFJ(LA&&u}5pOx*BKP%fOe^$0r{;X`T{8`y< z`LnY9@@Hi`=FiIZ%%7F*nm;Ss_v5}cU**5qww(3tkk~)20HUfgX^i4muHU35uS?Mf zLoFbmpq3|@4+hT-9W#NJ;Lf?ESi9*jQIwa$iJ}FM4qY-qIZ=X=T3?$`INR5QX(u~z zsAss0)Ke?e_Vvem?N_B1XI~GsFxG>1y*1jjMk^MUHm&i(L~#fI<9=QxRm~XXe=3Qp zSD{^g7eP|gDz#Zn$G^*KLpy2D3%ob_mfE~4YSRMpF-vtM@H0uOUcm_}$ly>>fp>45 z?CEvx`mYiKemSTP@2y{azk$luM*Nz&1Nd|QRYV}~r%S5*(zd8o{{A^H(1>E1>>Sgj zgQd#)C@HL(kHlA9I#)aVa-wKu28trq+pkk^zYYWB$e8>!XIZP(SZ$i&)@X*>u=?2S zK}%ifzglp%_j8`z{4MpR{wucvaG6t?G*{Fwi4xYVO7i-o=cQf&@{N6+&+>V6K8-Gl zl8~(^-tOTax``@Z?h!?yxGOKJT#L#=*;+)YXcT>bZ%(}o%Sb&{xwaM^=T$u|HSckL z`U&-n7|Cs_&cM{lK(>cQC$y>he*SL1q<9x;yReShT%q1GQQW3JEK#`Pco{-zaRum6 z(UEN`nwqgTj^61Nr0MQS-_p(dMx9&0{eqeV9v4)Lmf7&2sMonwuV8JQJk2Y}f49|P z0?5VxOq%O% z3;o(z!+`{OrS=}DgsHv9d4ckk52C%tX>b0G(yXCzR&#W{D9&U?WcsYRR9)`m3&{1=!G##$*{!oO}(X}O#|KpL=_helQ zPojnSZx&j~%bSo5i~C#LBskN5HOxu-QrGmN%DOGsWYF7;H#r7QUy0X)fm4yZH_One zNL*HUs|KWxAcjvx;t{9sDw2&g?xu=leWpDt@-4nXvwBq|Yc%eriliesaj(d-+E4dt z@9n>88S3}Ptr`Ed#yZA7I{Fs>)hy?t2-SPQ6NtTno7232sEN<}fbWfqEj7b|Jg)IP zR5CtbxW{&+-6p$~cAK<0Id14|(x$WXy&T>{4!ZMaWdZVMd_Ivw@ch~6zYYq_A$b0* ztU>;aJLB9E&!2JAnri0HxFf>>dH#&cGK|0cSvlhJXXU`lpE1-pSkIqv!GweL{23Qa zI9Si0alwQS3FObXpUI(n{){V69J=Sv%F)mGT@_>OfVnO=>3A`gE zROVHVIrGbuW6ij7j2TysE#t~DWn4Lyj4Q{Gapl-Ct{gMQm1D)Ya*P;Pjt%3=F=1Re z7K|&$fN^Et8&~$Zab;guaz(?J?VgW^vi{dtZ~NvQNI} zeQ|p%n=RlD_opwq^}guR$~3KZJN3qj|MY;WlN610S~OM*xGJbF@Iyhh>P_0B8SWDm ztZlh|KkXG;?Z0Z*DfeKJ$MeG*u>#0P?J{Zd+A-tESuaA}Kt4;z4z z*sulDD0T^v45_+?ZN191VfzP~)d!0j43`S7fS-@C{H*}uILf5y-SeY&Yt2hunX`le z`9J3@xyNo0W{Lb1jQ7kl!uq~A7RMR-JeUG3?n=I#>$KnfysymXK_}58>h*e0)O!6@ zo&pYEGgkL-hXh?=T~fS2nD1Wy=~@Hkxr| ztJUkeYeQXkZK&(64RzhMp{~0&)OFW}y6)Og*IgUxx@$vScWtQauIsJq`Dr%q^0UEP zGiCS6^HKJYC>s9kSlm~XZQS51Et^=zO+CAAIhZ6>jwMm$P!d%yXSWnc?Mb^14>gaWa_rUP9XqdV8T+q}WxTRTGn1*0hp&3M_jnLXc!wsR zA1<{HkQpsU=BWFinb5Kh>P_A$KWrkYdi&Ni`ggogH~X&)9SSuZg{t}a?(0?9(to9T z4tC!^CHp{}E3E)>6C{(SgxkjoT~k!#l_{$F;GLmEo$NA&Q1&+2Q8ioFsS_2@x=u=| z;I(yqUvHeO;6LzXJv)0S^S|6ruzu*j>-j&Uoaj-shKm&s^zFwE{%bGhf^m>(bg@Ij zFV^5W=XJQp`D<}H0-XoOi>$d@R^`*)0KfNNjmWza86H|(TSv=e?kyR8lk6qqn^Yyb zSMpSPZ)&Y4y*1u)CqIq3zYp-5pxWPb`0_nN3iy>SRBbYn_JNVm3KANPgjTFxGDzT$ z{wvLK<30oG7XKBsWqUxq*nb=J3)%g}tE9;QyfjMCp#)Ek5_BlR&!Yq#O7P!Nf(|A4 z*z>7y=aS9<-sHaxmBV zCJ3fBl^_ACW`bb4yb>%Y&ONB`x|vpZU2ldJUe}vph1d0FSmAZOd$GdPGp+FSOe;J+ z(+W?|w8GQ(xWYevIumB{OV1dDePBzV|dpd#6j`7rCJiQ>sQ-|?%zK<)d$sc?6p!CBr zo?^*w8a%Iy!PBV^o(_ZOk{CQSWnm++X;?4@7DexN7y~a$RDBF|j`H3;Cpx@Chu@H> z>Dn0R(BX$fS9a*|OA}S^x6TK=3+X?#A`mTLwY;ZY`R!1`UHWa@J4%c~#m%H_K zpxd+#&`BSUPUZ?Ru5W>2A5%Xai$Q=>tLs&JJtp1|PB}31+MgBne@^ zY-j|NSDx=Xy)5}RgR$kvu_^al{@yBsYV`Hz^eNGWVc&*@y`cgr@+Y2CGv}I`;}vdh zzb?$~7VwO)gKMk2)I+&4{K%&rR_XB2tLBw!q_&FXTxi%m9_9I-6#2Kx%$E71$@Pnj z`lH>~FS40G+H(COzw~DLLu#I~EZ6v>>((!FwmkXtcBKB!F$8n!Ysermev1mi)npL`cK*r(aQg% z&CmaBYO4Nh&}|Ki&~(!xG~H`hgr<89i_mn_B2?drH)Oo7DdTlb8Lw-~cwJM*b)QE= z##2ohPc>yc)s*p6Q^r#@v#`uqrvl|_FRE;2QDq~GD%W{Y<&3?;{T1vp%|zPFw}%h& z-`PX=yR)WfKjs^o$9e+h8h(gxQdjw}ai8;D>UU$e+G2}yW$b!dJ1iY+U_bj@-^eN^ zv;9ObhNbo~a4X3TJKoBFbz6a5En8TNisNHXcYql8eaE+D-0BsBq`&XKm7L>W_^+~{ zxli|fl8K?f*gHwA+_IY3bA4mVp4GT=(`pXin63PG zc<9J^;KP%j=8X>b@X27gf}fox2#{^BT9;*Ep3faoz-K#UiGdFcu@>;epgO?SSxoR9 zA=U!^CBzP&2flyI-6Q9LU+J96cD%zoLTs!L-uQWgIj0d0ToBZ9;FF!QmINOfVx8k0 zUJ_#Z292*5W2_r$5HRbD$_D&NCIsb9@KK++*nRKz{kd_JJtt3C5ZuFkcl1Ucx4g;zCRNKeT0@!-oV(jm|!*o8frlNW_CfQQ7&vL64sa89 z(^bWF{J4w*>+dx75I^LaYPCwXK*yyiOJqtMGRzCUDa@>TUtC5G*Emza$2H zWl$a98=bP4;4?$4^%;kl9x82VobKY*#qnWfbZ>PV0aMcw2QLkkzqpT<{-bkqh7KQ^ zv-NgkBYn5v`12YMAD#7GqCYcyh zD9x9}wfSOlP^9_|H1->Irk6J+Hg#4qxgME5f%s)DQ^j>U` zh(tC+xK)=mI9;kL4E>E`T6n7S+HfxBVq zP5=)NY7&U`Th-Jbrzw}rJ?uG?12Y}faKNrxVz}sR@PXP4>dbRXfYGCHJG6kk-uEFL}UgWMhA}bLmJ4GGos5^DR^Th^?J)x*T)*&k|7)wDTAIOqpVk|XiZR1#D(z=rLFq&4m0?~;UwN#3% z7x?8(W|Klu8i&$6Gn8iwxM^&(yTF68^#aVgp|ujo*|lW=?#6o20)9BCF7OXdSxhk7 zVQuKVA+@gY6H*_CzKA43=y1=WlnBcX+_2z>g7K>RI$U0|@2~KNX_hyeVlr3;z z7CN;raAhV2W|Ju~AjXSj3cf1V!7lLTEHyBTpHc&|_E~D+v<`Mz2a^Rf)(5j7Dm7rf zHiB6rB?de!vy;GVGbILOmuY1KV`@nZ$o|p9z%0TN1F{~Q*i08>Hj@~0N)E`nY{{_@ zvj|HJ_@->{gkO>+(xQS{BQHmkX6%Sf>|~t24t^gVqgqDi2;+Hr~lMk*m)9T z?ZwQq)WFz#DlRZzqQNhTZBZA<>TRiku@sdluxW8;XJt{rtn!Kq+&b-xfTP*=35?mP zn7|FG3Vihc8V2IxJ{u_fq*gF63%`oepZ84;{$v2*OR^RK<5yA(0GZjAEtr`tF(6ac#F%HyG2@tA-%ooh z+$eXok7_zYU?0U&}MLRpj( zN7T$F$>KgUg58wmus#!rV`i%X_?Beu0G}S_&Lptsl*I&}6k;tPr(=2v5y-_}i}@-) zcDNzVyT& z$pils)Fg1{u!zR`;QhmxY5`v#)Fg0K78CrQ5NiRy8`K04%gf&Q0b_buJ>9%|To`5( zz*jhBBY|a*?WS>Hoc~G<$T@(Cfmt;r2E@!VF))j&#DJ`$CI-fSk{A&CsVbZALb0DD z27F{V&0CmKEVdStRTh&u_!`a{Z5$ZGO9cU9cd4d8 zY%Gfj#+jx}fjwXFO$^N9FEQZPGcjzi1#U=L)F(PdM^w2whq6$4>&8{9?yYW>c9bQC z+Q3p$Vn8e<6&HwdkrWV5ouq&`ttACKJ2T3_IIf0)@Sw&ONq{-!X?xUH!96rGq(y*Hzpo|zkGI| z(0OjXnIssSO_E2=j?<>o!w)WBsN)O#SCWU$?h|Sn1s}-FGcX32V!vi~pU}CPIR>WF zCHcD9v0xmM*;-(n<&r#nb{uLwC$m<-3>rzkVRkr|ScLSlD#Pa4S>J5^1y5MpyT zh))RpZt=mK#7puOv-^bbaGN9;7q=u;CqiS{VLBK$wgbF?>zOo$WxK`{w!k-3n-9O_H*)wBDA*qBG_agig*>C>XnH z5TDS+nIst9BuNbuLiq{_W~G#*76(GPl?KLIlcaiz5E{?gAB@2^kR-%je~=R)mR_-% z;iX+CR;^l^c49T8G43$m#Ht4gVZn)2s}jOu6RUn9^pVVd17l!FQth%n70#k>wFk50 z=dVA(vGkif7&VZ~!=V679?bHe%fsDWm5`?~6UC6rV^5+Itc+mPLoN@8Vla6yN+Oq^ ziC)O%XQB#n`O916kY!7Ti_JRAzZ#GF0pqm?GwTUAofp7H)vAh1C!*5OKLY< z#U8Vy&m~vRC&j*INuLlat=LyD*`QI*FuhX@WBY{<5V_2K*jNYK~3i|HGv-HQ;a31a-6d zvHq+0pIg#o!0)g$4EVj0?D0#(L5d--6i!>(WY&Lr=}gV~GnU5rHR{6J1&o?dPJ1qy zsaZe1bf#wg?MpUj*5g1??sJ#c+$m!3v$T*2c=@0Zk$$HnfqG_F;09a-$pmh=gs zmc;&KNz=yQi%Xg|23stNjR9xoO5vMJ`-E@+i~Xv`tDF988^m6#o^_UOgV@h5jZFle zV6i(btzG66`-G(%+*;rdmSk&bpAf23?4C<&8;)=Lp%SM@>p4kkIM=AZfDqT%u!7{u zE|oMVR~x4zse0NC2~CsSyD_%CZVXZ z2<4kXN{H-U=h=!XV@iPL*k;`#(<(KWNjNIHk#_h)g8*%MJA_ zU%%3k1BJ%HtNKx>GFC1Lv(yRS9`>r#!JU_a18TT^&6qitIAEG2d-j`ILay{mM?o$Djld}yKf|Cq} zVZ&IX=wFEzTtOS07j3YDw0{?EQ2UA~ms7c>u0u%L07ro+Zv1e}EeZpW?X@V%Jsg*` zYRk}kzW~CeCk<_~<3^IGa=h&Av0m)I>iKRk_5AJx#?bck4vX$(>-n$a5tbLQ5WcniY%Qg70EEiT&+mTjNMt0 z7+Ew&MY7>$Ij%_7WK5NcTwe`Gyvfw{WV?T~%LyavF*F#Y#xXXSCC1@VVv-nFHuV1&>rl=6 zvLh<8>D)O%TXK}+A(|0)Ba!zBc zei7DgX;L>TVq94dCT}v+=eEm!kDH*|@T-#+79>?*Ga*G?etw zz1eQfYel_J?;TyqxNDl<my%1|47uKawZ2aek;kiidr*-C zPINLUmcz?LpXB=Bz`72iqFH`xoAO&bwEp~RitKAeCA1wt|CB}JhU!H^dT zYX?(Lu(pG_tw`|icQExdm(|m(?O?9-hPXa8$idzqoKan!stDw+nHmIX-gJ6;>{e?Y zrq4Cx<^B)yB4IU1J;7Roe5pwA?;E6^=CXR4wFcqa?7Zk~?r|_*OVA#>{(5YO!`sW_ zUH|xk5-(#YVtL9XinD!gRf#Ic(!cp_)t~uqHWE3Nd}Zn;AaAZ^(s)~TTz@xxy`C52 zmb^$<-BeGo)=l3j68!sas;9ZEo@T9^9^@Brd8ypyKbW`5&0Xm(P(I-xioU>oC5ndU z0-LC^1J?Kf)V33R0&Sm?ry;ML#8qK3*^SGK!wcS^HmvbRX?$hFe)G<0#gZ2TVaf8`+J=lxd^_x5_+8ue*^;Z*~vYy4MI-*UJnQN7m;q|WnSNp1f60kw_) ziuz!0Kz+l1MSbJA0rfNg6?MBqT2d5niTAiQ1(;DFF(3_XV&J1=kkme2x}nDZv5yi< z3j8o16S9RaSV@2)id@$tKpFG$F7rB6u?bM}DmDR%o>$`>uSO-fzR~`gtk7UamQIU* zGb_f{TeAiQpXuB{k`NhNVeU@8$9P$^O^(ZnjBIkWG{NMT%fsE%GN?w6TF|FN@AQ(% zzdn-!De{9C^k-6(#omCs`mfAGAOk|qYkHX!MFBsUA_7^aCB;h3@Mv&^Z|n&?&VTKn z2!Nj%iN}1Iwf?!W+ND$eHJgOPCQOnoqxG8#ySukWA4 zJ^#SL>hl0!J2k6r?6HutidH0xKI>>jvY5{G6|^F^^1vZExzYoyxs@afFRN}vvh-el z)Sze;`2!Cu_Z7Dy5AgsibVZ)>>OnLX51tBcaUaaUu()7s132)Nl)1a(=|KlD#&+m~(-_+^#uzr#@X(HZFk{Wi3TCWXTY?#DR$ee;&C&xi)=Un} zSTi{=W6k8ij5R9@n6YMM0W;PtE|}HD@&GgbEIlye&*Fj^fB9HsfwH*ZG(LB17@s>f zjL#isI6ilr;rQI~UKyV+h%viEAIt)0?N^S+6~3vA&J<|IP7UF&_0c zfa41@4*Y%RWH|u;7E}i~{bEMrSPRO!mxU+`utDP9Y>XHXsByN*la z3;bc{lq(S9&N4u)zdV-1v3_aqnOwOXqMmV@m<)JNUm`WSfTsmD4*a82785+=i>G1& zmjpEq{FGA`6a2*xYXPwW^l2mDP1ynr{!Og5Eg*XZ#RUHKz|^$hO&w}6)iH4Z#5Tl2w3!~)*}-W=38@J%mG^#s4eIh7W8 zXHet7A0M1z{?2jt5L##)c#u=pc`tbR;PH|EYaI9(=aeb%(QY=XTd*8aN1}jeB})uE z>Ka92K=y1V21Xf442VuLF);c`VnEcCiGfF5O*$V*z5hS=qpILnV#_x5_jp7(J-6-Qkb73{T)V+L2wUq=5JhEl==G5wpc6 z=0ew>CU%A6*JQf%O^)B4ap0t1Tfq6T|Is)59Pi@48b?63OO`8`?UL#Myf#biM~-*T z6fAhp(8DbtYFnuR(b|?N_>2@2xG2-PV6?VU1AaOa1AjhLa|?*pR!kroTI~TuLtD|n z`?waiJRPF6O$_{*BnEtFXxFhmcuVJ$Dex&ljRR5Rk^*j-DOd2;p@Un%X9P74L}M#4 z;9IlAz-VuY0q3|r2c0Jt_Q8hA4| z7bFHeBC{Y?I%e;0Ie^*wD=Kh>TNNe-o^VcW1UxaQap0E6rPXMW<6|@KM8_B=N)3n) zy=tW62g%?wH4Y;M--2;q_HL>J5c|c%O1tGyw>sY7zq5u8c-#vIIqu@WqJHb}39j|! z@mkX(&~_bPxxom$+10nmwLJpwcFinux<}wjSGppndIWBAeJXNwj{y5Gk!yNrJbV@v zi4)>N*Nh@>>=F1%BBy%eOJp#8S zQeOh|z@3R)-6MczuNs8F-ma^w+zFuEMNan!pxs5T?h!z7SJBbfqpp7|lEAYQd1H?N z+g?eo?Gad+B&T}>*bPf^sz-qBu*lUt0;u{b_i`s(k*IXkctsNUt?PD?H}(jyQLZEj zpvpx~^$4(k7CGG`u(7M;Dmnoy0Fi5Z1kn4HB!L&C=+iv{SOb#0u}9!Em(;p|X@EIU zrAPoxU*$~zRbNRGV7p#P61c&Q0g=-^0_b~@t9t~{(N&rR(9%_O0_bFsQ#}Igl11Lw zBfx&Sk|c1U>*z|7z~>XWwnqSUD#_J70w`3GYkLIHZX&091hRvPwLJnTy()JCXuT>; z0_Zc5YkCAe9eVKqlpDM0Dl!4|m&mCe0hCphA_4Z#l_UXlS0#y3!jV{!r3zZ@8&2GP z61uwgVAnLqX8X)9IQ~w?f&b{7v?y@P*n3U_XJ`AsrH*mB&p2?; zIb{nxFQ`c%ipvymske+nZJ~FJL+zkpj4O4Caa;K+jG{2E+`k#eqR*0UT)C1P$8L=k z*|>5cHm+QUjVqU7y(`Tk%o1y2<;p5CHdd^wCRQ%1#+9q8apn4H94qA^zE&B>Vl|a< z;LTzmbHse`V`4Wl31nAd$$?p~R0|-hm5FWQyO8P!m>8J#QssE7$6&QIF))jz<_VCc z(!{_wMy4&`Cb5;71hS>EnBe`B7?5p_iGf*)t+*cJ)@&C9o|SeaK=w3>31m-W8Gu>A zB?e>xHnDQ$HEt8%J3PvN^=8V|dNXAnVb)+J31kJf=wKFLi2-xRCYu13VvAa?#Gmt( z_-bD{P3A#v$ZwMj`m1{{^1!wJYl8Q8g1LMe2@qjmE4lM9rgF9kA7_XJ00{4hBas5|Y z#~8#CV;RP4Wd#A_wUQW+<=DhZQ&?iG(k#a&2FBqfG2q=@trfMjfGr0WaJ*X*1G0{r z7#M?BYY7l@*Tk@LpP4Q5r9EqMr~}MZ<@yJYf(95KI$|Ce16E={%vVbdj0%t#T429e z(e=-E>Z|;GR{6d^Q&b=xDa!$zR{jZA{yTh?H!<+sw3Gr_+LZy2rQKqJ(~>>`WX(1) z*6P1`2F8IO602|v$O5fQfh^D#6U^z6#DFZ&CWf_qamoPryPzh3EYKDcjI&7@0C6^% z7??#{VnDn|CI)6rml#X>A2KHsm?hko^!bGM@TFeSf#Lg6E@0Mii2?8KlFotoxtY!U zOUD?>mF2smuleuK*8ZCu|25;l=mX6{;ImvC=vE$Z`^;uO%rS;?mF*QyJ~q~QO%lhf z_jZ9C%!02xfE&l5$|P`Ec7OtYc{)G=zAvaQ@ZM4+b5RhP(%6t$jzY0PhKY_sF%FDI zQT>5UmiiY%xs3Jy(=kfMRy8nMM#-J-CnoRl6BEl7d~uwjOajqGCI(J=sf%9vbEdxP zdZ~+EV&`C~p`*}GDjSfUgNdP+{>wc%dN&-1eo{=}-B(pzRMoZFq0CPlqq3|ZV04yp z1)kyOG%6bo9aNUZoc71L`U0cIG{1lx;aF5K?i*za#7|>lbtTtD->q|Hrwo7#W5?44 zvdgi=z)8n-fw#o|N&mgkG42_QdY0?9i$ce>fN68nt#59+s5mw>me?9scie`s0S!j6 zsXglYtcyNlTVknw*Yy}TA1pO68cV6w6;&4ng>sS<@B`VV0(@g|$IJ)c7Rsv&WG7)| z1EaB&0}zE}Vqi3u#DHJizzK;(tt+%Hj-VY~Ntqb#wxPzaCU3c04Hmgr49icB{g_w+E*<}|M zSDXfMIn(9*R_yO*^*Op_)fmXKcCc=UT{o+Lp3i&Mgn=v}>|C*bo>jAY#r|nlpH+kv zWROC+c8I-WR&A*eJ7>7R)TckD@gUv9oMjCWtMZ=XEUSrF)%aRxSy05PWlKX?tjfSe zEG}V*RV`RGSTV%@Wmf-@zDD3B8L-cEmQ_WpT8G7hWkT$K&+0$Z7l?iQSFFl#h=*RA zSf%h053#^VRwZK@VZjiqb|8eOL#$F@F~LY4$P&U_7OOI_ps;j^RgDR;dJJT-T$##Z zRkCA!LgN({tCF4TEN)@3YKJd7`yKxsr297yG4;i&49xo9x*020bz^cfv&E{9Iojk{ zbHJ8UeUQQreF5OrCb25n5kAlHN(@*+%y_XHsdqJ_^VemVvCPfGIna^viWbDV(*SNtaJ9Xwv1!Eeu_b;ja{KUQpWx zi2aWRO&b2U3z{_ivlljL_`MeP%QZvkK51cSc=iTjk6q9wgi}oHTNcz@WMYqB(8pnx z*$9U(XtEK0zM#oQ*m7Z$jWBOv*a+-1l-oxagcpqi60x6JP&+OWd(na>d*Trbo9v1A zX-xVyg_TMve04$C6YNgJ?zb?UYMgqAebK@=1Hr#0w!5%T2pdG~(uGYH$#)loFO5}C zva=R8Y*N}Rfox19xaq>$Hbv}43!4m@%N8^lG^Z?RGHAZMpkFS4O84M}O$N=@3!4m@ zqZT$9G;frwn=ZKHl9Gg-`6E3!2QFmoJF>X;kD&C;R?ek(?Lf)2T?jI=E{p5`WF*=}OJo z9^M(&=Sq@Anzgth%Ol;2#HYgUq$1gVumz|{W;OPEMPjI<-Yb$BgkG*l3}zg<6^Toi z9co3E#%V>CdW);-S@%pw_i*P-F{hjEnoai_`fR$_&=b?WhMv&%5$}PlC#IWvLXySK zwklFXPfW+{B=k`wIltIERwUiSey}3TvyzI$Ym{~5bdSwi){)aq*KyP!z7(=#RcT_S zWxYGyYq$_I-NPozdUv|l(7V&UvUho%AnVd2|MV#gH=m3yj(V|Q=&(pDrc z-E8trHFfz^TwTk$e5$F-r<%Has@KrvQ_ z*HnxHu2fgKH%#cMrg1RU)a6r6T|U*+Z+kXe_nZtC*Y%@-3J*4x!hUB0@h%U4I2W4Bi2Z0PdUOq_Bt27%X^y*sg@~%$SyK9|OCHPAhXddX`akeu-QNw4tVY+OO{%DFloR|dChL~#a-7r{o1 z+d~{|iejV5OPQi@+Ogdbg$n`ifvB=Ij`DJ@@?W(ykk=D*FkLU_WWAh|l=DC@uhIf? zmtAQAQ*CNT<0pAx-j^EjlAjEQ8riP)%PbmdKz!V4a-=!BUYn%L1|TnLeNP(TuF|%l zMn2R{7sTdJDQcjhRxf#NsP+72+bRB=4K*mfQJ{`5y=S7>4r6zV!vDeh(4uglQ^&?`X1>_=$(gJd< zEGb|rdbeKm+P{ptz>EBa)cP!NB>1x^$qFEOWXmCWt%-M>YF{`eFWTmwG!uoRBx(~% zkUDC;wWS0$lEJjV@X)by>Zvay^;EywNdAOhzWjp!W+NGjZ)Ru^p@g}1C<<>6yM9q@ zB3YC~F@m|=EDF!toam}?{QfxOBvlUEFMBy}j!UC0Aa4!m+H1X>6BKHXv_b-(8Po(Y z6}?q2`b1f%8@({UPL0SiNbHN^j@$|$2k617R`FeYeVg7e|6*E{5KnFP<&)X9e<~vD&X}Lg{v1ApC~jg>Q)p} ziP!E$aT0^aM^xFY-}OS>9`Bd5fPC#swpzVV9SYU)3qk4+AfIYdL?D-lBn3>h>C|ge z`)v5HynJ`2Mr7?H!IPsTD}dyYt$kc;IK#c-(&lBGkQWW1LIXG4CX|G1)c|*+YUE*~ z4@`B^5A|qx;7R8dMp4WgT#%wr!hBLg6lbR#GKeah z_0L{{hs7J8EgZlI)q4@?(if%Ai!1g4_b?7n$knC<*GTa?K5Cuvav za?dA|=2G6Q$i6nN$ctKQTmkQP1C)(hrfq|W#HpLveN>7XXbG#Ayf%n7^;Zo3)qhp* zA>X>Pwp^OFR=}&B%B0I;lQ51(`Cr#Hd6d^Rd6d^Rd6d^RodT?DI^$W_S^D5sVLmvOa*eN($(4t4#+4T%j4Kbxjl;FXfvIuqobU-4hhKnQi*e;yxN$fQlkdCkucl3&<831~ z^ep!t^7`89c%y9};J2O1q-n^x{z)VKFBBmD^-LPKH?ML@x|}kUjE@nKyAPVZ{C9Zh zsClIOkQfKGe{;WuKO&b+hK?9IeCXlN+U{A8t`+m4FB_bF(DlPZJN5bgA{xy&KAFhf zFyrd;WT%EXQUCXKWuEsLI^(#NwOj{mneTuta~`ned>pW4pD*+pKhJ;d6bt;8;1>76 zR|mI4Kd_G%`^Yw}b!WVTxwsGB+z(|;4m=iIeYK!v_KZBo`rswbX{`soB&asQh0{F%0S^Mi=_@u?v$RHsDH4MO*NwU6xE8~RMz!n`RJ@&!B0rz1h{)p<3Pr-MgVX!OAO4Y zl^F2#kyr=#?kpylk*t`&Pesf&@LO3-a5m6^3=C@@+L5vR4-acgj1FMTsIX?d8aY1b#%i%4#qt?4_+#3baOENE7wn;UEYI7@pw!S%bZddwdNhav*$V?``mqwkk%FZbWffx}yU zvtl7#0mP2aq_G~4N-nhZ<;9Mq@&K_Vq4*VvLCv0|BH5HMw=1&Tl~iQ8Evd+IUs92! z8C;Q6g;xVBvaHN`MZ@7)q19+2O%2jZO;dBW{KQk^>l5qw62)A<#?Hqf0XPjr9(m0|;? zw8!gd*LHktKPj2JE(ns3?8bVjYKhf7T>m`37~9_$#x}SGOe4Nl!Y8}*z9|+k#j3UT zS>DPlZ05Eo*EQpqwk&JLF_Bo+j4Ky4tbZKerda{}xl@^R zSpc1qk^iehz1I#n$et=|0FW&!xu~+jqUza=lN~QVNvf>vm0oVrZgd79L}h0Wy=uEY z0ctL10PWP|4EVHXgt$2a%EJ7jD2ygoDRQ#6+^NxmEg&!9HaJR-ap^auSinnzs*S$i zxPIn)Y^FQFs2(k3XfsZ>8`idi{6Oo?{%a|Lc{g3f<`q+3A8n|~*ZhE%kIz_2VBR{H z!r=u`j!qkN(6|2KkI>w!ukP`VCU-O{vP^B*zv#k;%Qp0F zN4DV7pBel%+)tnc z^CG)tz+-|Mr%+!BY8mjBpvEcZ`BBbgz*O{cik`~347mA6DCc;+=*#}=^1;(>J|9x$ zP^2~#-G(q_r$LPafBH=%)md@U0Di=OwUznB=>uxJGeYX+Zy&(-_^+fcJ$pcX-G4>t-{;Tpo{^9}kR{s@M_J@_C>=5JVoQ2Uzoj*F<*k^)LTjB7~MBUS_q=Bow6aiW| zZ*AJM5+p!_=8a30D?tKGB@+bG4wWDQ8X|9$Y%Qptq~G1KOC6Q#bdSJYRCu~K!wOIL zW?13r-V7^Tf2EfScYOu1mI5<@&HphgrtrgjB$*_bb{rrdM+d#enp(TBF_Q=&J-IvXltLj_XgcWe{0aYM~leAfAKkis5wsueuHuyy zEk&CCM{8ZCJ`n#A84a{ka7vctda4hRasSdU&J{p>Rb7R|rEYw)X4aNNo_ zyk`)=f)ly6H}Bj5`LF(4N$%r;Lle2SM_^SVb^h&vJ9F}w4-C@0*?+5yFs{DlMpi}s z>5_runU@ZJtK7fgL-@m=4N_lu@xa4Bmyw5i;FCG|V-Nf~C-=K-5bZ+$tung81K-Ta z|M0-AIeE0(;#c`^Rru>XaC1(U)A=^HmBS7C(84<`ja;isw4y_~!WWBq#*U-CbdvrCuTtz34b@|#}LznBjD)la}Pd;Y- zt|t!K!VD_ZKo%NlaTeDl{Xr?Tvj=`PsP>Hx zf0HQSL(hwdz-@wR178t4w{alaQH5abeo5@V#(`|$BnA9fk^-`Uvo-`j;esd_aL=IH zz*B-62fin$Ht@Wl#(@_F)dueW(Z~__;-K2V!-5(IzAmUX@Qp!@15XXA4SaV{FF z)dqeksBz%8gK7h}iky` z;PpYZf%m&Gq<{|$sttU2P~*UbLA8M^gBk~(98??l+n~mQe+#M&{M09+T)?je)ds%Z zS5D17Ad9Nn9=P8pBQ4+oLA8O`1T_x)UQlh|O+k$Ve-~66__v_Oft&ggu5tli8`L=P zgrM5MPX#p&L>(wC;GSwiyQ~;6I2`cvY^I+uMVmWydkJ@;7vibfqS}w zRUv@OgK7gW4Qd?trJ<Zv{0DM1QNHfxk{tz~2Vd2F`YcuW|uV`$`M=v?K*w8dMv2 zeo*5;Y(S+2{Bn{4ek-Upke!msh2f9?KvZeZq1-?9mcf)Y#RNuuo5$~@!Q;ci6g>LAK~#wWpW~E?flp0h!0R$G@XbjKhy`M)fs>ul!Omb4 zXJX(B&xx`Dw|7Is#K71kszTi!>0pnrQ?Z!fy+0Tk0C#bN#Kgcygptz0BEchUVqjFE z$^pbnT&3nJ?B7F`b%1|y%ESVPF6$0Eyl+q);O0(QOz;Pi7!Yk}V&MNyV!#_*Pnj6_ zme5@t;EIdVa07qPIaMCWp1@KAvwf2o@K)c^nHczqq4zpKl%0uzSzeVI@D^WIO$?mY z)eh?_dkYf-vtd+fK$a*I17qe(4EO-I>rD*&NarL5WKUpXV77!31F}mnF>qRCI;=9U z%iO!*lblm(!0%;Z;9HUykmCl+6#US1-T)kP%EZ7NPbgC$Clw|JPOD{1w2% zoH8-+-eDfJf$gC7Vc~g)pVnKz2pZc`)Vwha%#?T6a7X#D5#4s5!3RHU_Hi3!l z=nDT?{;RLZ%>!d7XifsL6D%qiLqTFdw$LU9X2Yy;3B-0VF)({!i2<=4OzaD8Qp`*H zV&Kc2GO^g0F~eZyU(IS#7>+3i^;@L>X=E!fw7Y`q=8?| zOeQdg!vA?u>lYz>$2u$Q_gruE}=#~%*v*m+<~3|%Y( z?iJQX7r5t}Q)(wTet*V+KjoZy82Fg5Kqi4r7RYTUryRf!4%=c9h@oJOShoB0w4aK)JEV(JEshQoW`kAz>jA!!B?c1z#j%R3EV5QE#B<-tc(Mn@0`j3 z#K=%NfVsT^#_rHy2I6k8mIPy#C^aC~iHTvBU`H6YAwvQWfysfBw_p<2z@3>>0gU;e zO%0H9GfNH3QKt$Fyx7m$Obq-D=OhN?Y|X^B@*}lL|CJb!!%!0guS#M-4&|y${c&#j zfU$s7Eg%+o@-CV?1cCU&!@@?ZXI97fvW z&nE>4##mFefVi40Di~Ljss-GTrG**whA^4N`d~~adkqYHrOVA4T8CsRP>|e(4-h=rUjRy5YcIt9Qg921xxj2V&(4NI270WL%*eyg}-LU z2;fKi#$5x2JwAJROO8GK50V%VJ!fJ~3U2(8!Lo9w|C;v$e5`YtCn&uOLTs$hl_iv) zWpRotz{~tsFXYVQ+?!3m$+5LZiK${hbeM^uygr#Juku*f>MOUF-j4SU~8HeULGL*@3cK0X{6WfsHSQ-juIlKE) z6ZH{?C>8Y>@UC!1-M%>_}6 zlH}315hKm@P_&U;=~)IzZ*_PR>XEMLta&*kxf~h`q`4l71(Mv`88Oma=R}MoPq~d4 zX>RUBjO10$ir1o;v}YBpN1A&;qmHz@AIu>c>4q#%rcG7ST+zgn>R7C}c*#PRO!`=7 zABRSbw#Jef3?IH_6Q zrOm%h%He9q70&oZng`fofoItJd+zJ&b8AzT2iM$bNmY{NSv$EkGO9?s+oaC5u}zA! zQ10<8l%(r9XU0L2T^&{y$uB(%2oau*_*36{}z3+R7%7SDd5$9Q<8uX7hvk{cXWh~$e{V~qvUJZu-= zNb<~Gw$UWN@!UVpx!tR0jsnZnBt6Ly3zD4c zuyRP&K}KL|W`geJ;gKHYWDdbSAP@9p4x}48X+pO%Kz`>*6G&Hf(u5$%REO2AJxK52 zHEAAVOLR%{HoMF!Zd$ovHLdbLU6=D2_OrE+R2VVR?#=itlBH!ZrfQ@VhWSbxCpQUo z0?Bm6R3$ys6=Moh?6OEkN?|5=_Ryrc*OrLz4E-%n9>UyYkCU#1n3^>5+{h<=oU^MA zwE@WuxeQ*C1)iFuc_1!gBqQZM^*wnGlNx3%Qk7(7PXf~tG!q#UOVVyq6XJ9KOm1Wr zF~3>r(Z)o_o7Ir!!}n74DkM7B1C3EWPtSzM@JKV`NeXl$ISz*aMvU||?!f>_o*Bp} zC&|3X)Fl0tTazS@5sVnqCLW0!9%<%J(kzmEu)v6s{&gO&HCZJ2uz@^IL6VO#nwq5h zJ;9nmlHSJ?HsWLEXXXTe^bV(Lw@AkrOw7*m95RsRnS}X`Kho~`L}!vr(2T=;@L(G< zGl|HNi>>d?fkuqqxEk!?k>+FeGT%sgPcfLRwZW;pQAe7G_~w-)q}|i|ZX|i?VXA%x zHGg>2k>;t0OdFDArHDL(cT>b5NuIkKt31TuA-Lg@PFc#n?#6>~CVVpXndp50DN~b& z<4pJrkF>)@H;=ufZ9H_{I#5S(_0feJrv% zi6u!sv?(=7GPjdqLz1WGMj7d`t}^{VWA6S(FVyN5hTqs>#*Bgsrd|Cm>I&d?R{#MM+RI_jYiTu0WfXhcRD>^-`qN$ zi{t_eoCAC~2;c#tLb!kR~{!xilI%(p(RX9BJ~<3KSOPdc)Nt z%;d9aJi`t%dG$|OV6Qo0Chy|%7+aWI$NSH*TRIzfE(E59+`)5;9YD!=_o_ zp>()53v;mN505Bb@mISC0le_@#5$~z1%4wqtdRvS3t>qXxC$62N%LF6CKRN(N`x!x z2id}AxK40?Z#44uC|81TZ5FsJnCR-wzNyS7*Lb!aw!&>bR|r#?^bRZ_VL@*GxojAX zTnV_#Hx1M)fsx~?;GP2b-;K!oth+oX=%iaX%R`XlWezKgB%g3M7Ws&KqlHsU#+-FGqQ zq1YT7tE5MPC+jgucdMOEl3Q+hRDt9Mk22CBGU329UhLVP%v2*i)1AH;!14BwuzQHc9rvzTDU(JrF#xNphpZ$|hOm z9@ksab-gIz<5jgH1NbGNhS?alO%6so0>d5 z;Q4^z@r;1y12PmyGV2g+B>(W-4kyj?0TE+<631obGc-bVGHW@L}wVX4BY?6(^GGe4Vxnd+k z9x>9zt{BM$9x>9NxnepQlUDh2G1(g9w1WAUh>_&sg>jcOPcLMQkUZ7%T?W#8%1^{d zMmq0c+GZ^9?1MLM437sMOyvwOQVPe^jOmz><68i>c+M!8k{yoY0wYJ7UtusCX41W# zV})#zJcTe-_34A*@%VvH=}A0!62TnMh_%OY0#6~#TT4mv7(%L&UQ-VUaAvse)0)lZfNzyH_;Qt-%umBzX!U{YsKKsnJH7H<6?!N#>wNj5Kc| ziEkwNjD!&*%`*xSBgr!eBSxAp0uV8h%u~bKa9qLj2oWR6gw%+U<`?s&2_z$Zt%B*O zsY;sX2vU_K^G+j1nrWvvLh^;DZ7)c8Niq)=DU!@XML$V?Bi-mH&4(ajTs(AP8EcC!~ERxeFu&~=@ZXM487uaz2%TaZaexSj~p zeQ^>Ol&~Qdcyb+5Yg_$gHQiZFtz{A0?B+vU+VA=^Y z##cc_+Uoq^Nh?Y30Z(3M`AkwVONVa=v~MDfgS?xx+-7$5vAN*(B%Y zQ60}Slcbr+iDYq-lh?W5!RXAquCgZ?Aybz$CKwN0Rgo@I-Q1QZY-_J@=bPHv-Q}vc!`)(@xSn znX{5C@m`koi6!ryEz(RCtt3kadXhxaJm<5PSn{Trq?u}p&Y~CaS`fDa;acRx8UAGg#q1 zmQ=30YPLSp*ty7hO^1?R4xW`{iAk=JB+V>WB3bX`}aJOq<;fXBo`$Wvviv0X))3~nHI_UNyRLAiCiE1m!(#f71n54Oxu#zlY z?vW(TmxYSt6G_D^&GAT*W_lx%GHzK)deU7&Nb?9?Bqd5L@etkgJ87m$R+1&&5EZWU z97|^|aV?SNIlD;8C5xr|J(8sP__#<)AG74$3z6piRgskW!AHy+;Pl>jPnzG85=ogK zEVc7UlI8>IA}LolmUw5t`oz+6p8BMjMOsOgc)vinG8b6l9RuSjX>Qi6BulqrpJpUU zGf%aWEOCQo?X$!O1FbAe{En7zpGqobsl_vH?~!I6E0Rl+idnkBBT1Thtkua9ztbgL z8D}g-+PiVrWm-y_+b*dsy~h$y`h_dK&ystd@86p7JU`a7)ce}^@+7BTc_yr}rl?*W ze9DQ*sfi6~CaPZf^5mvo`SN6_UitDQrC#~+q^4f^@+7EUc_yt)O-+1AGconblg9+r z$dhIw>Xj#t38|4M&2-c&Pae}!BTw2%N&}VN3F2ob9bPGks#kw$=_*rEuRM87NsT|G znUH$r$zx(_Uk6u}zv;rdOUkW}8NyG;>X_JbBDHjXY`QmR@=Cm}44w(#$2j^5ik6H1edG zQF`UcV`gdONi(nX%9F?Z(#Vr$9_f`QkNKpLC(UfqD^DJ?N+VC2Ii**gJm!{0o;34J zuRM9oFpWIvdyyG><;i27Y2-;W=k&^x$86Kclm0D&e)5=e8hO&pIKBGGW9Dh(Ni*;C z%9F?Z)5w!%_UV-;k6EaZC(RtxD^DJCQ6o>9nW$HuJZ7Xuo;34OuRM9oON~5f=AT}9 z@|cGjdD6^6z4GKS8#VHznTvYm$zx7x^~#qgOZCc^ma8%k^~#gSeAM_unt7*J zo;>ECMxHdYPp>?A%tDPkX=adKdGeS^8hO&pBfawEF`qQ@q?tE*<;g2=F3CL6tAo6~ zkvmFuS|zQ#N1Bt;;yKbhF0H&rnhjDS9BFnfEp4ocV@_$#At}ytay-T~okW_4m?F97 zNayV;?vZBK@??)vdDoE3aB!54$nD1a=<|y3njx1)0hnvPt(##n}^1UO= zd(fGjR^EfogVUV*%l!VJSZbD5%o1}-;U1G#>hUMrDd6X&|h?3nO4japZOQ=6=}sR@yJxTL(-fF9hs8~_pr2LmY9_q z|4B0&70E->idkYlY9vWB4;9JbX}&k=7)fTO{Az(nwn-~yiFv7TTc?$Jtjg~mh~(+w zJq})(rwaG9H0R5i%v6ni(#%>#^8J(uhpk<83M+#9r<8iw`mB2_J1@oe^-ifjKgBtM zpEJ)mxvR_XyY-*qB7FG?w9i5mgoUYt_iW9wVe%6n}6V@i3C zt?Q;lI<^j`IFGk;J7D^cG!Lr9`=Kem2aAOJeX8@yFm4%y`*~`453@I{7+S!$^V-+Zb= zBp0PRPdf2UX2PAHTFer+F2bFcTIwM=p8yfb7gK%jKojor)Zz$7=Mz)oIXX{DjdXN= zUs}12&XaHhg0Cwm|Eml56bWA)AWvJ7W7Zv5El?@2`IxX2GyO;K zP=fpfHc2M@9%+7w;NQ+OVO^uy`g{K>B-<{J_i?|&b8%rYU1m}&ES|RUTRp4NjpuC5wEgmhp1Sl-+Bx~^jCvlRs z_%M>NBE;xdJfp@ZH$_V89tE@G9P>evu5Rb&+T5|~`@P;vp=FRt$>B<4l+pja}k~^V&5utQ-r&f@p z>t&|jOP`|ml}lCRE93j8R;5?2vTVPyY`>$vh+hH+-5awlonQapn>@@Hxpo%WThpA` zhR4~>scm?i-tJA;mJ!~!+|oHN<8ytcE>FRD;$?WeLCSXo8y@4%0cCg`oqWZu;qg++ z!(hYXA+URBDK@Ye@%k5*d)~G;(wEuX!%F`b*BH;c5La3I+J9dx0RoS$M~mx~mS?D-1^!eZz0 zJCMTCVHkqwv(1$PBhq{ims5ycRw*C{T`aKXfo^Z_pX%4q7lv*FniooHXQnG>st2wN zj;?jW4c10WpbV>KNCC;> zn{6e;H{t1`VxX|NOXDpXVey&gU$9n1=$lqBcPUW53P5s(!wT_>NBqLLtN`?2n&Ux` zBwzO|QY5*R6!j!sKST7BYifkG^b$DJ8z|v94fCE2|J?DUD@oe$NYhq{6BA#COj`^@ zxnmMv(`atLKz>!yY_6=7RoPB9O5R)HZ;UUaEJl=8R z7TWOixb^E#cV4IK>Q9fL-~Cp)t3SO={W6BN`@+)R3rjm6VetEXcV7kU`kuJh$lGoF zzGwJ-&+z;1``Jpr?|V1yrth`$@r;|X_)59^=8<9b_Gc(YIG4^#^>_=;vDZo7JCbX~ z$9TAi`HH+T=O8>^%;RvmOmD#>!`ukUc=#31_MVP|SCKjZCz(7;71nwj4)P#SST%8} z;VpG>;u<_L$+0Zzd*ft*CqPnBf9*wB{9X&cs3I(W1MCERJw>BB9?95aHU&kcJRix!#ey!(nAJ%HJW{B1Q6W+$9nZ82H1{0U|~69EX+3zS!Y@ zEs~_$Jz4CYs!sO=NxD6j!yc=Po)e2C&v00o?8MJ_(i;eptc<6JCCcpAhR#wFBpGyA z+3f0D(dA;1q}%&h?ENd9FCqp>-sP||{R6`J@g;u8Njj0FJ4Q17V@jz~X85}&!#`g${C$z(?~4q7Uu5{_YleTm`Y!!< zV%**1jz5w-^p4Pj`XwFmowt(leAULt$;@y&ljQC+EXQr316ca zX6jcfg_+!;@I6XlCchrZHy4GOdOI3sazDy91cjOU3CJ*$U)AB)al%aA0_F36VW$2r zb(qQT1MpHGW-^P@&n90G!9d($gr}pbuiQfat<;*`Ug8mT@)QUcZ0-kk)H=+0f^BlO&^@ew*{*La4W zvpL*u9h@H!oZs9i`$H4-N5L26I+N^Ftq=5U6v_G&AIXZwmy__tB*Nl%*dBGa`p<$~ z;j%bgesfuTV7NEFW+u8Oft=^E^wSL@#j}BS&RvO2erdg*%VHkGH|j}69mFPR*f~xE zgCu)6tS)rwF2|`Lf9!(J$rvZeCokkIlpf4=obsK8o&hs7=h<0O;aiT`t|V#0Bki~4 z+lSH?n_>e^(N9DE6`*G)MplQ(OsJe6eqgRE4>b4 zS4pd=>Vbuj?lyiR^v7w?baNHn`2cCmMdrB?$Zr-zwe ze|iM{k#{F9gE+tFP5ZV~uBC zSHow|eY4K+^u0R6)3@pjPv5CCJbkCl@brx~ z!_&9a3{T%YGdz8p%<%MGGQ;B?8r~!`JbjPM@XC&pJPcFH561AOrpcK6adKbb!<*tp z&L1cL+ntS^KThtOg?Z~SY!?rY{0nG!{y53+E#XOA-c2-e{y4cmI>dX4My{+l$z_6J zy3ZMf86;;qtV}(?q@s?SusFO7cxks|q$D@BrDBNr)>dDAmks^7SD@BrDE*B}1ce+v}A97fkB)O##zw{MBSRCjtJJ082kmPqD z#UjblpZ3rf5>c;ZHgZ?@E%f@JQ3v zflf?(2Pm|~K*#|K$H#nniTrA9>=kcewzWy04+FWB!)riDe4>4aoQI=~{O<0~wkUkHoQWqvIzlFY9~J;~Bj zZT1Q?XVFEHnX~93$;?@#NHTL4DU!^bMT#UZo+8C-C$n9VBFW3CNHJYvwkuL3neB=c zNoKnuMUvUBNRec=D^esmg+z)Z6Eu<1`I)eoo-x}M7D;BiqKo8SN__QD6(>0HxdRkd z*%LoB4IRvg2JBO(it|D3Jj@fC@Uq}vsbuV9Q+JiZbh5dUT0cIkt? zQGaKn93;s%l}G%Vn{QXFlPHrgGK*r$WO)9ysUj&gaS6{d&%X)SEYARjPiksmgHhMn zX!veAEc9)%Blm+&RE-ZhQ#CxMs!T==k0~c}Lc?QH$PCc%m;y2(Gd!J<86HzI_rxr| zLwB8B85`VBF}*T8Pq@RRKX#GxD}U@tKa6l=_xC)E@W;-dOX=82`pW6gos+Og@`@mt zwhpF9>2WA54nuB}ghi6k69a04V#B)I_+DU#d(i4;k0fJBNUH$Wmqk{ckABFU*IQhMeIixZCQv!C%_=h7ow=lpZ^Wvmgafw-luLtF{xU>%(EupCZl zcmC#d!det^)}$Q1&v>nKQ_7bv90;8a9NpQ}eXVn{?|Y`~6i9zG)ds@^L0>EkkMoVA z-|+PCH$0Aicj1ZeR*jC}-`!uCcRIYnVsv>46BbEc!v1%!W`Fk~z{!3wrdpJ1LpDCX z0_eF%NLDdElE+24X3cOe2-&>T`MLA-uy3~W9Db^!C`fXx!wT)eF9Gvs59qnY$A%X;HoB6eM;>X~`oxKe?}i|4 zF%aS*$(Un8bLD6nZI~N^q}g2a_9V8GjglLJ)b2LMcSG9Kzy4R?~TLOGvL{BBh@$h%j#VwPte|$a>;$_P&w6?yDoG;v_rVGcw34 zPO{Chb;SeayoF!!K)K8exuX8pKTzHnFQiI!UQ87v$=_|0dEs9ceOuFgWm!BBS-^2X zWa5qRddZ`lH_rObfZL!37gUo&aYbcy!#fTt+5pSSwf=B^2|DsNS+9+HThf?n@tjPgNb;P_b7V$OMM^&c zDy*{O_5agvT`+z!|1|P^FZ;cvoWo2<(F`*k4a3vn_^b8HMpe%eVQKG$rJWa6*}g{} z`dYhrd$(3^cxCCA(d73%()iWNBMig69ruc4HQbvO$tuE7k*roEt1=Y+mtHc;vzuDZ z8BUO7Glv!OU#op*kN#_QV%M3OSmSvlWs}fkt~GU|C!tI}|Mav!?h(09AG?%D!t~$+L*Xsg3 z_ejXP5Fg3TbcY&i!lExXI$sd-ZB`G5f>w^AAjvTfD>M{idxCS1Hbis(b|3sAS=ssa zQix`5O-+#drGGcYjz%FJ4`tGvCo2B)QOGW%E}ELeASEv-ukYhd)ja zvgy=d$EhI6LWh-2lKx8ON78jYTmMFZoanMOe067pL*6{NJPs&9+=`z~qm3DkCtXR> ztVf!*>Nt_}Ww5lxa7jBz#vD01M^B__@dbdMn5338gCak&Th(u{v%kr{q_!r0vatzJ z0>-Xi6siv*Tunzu&=0BbT90IF;cqiizh}gT-Gb6{%MdJKlm27BAm7 zIrmUQ{MA7ASA?q^of_{r)rIEnbHeG`N!s^FM{|SCl>C9_*-ByQMhc5&X+v0AcL|*R#c4;7WF15+!fO5nq`!A-k#s%s zb=RF}{aRqepWmer;}ib*T^3kVetwr75$Wf5&q9B(-^|bNQtwiy3w%>?x$>{HU*vrh zCZ2MK27e`&tg*Lq!Ogk_*;%oZrDfHgXFvT1P!=BM7{||dDqaDSZ@Ct!RbYMSO7XX@ zk8ys7Eo%kRqqm$iDT_a6#HWo#7hm1PAC3~19w5umz)e6&rbu4kG%(ZOz)ZGgnUmIK z`dgDp*AH}D50X68VP%r!&pwM2{s#KS_Sh#haHoZ@3bh<;dm!& zB0iF~kQ_?b9$z-p%tO+Qx!LG3*o>^qLw`hl^RVq*c7iOv&!YKmc2mrqV1{?^LaUpAaI#~25aoawF>7F)UpJua-@RHq7y{qlx0fqfSXnyVOYcBsomUC%aQ`FkLP zJ;1ppQhKThOV2c6aiXQTFPkNKw8P3IIn`lhkbJ;lWs+Rzurf$;9?NRVVf-$Jvp7NW zQ-_sFvKvwLWOav?N%9igK&k?A&eHxC391~XD zKCQTYT5tXlr98sfS_Vm;=CE?O;<$;L@5!D2^+c`9T{dsH5*U6581u6C zoHW>XbGP~3w%(aQ&$$L!AL1iPm1^My3XOrnVhXni`L(c^c0K5%T~4yG#GhGw;YvZE$h;IO*TsRtdWf^$HwbXm-8To1a?gI(}Me#86EYjz;e9cF0G zb0R>6o1EHRNz#T#+HcEuen4AnV&vA+ENzI>e%(>qLEUDbPMU2qKRoW&-r29+w@<%i zx*b>EjnkPJhTeTTM^bZ)D6{A71e$vX!_%7w!{b(g7fi!rGS39u@R)%!<25|SicK** zUS62k8lKK<4Ns@GhNnk~zy0aO{`RLA``a(iB>UPQd7tiYf9ZR2xBcl6+Mgbw{r~ws zo$ar35BD?KAv9|&Pm^&DNa!Ci-kp!`(mj`lKWzjBFTNRNRi~eSfogH zbS}%~+#>6Xgy`}Q&;M}qt2@zrc|iA~;puKPJl&6mr#sT{bWa){yOQBIJjVa8yg*cJ ze#4WxV)KhIRD83O3uVQ#!!jh~Qu|;38j>%t;osuiZVWo4vvtbxuQi?YO1p;Tna(BmrAj!KOR><#Eh)&IPoC=YA)L{il&UaWLlDr!#`%PwD%&TO< z^1JT)!d@5n*AM8~_R_ig9J5_X(n*grZM_%$(G%KYY{Y4jF^4I>*3zumN|R;;%oq09 zbhcA&dHdVv+e%-KTis0e&32O`a2ZCT;pxQM@N@#sn$gnFiY#9nXEtM@Rq29T zGvs%{m+c;dZyL4-n&<6FKj?f5F=qqFoi1zCbGG;R07QhL*9H&B4+om>cBP|Q4lqJ@ zuES&JTY-{)Ci4mSHBPl|I%&8Fx5owpO;bpZb8ek=IRWW-M<*@!-Cw#6_iy${@oZ4bN*ObT2|GVlTy zj0}*0C0RKn=e|OgFAt;#PdXm>?gLV!Ic%DFNc+?rX>QJp-nf&T zmSj*9-ItYN2O359Wn7Y^y$BiYj%Buyj8;;h*99;$+%eZ{Y;;ZliX*K+b^;o)$)MLbVxiAKcEjj1V(he;9^MMj8$G;cFIuaM zfu`Q0AtA=$uT1xcO&meEE!=!%gnPoJ*Ah&QSN z=*v1zKaWTz&Hk2e{E&3JK9eK|veCwoH35Uo@Ropn-QkT$Ce2|X7Dx_tx;~TSY|jWG zy~Gg>xWh6OJj31;qQe?p+ndc0UERv5qtW1&|Mn)NFjv2AZA;V!}#7@QVSP2xH zB=>V>b{0tv5|JXw>wxGd$xDLK&mqJ?VtAz6JA)&WBnOFTBgw0Z*d%$QXQYw7-%*xD zvOFX08_!51&Cw;RWEmpY zygnE)(rzDTvyVCLjTmW8dofCqy=cTpvl~T>B!g_kNHfYJMzXYkZ^ZQd!nri};-%|b zT*71tDbISrSoiW=`AG9hSvgQWnB==|%KFFn?D144T^)14R^}|>46$66yq8$gjI)(w zX^S(na!9WBT#HGwN2GF>Bv)%bMjf8EOGkT`YfI9nNy@W z1#NwnO6%oF>w9_nt9qc)JHhJV-Y+h#ix_^dJbCN}Ge}9Z6TI@}=>@Mmd&Y^s=yz!J zg;&0`9$~b-^5ik<#(&a`xmTXNz0nWS(>)qSm^YcFb&6-+^lDffVcuNa&{=2LF_Ah+ zjAu7=u2$?Ox$cwXTrrhNvv;KOwGGQVZ>Bda@4Ok&&{@Km`iP}F8y2&~-V^Ta4V|Tp z{THb(Me>G*#pUV62#XK1M`i(X_5B@-1h0L9WVgafzyvK>2lN z`E^I?UB7N$hqr^@7XT%iB)Qv>eG*4bfiqBj(QF0ZWi#o;5E1+cTJP=UM^m9*E`MZN|LFQN1934OeYcc9YD|)k4FCb zQxfgLeu3dt=?x>WUtm~OHl6L1d#wKU`R}nJ`{pr)M5hR^=VB)NwKJ-^l4Q2zk>*Cj zJ<0IJ@^aYn9Ji3<-cHg@ju>7vg~f@@G(k>aI6}E52#X%D)e+8V=mA@6;>KpOO%gY1 za@*pI+hb@8cPC~VkmmM8rU4tnt%$75+=005%VPVuFiSa%2k$0uUuum%ea5h`g<&hv#@Hd2$QQ}C(XYIe$z_M6=c=a17k6MhIg$$lNp8So%JYK9 z1zx0h!Q(YbSX%d`NUFRW2Wo1HfoigBt;+Dq(k14!s`5G27fww8nxh@kbW|p^UwO86 zQ>3()cR=agKuMEG&T&}2oTw*0q8nA@8ZH?oi>_BrKQMaIHGZ#r$=jr=fxv!YR}Z>< zzrgWA4a*yy8!8Os3mFOx?blD}F{Dp9NlG_`OT!>HQ%dJ|=y+b>GEo!i&?z)%XrC)Y zDhI{Ey$Y_#EeJerD#@o|(Y5j!>wh71-jKo*TS}cOl>&j`EF?=II4VTBqoo)c+IwJb zpTa=3{mn<6Y~k#1A+uKj${nRVd`Pc?QT>Jw=@S?xrQUf?@g6A_<`y{RSEQUbl`}NB$2-j{atg8z03UfWYi-b2Uw|}3Z!-o`xg{~4t zp8>rJJTean%NFy7^cx!JBDV-6l9m(5mQw%RLXY@V;S}T!%I!7GYslPBv>t}dyeGvG zdBgIo(LbbASkP-kZo#nJ@W(A`8XK1kAKW{);NslE0Ym!^3%n8LW#nEtJaFV^9y94 zgg^XBO46WSg@py-a?OLB^3X7&o-l@a1kQEKRv;*hK7;ea!dXHWNSnfi0a6&yYuJEr z;b!wmUY`M!d|Jw4SGvavza(W-7?L~EI`*b8#Opo=%y8&z1f#w z7`wxa^9K#>MUfu0jgE{$2_uE(hgn^R=MSRZ-C<70ykV?W?O;=@-T5-L3eD8W7C)sk z!ySHZZoj~x;m_Ujz(32wn^!$jV7)D@kc_B4xxIV!xgyZ|&~OV`hR_AVl~_uQ1A~Q> zC>rv|un!mH7G~rY8Xu;I>$>HKrF>O^j5qYtn{K(c4Eey6I>y#zR^nXKUodyKd=SbT z7U+JM5s>JbX_+hkGi0#k2Kt8C*6DCJrPVcU7#6rU{6W_NW;R>VJL(w??S}ScU@O%Z z(NJ*I$dK)UuDyDnH>6N5LbbvlhXT8bXI4CEICYC9f`DD2f6?y8RS#BnC(levtV zu{>1_oB74^Esf|%yHT8k7_BddKQcqg9cS%&^%;Gy~q#$tI zA@Xs*f?k7j1DWAZ&Nnm^N`4S1GXLc7UJHR4z$bwkVwGPB1*?H;fWHDYtOTRH^76%) z@Lv^RRbU1X>RgCX{&QK^&EFQ_ufTw;#*zMx2fsaVj=dEVcnYZNbcWm@;B?5bo|YdD zxgy|AkY_zDkFOgC@K)-;NXWCEmd9o?unGDHK%Vuq{O6F{1?&cS*3Y1+E0H0@_dA|HHw51h^S^kgO7s{-!DU%8-jDUmT*xoGnD#wcHuVy!(6T$*OftAV!U{$B#Qw}1nh+RugqT}exAg4{M>H^{M`mj45C zho#z2+C!f8w0slDodG-z@~o%j&xKqF*bMTlr{xDg?pk0y$g`f7p8~l@fmI>TdRl%V zuNb0fz2yK5wO?RuI3vgBsTV4j-34Sw_wY};1di$o(zE$vxcInqY;Sb|Xzv(CY zfqt?buBVpT+xoRX^#2j~ul=dk$8rt^b_Y%c?(6dOyE*)AtJ<`qf`n%VE z1?}1Z+yqR@(=D~-eNFyw_}LCv2%HBD0xtvVR{h=UFG0Ir2CfGF6s5iUntbJfwnxqa zwgV0V>i&vVelzqOaD~;hevrk_fyuxoz#_;!1Jw49gIo}p1snp@@(+Rk4DbcuYfFf?e^p;I#AT+6 zALBU&{QoqbdrNWLWBY=$!{# z0sI)KyK6bR>Wa8 zaQaxQ@kQVY@GnJK+l#mUtSI&$g}rymu>T$84j*SdyBK)oc|rD(^Cz@;}@iHw^pz6${X81_=@<3TFZxZtXm@Yx zdkAq{1x!YqngF%^g)z$ag#0L=ZvVZovoMOicbG%=R#jc zU?*S~ptcgLJpK6+?f4Xa)BkxWFDD;zm7>^Bw7%r~Yzw~yCf{$%56#dmx8+#n^P%^4 zU<>GP3)EJ|$0*+#^5+6C0A2{x`eT)6dk=-aI}sPg=V+AA05*i&iBaq)THhwvZC-3! z+6}mUrf#_{$14B(1GZjGrGEg*wSk8Mwbi3gzc;W5a>Y^PPmEEX?fDpS*fP_4!1i}X zc_?rTA9(HYdsaWN!L0>(kKOf~rz{WtYEklohf75{z zAy*Vd{@NJj*`DK2?@hFu?SBn+J^`KzxlTasZ=&^8on3)uM>{Lg^e>M7uN1GYuIAW+MJyfK z1W?mN z@jpLC`JU*Pvldv(J%K+j)Slq;80BAq{1)Iu=r00lEAPZ8Uj+H-!25s?0JZ*D<%dAe zjli!E7sh84%9EqSE8hC`7TFfG0FDCQ0K5QrIZ(GZ-umxD@8`gRl*(ZflYk5B>=!OS z2mHLYE&twh&y`7IAweGMPBc-LHup8&P~Z86Gk z!8|zONvr9zrFQ-_dDddvC6?a}xCwH{p{(tnjL*ja>n*c-h6AbRsVMaasQS%ReQoat z=t+CZeo|#W8=s?rqn@(%7Xo$t`l!eHWyzlh`JTYz=3D*EfyuyQfZATX^7&xYJ;VD?W|egH6D`PMI3eLaDfe`d?$fm;8?G0HbyZuOl6Oora0qv$V$+zr4< zz$rlOPptB@S6F|R1KX~&ly=jlUefvSSd}=L=+P@>WSw9MatjBzI!*BL;_LHtZewY3H1|aRw zkEdXte(3t=Kz~J!Qdffv@#OlV1h-cE{Lpk`L^BeB|*LtNh@j zt)2xy>R$*uI=*9Kl-~gVzX!I2-_iV!RlXPWkbK&?Mk`K#JkePe-NcDLmnK-yVBdqDazwyl+a1b%9N_O|}Du>Tn_p!_=zesu%Z z0;WXqH-I=)2G+>5?Q07B^io?c0oH)r@j%`FMC&U)%i4b!cpkPTMC<$DOzY1lK>9&H2P!|mgxnuM9lu2D8xA|8 zfu~{~UI5$<{|-R;YRKIa#lJ-Bs|`DKfn(suWZ-4MJmBGwJ2{GfiPrZ-Yumqzf%NM> za7IJR`b^j(>-zl(j29W*AxHW~J?DumZ*CUF5iPm>n(8h0OXNwcNq72-cVapex ztm74L{UNw+4F}%T$J%>xsKwFX4+US_kGKBHUe?Yk;GqL;`6ytA{Tj70*3>&zh|I5V}WN6u$%miE=>gU!wJeV265dpdZSw zYf;wz#9O~xmW@vq@Eh3q705WfjB+2yjR9(Z60NTl>`?EU@Z)VD{aS;v_9x!@gDw6QRwl^k5`9_dG63FWeuR{$nZ+IPQ2D$Tr+J2(-eTaPHGvEjC=NsT?;1uB3 zklPK^{v}%9J+LzaSbT-;uLZ!7z?*@yAh#@ve~H$|e2sc9!8q*<2&xz5}^$f!e=B>ze~R)H@%3EK+_wj4aO6QH*DUX1b+Ab%}z z4&uL*<79-jHw$<()VO>`#X?vLe!&qC^`eT)^3w;fNpFl75-!{hDnFCCL-047VKhgSjqW#qSEc{poTm*a?NIxG( zS^Jl8eXvs>aa#^t7o~qHgI`|xgU8wUFB)%g6R`3%k^4VZ`J17C8t~PttzPOMjPeBF zU6A`2sNjZuV zu#Kvpit@?89*`^ei}YO%yCLFDwtZuPeZbEH>i(Pz{%qjp8*Tj(pq76Ha$WE_?G(Wt z>+QnltAW(JxAmO>d-Sg?`)9-`|0CL8AN3jmj|1xV#VY?2;`lmnJ#ZIL>yK5w{v_MK z!+YzaL2dg79w#_%-0)N|ZMOwZHv~Yze^P)Vm)2xdFHexDKfO ziMM|DDYpIDz?Wy(@&@1p;H|*EkQ)os{v=x8>99k+=fRKmz|(=}0JT5y*3X)3*RIf{RY)~DD1X7J-!ApL5JGV=%ep~qLE z_2nRM$psF0#P;vfg%(GE-x>UYC|?QG{v}%9v{}}VdB6d)ZFw9}+mBWLD(GdsWaw=Y zMgL`xXT2cg=$H1V5#(9#%O|Y=$@48f{rw z*N<1eA?(t=_E+nVRsMMR&$tv}p3MYm{inw$|HXqgZd-saU|g&NeuircgX z^)_G%?9z`c*ew9w1Gy)oT#pm2PhbDX!H3G=lEu6OJ=UKe?t z;dQtZt}|VLM*uqlwZF4s)Su}3`(d7P-AKYZ&GlN_8-(jAuZx`btf%ESK;Ocr?R;7d zd}>+b`4y{t@29Mu{=j_by#{#w^Y-)mfI}cR1*rW^w7y|Wto_lzX+YZ1_G6Ww_N3MS z6!7HdY`HB^>yK4_{9>!`2H+&%6rk20tNiDSto{t>YlD8f1lR%nb}4Ws+Vwi{tY>Zg zJYeIcwmc4~{R_Yj?Uki3(e+y^|8#q`y;$W}AfAltX3Vz|pw_=OM)@I-9|q(+y952z z82!R=I2v-(f!cne^>G|*$9SM$yxts-anus{2mCz-W$oW}&=XBxyz(0nx8022Yj*s0 z0#;sS%O?ZVUa{p6@SB%xxdf>F(VsVtQNPwlKl4`n+0WacmwwU?{bV~%d)d}wJBnVk zW%@Y=<#E7?uyYm4`?^2RF1PLZ4LAh-G#Qu-Wcx=V9@BxkeTmk08vGgsd<6cy1Y8e4 zN|awqqxhF-eb2mL<_sKQT$7^z7??ZGLU{TjvpX?jN==S`)3sY60L6u;`9k{^@o_x zz~P&0c{Z@}dRuM-EPT_JCjxbU>(67=ul3Q-S!@67=ZcU1>?iHePqt$-{A4>;LJ$4? z|F&221KW;cfd`-;>H@WY^F;Bq zzd7(u^veQZkN2$JeBddN>ju>AOSHb4utU9L;Kz97*GQDLKk?Q-`gPm>4#1Liwj78O z&r@QQe`B@P_a<;S;(k3a^IiM-AmB#G{Q%VMO|-trurm$Fal!e!6LCNAee364keeUH zzeMXB1UuCG#zyPMI^YW6Yd{^Zc6A zegxG1#9O}@{jwbR5bQhxyc<{?#eTf?Y4;`AXTNZKjYhu|0bhsQ=Rh5gMC{7MDZQS++>t`Fw}kAd7d zKh>)}v{Vdl;zWmuP+GVm@34 zOs>3t*yI>s-AcCH6nON0w%itY#BX-|E(Y$|Y0Fi2S=9dP&*QbH^|KvMZnyT?j&*1c z+d;c*2iwVZu$=?Y4z_bO^s*iMn*A|5Y`bRyoBV3aEr8nJ-DuB#kiQB2JRQjRWTL;T zLGDQ4-q!aS{G*?{lkE6Qf9*#5l$_&(%*1nPJsT3?M4YrhtdeyxIkCA;nC`@_GwkUI^i{Y$jI0@%5o_Hcb_ z0@U`$$0*<8C)>XBfSWNdN}|k*Hkf*Ny0> z8Nd;cn+nwaBwAnE&o-XzfF~jjrvRG)TSSRZy!C1K0@!C0*!@EJH4){3n1?f?%*RCQ+XlbR z_{GMLeld>pYbN}A9DZ$%;$Ncm-HLT>F>n;tVXn)1e9eea{%g$hq$>8hv-JRryMS6h z<+|-}<&LUuaRzW=HCz51m|WGCgD6jgUfTJq^>0Bt>Hkg2|1KyO0&j!=n}FKiZO~T} z@rb6cFZ3n4enZ9=xDat(57hS9?hDZm>?ii4(@&_+aln4u+xk-A7yT>Ce)AaRzd=78 zh({mZ}~0@U@jy{fgW{|5ml0Urcv z`9r`z4>%IYdO?(X0(JdYz;9K@+8qhp)zFrMDE9^?y8h>|{}r%)eQWn<;LdusTn**# zAy+xs^0hyS)^{N6)COJ)KWyOYM`FKiPm>B>`Vnd zk9oRA&ErQoFAH`i9BTb+0YB*1 z`nr~%48Ha!-ujQj{z{;>*8qMs2Yv~;UxC`6*^pZeYy$sV0JZ#+G0Gp>$i`#Rkrr12 z+c&f2nJ6y?YJ2h4Plx@Jfq6}>-BG{`fZc(uA=eeC{YkXGY}n}q+yFnm0MgINC=Y<# z#3=qHT3_|UZM+Two|R_HmjD|B(}8s$cRWzXFVXr=ft}NVr(s-id?llt0z4aX-J|%I zXnh~U&Sqerf7tj91D*}c0B(WYo+$n$T3^*8tUon@cfyZHfb{cvln;U2u|VCwiPkqC zb`}GFILi9_Z{Ql>C%|VR_jVNj60Pq;*!dJ#1Aa6FavpET{QU}Y|Bm8cqV-K|Y~ytu zu$G#)8&mD)TY!@x_b^cRZ=&_hgPpgUSU)Dh5Bk*v<(@$8PrUVihy7&O*Y*a2KLL0W zume#0vjhBkSkLlP&@P~suLQaB%J;@~?3ClI-s#6%oZrG?5%|}E-yY?wf!cne^({Nb z`tc%gRdZW@54aS5oqvMmzXrK4kF{m(U!wKZhMl8;^d|s+CW3z_@Iqh+sQqgJ|4#-s zMLSPsd!hFYU~9;A1@3Kq4;*dd`Y@3F@HPDF4J-sc2Dz7j+P_5Ws|h=`fm1P#9{`>T z>;S9>xfW6UOSHaWm~SJ2^o#TD3ive+I015Z19kiot#3K(t^#&D#rF51Z7jY4ep~Rh zKk?Ro^ki#i0dO(!DWJ9&tNiGbtp0_-#lR&%tv^=zUrx08>q1`(_}w;&|4EQ5ul&i- zKNt8+YisW{;Pf+W`B`9R;5EQ$r`gZH2kQ3DQ=e=7@ycf@|I6}M+l#mU!LZLbHbK9z zpR~OuG0MN%(#H1|PngKI=6=zZIh19l#?|FAd1+#1T>SJpn(W>0|v8TyJzd;;lad?f4kT zIB=Y@U)au?@M9|Q1I(+RfZD%lW$35Amj6%sI;r;P_UiV;Dt|Tl{Vw2xK#p^*zdf#B z9f9lH+VPrkj>S&kKL~!J>t71JgQ@>)Yd0CF?L7^D-UDt{^|buUG0G2ud_J%p;=p(` zhF>QGuY%k(pthfAeZ$~S?elD$CIS~;WXnxZ&If9L5>@{y_;D-jJ^(zoz4fC9a6II0 z2S)QJQTkTE&Od=I5Qnx=;;}A9dFt)b&bIUA4i+~6>jV1$m!EGxZ*YM{-TunZLw&k_ zyz(C@``TZvKUVp1@c$Yh#{tLVc8r4>h{q(zJqpzJ6RmG8?EDKD#5m{~WjuTkqdfIy zp8Mx<@Rb?|i%~ur;~*Wl0Dja!Kk0a^RiAU5QGdMh)!;Y%=eVW6T7RtaZ$bY~U@KfF zc->$-PQTE`k9IjuFF>4%qs*VZt-lNGP6E>Zj%Y_&{_FS+C_|r?pAe(`O30sxd3OZ- zq~F^S=Uu=DfjptycG$fOcs8&oia(>ECz?Li@4c7m zzX<<_USh}lMBuK@k=KV<<@;T1^=tyxfZl$uRgy_)z{-AR{0yF_(wZh zf2{K7LOQ4op2K*JM?Zqm; z8sqa2==%Zf;5gFyW0em;-$)?i#_|6G;6x~y{f$+AIP`x6?0Koxy9l@v_73kF+1@AW^M_P@?O&|&cSP}zcC`Lj@8ItSa$M{}S^M`y z8TwfNjlERAE8==BaPjqa+}69n;>s&5t_Rk-%$C~&b$j&ZTA!Au9@?SZzEl2emwFOi zzvOCbr`t6aUk09jtu0SOc>z${KMZ_b{{!&%cKtl`!*#$S^waIYeBe}|_CMbGkHYS& zz&8=Mw}CGM*8sKscrGt94r?Cb#c2GWm< zA(so({v=x8CfL~tOuEj-voer=?v4_lcNLNc5`5V73^#T4gk`RT*!?BYJU=~ZyxL|izUI+Nq9ry+OqMu73w>FA@iPrZM>?HTHak~fp+z*@zybGwp6^OS! z?bd<)Ww5grI2K4h8bR(Pp!O%x`Y!BkS{VLNwmJ9 zxz?Ylz~-ZExg{_ScpOms6K{Rmy$$v|!cG?OU?Bat2Xc#m+Mh)0d$XU7$3|dx^jjA2 z5@06qBgkz7YX1_gk9Ky#UJ9;LErFHBTmS0=cSEjjf6LeYC0buA*y#pbg*dGSJ_mdW zsQrnzKJ8|~{y$;oXW$$l{pbU^F+lB4qV?T8!1lvjU=#S03gmU-aFn$_@z$r^Ct$zZ z_0}JrJ59OTmLCExf!tc4_9xN$-psT1Hvn(OxV|6Qp}>AV5m=IM%RC4D0QGhbw0!OF z-qxQAyQcx^UkjYi-Uj}oz%1aEK<)1vH`;a_caz0xI9Hhn(w?E{L25zTZk=3L1$0}dt7OUq9ApO1q{y%@4{k#dv zhu><;X9BhTv@-PV?fPG!zuB(Uh}Zj!n{v1$M)`XnKLfZ3ad;7U8*mm8a?60qd?3;K z=to2J+all+;2_|9U@KsEp!V-$w1fIsf8t+M{|St{hwiZBZY8k&-L|a#ja9xr^i2Rh zewWqz3a|(8e&GIh+Rt-<+WzTEpROOTe5$gq{nh$omEVPUGcKFao)Vzezd!ipm0t?| zZ_^I?@p$0tXy0d1;u~*$>b(g4NxK|R?DrZ`#@BD~tE~E;K);Sxy!A)IuN~9vIBar{ z#gh9iYJ0KDe*^v9puaox4gjvY&)TVl@*ddFx;L`@>d-@dy1w=|R{2J-OZ(bitv^=z zR}l}!Wj)%v8L0KY8>2k?XDsTiMqD=n*Q0%318;;}F;Lr2w7yp8?*%~m#qstW{Cok( zaq%pbv$F0zb=Y@w4?RMD&G$J8HaqdXChGR55_3Z{s^GnuZYk7=)dYHHvt|1xkf;3 zKhgTGLBIY4q+c9g-@&hc0XZ(VqOAR!QHDO&e{L_;zZh{n=OH^@djhx4iadT}m46oc z8$<6!(AyXI+r!pQYm{e0ZZ}ZJ>qDha*N<2JWo2LctM$h!KOO!vE)!v|C`x;0$0*+o z@>jAR;<^r)hj>o_>h{E2pL)N8e%j@DV!uBQf3*F3QLn7}JpV$`4L`s?7=OONAv030yi zmbJZDuWjR_~X<(ZFTEqvqMq#{;$f9!j6CAFq5nWncTN^~Wk-5B@VQ0oY59 z(%z$Dl;4E@{0Z0!{dh6(8`#+s#a_JisrL%>C+%`PvEPr4GQJw1URm}34LRK(@z%cu zeqFP`j>DP2W{V@whgju*h5iuqPF`g7&H|ne91Hv!a%U}!Y`+0Mr#@ZZ7oQmAE5R=9 zYk#%=Smie%9*oOM__rRY^?x0s{B+1KVm-w5K=kKav~NX}_{LkGdXH6hIiA?>-{EuJ z-VfndS@mDoOZ7V-PMv{2EVtwEl6Nh32md|rwg2(fpZkKf^EB{T;Buh07pr{9^H%?M zV1s40+z6NqtOwNg;;p~zIcx77;Jd(GKy5Ep`B~7zdOgw3e4y6f0P<%5Cqk|$ihQ#e z<$FGB+xr&q;?=gC1$_8bTiyx0=w(}e45)t+8ks6ACVu>gUikMJ?Sb|6skTF~kiAZGZjNYegN^4e%Tl;qg4R{0Z^< zF4(U`#utIs@3SGsrx8CJ?8|edK41R%k<@DnZ|jAd|1Qt3Tfv84l6sGV1>jQ9)(y$`te&&pZ5nb|Hu!eKNG;=+?Ou|t)I8yyS*-X`rOfr`TWIo zUY|?!Iq(Ip_a}h*-1WtqqVof2>wRVFS^fXD-ZbW;^RxZ1^9eQn0{XlO)cdIR;br>v z1~?IX(W9R^HRx%6;lGrx_x+h~$-2MDet8+Z7<>-2{i{o!=4;eG{B<+;?Ku4DeS8wU&2LGb&3}#fe>-2#<8wHlM}x_r^*e#<_$2VV z?_^!4w>l^ong#z6yx;jhZJ&yPRU@UQQ z9`W5mjNe)&^WO_z|Cfvxf~mjAcm`n*0vy`cJcqpT3a# z@zi^0kBpxNcl<8nwz~u$qK|99cexIA{7H`6etu_;Tm5k3Bk-;MYw~OBg_~bW|Fn+* z_H~5E{{AAw_^XM(4qVE4z8c)}v-Euzcr$U!Ks#T*^#)Vt95C){@pAz<41TnSpK$X# zp{qK@^u5HR|6gwsf062k`)V`L_UqfvCH{Q!=Kd|?h`oZ}vJMBs+x!OP+5Bb1|J(U* z;9uuayj6UcfY$HFA;xDCKNbAzAi4gwXdqY~5UgKIa0YSrfVRHhdOvTJ`8J_mxz5{T zy-SJz4lE1_GJX7ELv;8}qc=dHWpL2S7eBRl$ zLH1V!c^apmldS$t#4iN*a@{(fbv}&qR?p*1&RabX59PWt2-NFL3yKel8a>UD8m3)zpwpw+w8=pE?%G1S+2UGRg&I`sqIKf$aO&l; zPjug?&x!D}IA525*53y;=>6OIms4Nobvyg$0gwH3V~FwHi6097#(k+yBUx9yZ{@+; z{)C&qf%j{*sNej1S-+N`zK?6h*wzm>-@gCTeXINWQM0e7;`cVt`te)uZax>c*eQL{ z`?S8Fyn2uD`nfot@nzsZFb}kTSB0qWcmA);>k>YHuKH8vvjtqWTgJUT{Qqi>e`xZp z-%#V5;>-HeI_hr&K5V^k^MB$!+@xQn5Bj-Xuk-rePCwVT$H#*nej1|VrKkD*{-yi` zyKZftZ*!ug#Ft&ON z(NR6kf8+q=AKFCLo<7rY&O zhPY2bt9LlO>S_Lj1C)O&&-u?EBJ(K)zvx_j|3ZyVMQ?`cA1%6NpzTL(;*JH&HLiX2 zewu|C{|xgj0e?PGbn7$UtB#lPec+qKZ3L}fzxBRgKF72cAJH8Jhk&IWWLyr$9xLMn z(E9URuQR?TgID5f38=mzjuT%+_$u-6=eJ%&8>!m~46tvG^w>Y4#>XBi`d5LCPLOd2 zFp7D{fx0dQ9`pBG?>2lr32y2n{>s1)!OuXuU&77Tx~r*wIeobSeBStYiMUTd>&I`s z;}4U5q=NDIQlGkSbscrzmU*n7-+F`EiN8d!^cWd`0~SWgcp+%}6>feZbw323;k^C` z)P0@B{tnQWNRR&bt=IE#ng1|wA$@ra3>+!P8-TVy;pXR4_XRM4{X8Aiz7*0Q?Mtjj zfBe>a178OnA$?F^3-G7Dit$%~uObhBe(Np8*UMl6>y`%&I!b)Ufp-1E&ELX({tqys zi`44?&NxZN^T7t-6wvzdTW_SPXZ_gv7vMV;ybN3b+W6FyWqz69&tqkL*ad>OjuD&z zpTPJUu<fU!|BUfxacQtFh0|9|sSlmDH}^M#%=U+vpR^iTVyeN7)J zaoX44N67d>c-x-?rN5hbSik46?&`N8<5u8L=ZpV3j04?e+#d9r&w;9^eh$S?P4lyU z!_C(|bfW$l^hx`=iT-IH?_~S{I2*hb?1j!)kNzI$dg>=`Kj&xr8*aY#A%Xg(^hx`g zVfxsaaZj)%*a6Hyr_iIn2fCj6xn@7-XZss&zV=}O^%J#E;NJ7(eAhm{!1zt@e(-7V z0d(H<=67-g(Dd;c%>-Rv{Q$LIFQ`7vc-*EG_4-Zqn=VrhS~x z_%3i7cs;lpozFn)_dwTEKOgMp{H)(_^R*9~ssAQ@(!QpcJ|52aIIs?Q2)F~C<~?Pd ztltA&PyIB&Pfhc)e#6bzKD4F&82Y4r-NENd?c;-ti@_Vgd%)w+8RXI516@!3oUxzt zv;7S>U;8kO`djFe_H~-+gO^1)a2jxH{AS`UUHqx0rkDqM*4Xl@9oxt zGl*LZT0hD!<@l}Ssm>6_$>8I}{dj=%x}GBQJp=sqA{qY-o&bIT+WCc>Z}n|`Tko0# z@wW?nu1LnOgM06h@iN9Q+$Q69z|~jD_?fE(cjOB00&P8eJluL#U+3|kOT>rHK)TK)7}#a|)#ChJ!QTEAC>7~gN6=uZT-zaO(d ztp2DF<6pT(^gGWLRNcc^zucRJp9=N^r+~KpH#O*m8=synex`s67Rz`UICO!GlfZo9 zZU=3BzxCdnBK6mT-`p+Z-@#+&%lHiNBjSDltv|o@Zl}(j;3|B*1rEp86!2c+Ui9$i zx888-oCluIx~749xDH0#E`1zF++`mA{MNfSOX@xZYTtC7Ke<_s?*x|<_W@|v*KfT{ z>g0lpxDGuEK1ko52QMS;4iA5R>vf>c3E-XVJKcv5vhPa4XyQhB`14!uvP@aO0iJg*AVvrXxGQe(PPFA?ud}_Qlso@MqTbVD8hG5H}aJ>+82(6m@!lO0c}AjhP|i3&9xhJka(l-2A%KZw7wCbBaE1&b>+ed;wkzW`nKCiv_K} ze_MZfy7*fOCg48{RG&JJXNda%w0`~8yNNogyQEP3-Vfdm-VItm;pU&f^Zrn<75k_) zSbl~0Y2mTI!p%P-QS^I)vsss$z`57S@w-7g|8VoiXcv+8VQ12TlcME^g z^@2me7~)2O){ozM!E={Lzw|nI@QpG)3S3Xz zFCPB<*87V(wUfk$UYGScaO4fbpAH^OTnEsuuitu)QfCFIpVK?jM_t!BtnX^#KJf78 zx87&e`4UuLr{ix3eMcqYf_{?4})tb$@o2RDfl*M*E8JwGV1;e&gD6v2(FN>JA3=y7~m?-4@oR_B`-vNKTL;9xY@vFpb_VDMo-gng5 z0je*352e?YG_Ehd5!WJ3eB1T)TkmA*bO+n<-t#1ID(_F`gMEk_<>Ak7y>ZkT59)h6 zeb1b z;{E4l;`Vs>^II>T?=NS77qHL9fy2P_L3=)go3C|eQ$LA)e+Agv__&t1M?mYxZ@o9E zvli6vN%i~S4!6mAW`G|N_cv($eQl0w{yF5^_%)Y`{x+kwY`e&=i5@2Rif zTk3Uw`<>$NZ*V7Z4W|lk{rIi7jyj)#_i|o63C_pYW8h}u_IUX7Tkqt2=|gu=&-?H2 z_c-^**TFu-jRkH0{MK7XozFn+n_j0*!{=CVGjV@;`14z@?KJ7%5ukpr(3R(lsjRE6 z^RdL82HO7lt(Q%mso-V!((n1#E)@S;z!}6n=;6g0lYUi`^^)9-!td!);VyVb*=-+FIR=RHur*VlEP%DUbNt|RVe4}X5^ zWnL!hmka8;>T~3ocgXSa;AO-u0PXtvt+$dot3X{>{hsi6e5ubDiTlLEpWk|oFPHu_ z2labj{hswKzF)lnY)f1$X#3~4-W$|;2lV>))AW0b4~hGahd;mdvbb*C1nTFOQ@Os_ z{#+hne9L=feVQ#3j0D#{C1a}}YW#$UMCS^y9Q~icQt&^Ztru?oQx8i0XTUt>brra$ zSdK@m5G)~X18DvDt#>lpTYW%kkNI&aS=O*^q&0rRIqsRUWH-FjvQvWef`~DF9KY@K03qDEQTF}nl zZ@oO~Tn^sFzPlg16<+JkVtgfN{rRmIf1mU(8GN3;>Gf&(aykAQIElD9p!MgsUMzJ~ z_b~SD5nwa0jmLftH@}eU_ik|flhTjNz~7&caU|n9j3tnmkK!M+ z^)3rB{y5@K0F&5HdS57@P7xSQ+yKzl_ggQ9>(CG|5+AW1^Y8SS^k)e89P9isX#MsK zF@7)S)zMrJy3wz5K&#)Fxc!Zv%6YK>RNV_b^sfvtei7Hz_rdw}Mf+s^KNMp8*ZA!F zjI6^LaPy}!w)&yQm#r3^-Qb$HWxNT@dR@l(psg2f{xIs^3|{@A)GJb4E8`L{;T;(l zfYy)SdUf&D42=Fn>h}fP;PXWAg%9L-fN^Wh1FheGTmR-&;^#K7F}@E6XW@4Nco%U` zg4VC!dfC)b-Fxxzfbn$?W9ui}{I1mR59V`z%?53~2E-i+mc1nXEeCCU?$dI7BiNOB zXx|e{<@jshA8TY>_boxIcS{X=;l__ZUwsEk#76{Z_2WZ~KbZIkaQAxA*L_)!{u~3g zA?`%b*7sYlkahnM?D3KK8wSSebqI{*I;7Vn>(6h!h-bx5C$N-#@}tLo2{rzy=S9B+ z{NPg=>-{EugNzHnX5a|$P4c#Ywjckt{+JiU-y-mQuESHn0@kevjAZ?E9j#x#^)}$^ zC$NzF>;qsV=UGRO^DW%`$QPwQ|tLjGy)Jvu8i`ej)!r>*a5j`7Q#B zzLs$bXxHYRL}YeH~ty=to3V}pRE^e{^wsxKU&i7L%=qmtru#1 z9QxT{)K^k37PR`~LX3|fz7weXqy_usR<64bgSK9{`CGq``2?t6#=Ocs=GTt+`JkRh zzp>AHa9`E?*%@4q?gXv>GmW0j4>$fIQ{Vcv`k}_}*(CkbzC_TsNRR&2XTJLzzYP85 zpzaI3u8m}0q=8Qn_Yr94=eOSZ)EN(6#q~~~3;yE17Ky*rtcTwB(#X5c!|%VXpK0n_ zzqWs85U;*USm#oY^*);TKHyT~G|%eK-YENN30TT?zue>gI4{Kb7~)5Q`W&X~_7L}{ z7eMPT+nAccXtVSd0F206#id>U{$)BW@jN>-(*j zNSz6w`cR(%e6U-XrTXfO^`uGw9#L_|iTmGrj@Tb-dMMJ$s{n0r(hk zZ+OHH3^D$`-QxctuoLG=KX4W2$-Cfk;z~ig{(kF?q0U9%NPJBO+komjiMXpg{Q0eS zGIdn9J=f_DU<>dl(Dp0b{7-ku`bFR)v$>qFMWC(Miu+6&I1gWX{SG&N3c7QC5?|Tq zYn>?viN69cDj?$oFp~L1f!5Ezt)GwocR=gk`Uy3DgXvFA^VRq-$@>w^qQBNpsPVc^ z&!VUM=1KO?`K+JzA*QLU*V*8Px-u>Udw@g1qxQ-^IF$9Ze*f3?tv@^en&xNcV zrhm4-w*KEC#y>;+=iry%4$$g{8b21DE5U2Pn>_SGjo1Bi4g1&b*X!YL_BdY_!R!9F z``ga{ed2!xzvOv$GpNtMn;83@KXa#?PuGBd^BmrR^K~BltDvnPZvI+yOTl>R>U~Fj z^n(9{xE&sT{MKvov-GD0sLwI_+)&RvHylb_G-&(fx87vx+yuVCb#a}?^>KQL@v8e5 zd9jV<`kV&pb6h#kb3^&uv)tqJ&vJD3SI_n@-2AJ5k@b8CEa17I(Bt{w))3=W_mE$u zPEmd7S2LbZ^ggzf`2`qMgAKh*eK=6wx#0e#gzTm83*+XCu3 z6nU(N#%(4375e%icxpZA_XzMu;_Ce->tXBrt=E(~EkX6Q1%H?0Yd&}waa}$9`K|W{ zb#vHP`rLdc{*u56pzhlQ#bzVAeotMu0e_ik4lVu(+feAfioCR8c*L9KO^T0-NGHwUnHB83K!P|&? z4E(qCCQ(Oy#^GZm*dH7UT0i0Dcc6YJ@DS>B0G~fs`tu$bMcg3J`te(@K6O-g!cg&( z23`mzf!0sB`HMSCy_dn#?lLX|ZM{cBj6aq5Snx#lWgl=i>!AB~AaU`at?#$qA1BIu z_kw!fsLyTqQ=j$mb)<(szx6)Hm+GF(KJ5w~3w8!=zrxMGo%)NwMx&%(?Z6cyW&A3* zgt%uw>&I`ssnk*3_wez7@%0X4>nGg&v`#Yr$>78hGM)u?=_li}z+B>P2dy8!_0Fb_ z>JG!l2;=J<#@0```4@DQ`CklvPG5ciV`Am_xnK%$SAf=!-+Fzhqq<}9agp(L9%Jh# z-2B&%m-)X1?j0iIX6FblJ6rH2u#~v%p!MUo-h z=XGyz%pf_Q0bWnseW2}!-+GDEQQhYK#ZN1+KG+nre!|VKP5skA{d{)hDdHodt6&^x z>xY}afzP=c!7o6qZ|j8`KdZg?F9nj4t{G!h>KMt1Tb$C9wj<|b4>&I`scnGg&r`yRqp9Sl3Ug`V0v8T!LOz>smJ_W5Gzx5VSM|G#;;|k+zDr4&>-25jFllgxF zMxH3+9$*>IH~O4n>xY}a^-!tz9rz^c^BSo4v3`9d?kD07#;^6`x89r7Q{8j%F&tE1 zLl|2>;pQJj{bRuU>5KNM*QwH%q2LL`oe5e$e(MFOqq;p$7eBp0eLvofvGo&f{_Aa} z-WT9Q?AK-BT<`(V)((_6+Rn$@47BS-Y5KzBgX~x+42{*sIwbc6s?8|+1I5>p+dLsA- zaV;pX4Zd%f4e;!)BsJeO? zkH_~VQ$mbyb)NLQXTD$@cz5lCt@YqI)c78GqT3r>@VAVYf*-ys7I#9wX3)=#+kqq0SR z40s%U(LSwyNRGb;#uGOUw0`{7>p>mW9gUAM;Mw2^(E15CzuOdb!=ADm3wHK6t5 zw_ZQ$sP3v)#m}?gqu`UE^%HJ>?@Xz8I`}O6=WTHQD{_1(*q^v@p!MUo-eJ^H-DrGt z2af~0fYwjA`AHcv|5WgvpJcoO{CbOw_kfwiT?<-2e(Rk@9o3zVk1Ny&I`s80x6*`5%d& zi@xQjvS$8Wvn)KT5l^yLNcG4LtS`Uy9G%s83GT5l_lE3QQ)h0JMJm*6T$b)jj_S@pBP)4mb+5e!|U97VsD1A}$c#`te)uRqCm3AI|ew zbKb`=wtm9RZ$ka%pnk8T@5%Z-FMSvbwk57BX#M!Dw{48nSKa*QWPAlU8O#H%pK$Y| z&y#vH!6WXG@i;K@HW|l&`u$sRzVOzMe*bnjdPjlBg5kz%-PP284lMET6Keds=(L#6$# zxRba>)5WLt%$q3$ZM7jeTu>&I`s_h(8!%E8&+%J>>^DmW9g ze!|Vyy1!Ci_lzUq z!6C$@f!2@TdIeX?{2v6D{D(1kJ9sx}{e+vZbswgFclM9&qaUbSoBR6;;@$zRAHVe? zuaSOq1WyE`KwCf5_|wptqq_G=y}4k*d>Ow4+Im?ge~`(y@$X+Ndgb7NTJrBJ3<3Lq z{XoC-weGLfzmGbrz#~BQ@h5SIT_?V+AHVgUqRvLJ?;lck0N4{e9khPJ&DXkLQh(lG zQeWTOwb?D>lfbRom+PzVkKcN`snhlbsrMZ|egwY+w}G}l;pS`I!>NDQ9`Ugpe9QPa zhPcx}>&I`sx2f|jxcF!BR|L)n7lGDKxcOT5N9xaGpWY4DqCdKiej%>$jn(fTzx95k zPUCq}Z|(1b?}IOcZ-KTy;pS`I2WEhhM~BNANJP zJ!t)eo3C}hq5h53SqwG+)yEIS)xAl4T0eg4eM_ANg;Hr!52a6C)|9k`xW(X;eM|7`9|hG{~d9) zZ?1m-_^nrZht$~sZUoCf+mBG=e?+I-BB@h)x1heaTzZ#`>n;|w^&-jB{4$eo=@=h3#M z#OXW&2g_J}{;%t0MT?)C!QxY7{1RyWT^?fm){{l=peVuLS?Bs5`oDx2zlMGCJy`ct zsnZIy{?~^X-|ukI8wjq8k?}X+1K=v~T;e8xw!Ytb$5Kai)yGTtvGqfZU)xUR`w6%g z-R7+0`@Q7&S718$IQRv5e}dM}zpWqLTKx3{r}mNYHDDX|+ezSQ#Ek~6U%&NQP)BuR z@X^Qk>cQCh2{-?VL!=+8!E*Yd=TQlDKLsxWmw+#kw+*!Z{%!rcTZ#Wyz){D@_&hKQ z906K?;pTr?SL%HYrg2_e2ENrvjvs%5;P=EeuP0;c$8WtN>fH}cWPSBK7}G_3WPpzl z_bO=p`K>pLI;yMp{RMjeHwHqD?}z?4a9cB(@3-I@@Eg#S3xu10PaUauAGnPEKLhIX z!f>8%9wzP;(E9OPuYfwLt3Jl!$JP%u{!H{Q0PDDn3#_$zTunhS6J`K^~rorgf}+qv{_ zHtTjjn01`^nghmiT^i$YeVS+VYl^q}){pJS>*#+82Dnbu2Fs2Tzkh>%=l`j7TSy%} zFZF#uA9Ux4k-lkv^x3vL)K z_&ZoSM8<)01WVDG)DPYiwD~pFGwA`<)w=5QwQ*8UeX6ed)On~+^>Lu}*Tjj>?cm>| zWZZ;)T0iSTj6dRB(K{W?LcajC`X`1M{{!pXc&OBg8zGnlTK(N2#_RgdWdCFh68&pI zs~>9o!|1L6%g2g-oeKo#Gmm0$HF0Y}TiZXEw zE|mHQaXmO|jEpY;ZT)cbTMZEXcHm;xWhFQiOat2!7Xw;9e(U8@=O!?Ar1H_T z)Q9S*53TdR(u?)*7nd!4EC-_|%Qy}kl_2BWzye zOg}c7_~#gxf;Rtm_MP@8!}N27>8H)V5Zx^BPEdVc#<&o)`G+RTdPRb%?1M?*g6q5fMlr2ePi zht%B;E+wu6w0`{7Tb?X_-Ua)yPX>T7V64af2{&Ksen9=#^2N``U=g?y+(2A8X#3;0 zUP+4h`4UW+F5@I{G&l~le!|Vyx?fZOy33^gA~2u2^T6+kt2063tRKJiwo<3wM5%Yk zG{LrDL$C#C{e+vZbq}Wg9`=dW)qS)TK7zQ8p!MUo-d^g|O_jbpzTV)$CfBul!6x7o@G-6U#8{hg8(ThQ^Eq&<(w#${{Bf#=0GLH3l-tt>71%J~)tsh1G zkKw-s?*^X$?R;-x-z@|$;k>*YEWcFdSD*RcL);4<`_*r~P1N}djK~o`k)WN=cOk~B z?!+w7)#s$C%=-qOlO6?ay|(1p{N@KJe*yK&z%=&d{a^r$0E^kLx^L`!ZkZ{4XvcMN zI(P+m5;zsK`72Dm#t-%>{>jZ)&@m-<#82U`Cx`r7+x@p~!#e-N~O8WOj^ z@x8AU-P6I}Sl9aW=hlbh_`_g-;>LltzTbLRQs)7%V7~Y%0&V@m5aU(%@T)}k*oOsU zz!#bKW^mbqa(o?lD0mBK{luE%RzKYMwai!j*W}mM3pf8<`gRMr@jmHKoBIXz{Mo?y zKW47*#h~@G7oGZ7OWZA7Uv3BIf`wog;`)IRU`y~o>#L7})cRotpza zC9fXipBVoFTE7Rnp8D*LzXjY6UjScZULS*fh)V;lf4}w8u9JQ)0*~Z5pbPlfayj1Y zalvx-MS$zC_2;+VX6kg(r})_h*McbWKE4X!2bYtZ`fTW|6WQhzZx8DE!!{peFZ7;(46M}pR$ z-+E_LcPME6#TkFrPq_JZJ~hoh-}JMl_+sMMfL+-K!$3QqP~+>|DC>0?Sip5_4wwMW z@VK6Zo8ObVL%}Dx&g*sG&M(yXap+zS&PM+#a4I+xwDrQx*SZDNU(fwR?{kU9$2G*= z16n_R>+PXV=XtUZzT~+}-yi+?gz(+@d>47IjH5v7&u_i@)IAuq{u;xpKkFyld^?|- z=3kFKYCmg=KZE%5wEy&5`)=nGYW$7pmVl4)x&1ltTb`?rDwcJPU|rR>t?#$q&(!}7 zwElJ*f7Va9`F1`v&3~ckXHD^C#P0(2x#er_OLjh?#y7Z0*6nz(7Waj^;BVCV+oN8% z`C9ix>g#iXzK=c}A9~;FO5E9?oxk6DA5o_s?+^O(+%gJWtNr3ST*PxrvB&d^-+Jq* z|0!tweQx~OeubNF=Tp=CzcBr*DgF%lela-ZG1;%V-~=!OwDSu$U+a#iepBvm`Z@jv z>fQ^c5jP98e*D%8+${a52kQ4Z(L5*gcwCMT0UHx{ENK1ttv8f9nP3#}U*hyVj4^OQ zi1DiXIeGeCS=VVa_ji3y{sw)}`_?S(SATdsk1RFEt-i4z2sQo&e5?PO{Mvfq<~QYg zqd}m)=Pu=aw_e8@-y{3T)<4DMFC3>%C3gcR}l~)cCW0!p*nyscHTTO+Raj@3=_%IS_n=`~7mT z2wV!<`GuRWb%#)2?<@M=;X31E1aX&u){ozM7v3rTnFs25qUX^F{(YJ2z+(1giO2r* zTkj(3#)H=1c;nCZE8KiLpPJ@B!Su7Hc>VWe#_@fCevYho@67&~3F>qEG>`qd>p@vh zFFo6zP~(q#MDz!N)1H;FeotieyM-8k%A=x}2kPgRi>YJv2Zb2_7N5(ugZjO-zDKqC z>q3kl$bIe#P``Ih&;`UX!u)A8Py|&x_8rVDhUnz5?9#vW!oEMevW81jm#J+WNhXp3M(8zAbgN zzV&PMLyg}_zqK#1%r_3S`T^#!|Db67yRJK0(|&psnw>UL5;t6gUZg z*MRHT7vF;y5;qgH{`}T^kUDRHWvq+tOI!cR5aU(%%ok;U>%4WH^t{kM=y~xH=ZCGo zmHMh@^TUmwNL{UO{aXD{<9l)buLR@R2f8oLV;_tKYl9;}TYq#7dYa$iU&;@3$(c4e zH*vg!x!HoL`ddb3Zc3Ml8F^jC=cT15pOlsy2#!({b5a9clBZ=jnS#05a^%vK?3}dB zj4Fe8=U8@1dZL@aZ&~TNfi7toY0f`$Q}UgEPH+a!vCQPe+{8eal+^eM*@=@=;!~5I zTpb0vB;{si=QsrgE=h6@x(TkjlN)rBI5{oJsh;U*I{)YrEF_}ibDY$q%*m5eGMt0S zDdY1d#wTVcW=u?RC41i1$`n%IC{WU$)DPEzK zJ1y%UEh^d74|UwmNjS*)|Jo!L){F3IDrNezDt7=SMLzI0^(@|E`q!hYln=zv$dtu9SSmh=CHR^)+ATpJDRL z#!I|nJ`WLYzS|0$pYL$4ulmmayFX*ntD@EsR=n!(F6KD@UpYUEe8mJ6Cdr+v`@=E? zW;nlB&M(al9u6q3e!c2bkmgBLAaJG0pBp0!uE_S$@L;bi2F@?nk+17nM80C#k(HzW z@vZE9lV5PY)K_fmF@Mc3GWmt$Bwz7|V>MDx*H77p$=Cf+F#Ckyp@P|>WBXnKf3R8q!&e-)IWq8d$$?)0^#b3!cVSx@CrM}hGJdLmG z5SDX~jV6Dt27)%Wl}G+2@|)hGXSN8~{78@d?=z%vU3KGl)bHYve?*St|9N!Pid9E} zz$xV0J{@|ST)DozxoQJ6U$H;=Rim8y;qlFa)PN5{KARMPuGIgA*mp;!_jjtEb z=ai~^{fg(0s{BC}&lgqs1_6CusLCH)@jOtKZy3<~dsV(s#eKUf-#DQ6X@4h0Z@~RazH4?=OLGz;3*__sqWnEUeqaBOIJ{doj^|d5f7$t^y1tbXUxd$VNpKtN>O|!VAy@A} z;ACgwE}sB@3h@c>Mew8GZ-x)#389Z4&%s9+ek**W;hQBU*Cq5(KRp%u5DEP_F z`nf*?;ftor_l-llZfvFA2Cyi{_x|`i7`6Y5uZT3>J-Bl!jD1c zefV<2?|_dhkU))Z;=HVJeHO#_M5haUIec&ULGV$tgt!qt4ZZ~aHu!7d6J`sc{6p}8 zIl^B<{LAo#@O=Cae5vtQN}%$);j;|i+PRPh`)~M@;p46n9qa~9*LZmMy6pap)%dGr z94!#YhcARbAKv|AvTogS__N{fhmU2Vf5She{9GZr!oLGw0N;dtTLxdqg?0q|Zus)+ zL|_LxjSr>|*9&n7@%`ZgETDV+b$>2|Pnaj;;{*bE@P+Wt5Pt)FT%iPZBHsO%aNRx> zz+VKv#o^uaWdrxSy6{If6h2}52|*?neyqa>*Abmj@I}ObZgjqbk2E^n8i`JBs*O~AQ3_k)s!tmqa z+ZsL_KGN{B;X4|BK75qn?}d*s{7U#(!@mMQ$nYP+#~FSL{20UUgikPh?Fi|As^MF} zXBoade7@nk!WS6+O!&Em9|2!z`0?-y4WA8PWcb`O864PzXHF; z@E^jL8h#7>2E*@!FEf1Y=InpNw}3Ar z_}TCs4L=_~%JBEX#~6Mke5~PLfgfb}58>kszXg7b;djC(7`}E3_P^m{7U!|!@mN*#_%7)ml}Qx z{077CgfBCE?Uw9+!?%DhH+*~eU54)pAJ}U4KYRnjkAROb{CN1bhR=qNH2iG%k}Xy1 z&WG=4;_rozGW<&T7{k8;A8Ysz;RhLh3w)g6cfyY`eC<}!{{+LgfKN4id-#QBzR~bm zCcZCxzTt<%7a5%d_yQB31wYsD1@MK2FN9xc_#*gX!>@qf@I}>id;xy7iGL5i#PDCj zuQ7Z%e5v7U9U}eTVE7jBMTS2HzRd95;kO&UKm1a|p9eq4%y$BOxrv_&zstnmr@V=O z5KGMWL z3BSg?S1E(biWW`iB1!zOCVZfR8bJt+vviL8fjC_$)K8BDCDF{bWs@I@y6VCO3|_xez7^bdiLH1ll_-@u%| zUEouV{u#;}KcnE6n)r$EamG(Re2MAL_3*J~UoC(S7@hm!cNzaH;0KxbSKwD0ejR*- z>CZRtS!Q0p!Ka$K5zZGbZvTr-{4wwarf)sq+Zw(fe4)`F2EWT(hcAS0VEQ%@zR2jz zf{!)xy$L?w_%DK=YkZc#uQu@?!FR-`zF#ea|JuCg{11GTnb%(qAAIlnhP-#v_rPrq z7e3-m;kOF}PJ|Dv5u!2gEzfdzcU{&{SD!1!s?J*ye|F?<7~Ga<6_SGPxbCScmIz>N7{3Xmc0X|}f@Wau$0zRu; z_$BaA#w zgcI@}hj*_JOU?ECY4`@_dj1Z4vAJ%4314dNzdM3_n?TvavhI4_sDG^ZFK!@y9;+jM zdpf-9r-9KK9OT;s5|&lfNkAuo3$tEt3(?6kIz_}6HkG<7>E~MbxaPw5$IqYWl$!oD z>>xf@oBkZ;@WFlJ{tK7R&qnmmCO%;LHir0uHdW*262HM*mu@FM;jpUlZxCN%?$;j^ zAA5wvFQ_YhuH)SJg69SQ-lg{8WQTYAUu1MnhaY784@0NuSkb>)~#Qw={IKEllR8u%E)FN9xe`uPxig3(_Ezsu~0 zHSk%c|DV9GG3Vnp_y$JjSNMG6vsOo0mq?@23O>rz?EpWB|*MT zAi(t}lKni(;obA7{FZt_W@rOB@F+T~ji2XKU0WLAbt?ntH+6tG3)X^@x>2_{&MPmqxvTP zH~4_rSAV0E@Q~;nMc=wOmv?u*1&<4#=R8-rKjR!ecwI8!%J&7ObyuWjQ785_n zT%VW2mzh4l1i#wozYAY%_JjLa==x0fO6oRfD0Lg1D16qB!XLqX+%JBoLQH0bV_%L&QYvyL+9ULaQ){S z|A#qzaR2X?_*nK&6nxa5!jD7eEcn8|gdf9tWuw2^tjjFbZ&5$k;8f@PGxujD@%d(b zUx8m}e0~C7X8N!Vey)lC-Qk1ld#u#`wUN|4{v_!`mhpKSe4OD&!zY+NPlR7+;-|tF z8vYvifZ^|iFE;*H!Y7!0@-ofEr|FJV9UjI9ZQ{V#y!r#vM7>7<0d@54_X@kM67R}vpLN8$%HmV_r%=ccOs7Wnczg}<0}X&x>9vc*;(rYB z#U?%lKE|y3RQO2ab1wWK^SpN(e3aP_55g}r{8R8H#?LE3-uWD7&fiZR-kn!O@V~Nl zt`7&vyjpgbK5RGoCpx?vA9aufu4diiiH|V*B#Zd+h7w=I`L#sjjnAiuFN~0QU6*ad z7aILPh%aqb)lcUh;<9P3%=y{iyzg^=4h`~c19Q#3?Fe6J_+Ic!4L=aR z*zo7WuQ7Zoe5v85!EZ49jqqiLzaM_P;a9mU55V>KE|An-@~^x`*sg}sX1So z$H;z&HTU<<@R8=a*B`#X?6;AsWAu~Y#~A&os&9N=1s`MhTi{cT&I9lT#^*Ee9nC&} z7e3$Ud;_0g`uv;foA^e(rEhah-ALt4d~f&!6CVd(XyPZqN16CJ@Y_xN!XV!!P;^(- z^X_@#OU(BsUlAXBch&d?r^vjvoBkgW;&%n(+XiAx{~MekewLd4w|029ZdNDJX@0EeoB?0R3!aUK z2%m#as?nJhGe`##9p2sN5vJ}G_%%jF1m98%#ep!k3uq{0~9iIWMRiEAoLl&bkHbejs(< zV}JH=c()J5MyEe~z|40ve1YjtQjl*Gh%lc|r#rk`H}*HF`-5}8bblU3XN~FGE9exN z^Yl}6qE2oY%s*7*0uB1P{+-W9YvnqS5IpMqceU_E@Nw|x!3W$Ibk0vqEjf^@I`0Wz zR$KVH;3Gc}evQz9*Hq_2;^Du8FN4>*5oh7^BZ-ehzc+lsI^pxt84q7_o$xutFM%&3 zK9=}r;Um{eyw?2)z5sp~IzK4?sl*qcQ@6kP418AA&r$FNhVKR6?M8{Oht65>G4Oo+ z4UB+~g?G-7;Ll|E^Wo*{9SB?wp8)UNwt_zoz!$+E178aNDtsOIjqq<6{qNx4h39on z;4kCZ-Z+8Jm8zX_h#8-ZiszcukE!GCY`W8eexq@Ty)KN0>|_-63=@UigD z>!9Gz68KDbUXuh?!CwKdeSQP}N_d@DDSQ#U^RY4bvm3q)Uhfx82TFg+;TsYk3BL!v z349OugKm=f)`jm2-w0m)kAgoGUVUB+-ws~uX2ExW*Y%wPA7yk3;kz1sF?@G;-B-)t zd%>&!r{Md*%UvlDcon`Md_Cq{3O~rie-0mK^tZ#0g0GLxZ}1nuYabd6l66UjKZy7? z@RJOG9DFvs`s@Zj6<+K1g}(w`_y1`4YvH+U2PVMJhgUy&@OQv#KWD)&Hahd+AB5Ms z55lj6SN~7IuYy-jPszILIUr`pd<_=DgNW?#*KkAT%2z6uQKro@Xx{P`H~6$3VcKS%z`h2?*#uae8kNs z1ew7x{g`!h44DxdGICh$J2*Z@Y~=U!M_c^6TTt*=kR~R>-uho56nLy7^(4l;2Rpg z@j23;R`9xSTf?`8Z$#Y=@KNxs;QPX#1+V-3T=>E8y5BB>9|o`fQ-i$o@AGUI|Ju)~ z#E&%kSHh2h*Z5oE6X11U-3LDrUj3|qpA4^kcn&@jUiBDF6v*C4KTj8&U z*Z%wre?7eVtUXlLWxmmA3V%Di&i6?8BKR}$GXQ>zi5~%94u3fDm%>NhBK>abB+3>n9JK*!-bzOGDPlwmK_0N^Q6~L>{BjF3- zn=r3#@QdNq&*|_*@apFr_y-k;^zs2Z(2LH9u`38QQ;mhH_GyEU$Kf>$&Z#YcW z@fUdYa|HZecwLth;p^Qh`&M;Mfp2X1!SF5No3bC`;iKSrO%k{qeh9p-;|=g5;dP(i z4L=TE*JUYuJiM;U6Y%2={~~;f;opK!h1Y$u9)7anzk<((*S`G(pAWD5_AmI$;r05~ z)cJt#zW2Dw=(mHv4qp2i4Zjdx&$|Ke55Q|bN5DS@uXU5)pEml_;9rB+KF@)F1HKvS zy9j=r(SHd33wYgc&%%ETuYFqszr*nB;eUnK_1z4=%f#=1{~KP{@y{UdyeBmG!Q+QZ z|08dcecpk24TJ9wulk40Yl&k;K zUi-gGd03Ed87Q7D`h*9L5Aw|e3k}~L9s9qBd78sF*W^k#+=EYY_!gDo^w)e3e!hp! z5|8*NJmTNy0ycNv|3{kdC3`r0i@?7ByRvZ0*4x?ZNl(;0Ji{<2?9u z5B_ow{ss^JE)V`;hp(=ms~o=lzNb;(Bais+J@o(b;9HKZzHWPmukL;k~|NBl?+ zKG}oM_s}o&h+pi%KkA|Lng{=Zht4Js{y!dktqZE}TZ9LHqz8Yp2S3n*zsQ5n@Ze`U ze0BS6zDN9h9{dUq{zVV|9S{C%hp*1hP7l7$h1K`DjR)V^gFnsTtE)TQBRM6d=BmM=4ug>RN9`PGJ`0qUUS{GHXAK}3t>+scGAG&(*{XF>L z9(<|?f2qS)*N5vp;_vc^f5L-*)kEiV5B@(M{2v~CvvJk;t%C>O$Kiwfgy%`!C$S#! z=XmgAJorq9udbg39{eH?orgW*S9|blJ#;>G`0CD!GLQK0J@{Q7e1nUt@Bd*Qd?ydS zw+BBg$UFbtS&@8lzrLHSSVEBB_wPGQ@X!e)C8npxPn?{Y5ucNrn4KF)%FfNn&6_Zx zOHv>{zTc=}BjV2)JaSZgyfZqh%INHVl@29m#!pPo9G{pTAN-?h@ril)0q1Y1Wu>R& zrX+Xi*{yr;fO{Z5EjiyA^@tA0-)&3In>=}%*6DxlS-~;`M)V!pKVC;}8U6jAD#5?- zMwRR|=P$J-<~n~)F6cRHT7LY5_~@=lng1M!kB%CimzbN9o#8~q|MRO;+6~W|`d{O_ z^-fE6N~GnwR`(;md$**_j7#z+ItBMLp;v0=Was~~vraaJZX$vPX6nVg+A zG0*vfapJ{0a-V5>hmM@){JFc_Y@MGIn46vG{*AsATYlI-P5s9}QhG{acFmC!Q*yJi zGqY@9baW-r_$d|Zg#LbIIe%bqKPMnv%Sp=2N^y34c3x6$e0<83ytGRb)15W0I}`8gtU=<$luE8@X!`#}C^OI7t z+>>@hN={0yqvw+SrVYr;NOIYDhm22l{!HRN2b{LJn6tls*&donnaR~0(bgf@KRer*jdPu=2+hpS%*%ED2IN1}?dP5=YM|n<5$acQ zAh`AR33u&Qo_|HSX^wlba!%%qlzlF6`);X}$yvG6;&bzyYqnF*J9FP_MK$vKTzf8c z{$glW?micZed4NjTlu1AR?hwFpw6{&LSkNeuE)Yon)=_5|M#Pb8O~of4c=ZnSayB~qaztWUPDIKjH@^RrVdF39N5;UE z+`+jilU;tGbFImC{!FV#Ic)X-XSJO_DJw+WG$$>^xqc7M8I_%tcj{Hhy0!b}#HVEBO^$bdf~SJLX{9IT z=B6d3#JhjHmBaxlxk;)0oIf0!nc+65LXOHKoy&P{ZuUs$ufTHosc7%Wl#Jy5`TNjA zQ*u)?lSicF=4EF%2fa_pYOeZ~FSl;ugzS`*q|7{LX6DIgKXcR5a{e!=)t}DQ)co(a zyHMQMthAqV`R_veJ+uG*bP>wTYF66Mnf-SmXJ#JHp4F_I-De>s*Vy6x_wj$7Qq}vQ zToO3{(<&|rl^#p_IS=J}qW<%+V(-UQk5u~@lbw>Bm!uboN(GWra+0#$XTN=`RCyNo zr$ly2@OjMjUPUMP@j+E8t~In2ez0@*?3b97nv&cvGsF1+m=U~(x)%&*_RfEsEGr(o zu)CiC-2={}S$t}Wd$n>$awxtlLpQ5i)k9{enr>utr7TrIut!yqo|Ph_svhc9br@51 z*t_a5+9XG-1T%;P+SrRW{<<1}U5&r4#$Q+CudDIb)%fdb z{Bq>>u&sYH~zXC zKi!R=?#54dM%>uLP; zH2!)Te?5)Ap2lBK^q!%Ijr-oleQ)F5`H$19tVVQ{+IMe4?q`fjx1i`KGneQnGnwcp zosC|dqttH&p$>D>-KTr!y`ixf9c4U5N2y6oskn!@CdcPxOmy$^m5o;1R3>G)(@4w7 z{O6@w{P>jIsVONL4n1K)O1AS#$|jqZM@Q=%f@;Gu(x*B1ZueH62`4@& z(W>cuo#edujO4`Z>_jI&C*JwY8{aS9d5@Xvyll+O%dvUdmg@2bWM(_>Gcx|kw#nMU zVDh=n%bpD9^Yx`E@#CFOZtv=>llBh~Wb>Fyg(>d(^o?q$r zsg-_rKgGMt=*FZbrcZF@Qt_V2<+9CdZI_!yPDQtM)42zO=1fv0f4aroP;IaKdt!cC zm0=|t6=igXX_>xmP~U$N|0z@PIOK+=RhnW_<<{p^Zhcba0dEhqF)4ZJ&O7%?GH$2( zTQaBe8YfjAd&C;P2U$+)Os>QSor6>O&Kq^H6s{C3W4j zZd|teDy?$4q|BV$)RbJkGPyCsD;1qmId)3r<^`216FJUj3ZqncT+x)ud)$3@>7=D( zXJtCCbo5GH$$RCEUiIa->og^8VkNJcm3|*u>GyLh{a)!>e~$A`rP7g0Q}iUMa9Vl8 zJ0A%>zYeJ6S2upT^VT^-4JB0>O-OUT>iFmFdBwXi=ha))H&hizDt+p$!kwGxy!K-X z|9tkW^!97;WakQ=>k?g@*XtQ6UECXZoO2zBOLV?m8W#KlATfPN%CxD@Wj}`)cg5Wp z$B(`W9FUlk%TaeT1r??Z2tG5Nm3FD~^_=sPtseny(<%py%p33Aj*@aKg}7(98}iS4 z_N+wb!vrkh>Vpo!0qK z4WSp=q+sLqEOOqd*8FXl`CiL;L+^ZTW!~VK7xMe1>%1K0+fY1Kt2}(4sC~XisQTqy z*RIunl@_0#IC*?>V&#){9|!K~v_I3W^gM%i=gg?ClQG&Dr+V;ZE#Y1bs{9qP-qJjz zt9+fTvHPQ|x3vAy)!6;f)r;=_=xXf#=;|$ee{?mrrf<`GO-`KXymrcS&XOEw7dS7% zbREart!;K!v}0r6YhZj=_qy!d4Jsb@YH-jaK0eLa{lS0Pz&&9-8qvGrTc>!v3r-3? zSWZsNm=^DR%i(;P5kJ9sr=A?2oF~tp+5ZH(53tS!IB#NV^`Xppd|q0*^97;v{X=p} zzJ4_lyufh4z2;QM4|Bd6c0OfI)njqaM5LN zaj{m6$f&MXFW}(wYJq!*E>jm)vK>aF6dngg+YRi-FZate_~fVM^z>V${BjHW;{fCK zB`jxB+B&UdDC1Gtm_xR2;00Ls`c09rh2}G4(F6EkoRR*!ZQ_InAW)h$<@!w4h+`D@ z8Tg4jIExrbgxN1}+bEw`%aU4Y$%J~gllS-<8?N8V%`+u{=8xfIpgO+pkkb8kR5pqH z$o^Yd2J&b$QSDV9WROgPdP07jmyO86-S!b#?Y7;z2~7-$-1X{5f?T8n`n=*|pn8}- zXh(oHoqbQBA-x-Y4zcxS&Fe$b8tENdW9GARI!#(5y<=;Pd|5qfAsGBZ-gzi-1d znK-{o64TPzh-Eh{*QV4dI6|5x2%57%^CuM z!@v4!26#PtX&%K5jHM^#Osv1sod9DoB>QqMY@QiQtb~F0xLN5oV)1lk?;I9!Ws}_B zSQ)yNc%fs4TL`%4U?nTdai+5kEb%BXJ;R+4EL4QBP+%Fv;em?S84|GK*m#V=8PIU5 zspP2bY0A^BL%UJ1MIoFP_n(Rxq!RvjzvwE^G0F5|c^Y^TGm}Hso9IbEEQ)2s+}7M@#M=dhND0Cn^r?I9-D|+>N7nM}W|dLB(lmK#gEhPzCJL9muM!-02Q4 zWk!cWPvK5uI-OR}@UoC$WB^&Lj&Kf@4^4t4Y&W~}n}6Vs>)BBkSme%Nr4;OgQJ|P*Xt|BaM6Oq9_$tdHRx0sfDv|w6E*nu^*SgU zz5f}&vn5?ixvRPW3?FM_BCB4>!Iyn#aWy#8ro-84Qeu&SsY~0q<7# zv6@%#Sx*mfoZ;MJtgmXY;tE%}kQq72-M5WO(IncJkWRaztD8Y*6O%nt8(WmKXtH~#muMfHNC%ibtw(6xJ_gzZ zmI0B@Y7nIgqh=ExnYzPQ#EEvORVwnE)RxP=q}4M;GSn?E0EGVfS^XxZ(w_ej?S#*E+J$sD z%-U0hf~_XwB3q%!ix~4eNv}t4n>z$~OoUn@yL#LuMQoAP3$wsqF{B@GFLizqh&IoU zMWkb&66=K2UzC!=^0qdddGyn#`d^r+v~1_I?oZpjR7^5i%LOWkVx5zbnw`#cXNuUOt-BX|b&LQxb6@*VXJpO1V-)Q0;2fwW;rYgz0&Oz=-YuZJ71MAK~rPtXm} z`ju<+uvwMUN0{1kg|ANt&HGS3JQmJYjoCPTnL;BlH^1dxKy&Ct!GG(D8^3P}l zC2rT~YL*%PYeF!Hbm(Xu?3&_&W9?cQF~ZiKY?*kq|c5}0isfryJ z|9JEojE^Q0b&Br}&mahMj`Jg8ElYBUc9Ar4_Q5$w@XkW$3YAAOy#V1XUghFs$1{l3 z{O))LJKkmz3heGX4yO55D%WM2?nT0d-QYJXD@Vhd(=;$+AMTIUfxkQU^j_80D6yaR zs{zb|$dx!NGB05^rvK4!s1D?r{u4}exfUTiO`)M7I3y&?_Uos3$Cz%1qeG3O>FM?W zcb#PP?3B*U@Km1O81d4A-y3TfP7nBf>|(bu!xX}8pv}YDA{RCloEDnCYKVm^-Kod` z(~hjQrLRuCEuD4hZGqR4)V4rt)!G89E7ENN*R7a48B$gTFP`n^OuPYxdz|o!q=1pU znSwCLu*Q02Y(cX51jJa%PLmW=ZH==?7+?R8$|=$7bU)U`j!x|T6;-&Zqe+~f#vopI zJ&o#UOs@;Evf|4rJyi9N3w6K-zQkaS&)vNDSux{ER2MtOE1+V_--+i&T_o1>S{;Y+ zrLK!xExaCrsVJmV7wrv?obDyBF5>xy@9+YNLD-!l?5^d+Rd=tL6w5R^(Iw>KkA%8f z)J8mU-)6~;ISobX2ZC=sXz^_v-b2cGwj;;dRhcwWfJ;UsSyu`ab%ZPCCA^y%#vO~v zNNz1H8wEkDN(n95@U*F zDt+$9B>D8aY6b=Jl?9^Y2Y&19;xK~DA!9+6b%5*}bH#;qF>RoQ5X8t$2l57On$ zS;tVReIN5#t#BQmncTsA7Q~RK(hpg!z?8c6ZVuDi54$a;f{Q4%*DjQ%wa41gHK?S~ z+U`4X4Ma}s>8V-+S@31uMUdR8p=Fs`znHMBG1^Qiz5Q>c%EvlQq+Sbk>e_^)kuB>& zt^)WHcVb=UMRb{Bu_ze%tqvA05uKZu6h$MxliLQ;P@wk5WTBo~>uNDdzY|Q?sRKa( zSBY-m94cnRRFEH?y?nwMu@n*N`i4SU%C$h$-*sW`T}VVWlrZXy^C>FFU1$BV>S&b0 zr+Pf``-k>#uXiYk_a!9S`o~%$>+lsBxCRCxR}XvbK=fO6v58GKa?eL@C* zV&hQRTr`-1jobib(g3EbV#`AgZJZ05>|h@a5yzU`4^g?pJtC$xmaHx`+6$j?HpW1R z{AgZB!dya;GP|%9IEBLKd4xpfy5(|VRq+=Eok{dvMTPW9wwOV-9VZl-bJkxF9`{kb z#6-*88CfRei>c^^fK(&{dq+n>RGY%%<+XTS*2~ooMBTCgCof_XU?_5Xrda=shxpF* zT0|9NyXqqGWvh$0DI)(#EE2T_Le?5;i7(^)gp}U1a~Capkv|x=q_Ru{qs7^iWwfjI zeiIV|)IFi!Z@OoOdsejfb|_FFdmD}RqDS5N<(HG=%i_z~+3lyh;_mq5@)J#r(`E$$V>xv?OZWI^c!=}kf3J=| zUz~ope#0w%xC1wpzUCM5ya%c`p)oSichxk6;JQqF; z<<32Icl~y%Zw|UJM>Gdm@8g7_TtH#%{nqyjymsNIZ0vy7Z@kE> z>pRBu3>`+bao)?+t}4<${R0SB^77gB9O}!Pic%9o?*rBOP)JHI%m+)1qQQsa3Gxvj zgqO|EPYd{tAx)V<@EptTmv_*QB05qV5YLMATX@~vMPRlJFtA)rEDSHbVObbDxIQXd~LAJo#HAQI>*NFC^SnQ7KLzJ5Zp}#>~N5mpl7l>$CeNu zjUD6Zi=fR?-!C5+b9hOwUko1}(b6Ui*K=D>NS0s(~l8$=S~4a9YcH&88W1s?Fip=r+E9pOak)!C4tUNpCe z+xDc%!TtxTU0?|y0+Dz^bPEWocfgsr5>Gy*Ml|{CeSZRi$d0NLAXvAqe@Bw6$4}$K zqQWzd->WuZc?#4wB(LATdanM_J=&I%i+kwxYgN`a)sx{WoE7?aYvJCQ@f4zHb@&V? zT~RzV&fI}G07czJa}l0*L7w9Tp&F#p2SHyj$AigB>s z!a=DjPRT{^9*%F!z#M58_UrxW?LJN-Zr%I4vqMxQdv-gs!FIsI7D@?3I@TB}z4j7Y zSdowui6Zb}D6xnQPToK2EBlbZ+xz=_6($~~jj(LQM5-K@X%RBe8i+v;4AV|+7N34P z-l3?+t*Ua$zp!?m$S6L1mJ?8TlGl*ws)A?v<2n`FFi~Y4PBoy+{C?TYo|hFE5~vAs R!AmMCFb9ppiT2~e{{eB6CcXdw literal 0 HcmV?d00001 From eb3c3287561a0e324f147d7f9b998891860fa086 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 23 Feb 2016 17:00:41 -0500 Subject: [PATCH 005/183] skeleton layout for build system using CMake --- CMakeLists.txt | 56 + code/CMakeLists.txt | 41 + code/damage/CMakeLists.txt | 10 + code/damage/damage_local.f90 | 327 ++ code/damage/damage_none.f90 | 60 + code/damage/damage_nonlocal.f90 | 380 ++ code/homogenization/CMakeLists.txt | 11 + code/homogenization/homogenization.f90 | 1396 ++++++ code/homogenization/homogenization_RGC.f90 | 1558 +++++++ .../homogenization_isostrain.f90 | 317 ++ code/homogenization/homogenization_none.f90 | 60 + code/hydrogenflux/CMakeLists.txt | 9 + .../hydrogenflux_cahnhilliard.f90 | 513 +++ code/hydrogenflux/hydrogenflux_isoconc.f90 | 63 + code/kinematics/CMakeLists.txt | 12 + .../kinematics_cleavage_opening.f90 | 303 ++ .../kinematics/kinematics_hydrogen_strain.f90 | 264 ++ .../kinematics_slipplane_opening.f90 | 323 ++ .../kinematics_thermal_expansion.f90 | 228 + code/kinematics/kinematics_vacancy_strain.f90 | 265 ++ code/plastic/CMakeLists.txt | 16 + code/plastic/plastic_disloUCLA.f90 | 2116 +++++++++ code/plastic/plastic_dislotwin.f90 | 2542 +++++++++++ code/plastic/plastic_isotropic.f90 | 678 +++ code/plastic/plastic_j2.f90 | 579 +++ code/plastic/plastic_none.f90 | 109 + code/plastic/plastic_nonlocal.f90 | 4031 +++++++++++++++++ code/plastic/plastic_phenoplus.f90 | 1419 ++++++ code/plastic/plastic_phenopowerlaw.f90 | 1226 +++++ code/plastic/plastic_titanmod.f90 | 1913 ++++++++ code/porosity/CMakeLists.txt | 9 + code/porosity/porosity_none.f90 | 61 + code/porosity/porosity_phasefield.f90 | 450 ++ code/source/CMakeLists.txt | 16 + code/source/source_damage_anisoBrittle.f90 | 425 ++ code/source/source_damage_anisoDuctile.f90 | 415 ++ code/source/source_damage_isoBrittle.f90 | 383 ++ code/source/source_damage_isoDuctile.f90 | 350 ++ code/source/source_thermal_dissipation.f90 | 220 + code/source/source_thermal_externalheat.f90 | 277 ++ code/source/source_vacancy_irradiation.f90 | 253 ++ .../source/source_vacancy_phenoplasticity.f90 | 215 + code/source/source_vacancy_thermalfluc.f90 | 255 ++ lib/damask/core.so | Bin 2117501 -> 0 bytes lib/damask/corientation.so | Bin 2592705 -> 0 bytes 45 files changed, 24154 insertions(+) create mode 100644 code/CMakeLists.txt create mode 100644 code/damage/CMakeLists.txt create mode 100644 code/damage/damage_local.f90 create mode 100644 code/damage/damage_none.f90 create mode 100644 code/damage/damage_nonlocal.f90 create mode 100644 code/homogenization/CMakeLists.txt create mode 100644 code/homogenization/homogenization.f90 create mode 100644 code/homogenization/homogenization_RGC.f90 create mode 100644 code/homogenization/homogenization_isostrain.f90 create mode 100644 code/homogenization/homogenization_none.f90 create mode 100644 code/hydrogenflux/CMakeLists.txt create mode 100644 code/hydrogenflux/hydrogenflux_cahnhilliard.f90 create mode 100644 code/hydrogenflux/hydrogenflux_isoconc.f90 create mode 100644 code/kinematics/CMakeLists.txt create mode 100644 code/kinematics/kinematics_cleavage_opening.f90 create mode 100644 code/kinematics/kinematics_hydrogen_strain.f90 create mode 100644 code/kinematics/kinematics_slipplane_opening.f90 create mode 100644 code/kinematics/kinematics_thermal_expansion.f90 create mode 100644 code/kinematics/kinematics_vacancy_strain.f90 create mode 100644 code/plastic/CMakeLists.txt create mode 100644 code/plastic/plastic_disloUCLA.f90 create mode 100644 code/plastic/plastic_dislotwin.f90 create mode 100644 code/plastic/plastic_isotropic.f90 create mode 100644 code/plastic/plastic_j2.f90 create mode 100644 code/plastic/plastic_none.f90 create mode 100644 code/plastic/plastic_nonlocal.f90 create mode 100644 code/plastic/plastic_phenoplus.f90 create mode 100644 code/plastic/plastic_phenopowerlaw.f90 create mode 100644 code/plastic/plastic_titanmod.f90 create mode 100644 code/porosity/CMakeLists.txt create mode 100644 code/porosity/porosity_none.f90 create mode 100644 code/porosity/porosity_phasefield.f90 create mode 100644 code/source/CMakeLists.txt create mode 100644 code/source/source_damage_anisoBrittle.f90 create mode 100644 code/source/source_damage_anisoDuctile.f90 create mode 100644 code/source/source_damage_isoBrittle.f90 create mode 100644 code/source/source_damage_isoDuctile.f90 create mode 100644 code/source/source_thermal_dissipation.f90 create mode 100644 code/source/source_thermal_externalheat.f90 create mode 100644 code/source/source_vacancy_irradiation.f90 create mode 100644 code/source/source_vacancy_phenoplasticity.f90 create mode 100644 code/source/source_vacancy_thermalfluc.f90 delete mode 100755 lib/damask/core.so delete mode 100755 lib/damask/corientation.so diff --git a/CMakeLists.txt b/CMakeLists.txt index e69de29bb..4a2af196d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -0,0 +1,56 @@ +# Initial attempt of using CMake to build the spectral solver +# --> CMake should be able to take care of the dependence by itself. +# +cmake_minimum_required (VERSION 3.1.0) +project (DAMASKSpectral Fortran) + + +# make sure that the default is a RELEASE +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE RELEASE CACHE STRING + "Choose the type of build, options are: None Debug Release." + FORCE) +endif (NOT CMAKE_BUILD_TYPE) + + +# The version number. +set (DAMASKSpectral_VERSION_MAJOR 1) +set (DAMASKSpectral_VERSION_MINOR 0) + +# Set up build directory +set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/build) +set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) + + +# setup modules +find_package(petsc) +find_package(hdf5) + +# FFLAGS depend on the compiler +# need extra time to work on these +get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) + +if (Fortran_COMPILER_NAME MATCHES "gfortran.*") + # gfortran + set (CMAKE_Fortran_FLAGS_RELEASE "-funroll-all-loops -fno-f2c -O3") + set (CMAKE_Fortran_FLAGS_DEBUG "-fno-f2c -O0 -g") +elseif (Fortran_COMPILER_NAME MATCHES "ifort.*") + # ifort (untested) + set (CMAKE_Fortran_FLAGS_RELEASE "-f77rtl -O3") + set (CMAKE_Fortran_FLAGS_DEBUG "-f77rtl -O0 -g") +elseif (Fortran_COMPILER_NAME MATCHES "g77") + # g77 + set (CMAKE_Fortran_FLAGS_RELEASE "-funroll-all-loops -fno-f2c -O3 -m32") + set (CMAKE_Fortran_FLAGS_DEBUG "-fno-f2c -O0 -g -m32") +else (Fortran_COMPILER_NAME MATCHES "gfortran.*") + message ("CMAKE_Fortran_COMPILER full path: " ${CMAKE_Fortran_COMPILER}) + message ("Fortran compiler: " ${Fortran_COMPILER_NAME}) + message ("No optimized Fortran compiler flags are known, we just try -O2...") + set (CMAKE_Fortran_FLAGS_RELEASE "-O2") + set (CMAKE_Fortran_FLAGS_DEBUG "-O0 -g") +endif (Fortran_COMPILER_NAME MATCHES "gfortran.*") + + +# add code(source) directory +add_subdirectory(code) \ No newline at end of file diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt new file mode 100644 index 000000000..742d7e146 --- /dev/null +++ b/code/CMakeLists.txt @@ -0,0 +1,41 @@ +# group sources for base modules +set (SRC "CPFEM" + "CPFEM2" + "core_quit" + "commercialFEM_fileList" + "compilation_info" + "constitutive" + "crystallite" + "damask_hdf5.f90" + "debug" + "FEsolving" + "IO" + "lattice" + "libs" + "material" + "math" + "mesh" + "numerics" + "prec" + "quit__genmod" + ) + +# compiler base modules +foreach (p ${SRC}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) + +# compile each sub moudel +add_subdirectory(damage) +add_subdirectory(homogenization) +add_subdirectory(hydrogenflux) +add_subdirectory(kinematics) +add_subdirectory(plastic) +add_subdirectory(porosity) +add_subdirectory(sources) +add_subdirectory(spectral) +add_subdirectory(thermal) +add_subdirectory(vacancyflux) + +# compile spectral solver +add_executable(DAMASKSpectral.exe DAMASK_spectral.f90) diff --git a/code/damage/CMakeLists.txt b/code/damage/CMakeLists.txt new file mode 100644 index 000000000..483baba57 --- /dev/null +++ b/code/damage/CMakeLists.txt @@ -0,0 +1,10 @@ +# group sources +set (DAMAGE "damage_none" + "damage_local" + "damage_nonlocal" + ) + +# compile damage module +foreach (p ${DAMAGE}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) diff --git a/code/damage/damage_local.f90 b/code/damage/damage_local.f90 new file mode 100644 index 000000000..196382c13 --- /dev/null +++ b/code/damage/damage_local.f90 @@ -0,0 +1,327 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for locally evolving damage field +!-------------------------------------------------------------------------------------------------- +module damage_local + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + damage_local_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + damage_local_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + damage_local_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + damage_local_Noutput !< number of outputs per instance of this damage + + enum, bind(c) + enumerator :: undefined_ID, & + damage_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + damage_local_outputID !< ID of each post result output + + public :: & + damage_local_init, & + damage_local_updateState, & + damage_local_postResults + private :: & + damage_local_getSourceAndItsTangent + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine damage_local_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + damage_type, & + damage_typeInstance, & + homogenization_Noutput, & + DAMAGE_local_label, & + DAMAGE_local_ID, & + material_homog, & + mappingHomogenization, & + damageState, & + damageMapping, & + damage, & + damage_initialPhi, & + material_partHomogenization + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,homog,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_local_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(damage_type == DAMAGE_local_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(damage_local_sizePostResults(maxNinstance), source=0_pInt) + allocate(damage_local_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(damage_local_output (maxval(homogenization_Noutput),maxNinstance)) + damage_local_output = '' + allocate(damage_local_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(damage_local_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + homog = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + homog = homog + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (homog > 0_pInt ) then; if (damage_type(homog) == DAMAGE_local_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = damage_typeInstance(homog) ! which instance of my damage is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('damage') + damage_local_Noutput(instance) = damage_local_Noutput(instance) + 1_pInt + damage_local_outputID(damage_local_Noutput(instance),instance) = damage_ID + damage_local_output(damage_local_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingFile + + initializeInstances: do homog = 1_pInt, size(damage_type) + + myhomog: if (damage_type(homog) == DAMAGE_local_ID) then + NofMyHomog = count(material_homog == homog) + instance = damage_typeInstance(homog) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,damage_local_Noutput(instance) + select case(damage_local_outputID(o,instance)) + case(damage_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + damage_local_sizePostResult(o,instance) = mySize + damage_local_sizePostResults(instance) = damage_local_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 1_pInt + damageState(homog)%sizeState = sizeState + damageState(homog)%sizePostResults = damage_local_sizePostResults(instance) + allocate(damageState(homog)%state0 (sizeState,NofMyHomog), source=damage_initialPhi(homog)) + allocate(damageState(homog)%subState0(sizeState,NofMyHomog), source=damage_initialPhi(homog)) + allocate(damageState(homog)%state (sizeState,NofMyHomog), source=damage_initialPhi(homog)) + + nullify(damageMapping(homog)%p) + damageMapping(homog)%p => mappingHomogenization(1,:,:) + deallocate(damage(homog)%p) + damage(homog)%p => damageState(homog)%state(1,:) + + endif myhomog + enddo initializeInstances + + +end subroutine damage_local_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates local change in damage field +!-------------------------------------------------------------------------------------------------- +function damage_local_updateState(subdt, ip, el) + use numerics, only: & + residualStiffness, & + err_damage_tolAbs, & + err_damage_tolRel + use material, only: & + mappingHomogenization, & + damageState + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + subdt + logical, dimension(2) :: & + damage_local_updateState + integer(pInt) :: & + homog, & + offset + real(pReal) :: & + phi, phiDot, dPhiDot_dPhi + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + phi = damageState(homog)%subState0(1,offset) + call damage_local_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) + phi = max(residualStiffness,min(1.0_pReal,phi + subdt*phiDot)) + + damage_local_updateState = [ abs(phi - damageState(homog)%state(1,offset)) & + <= err_damage_tolAbs & + .or. abs(phi - damageState(homog)%state(1,offset)) & + <= err_damage_tolRel*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) + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + phase_source, & + phase_Nsources, & + SOURCE_damage_isoBrittle_ID, & + SOURCE_damage_isoDuctile_ID, & + SOURCE_damage_anisoBrittle_ID, & + SOURCE_damage_anisoDuctile_ID + use source_damage_isoBrittle, only: & + source_damage_isobrittle_getRateAndItsTangent + use source_damage_isoDuctile, only: & + source_damage_isoductile_getRateAndItsTangent + use source_damage_anisoBrittle, only: & + source_damage_anisobrittle_getRateAndItsTangent + use source_damage_anisoDuctile, only: & + source_damage_anisoductile_getRateAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + phi + integer(pInt) :: & + phase, & + grain, & + source + real(pReal) :: & + phiDot, dPhiDot_dPhi, localphiDot, dLocalphiDot_dPhi + + phiDot = 0.0_pReal + dPhiDot_dPhi = 0.0_pReal + do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) + phase = phaseAt(grain,ip,el) + do source = 1, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_damage_isoBrittle_ID) + call source_damage_isobrittle_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_isoDuctile_ID) + call source_damage_isoductile_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_anisoBrittle_ID) + call source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_anisoDuctile_ID) + call source_damage_anisoductile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case default + localphiDot = 0.0_pReal + dLocalphiDot_dPhi = 0.0_pReal + + end select + phiDot = phiDot + localphiDot + dPhiDot_dPhi = dPhiDot_dPhi + dLocalphiDot_dPhi + enddo + enddo + + phiDot = phiDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + dPhiDot_dPhi = dPhiDot_dPhi/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + +end subroutine damage_local_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of damage results +!-------------------------------------------------------------------------------------------------- +function damage_local_postResults(ip,el) + use material, only: & + mappingHomogenization, & + damage_typeInstance, & + damageMapping, & + damage + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(damage_local_sizePostResults(damage_typeInstance(mappingHomogenization(2,ip,el)))) :: & + damage_local_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = damageMapping(homog)%p(ip,el) + instance = damage_typeInstance(homog) + + c = 0_pInt + damage_local_postResults = 0.0_pReal + + do o = 1_pInt,damage_local_Noutput(instance) + select case(damage_local_outputID(o,instance)) + + case (damage_ID) + damage_local_postResults(c+1_pInt) = damage(homog)%p(offset) + c = c + 1 + end select + enddo +end function damage_local_postResults + +end module damage_local diff --git a/code/damage/damage_none.f90 b/code/damage/damage_none.f90 new file mode 100644 index 000000000..956ba5cc8 --- /dev/null +++ b/code/damage/damage_none.f90 @@ -0,0 +1,60 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for constant damage field +!-------------------------------------------------------------------------------------------------- +module damage_none + + implicit none + private + + public :: & + damage_none_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine damage_none_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_none_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (damage_type(homog) == DAMAGE_none_ID) then + NofMyHomog = count(material_homog == homog) + damageState(homog)%sizeState = 0_pInt + damageState(homog)%sizePostResults = 0_pInt + allocate(damageState(homog)%state0 (0_pInt,NofMyHomog)) + allocate(damageState(homog)%subState0(0_pInt,NofMyHomog)) + allocate(damageState(homog)%state (0_pInt,NofMyHomog)) + + deallocate(damage(homog)%p) + allocate (damage(homog)%p(1), source=damage_initialPhi(homog)) + + endif myhomog + enddo initializeInstances + + +end subroutine damage_none_init + +end module damage_none diff --git a/code/damage/damage_nonlocal.f90 b/code/damage/damage_nonlocal.f90 new file mode 100644 index 000000000..311570781 --- /dev/null +++ b/code/damage/damage_nonlocal.f90 @@ -0,0 +1,380 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for non-locally evolving damage field +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module damage_nonlocal + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + damage_nonlocal_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + damage_nonlocal_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + damage_nonlocal_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + damage_nonlocal_Noutput !< number of outputs per instance of this damage + + enum, bind(c) + enumerator :: undefined_ID, & + damage_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + damage_nonlocal_outputID !< ID of each post result output + + + public :: & + damage_nonlocal_init, & + damage_nonlocal_getSourceAndItsTangent, & + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility, & + damage_nonlocal_putNonLocalDamage, & + damage_nonlocal_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine damage_nonlocal_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + damage_type, & + damage_typeInstance, & + homogenization_Noutput, & + DAMAGE_nonlocal_label, & + DAMAGE_nonlocal_ID, & + material_homog, & + mappingHomogenization, & + damageState, & + damageMapping, & + damage, & + damage_initialPhi, & + material_partHomogenization + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_nonlocal_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(damage_type == DAMAGE_nonlocal_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(damage_nonlocal_sizePostResults(maxNinstance), source=0_pInt) + allocate(damage_nonlocal_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(damage_nonlocal_output (maxval(homogenization_Noutput),maxNinstance)) + damage_nonlocal_output = '' + allocate(damage_nonlocal_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(damage_nonlocal_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (damage_type(section) == DAMAGE_nonlocal_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = damage_typeInstance(section) ! which instance of my damage is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('damage') + damage_nonlocal_Noutput(instance) = damage_nonlocal_Noutput(instance) + 1_pInt + damage_nonlocal_outputID(damage_nonlocal_Noutput(instance),instance) = damage_ID + damage_nonlocal_output(damage_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingFile + + initializeInstances: do section = 1_pInt, size(damage_type) + if (damage_type(section) == DAMAGE_nonlocal_ID) then + NofMyHomog=count(material_homog==section) + instance = damage_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,damage_nonlocal_Noutput(instance) + select case(damage_nonlocal_outputID(o,instance)) + case(damage_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + damage_nonlocal_sizePostResult(o,instance) = mySize + damage_nonlocal_sizePostResults(instance) = damage_nonlocal_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 0_pInt + damageState(section)%sizeState = sizeState + damageState(section)%sizePostResults = damage_nonlocal_sizePostResults(instance) + allocate(damageState(section)%state0 (sizeState,NofMyHomog)) + allocate(damageState(section)%subState0(sizeState,NofMyHomog)) + allocate(damageState(section)%state (sizeState,NofMyHomog)) + + nullify(damageMapping(section)%p) + damageMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(damage(section)%p) + allocate(damage(section)%p(NofMyHomog), source=damage_initialPhi(section)) + + endif + + enddo initializeInstances +end subroutine damage_nonlocal_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates homogenized damage driving forces +!-------------------------------------------------------------------------------------------------- +subroutine damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + phase_source, & + phase_Nsources, & + SOURCE_damage_isoBrittle_ID, & + SOURCE_damage_isoDuctile_ID, & + SOURCE_damage_anisoBrittle_ID, & + SOURCE_damage_anisoDuctile_ID + use source_damage_isoBrittle, only: & + source_damage_isobrittle_getRateAndItsTangent + use source_damage_isoDuctile, only: & + source_damage_isoductile_getRateAndItsTangent + use source_damage_anisoBrittle, only: & + source_damage_anisobrittle_getRateAndItsTangent + use source_damage_anisoDuctile, only: & + source_damage_anisoductile_getRateAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + phi + integer(pInt) :: & + phase, & + grain, & + source + real(pReal) :: & + phiDot, dPhiDot_dPhi, localphiDot, dLocalphiDot_dPhi + + phiDot = 0.0_pReal + dPhiDot_dPhi = 0.0_pReal + do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) + phase = phaseAt(grain,ip,el) + do source = 1_pInt, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_damage_isoBrittle_ID) + call source_damage_isobrittle_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_isoDuctile_ID) + call source_damage_isoductile_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_anisoBrittle_ID) + call source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_anisoDuctile_ID) + call source_damage_anisoductile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case default + localphiDot = 0.0_pReal + dLocalphiDot_dPhi = 0.0_pReal + + end select + phiDot = phiDot + localphiDot + dPhiDot_dPhi = dPhiDot_dPhi + dLocalphiDot_dPhi + enddo + enddo + + phiDot = phiDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + dPhiDot_dPhi = dPhiDot_dPhi/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + +end subroutine damage_nonlocal_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized non local damage diffusion tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function damage_nonlocal_getDiffusion33(ip,el) + use numerics, only: & + charLength + use lattice, only: & + lattice_DamageDiffusion33 + use material, only: & + homogenization_Ngrains, & + material_phase, & + mappingHomogenization + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + damage_nonlocal_getDiffusion33 + integer(pInt) :: & + homog, & + grain + + homog = mappingHomogenization(2,ip,el) + damage_nonlocal_getDiffusion33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(homog) + damage_nonlocal_getDiffusion33 = damage_nonlocal_getDiffusion33 + & + crystallite_push33ToRef(grain,ip,el,lattice_DamageDiffusion33(1:3,1:3,material_phase(grain,ip,el))) + enddo + + damage_nonlocal_getDiffusion33 = & + charLength*charLength* & + damage_nonlocal_getDiffusion33/ & + homogenization_Ngrains(homog) + +end function damage_nonlocal_getDiffusion33 + +!-------------------------------------------------------------------------------------------------- +!> @brief Returns homogenized nonlocal damage mobility +!-------------------------------------------------------------------------------------------------- +real(pReal) function damage_nonlocal_getMobility(ip,el) + use mesh, only: & + mesh_element + use lattice, only: & + lattice_damageMobility + use material, only: & + material_phase, & + homogenization_Ngrains + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + integer(pInt) :: & + ipc + + damage_nonlocal_getMobility = 0.0_pReal + + do ipc = 1, homogenization_Ngrains(mesh_element(3,el)) + damage_nonlocal_getMobility = damage_nonlocal_getMobility + lattice_DamageMobility(material_phase(ipc,ip,el)) + enddo + + damage_nonlocal_getMobility = damage_nonlocal_getMobility /homogenization_Ngrains(mesh_element(3,el)) + +end function damage_nonlocal_getMobility + +!-------------------------------------------------------------------------------------------------- +!> @brief updated nonlocal damage field with solution from damage phase field PDE +!-------------------------------------------------------------------------------------------------- +subroutine damage_nonlocal_putNonLocalDamage(phi,ip,el) + use material, only: & + material_homog, & + damageMapping, & + damage + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + phi + integer(pInt) :: & + homog, & + offset + + homog = material_homog(ip,el) + offset = damageMapping(homog)%p(ip,el) + damage(homog)%p(offset) = phi + +end subroutine damage_nonlocal_putNonLocalDamage + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of damage results +!-------------------------------------------------------------------------------------------------- +function damage_nonlocal_postResults(ip,el) + use material, only: & + mappingHomogenization, & + damage_typeInstance, & + damage + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(damage_nonlocal_sizePostResults(damage_typeInstance(mappingHomogenization(2,ip,el)))) :: & + damage_nonlocal_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + instance = damage_typeInstance(homog) + + c = 0_pInt + damage_nonlocal_postResults = 0.0_pReal + + do o = 1_pInt,damage_nonlocal_Noutput(instance) + select case(damage_nonlocal_outputID(o,instance)) + + case (damage_ID) + damage_nonlocal_postResults(c+1_pInt) = damage(homog)%p(offset) + c = c + 1 + end select + enddo +end function damage_nonlocal_postResults + +end module damage_nonlocal diff --git a/code/homogenization/CMakeLists.txt b/code/homogenization/CMakeLists.txt new file mode 100644 index 000000000..84555e333 --- /dev/null +++ b/code/homogenization/CMakeLists.txt @@ -0,0 +1,11 @@ +# group sources +set (HOMOGENIZATION "homogenization" + "homogenization_RGC" + "homogenization_isostrain" + "homogenization_none" + ) + +# compile modules +foreach (p ${HOMOGENIZATION}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) diff --git a/code/homogenization/homogenization.f90 b/code/homogenization/homogenization.f90 new file mode 100644 index 000000000..00186ff06 --- /dev/null +++ b/code/homogenization/homogenization.f90 @@ -0,0 +1,1396 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Denny Tjahjanto, Max-Planck-Institut für Eisenforschung GmbH +!> @brief homogenization manager, organizing deformation partitioning and stress homogenization +!-------------------------------------------------------------------------------------------------- +module homogenization + use prec, only: & +#ifdef FEM + tOutputData, & +#endif + pInt, & + pReal + +!-------------------------------------------------------------------------------------------------- +! General variables for the homogenization at a material point + implicit none + private + real(pReal), dimension(:,:,:,:), allocatable, public :: & + materialpoint_F0, & !< def grad of IP at start of FE increment + materialpoint_F, & !< def grad of IP to be reached at end of FE increment + materialpoint_P !< first P--K stress of IP + real(pReal), dimension(:,:,:,:,:,:), allocatable, public :: & + materialpoint_dPdF !< tangent of first P--K stress at IP +#ifdef FEM + type(tOutputData), dimension(:), allocatable, public :: & + homogOutput + type(tOutputData), dimension(:,:), allocatable, public :: & + crystalliteOutput, & + phaseOutput +#else + real(pReal), dimension(:,:,:), allocatable, public :: & + materialpoint_results !< results array of material point +#endif + integer(pInt), public, protected :: & + materialpoint_sizeResults, & + homogenization_maxSizePostResults, & + thermal_maxSizePostResults, & + damage_maxSizePostResults, & + vacancyflux_maxSizePostResults, & + porosity_maxSizePostResults, & + hydrogenflux_maxSizePostResults + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + materialpoint_subF0, & !< def grad of IP at beginning of homogenization increment + materialpoint_subF !< def grad of IP to be reached at end of homog inc + real(pReal), dimension(:,:), allocatable, private :: & + materialpoint_subFrac, & + materialpoint_subStep, & + materialpoint_subdt + logical, dimension(:,:), allocatable, private :: & + materialpoint_requested, & + materialpoint_converged + logical, dimension(:,:,:), allocatable, private :: & + materialpoint_doneAndHappy + + public :: & + homogenization_init, & + materialpoint_stressAndItsTangent, & + materialpoint_postResults + private :: & + homogenization_partitionDeformation, & + homogenization_updateState, & + homogenization_averageStressAndItsTangent, & + homogenization_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_init +#ifdef HDF + use hdf5, only: & + HID_T + use IO, only : & + HDF5_mappingHomogenization +#endif + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use math, only: & + math_I3 + use debug, only: & + debug_level, & + debug_homogenization, & + debug_levelBasic, & + debug_e, & + debug_g + use mesh, only: & + mesh_maxNips, & + mesh_NcpElems, & + mesh_element, & + FE_Nips, & + FE_geomtype +#ifdef FEM + use crystallite, only: & + crystallite_sizePostResults +#else + use constitutive, only: & + constitutive_plasticity_maxSizePostResults, & + constitutive_source_maxSizePostResults + use crystallite, only: & + crystallite_maxSizePostResults +#endif + use material + use homogenization_none + use homogenization_isostrain + use homogenization_RGC + use thermal_isothermal + use thermal_adiabatic + use thermal_conduction + use damage_none + use damage_local + use damage_nonlocal + use vacancyflux_isoconc + use vacancyflux_isochempot + use vacancyflux_cahnhilliard + use porosity_none + use porosity_phasefield + use hydrogenflux_isoconc + use hydrogenflux_cahnhilliard + use IO + use numerics, only: & + worldrank + + implicit none + integer(pInt), parameter :: FILEUNIT = 200_pInt + integer(pInt) :: e,i,p + integer(pInt), dimension(:,:), pointer :: thisSize + integer(pInt), dimension(:) , pointer :: thisNoutput + character(len=64), dimension(:,:), pointer :: thisOutput + character(len=32) :: outputName !< name of output, intermediate fix until HDF5 output is ready + logical :: knownHomogenization, knownThermal, knownDamage, knownVacancyflux, knownPorosity, knownHydrogenflux +#ifdef HDF + integer(pInt), dimension(:,:), allocatable :: mapping + integer(pInt), dimension(:), allocatable :: InstancePosition + allocate(mapping(mesh_ncpelems,4),source=0_pInt) + allocate(InstancePosition(material_Nhomogenization),source=0_pInt) +#endif + + +!-------------------------------------------------------------------------------------------------- +! open material.config + if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... + call IO_open_file(FILEUNIT,material_configFile) ! ... open material.config file + +!-------------------------------------------------------------------------------------------------- +! parse homogenization from config file + if (any(homogenization_type == HOMOGENIZATION_NONE_ID)) & + call homogenization_none_init() + if (any(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID)) & + call homogenization_isostrain_init(FILEUNIT) + if (any(homogenization_type == HOMOGENIZATION_RGC_ID)) & + call homogenization_RGC_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse thermal from config file + call IO_checkAndRewind(FILEUNIT) + if (any(thermal_type == THERMAL_isothermal_ID)) & + call thermal_isothermal_init() + if (any(thermal_type == THERMAL_adiabatic_ID)) & + call thermal_adiabatic_init(FILEUNIT) + if (any(thermal_type == THERMAL_conduction_ID)) & + call thermal_conduction_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse damage from config file + call IO_checkAndRewind(FILEUNIT) + if (any(damage_type == DAMAGE_none_ID)) & + call damage_none_init() + if (any(damage_type == DAMAGE_local_ID)) & + call damage_local_init(FILEUNIT) + if (any(damage_type == DAMAGE_nonlocal_ID)) & + call damage_nonlocal_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse vacancy transport from config file + call IO_checkAndRewind(FILEUNIT) + if (any(vacancyflux_type == VACANCYFLUX_isoconc_ID)) & + call vacancyflux_isoconc_init() + if (any(vacancyflux_type == VACANCYFLUX_isochempot_ID)) & + call vacancyflux_isochempot_init(FILEUNIT) + if (any(vacancyflux_type == VACANCYFLUX_cahnhilliard_ID)) & + call vacancyflux_cahnhilliard_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse porosity from config file + call IO_checkAndRewind(FILEUNIT) + if (any(porosity_type == POROSITY_none_ID)) & + call porosity_none_init() + if (any(porosity_type == POROSITY_phasefield_ID)) & + call porosity_phasefield_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse hydrogen transport from config file + call IO_checkAndRewind(FILEUNIT) + if (any(hydrogenflux_type == HYDROGENFLUX_isoconc_ID)) & + call hydrogenflux_isoconc_init() + if (any(hydrogenflux_type == HYDROGENFLUX_cahnhilliard_ID)) & + call hydrogenflux_cahnhilliard_init(FILEUNIT) + close(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! write description file for homogenization output + mainProcess2: if (worldrank == 0) then + call IO_write_jobFile(FILEUNIT,'outputHomogenization') + do p = 1,material_Nhomogenization + if (any(material_homog == p)) then + i = homogenization_typeInstance(p) ! which instance of this homogenization type + knownHomogenization = .true. ! assume valid + select case(homogenization_type(p)) ! split per homogenization type + case (HOMOGENIZATION_NONE_ID) + outputName = HOMOGENIZATION_NONE_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (HOMOGENIZATION_ISOSTRAIN_ID) + outputName = HOMOGENIZATION_ISOSTRAIN_label + thisNoutput => homogenization_isostrain_Noutput + thisOutput => homogenization_isostrain_output + thisSize => homogenization_isostrain_sizePostResult + case (HOMOGENIZATION_RGC_ID) + outputName = HOMOGENIZATION_RGC_label + thisNoutput => homogenization_RGC_Noutput + thisOutput => homogenization_RGC_output + thisSize => homogenization_RGC_sizePostResult + case default + knownHomogenization = .false. + end select + write(FILEUNIT,'(/,a,/)') '['//trim(homogenization_name(p))//']' + if (knownHomogenization) then + write(FILEUNIT,'(a)') '(type)'//char(9)//trim(outputName) + write(FILEUNIT,'(a,i4)') '(ngrains)'//char(9),homogenization_Ngrains(p) + if (homogenization_type(p) /= HOMOGENIZATION_NONE_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + i = thermal_typeInstance(p) ! which instance of this thermal type + knownThermal = .true. ! assume valid + select case(thermal_type(p)) ! split per thermal type + case (THERMAL_isothermal_ID) + outputName = THERMAL_isothermal_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (THERMAL_adiabatic_ID) + outputName = THERMAL_adiabatic_label + thisNoutput => thermal_adiabatic_Noutput + thisOutput => thermal_adiabatic_output + thisSize => thermal_adiabatic_sizePostResult + case (THERMAL_conduction_ID) + outputName = THERMAL_conduction_label + thisNoutput => thermal_conduction_Noutput + thisOutput => thermal_conduction_output + thisSize => thermal_conduction_sizePostResult + case default + knownThermal = .false. + end select + if (knownThermal) then + write(FILEUNIT,'(a)') '(thermal)'//char(9)//trim(outputName) + if (thermal_type(p) /= THERMAL_isothermal_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + i = damage_typeInstance(p) ! which instance of this damage type + knownDamage = .true. ! assume valid + select case(damage_type(p)) ! split per damage type + case (DAMAGE_none_ID) + outputName = DAMAGE_none_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (DAMAGE_local_ID) + outputName = DAMAGE_local_label + thisNoutput => damage_local_Noutput + thisOutput => damage_local_output + thisSize => damage_local_sizePostResult + case (DAMAGE_nonlocal_ID) + outputName = DAMAGE_nonlocal_label + thisNoutput => damage_nonlocal_Noutput + thisOutput => damage_nonlocal_output + thisSize => damage_nonlocal_sizePostResult + case default + knownDamage = .false. + end select + if (knownDamage) then + write(FILEUNIT,'(a)') '(damage)'//char(9)//trim(outputName) + if (damage_type(p) /= DAMAGE_none_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + i = vacancyflux_typeInstance(p) ! which instance of this vacancy flux type + knownVacancyflux = .true. ! assume valid + select case(vacancyflux_type(p)) ! split per vacancy flux type + case (VACANCYFLUX_isoconc_ID) + outputName = VACANCYFLUX_isoconc_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (VACANCYFLUX_isochempot_ID) + outputName = VACANCYFLUX_isochempot_label + thisNoutput => vacancyflux_isochempot_Noutput + thisOutput => vacancyflux_isochempot_output + thisSize => vacancyflux_isochempot_sizePostResult + case (VACANCYFLUX_cahnhilliard_ID) + outputName = VACANCYFLUX_cahnhilliard_label + thisNoutput => vacancyflux_cahnhilliard_Noutput + thisOutput => vacancyflux_cahnhilliard_output + thisSize => vacancyflux_cahnhilliard_sizePostResult + case default + knownVacancyflux = .false. + end select + if (knownVacancyflux) then + write(FILEUNIT,'(a)') '(vacancyflux)'//char(9)//trim(outputName) + if (vacancyflux_type(p) /= VACANCYFLUX_isoconc_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + i = porosity_typeInstance(p) ! which instance of this porosity type + knownPorosity = .true. ! assume valid + select case(porosity_type(p)) ! split per porosity type + case (POROSITY_none_ID) + outputName = POROSITY_none_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (POROSITY_phasefield_ID) + outputName = POROSITY_phasefield_label + thisNoutput => porosity_phasefield_Noutput + thisOutput => porosity_phasefield_output + thisSize => porosity_phasefield_sizePostResult + case default + knownPorosity = .false. + end select + if (knownPorosity) then + write(FILEUNIT,'(a)') '(porosity)'//char(9)//trim(outputName) + if (porosity_type(p) /= POROSITY_none_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + i = hydrogenflux_typeInstance(p) ! which instance of this hydrogen flux type + knownHydrogenflux = .true. ! assume valid + select case(hydrogenflux_type(p)) ! split per hydrogen flux type + case (HYDROGENFLUX_isoconc_ID) + outputName = HYDROGENFLUX_isoconc_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (HYDROGENFLUX_cahnhilliard_ID) + outputName = HYDROGENFLUX_cahnhilliard_label + thisNoutput => hydrogenflux_cahnhilliard_Noutput + thisOutput => hydrogenflux_cahnhilliard_output + thisSize => hydrogenflux_cahnhilliard_sizePostResult + case default + knownHydrogenflux = .false. + end select + if (knownHydrogenflux) then + write(FILEUNIT,'(a)') '(hydrogenflux)'//char(9)//trim(outputName) + if (hydrogenflux_type(p) /= HYDROGENFLUX_isoconc_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + endif + enddo + close(FILEUNIT) + endif mainProcess2 + +!-------------------------------------------------------------------------------------------------- +! allocate and initialize global variables + allocate(materialpoint_dPdF(3,3,3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_F0(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + materialpoint_F0 = spread(spread(math_I3,3,mesh_maxNips),4,mesh_NcpElems) ! initialize to identity + allocate(materialpoint_F(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + materialpoint_F = materialpoint_F0 ! initialize to identity + allocate(materialpoint_subF0(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_subF(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_P(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_subFrac(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_subStep(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_subdt(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_requested(mesh_maxNips,mesh_NcpElems), source=.false.) + allocate(materialpoint_converged(mesh_maxNips,mesh_NcpElems), source=.true.) + allocate(materialpoint_doneAndHappy(2,mesh_maxNips,mesh_NcpElems), source=.true.) + +!-------------------------------------------------------------------------------------------------- +! allocate and initialize global state and postresutls variables +#ifdef HDF + elementLooping: do e = 1,mesh_NcpElems + myInstance = homogenization_typeInstance(mesh_element(3,e)) + IpLooping: do i = 1,FE_Nips(FE_geomtype(mesh_element(2,e))) + InstancePosition(myInstance) = InstancePosition(myInstance)+1_pInt + mapping(e,1:4) = [instancePosition(myinstance),myinstance,e,i] + enddo IpLooping + enddo elementLooping + call HDF5_mappingHomogenization(mapping) +#endif + + homogenization_maxSizePostResults = 0_pInt + thermal_maxSizePostResults = 0_pInt + damage_maxSizePostResults = 0_pInt + vacancyflux_maxSizePostResults = 0_pInt + porosity_maxSizePostResults = 0_pInt + hydrogenflux_maxSizePostResults = 0_pInt + do p = 1,material_Nhomogenization + homogenization_maxSizePostResults = max(homogenization_maxSizePostResults,homogState (p)%sizePostResults) + thermal_maxSizePostResults = max(thermal_maxSizePostResults, thermalState (p)%sizePostResults) + damage_maxSizePostResults = max(damage_maxSizePostResults ,damageState (p)%sizePostResults) + vacancyflux_maxSizePostResults = max(vacancyflux_maxSizePostResults ,vacancyfluxState (p)%sizePostResults) + porosity_maxSizePostResults = max(porosity_maxSizePostResults ,porosityState (p)%sizePostResults) + hydrogenflux_maxSizePostResults = max(hydrogenflux_maxSizePostResults ,hydrogenfluxState(p)%sizePostResults) + enddo + +#ifdef FEM + allocate(homogOutput (material_Nhomogenization )) + allocate(crystalliteOutput(material_Ncrystallite, homogenization_maxNgrains)) + allocate(phaseOutput (material_Nphase, homogenization_maxNgrains)) + do p = 1, material_Nhomogenization + homogOutput(p)%sizeResults = homogState (p)%sizePostResults + & + thermalState (p)%sizePostResults + & + damageState (p)%sizePostResults + & + vacancyfluxState (p)%sizePostResults + & + porosityState (p)%sizePostResults + & + hydrogenfluxState(p)%sizePostResults + homogOutput(p)%sizeIpCells = count(material_homog==p) + allocate(homogOutput(p)%output(homogOutput(p)%sizeResults,homogOutput(p)%sizeIpCells)) + enddo + do p = 1, material_Ncrystallite; do e = 1, homogenization_maxNgrains + crystalliteOutput(p,e)%sizeResults = crystallite_sizePostResults(p) + crystalliteOutput(p,e)%sizeIpCells = count(microstructure_crystallite(mesh_element(4,:)) == p .and. & + homogenization_Ngrains (mesh_element(3,:)) >= e)*mesh_maxNips + allocate(crystalliteOutput(p,e)%output(crystalliteOutput(p,e)%sizeResults,crystalliteOutput(p,e)%sizeIpCells)) + enddo; enddo + do p = 1, material_Nphase; do e = 1, homogenization_maxNgrains + phaseOutput(p,e)%sizeResults = plasticState (p)%sizePostResults + & + sum(sourceState (p)%p(:)%sizePostResults) + phaseOutput(p,e)%sizeIpCells = count(material_phase(e,:,:) == p) + allocate(phaseOutput(p,e)%output(phaseOutput(p,e)%sizeResults,phaseOutput(p,e)%sizeIpCells)) + enddo; enddo +#else + materialpoint_sizeResults = 1 & ! grain count + + 1 + homogenization_maxSizePostResults & ! homogSize & homogResult + + thermal_maxSizePostResults & + + damage_maxSizePostResults & + + vacancyflux_maxSizePostResults & + + porosity_maxSizePostResults & + + hydrogenflux_maxSizePostResults & + + homogenization_maxNgrains * (1 + crystallite_maxSizePostResults & ! crystallite size & crystallite results + + 1 + constitutive_plasticity_maxSizePostResults & ! constitutive size & constitutive results + + constitutive_source_maxSizePostResults) + allocate(materialpoint_results(materialpoint_sizeResults,mesh_maxNips,mesh_NcpElems)) +#endif + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- homogenization init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then +#ifdef TODO + write(6,'(a32,1x,7(i8,1x))') 'homogenization_state0: ', shape(homogenization_state0) + write(6,'(a32,1x,7(i8,1x))') 'homogenization_subState0: ', shape(homogenization_subState0) + write(6,'(a32,1x,7(i8,1x))') 'homogenization_state: ', shape(homogenization_state) +#endif + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_dPdF: ', shape(materialpoint_dPdF) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_F0: ', shape(materialpoint_F0) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_F: ', shape(materialpoint_F) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subF0: ', shape(materialpoint_subF0) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subF: ', shape(materialpoint_subF) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_P: ', shape(materialpoint_P) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subFrac: ', shape(materialpoint_subFrac) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subStep: ', shape(materialpoint_subStep) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subdt: ', shape(materialpoint_subdt) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_requested: ', shape(materialpoint_requested) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_converged: ', shape(materialpoint_converged) + write(6,'(a32,1x,7(i8,1x),/)') 'materialpoint_doneAndHappy: ', shape(materialpoint_doneAndHappy) +#ifndef FEM + write(6,'(a32,1x,7(i8,1x),/)') 'materialpoint_results: ', shape(materialpoint_results) +#endif + write(6,'(a32,1x,7(i8,1x))') 'maxSizePostResults: ', homogenization_maxSizePostResults + endif + flush(6) + + if (debug_g < 1 .or. debug_g > homogenization_Ngrains(mesh_element(3,debug_e))) & + call IO_error(602_pInt,ext_msg='component (grain)') + +end subroutine homogenization_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief parallelized calculation of stress and corresponding tangent at material points +!-------------------------------------------------------------------------------------------------- +subroutine materialpoint_stressAndItsTangent(updateJaco,dt) + use numerics, only: & + subStepMinHomog, & + subStepSizeHomog, & + stepIncreaseHomog, & + nHomog, & + nMPstate + use math, only: & + math_transpose33 + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP, & + terminallyIll + use mesh, only: & + mesh_element + use material, only: & + plasticState, & + sourceState, & + homogState, & + thermalState, & + damageState, & + vacancyfluxState, & + porosityState, & + hydrogenfluxState, & + phase_Nsources, & + mappingHomogenization, & + phaseAt, phasememberAt, & + homogenization_Ngrains + use crystallite, only: & + crystallite_F0, & + crystallite_Fp0, & + crystallite_Fp, & + crystallite_Fi0, & + crystallite_Fi, & + crystallite_Lp0, & + crystallite_Lp, & + crystallite_Li0, & + crystallite_Li, & + crystallite_dPdF, & + crystallite_dPdF0, & + crystallite_Tstar0_v, & + crystallite_Tstar_v, & + crystallite_partionedF0, & + crystallite_partionedF, & + crystallite_partionedFp0, & + crystallite_partionedLp0, & + crystallite_partionedFi0, & + crystallite_partionedLi0, & + crystallite_partioneddPdF0, & + crystallite_partionedTstar0_v, & + crystallite_dt, & + crystallite_requested, & + crystallite_converged, & + crystallite_stressAndItsTangent, & + crystallite_orientations + use debug, only: & + debug_level, & + debug_homogenization, & + debug_levelBasic, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_MaterialpointLoopDistribution, & + debug_MaterialpointStateLoopDistribution + + implicit none + real(pReal), intent(in) :: dt !< time increment + logical, intent(in) :: updateJaco !< initiating Jacobian update + integer(pInt) :: & + NiterationHomog, & + NiterationMPstate, & + g, & !< grain number + i, & !< integration point number + e, & !< element number + mySource, & + myNgrains + +!-------------------------------------------------------------------------------------------------- +! initialize to starting condition + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(/a,i5,1x,i2)') '<< HOMOG >> Material Point start at el ip ', debug_e, debug_i + + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< HOMOG >> F0', & + math_transpose33(materialpoint_F0(1:3,1:3,debug_i,debug_e)) + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< HOMOG >> F', & + math_transpose33(materialpoint_F(1:3,1:3,debug_i,debug_e)) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! initialize restoration points of ... + do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNgrains = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do g = 1,myNgrains + + plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) = & + plasticState (phaseAt(g,i,e))%state0( :,phasememberAt(g,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) + sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) = & + sourceState(phaseAt(g,i,e))%p(mySource)%state0( :,phasememberAt(g,i,e)) + enddo + + crystallite_partionedFp0(1:3,1:3,g,i,e) = crystallite_Fp0(1:3,1:3,g,i,e) ! ...plastic def grads + crystallite_partionedLp0(1:3,1:3,g,i,e) = crystallite_Lp0(1:3,1:3,g,i,e) ! ...plastic velocity grads + crystallite_partionedFi0(1:3,1:3,g,i,e) = crystallite_Fi0(1:3,1:3,g,i,e) ! ...intermediate def grads + crystallite_partionedLi0(1:3,1:3,g,i,e) = crystallite_Li0(1:3,1:3,g,i,e) ! ...intermediate velocity grads + crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,g,i,e) = crystallite_dPdF0(1:3,1:3,1:3,1:3,g,i,e) ! ...stiffness + crystallite_partionedF0(1:3,1:3,g,i,e) = crystallite_F0(1:3,1:3,g,i,e) ! ...def grads + crystallite_partionedTstar0_v(1:6,g,i,e) = crystallite_Tstar0_v(1:6,g,i,e) ! ...2nd PK stress + + enddo; enddo + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e)) + materialpoint_subF0(1:3,1:3,i,e) = materialpoint_F0(1:3,1:3,i,e) ! ...def grad + materialpoint_subFrac(i,e) = 0.0_pReal + materialpoint_subStep(i,e) = 1.0_pReal/subStepSizeHomog ! <> + materialpoint_converged(i,e) = .false. ! pretend failed step of twice the required size + materialpoint_requested(i,e) = .true. ! everybody requires calculation + endforall + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + homogState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal homogenization state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + thermalState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal thermal state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + damageState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal damage state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + vacancyfluxState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal vacancy transport state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + porosityState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal porosity state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + hydrogenfluxState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal hydrogen transport state + enddo + NiterationHomog = 0_pInt + + cutBackLooping: do while (.not. terminallyIll .and. & + any(materialpoint_subStep(:,FEsolving_execELem(1):FEsolving_execElem(2)) > subStepMinHomog)) + + !$OMP PARALLEL DO PRIVATE(myNgrains) + elementLooping1: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNgrains = homogenization_Ngrains(mesh_element(3,e)) + IpLooping1: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + + converged: if ( materialpoint_converged(i,e) ) then +#ifndef _OPENMP + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i) & + .or. .not. iand(debug_level(debug_homogenization),debug_levelSelective) /= 0_pInt)) then + write(6,'(a,1x,f12.8,1x,a,1x,f12.8,1x,a,i8,1x,i2/)') '<< HOMOG >> winding forward from', & + materialpoint_subFrac(i,e), 'to current materialpoint_subFrac', & + materialpoint_subFrac(i,e)+materialpoint_subStep(i,e),'in materialpoint_stressAndItsTangent at el ip',e,i + endif +#endif + +!--------------------------------------------------------------------------------------------------- +! calculate new subStep and new subFrac + materialpoint_subFrac(i,e) = materialpoint_subFrac(i,e) + materialpoint_subStep(i,e) + !$OMP FLUSH(materialpoint_subFrac) + materialpoint_subStep(i,e) = min(1.0_pReal-materialpoint_subFrac(i,e), & + stepIncreaseHomog*materialpoint_subStep(i,e)) ! introduce flexibility for step increase/acceleration + !$OMP FLUSH(materialpoint_subStep) + + steppingNeeded: if (materialpoint_subStep(i,e) > subStepMinHomog) then + + ! wind forward grain starting point of... + crystallite_partionedF0(1:3,1:3,1:myNgrains,i,e) = & + crystallite_partionedF(1:3,1:3,1:myNgrains,i,e) ! ...def grads + + crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) = & + crystallite_Fp(1:3,1:3,1:myNgrains,i,e) ! ...plastic def grads + + crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) = & + crystallite_Lp(1:3,1:3,1:myNgrains,i,e) ! ...plastic velocity grads + + crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) = & + crystallite_Fi(1:3,1:3,1:myNgrains,i,e) ! ...intermediate def grads + + crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) = & + crystallite_Li(1:3,1:3,1:myNgrains,i,e) ! ...intermediate velocity grads + + crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,1:myNgrains,i,e) = & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:myNgrains,i,e) ! ...stiffness + + crystallite_partionedTstar0_v(1:6,1:myNgrains,i,e) = & + crystallite_Tstar_v(1:6,1:myNgrains,i,e) ! ...2nd PK stress + + do g = 1,myNgrains + plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) = & + plasticState (phaseAt(g,i,e))%state( :,phasememberAt(g,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) + sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) = & + sourceState(phaseAt(g,i,e))%p(mySource)%state( :,phasememberAt(g,i,e)) + enddo + enddo + + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + homogState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal homogenization state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + thermalState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal thermal state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + damageState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal damage state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + vacancyfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal vacancy transport state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + porosityState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal porosity state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + hydrogenfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal hydrogen transport state + materialpoint_subF0(1:3,1:3,i,e) = materialpoint_subF(1:3,1:3,i,e) ! ...def grad + !$OMP FLUSH(materialpoint_subF0) + elseif (materialpoint_requested(i,e)) then steppingNeeded ! already at final time (??) + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionHomog) + debug_MaterialpointLoopDistribution(min(nHomog+1,NiterationHomog)) = & + debug_MaterialpointLoopDistribution(min(nHomog+1,NiterationHomog)) + 1 + !$OMP END CRITICAL (distributionHomog) + endif + endif steppingNeeded + + else converged + if ( (myNgrains == 1_pInt .and. materialpoint_subStep(i,e) <= 1.0 ) .or. & ! single grain already tried internal subStepping in crystallite + subStepSizeHomog * materialpoint_subStep(i,e) <= subStepMinHomog ) then ! would require too small subStep + ! cutback makes no sense + !$OMP FLUSH(terminallyIll) + if (.not. terminallyIll) then ! so first signals terminally ill... + !$OMP CRITICAL (write2out) + write(6,*) 'Integration point ', i,' at element ', e, ' terminally ill' + !$OMP END CRITICAL (write2out) + endif + !$OMP CRITICAL (setTerminallyIll) + terminallyIll = .true. ! ...and kills all others + !$OMP END CRITICAL (setTerminallyIll) + else ! cutback makes sense + materialpoint_subStep(i,e) = subStepSizeHomog * materialpoint_subStep(i,e) ! crystallite had severe trouble, so do a significant cutback + !$OMP FLUSH(materialpoint_subStep) + +#ifndef _OPENMP + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i) & + .or. .not. iand(debug_level(debug_homogenization), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,1x,f12.8,a,i8,1x,i2/)') & + '<< HOMOG >> cutback step in materialpoint_stressAndItsTangent with new materialpoint_subStep:',& + materialpoint_subStep(i,e),' at el ip',e,i + endif +#endif + +!-------------------------------------------------------------------------------------------------- +! restore... + crystallite_Fp(1:3,1:3,1:myNgrains,i,e) = & + crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) ! ...plastic def grads + crystallite_Lp(1:3,1:3,1:myNgrains,i,e) = & + crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) ! ...plastic velocity grads + crystallite_Fi(1:3,1:3,1:myNgrains,i,e) = & + crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) ! ...intermediate def grads + crystallite_Li(1:3,1:3,1:myNgrains,i,e) = & + crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) ! ...intermediate velocity grads + crystallite_dPdF(1:3,1:3,1:3,1:3,1:myNgrains,i,e) = & + crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,1:myNgrains,i,e) ! ...stiffness + crystallite_Tstar_v(1:6,1:myNgrains,i,e) = & + crystallite_partionedTstar0_v(1:6,1:myNgrains,i,e) ! ...2nd PK stress + do g = 1, myNgrains + plasticState (phaseAt(g,i,e))%state( :,phasememberAt(g,i,e)) = & + plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) + sourceState(phaseAt(g,i,e))%p(mySource)%state( :,phasememberAt(g,i,e)) = & + sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) + enddo + enddo + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + homogState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal homogenization state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + thermalState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal thermal state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + damageState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal damage state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + vacancyfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal vacancy transport state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + porosityState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal porosity state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + hydrogenfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal hydrogen transport state + endif + endif converged + + if (materialpoint_subStep(i,e) > subStepMinHomog) then + materialpoint_requested(i,e) = .true. + materialpoint_subF(1:3,1:3,i,e) = materialpoint_subF0(1:3,1:3,i,e) + & + materialpoint_subStep(i,e) * (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) + materialpoint_subdt(i,e) = materialpoint_subStep(i,e) * dt + materialpoint_doneAndHappy(1:2,i,e) = [.false.,.true.] + endif + enddo IpLooping1 + enddo elementLooping1 + !$OMP END PARALLEL DO + + NiterationMPstate = 0_pInt + + convergenceLooping: do while (.not. terminallyIll .and. & + any( materialpoint_requested(:,FEsolving_execELem(1):FEsolving_execElem(2)) & + .and. .not. materialpoint_doneAndHappy(1,:,FEsolving_execELem(1):FEsolving_execElem(2)) & + ) .and. & + NiterationMPstate < nMPstate) + NiterationMPstate = NiterationMPstate + 1 + +!-------------------------------------------------------------------------------------------------- +! deformation partitioning +! based on materialpoint_subF0,.._subF,crystallite_partionedF0, and homogenization_state, +! results in crystallite_partionedF + !$OMP PARALLEL DO PRIVATE(myNgrains) + elementLooping2: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNgrains = homogenization_Ngrains(mesh_element(3,e)) + IpLooping2: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if ( materialpoint_requested(i,e) .and. & ! process requested but... + .not. materialpoint_doneAndHappy(1,i,e)) then ! ...not yet done material points + call homogenization_partitionDeformation(i,e) ! partition deformation onto constituents + crystallite_dt(1:myNgrains,i,e) = materialpoint_subdt(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 +! based on crystallite_partionedF0,.._partionedF +! incrementing by crystallite_dt + call crystallite_stressAndItsTangent(updateJaco) ! request stress and tangent calculation for constituent grains + +!-------------------------------------------------------------------------------------------------- +! state update + !$OMP PARALLEL DO + elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) + IpLooping3: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if ( materialpoint_requested(i,e) .and. & + .not. materialpoint_doneAndHappy(1,i,e)) then + if (.not. all(crystallite_converged(:,i,e))) then + materialpoint_doneAndHappy(1:2,i,e) = [.true.,.false.] + materialpoint_converged(i,e) = .false. + else + materialpoint_doneAndHappy(1:2,i,e) = homogenization_updateState(i,e) + materialpoint_converged(i,e) = all(materialpoint_doneAndHappy(1:2,i,e)) ! converged if done and happy + endif + !$OMP FLUSH(materialpoint_converged) + if (materialpoint_converged(i,e)) then + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionMPState) + debug_MaterialpointStateLoopdistribution(NiterationMPstate) = & + debug_MaterialpointStateLoopdistribution(NiterationMPstate) + 1_pInt + !$OMP END CRITICAL (distributionMPState) + endif + endif + endif + enddo IpLooping3 + enddo elementLooping3 + !$OMP END PARALLEL DO + + enddo convergenceLooping + + NiterationHomog = NiterationHomog + 1_pInt + + enddo cutBackLooping + + 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,e),FEsolving_execIP(2,e) + call homogenization_averageStressAndItsTangent(i,e) + enddo IpLooping4 + enddo elementLooping4 + !$OMP END PARALLEL DO + else + !$OMP CRITICAL (write2out) + write(6,'(/,a,/)') '<< HOMOG >> Material Point terminally ill' + !$OMP END CRITICAL (write2out) + endif + +end subroutine materialpoint_stressAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief parallelized calculation of result array at material points +!-------------------------------------------------------------------------------------------------- +subroutine materialpoint_postResults + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP + use mesh, only: & + mesh_element + use material, only: & + mappingHomogenization, & +#ifdef FEM + phaseAt, phasememberAt, & + homogenization_maxNgrains, & + material_Ncrystallite, & + material_Nphase, & +#else + homogState, & + thermalState, & + damageState, & + vacancyfluxState, & + porosityState, & + hydrogenfluxState, & +#endif + plasticState, & + sourceState, & + material_phase, & + homogenization_Ngrains, & + microstructure_crystallite + use constitutive, only: & +#ifdef FEM + constitutive_plasticity_maxSizePostResults, & + constitutive_source_maxSizePostResults, & +#endif + constitutive_postResults + use crystallite, only: & +#ifdef FEM + crystallite_maxSizePostResults, & +#endif + crystallite_sizePostResults, & + crystallite_postResults + + implicit none + integer(pInt) :: & + thePos, & + theSize, & + myNgrains, & + myCrystallite, & + g, & !< grain number + i, & !< integration point number + e !< element number +#ifdef FEM + integer(pInt) :: & + myHomog, & + myPhase, & + crystalliteCtr(material_Ncrystallite, homogenization_maxNgrains), & + phaseCtr (material_Nphase, homogenization_maxNgrains) + real(pReal), dimension(1+crystallite_maxSizePostResults + & + 1+constitutive_plasticity_maxSizePostResults + & + constitutive_source_maxSizePostResults) :: & + crystalliteResults + + + + crystalliteCtr = 0_pInt; phaseCtr = 0_pInt + elementLooping: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNgrains = homogenization_Ngrains(mesh_element(3,e)) + myCrystallite = microstructure_crystallite(mesh_element(4,e)) + IpLooping: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + myHomog = mappingHomogenization(2,i,e) + thePos = mappingHomogenization(1,i,e) + homogOutput(myHomog)%output(1: & + homogOutput(myHomog)%sizeResults, & + thePos) = homogenization_postResults(i,e) + + grainLooping :do g = 1,myNgrains + myPhase = phaseAt(g,i,e) + crystalliteResults(1:1+crystallite_sizePostResults(myCrystallite) + & + 1+plasticState(myPhase)%sizePostResults + & + sum(sourceState(myPhase)%p(:)%sizePostResults)) = crystallite_postResults(g,i,e) + if (microstructure_crystallite(mesh_element(4,e)) == myCrystallite .and. & + homogenization_Ngrains (mesh_element(3,e)) >= g) then + crystalliteCtr(myCrystallite,g) = crystalliteCtr(myCrystallite,g) + 1_pInt + crystalliteOutput(myCrystallite,g)% & + output(1:crystalliteOutput(myCrystallite,g)%sizeResults,crystalliteCtr(myCrystallite,g)) = & + crystalliteResults(2:1+crystalliteOutput(myCrystallite,g)%sizeResults) + endif + if (material_phase(g,i,e) == myPhase) then + phaseCtr(myPhase,g) = phaseCtr(myPhase,g) + 1_pInt + phaseOutput(myPhase,g)% & + output(1:phaseOutput(myPhase,g)%sizeResults,phaseCtr(myPhase,g)) = & + crystalliteResults(3 + crystalliteOutput(myCrystallite,g)%sizeResults: & + 1 + crystalliteOutput(myCrystallite,g)%sizeResults + & + 1 + plasticState (myphase)%sizePostResults + & + sum(sourceState(myphase)%p(:)%sizePostResults)) + endif + enddo grainLooping + enddo IpLooping + enddo elementLooping +#else + + !$OMP PARALLEL DO PRIVATE(myNgrains,myCrystallite,thePos,theSize) + elementLooping: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNgrains = homogenization_Ngrains(mesh_element(3,e)) + myCrystallite = microstructure_crystallite(mesh_element(4,e)) + IpLooping: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + thePos = 0_pInt + + theSize = homogState (mappingHomogenization(2,i,e))%sizePostResults & + + thermalState (mappingHomogenization(2,i,e))%sizePostResults & + + damageState (mappingHomogenization(2,i,e))%sizePostResults & + + vacancyfluxState (mappingHomogenization(2,i,e))%sizePostResults & + + porosityState (mappingHomogenization(2,i,e))%sizePostResults & + + hydrogenfluxState(mappingHomogenization(2,i,e))%sizePostResults + materialpoint_results(thePos+1,i,e) = real(theSize,pReal) ! tell size of homogenization results + thePos = thePos + 1_pInt + + if (theSize > 0_pInt) then ! any homogenization results to mention? + materialpoint_results(thePos+1:thePos+theSize,i,e) = homogenization_postResults(i,e) ! tell homogenization results + thePos = thePos + theSize + endif + + materialpoint_results(thePos+1,i,e) = real(myNgrains,pReal) ! tell number of grains at materialpoint + thePos = thePos + 1_pInt + + grainLooping :do g = 1,myNgrains + theSize = 1 + crystallite_sizePostResults(myCrystallite) + & + 1 + plasticState (material_phase(g,i,e))%sizePostResults + & !ToDo + sum(sourceState(material_phase(g,i,e))%p(:)%sizePostResults) + materialpoint_results(thePos+1:thePos+theSize,i,e) = crystallite_postResults(g,i,e) ! tell crystallite results + thePos = thePos + theSize + enddo grainLooping + enddo IpLooping + enddo elementLooping + !$OMP END PARALLEL DO +#endif + +end subroutine materialpoint_postResults + + +!-------------------------------------------------------------------------------------------------- +!> @brief partition material point def grad onto constituents +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_partitionDeformation(ip,el) + use mesh, only: & + mesh_element + use material, only: & + homogenization_type, & + homogenization_maxNgrains, & + HOMOGENIZATION_NONE_ID, & + HOMOGENIZATION_ISOSTRAIN_ID, & + HOMOGENIZATION_RGC_ID + use crystallite, only: & + crystallite_partionedF + use homogenization_isostrain, only: & + homogenization_isostrain_partitionDeformation + use homogenization_RGC, only: & + homogenization_RGC_partitionDeformation + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element number + + chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) + + case (HOMOGENIZATION_NONE_ID) chosenHomogenization + crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el) = 0.0_pReal + crystallite_partionedF(1:3,1:3,1:1,ip,el) = & + spread(materialpoint_subF(1:3,1:3,ip,el),3,1) + + case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization + call homogenization_isostrain_partitionDeformation(& + crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + materialpoint_subF(1:3,1:3,ip,el),& + el) + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + call homogenization_RGC_partitionDeformation(& + crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + materialpoint_subF(1:3,1:3,ip,el),& + ip, & + el) + end select chosenHomogenization + +end subroutine homogenization_partitionDeformation + + +!-------------------------------------------------------------------------------------------------- +!> @brief update the internal state of the homogenization scheme and tell whether "done" and +!> "happy" with result +!-------------------------------------------------------------------------------------------------- +function homogenization_updateState(ip,el) + use mesh, only: & + mesh_element + use material, only: & + homogenization_type, & + thermal_type, & + damage_type, & + vacancyflux_type, & + homogenization_maxNgrains, & + HOMOGENIZATION_RGC_ID, & + THERMAL_adiabatic_ID, & + DAMAGE_local_ID, & + VACANCYFLUX_isochempot_ID + use crystallite, only: & + crystallite_P, & + crystallite_dPdF, & + crystallite_partionedF,& + crystallite_partionedF0 + use homogenization_RGC, only: & + homogenization_RGC_updateState + use thermal_adiabatic, only: & + thermal_adiabatic_updateState + use damage_local, only: & + damage_local_updateState + use vacancyflux_isochempot, only: & + vacancyflux_isochempot_updateState + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element number + logical, dimension(2) :: homogenization_updateState + + homogenization_updateState = .true. + chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + homogenization_updateState = & + homogenization_updateState .and. & + homogenization_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + crystallite_partionedF0(1:3,1:3,1:homogenization_maxNgrains,ip,el),& + materialpoint_subF(1:3,1:3,ip,el),& + materialpoint_subdt(ip,el), & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & + ip, & + el) + end select chosenHomogenization + + chosenThermal: select case (thermal_type(mesh_element(3,el))) + case (THERMAL_adiabatic_ID) chosenThermal + homogenization_updateState = & + homogenization_updateState .and. & + thermal_adiabatic_updateState(materialpoint_subdt(ip,el), & + ip, & + el) + end select chosenThermal + + chosenDamage: select case (damage_type(mesh_element(3,el))) + case (DAMAGE_local_ID) chosenDamage + homogenization_updateState = & + homogenization_updateState .and. & + damage_local_updateState(materialpoint_subdt(ip,el), & + ip, & + el) + end select chosenDamage + + chosenVacancyflux: select case (vacancyflux_type(mesh_element(3,el))) + case (VACANCYFLUX_isochempot_ID) chosenVacancyflux + homogenization_updateState = & + homogenization_updateState .and. & + vacancyflux_isochempot_updateState(materialpoint_subdt(ip,el), & + ip, & + el) + end select chosenVacancyflux + +end function homogenization_updateState + + +!-------------------------------------------------------------------------------------------------- +!> @brief derive average stress and stiffness from constituent quantities +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_averageStressAndItsTangent(ip,el) + use mesh, only: & + mesh_element + use material, only: & + homogenization_type, & + homogenization_maxNgrains, & + HOMOGENIZATION_NONE_ID, & + HOMOGENIZATION_ISOSTRAIN_ID, & + HOMOGENIZATION_RGC_ID + use crystallite, only: & + crystallite_P,crystallite_dPdF + use homogenization_isostrain, only: & + homogenization_isostrain_averageStressAndItsTangent + use homogenization_RGC, only: & + homogenization_RGC_averageStressAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element number + + chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) + case (HOMOGENIZATION_NONE_ID) chosenHomogenization + materialpoint_P(1:3,1:3,ip,el) = sum(crystallite_P(1:3,1:3,1:1,ip,el),3) + materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el) & + = sum(crystallite_dPdF(1:3,1:3,1:3,1:3,1:1,ip,el),5) + + case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization + call homogenization_isostrain_averageStressAndItsTangent(& + materialpoint_P(1:3,1:3,ip,el), & + materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& + crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & + el) + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + call homogenization_RGC_averageStressAndItsTangent(& + materialpoint_P(1:3,1:3,ip,el), & + materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& + crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & + el) + end select chosenHomogenization + +end subroutine homogenization_averageStressAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of homogenization results for post file inclusion. call only, +!> if homogenization_sizePostResults(i,e) > 0 !! +!-------------------------------------------------------------------------------------------------- +function homogenization_postResults(ip,el) + use mesh, only: & + mesh_element + use material, only: & + mappingHomogenization, & + homogState, & + thermalState, & + damageState, & + vacancyfluxState, & + porosityState, & + hydrogenfluxState, & + homogenization_type, & + thermal_type, & + damage_type, & + vacancyflux_type, & + porosity_type, & + hydrogenflux_type, & + HOMOGENIZATION_NONE_ID, & + HOMOGENIZATION_ISOSTRAIN_ID, & + HOMOGENIZATION_RGC_ID, & + THERMAL_isothermal_ID, & + THERMAL_adiabatic_ID, & + THERMAL_conduction_ID, & + DAMAGE_none_ID, & + DAMAGE_local_ID, & + DAMAGE_nonlocal_ID, & + VACANCYFLUX_isoconc_ID, & + VACANCYFLUX_isochempot_ID, & + VACANCYFLUX_cahnhilliard_ID, & + POROSITY_none_ID, & + POROSITY_phasefield_ID, & + HYDROGENFLUX_isoconc_ID, & + HYDROGENFLUX_cahnhilliard_ID + use homogenization_isostrain, only: & + homogenization_isostrain_postResults + use homogenization_RGC, only: & + homogenization_RGC_postResults + use thermal_adiabatic, only: & + thermal_adiabatic_postResults + use thermal_conduction, only: & + thermal_conduction_postResults + use damage_local, only: & + damage_local_postResults + use damage_nonlocal, only: & + damage_nonlocal_postResults + use vacancyflux_isochempot, only: & + vacancyflux_isochempot_postResults + use vacancyflux_cahnhilliard, only: & + vacancyflux_cahnhilliard_postResults + use porosity_phasefield, only: & + porosity_phasefield_postResults + use hydrogenflux_cahnhilliard, only: & + hydrogenflux_cahnhilliard_postResults + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element number + real(pReal), dimension( homogState (mappingHomogenization(2,ip,el))%sizePostResults & + + thermalState (mappingHomogenization(2,ip,el))%sizePostResults & + + damageState (mappingHomogenization(2,ip,el))%sizePostResults & + + vacancyfluxState (mappingHomogenization(2,ip,el))%sizePostResults & + + porosityState (mappingHomogenization(2,ip,el))%sizePostResults & + + hydrogenfluxState(mappingHomogenization(2,ip,el))%sizePostResults) :: & + homogenization_postResults + integer(pInt) :: & + startPos, endPos + + homogenization_postResults = 0.0_pReal + + startPos = 1_pInt + endPos = homogState(mappingHomogenization(2,ip,el))%sizePostResults + chosenHomogenization: select case (homogenization_type(mesh_element(3,el))) + case (HOMOGENIZATION_NONE_ID) chosenHomogenization + + case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization + homogenization_postResults(startPos:endPos) = & + homogenization_isostrain_postResults(& + ip, & + el, & + materialpoint_P(1:3,1:3,ip,el), & + materialpoint_F(1:3,1:3,ip,el)) + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + homogenization_postResults(startPos:endPos) = & + homogenization_RGC_postResults(& + ip, & + el, & + materialpoint_P(1:3,1:3,ip,el), & + materialpoint_F(1:3,1:3,ip,el)) + end select chosenHomogenization + + startPos = endPos + 1_pInt + endPos = endPos + thermalState(mappingHomogenization(2,ip,el))%sizePostResults + chosenThermal: select case (thermal_type(mesh_element(3,el))) + case (THERMAL_isothermal_ID) chosenThermal + + case (THERMAL_adiabatic_ID) chosenThermal + homogenization_postResults(startPos:endPos) = & + thermal_adiabatic_postResults(ip, el) + case (THERMAL_conduction_ID) chosenThermal + homogenization_postResults(startPos:endPos) = & + thermal_conduction_postResults(ip, el) + end select chosenThermal + + startPos = endPos + 1_pInt + endPos = endPos + damageState(mappingHomogenization(2,ip,el))%sizePostResults + chosenDamage: select case (damage_type(mesh_element(3,el))) + case (DAMAGE_none_ID) chosenDamage + + case (DAMAGE_local_ID) chosenDamage + homogenization_postResults(startPos:endPos) = & + damage_local_postResults(ip, el) + + case (DAMAGE_nonlocal_ID) chosenDamage + homogenization_postResults(startPos:endPos) = & + damage_nonlocal_postResults(ip, el) + end select chosenDamage + + startPos = endPos + 1_pInt + endPos = endPos + vacancyfluxState(mappingHomogenization(2,ip,el))%sizePostResults + chosenVacancyflux: select case (vacancyflux_type(mesh_element(3,el))) + case (VACANCYFLUX_isoconc_ID) chosenVacancyflux + + case (VACANCYFLUX_isochempot_ID) chosenVacancyflux + homogenization_postResults(startPos:endPos) = & + vacancyflux_isochempot_postResults(ip, el) + case (VACANCYFLUX_cahnhilliard_ID) chosenVacancyflux + homogenization_postResults(startPos:endPos) = & + vacancyflux_cahnhilliard_postResults(ip, el) + end select chosenVacancyflux + + startPos = endPos + 1_pInt + endPos = endPos + porosityState(mappingHomogenization(2,ip,el))%sizePostResults + chosenPorosity: select case (porosity_type(mesh_element(3,el))) + case (POROSITY_none_ID) chosenPorosity + + case (POROSITY_phasefield_ID) chosenPorosity + homogenization_postResults(startPos:endPos) = & + porosity_phasefield_postResults(ip, el) + end select chosenPorosity + + startPos = endPos + 1_pInt + endPos = endPos + hydrogenfluxState(mappingHomogenization(2,ip,el))%sizePostResults + chosenHydrogenflux: select case (hydrogenflux_type(mesh_element(3,el))) + case (HYDROGENFLUX_isoconc_ID) chosenHydrogenflux + + case (HYDROGENFLUX_cahnhilliard_ID) chosenHydrogenflux + homogenization_postResults(startPos:endPos) = & + hydrogenflux_cahnhilliard_postResults(ip, el) + end select chosenHydrogenflux + +end function homogenization_postResults + +end module homogenization diff --git a/code/homogenization/homogenization_RGC.f90 b/code/homogenization/homogenization_RGC.f90 new file mode 100644 index 000000000..323ca2934 --- /dev/null +++ b/code/homogenization/homogenization_RGC.f90 @@ -0,0 +1,1558 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Denny Tjahjanto, 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 +!> @brief Relaxed grain cluster (RGC) homogenization scheme +!> Ngrains is defined as p x q x r (cluster) +!-------------------------------------------------------------------------------------------------- +module homogenization_RGC + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public :: & + homogenization_RGC_sizeState, & + homogenization_RGC_sizePostResults + integer(pInt), dimension(:,:), allocatable,target, public :: & + homogenization_RGC_sizePostResult + character(len=64), dimension(:,:), allocatable,target, public :: & + homogenization_RGC_output ! name of each post result output + integer(pInt), dimension(:), allocatable,target, public :: & + homogenization_RGC_Noutput !< number of outputs per homog instance + integer(pInt), dimension(:,:), allocatable, private :: & + homogenization_RGC_Ngrains + real(pReal), dimension(:,:), allocatable, private :: & + homogenization_RGC_dAlpha, & + homogenization_RGC_angles + real(pReal), dimension(:,:,:,:), allocatable, private :: & + homogenization_RGC_orientation + real(pReal), dimension(:), allocatable, private :: & + homogenization_RGC_xiAlpha, & + homogenization_RGC_ciAlpha + enum, bind(c) + enumerator :: undefined_ID, & + constitutivework_ID, & + penaltyenergy_ID, & + volumediscrepancy_ID, & + averagerelaxrate_ID,& + maximumrelaxrate_ID,& + ipcoords_ID,& + magnitudemismatch_ID,& + avgdefgrad_ID,& + avgfirstpiola_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + homogenization_RGC_outputID !< ID of each post result output + + public :: & + homogenization_RGC_init, & + homogenization_RGC_partitionDeformation, & + homogenization_RGC_averageStressAndItsTangent, & + homogenization_RGC_updateState, & + homogenization_RGC_postResults + private :: & + homogenization_RGC_stressPenalty, & + homogenization_RGC_volumePenalty, & + homogenization_RGC_grainDeformation, & + homogenization_RGC_surfaceCorrection, & + homogenization_RGC_equivalentModuli, & + homogenization_RGC_relaxationVector, & + homogenization_RGC_interfaceNormal, & + homogenization_RGC_getInterface, & + homogenization_RGC_grain1to3, & + homogenization_RGC_grain3to1, & + homogenization_RGC_interface4to1, & + homogenization_RGC_interface1to4 + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use debug, only: & + debug_level, & + debug_homogenization, & + debug_levelBasic, & + debug_levelExtensive + use math, only: & + math_Mandel3333to66,& + math_Voigt66to3333, & + math_I3, & + math_sampleRandomOri,& + math_EulerToR,& + INRAD + use mesh, only: & + mesh_maxNips, & + mesh_NcpElems,& + mesh_element, & + FE_Nips, & + FE_geomtype + use IO + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit !< file pointer to material configuration + integer(pInt), allocatable, dimension(:) :: chunkPos + integer :: & + homog, & + NofMyHomog, & + o, & + instance, & + sizeHState + integer(pInt) :: section=0_pInt, maxNinstance, i,j,e, mySize, myInstance + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_RGC_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(homogenization_type == HOMOGENIZATION_RGC_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_HOMOGENIZATION),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + allocate(homogenization_RGC_sizeState(maxNinstance), source=0_pInt) + allocate(homogenization_RGC_sizePostResults(maxNinstance), source=0_pInt) + allocate(homogenization_RGC_Noutput(maxNinstance), source=0_pInt) + allocate(homogenization_RGC_Ngrains(3,maxNinstance), source=0_pInt) + allocate(homogenization_RGC_ciAlpha(maxNinstance), source=0.0_pReal) + allocate(homogenization_RGC_xiAlpha(maxNinstance), source=0.0_pReal) + allocate(homogenization_RGC_dAlpha(3,maxNinstance), source=0.0_pReal) + allocate(homogenization_RGC_angles(3,maxNinstance), source=400.0_pReal) + allocate(homogenization_RGC_output(maxval(homogenization_Noutput),maxNinstance)) + homogenization_RGC_output='' + allocate(homogenization_RGC_outputID(maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(homogenization_RGC_sizePostResult(maxval(homogenization_Noutput),maxNinstance),& + source=0_pInt) + allocate(homogenization_RGC_orientation(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + homogenization_RGC_orientation = spread(spread(math_I3,3,mesh_maxNips),4,mesh_NcpElems) ! initialize to identity + + rewind(fileUnit) + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>'))/=material_partHomogenization) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homogenization part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + cycle + endif + if (section > 0_pInt ) then ! do not short-circuit here (.and. with next if-statement). It's not safe in Fortran + if (homogenization_type(section) == HOMOGENIZATION_RGC_ID) then ! one of my sections + i = homogenization_typeInstance(section) ! which instance of my type is present homogenization + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case('constitutivework') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = constitutivework_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('penaltyenergy') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = penaltyenergy_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('volumediscrepancy') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = volumediscrepancy_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('averagerelaxrate') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = averagerelaxrate_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('maximumrelaxrate') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = maximumrelaxrate_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('magnitudemismatch') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = magnitudemismatch_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('ipcoords') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = ipcoords_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('avgdefgrad','avgf') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = avgdefgrad_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('avgp','avgfirstpiola','avg1stpiola') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = avgfirstpiola_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + + end select + case ('clustersize') + homogenization_RGC_Ngrains(1,i) = IO_intValue(line,chunkPos,2_pInt) + homogenization_RGC_Ngrains(2,i) = IO_intValue(line,chunkPos,3_pInt) + homogenization_RGC_Ngrains(3,i) = IO_intValue(line,chunkPos,4_pInt) + if (homogenization_Ngrains(section) /= product(homogenization_RGC_Ngrains(1:3,i))) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//HOMOGENIZATION_RGC_label//')') + case ('scalingparameter') + homogenization_RGC_xiAlpha(i) = IO_floatValue(line,chunkPos,2_pInt) + case ('overproportionality') + homogenization_RGC_ciAlpha(i) = IO_floatValue(line,chunkPos,2_pInt) + case ('grainsize') + homogenization_RGC_dAlpha(1,i) = IO_floatValue(line,chunkPos,2_pInt) + homogenization_RGC_dAlpha(2,i) = IO_floatValue(line,chunkPos,3_pInt) + homogenization_RGC_dAlpha(3,i) = IO_floatValue(line,chunkPos,4_pInt) + case ('clusterorientation') + homogenization_RGC_angles(1,i) = IO_floatValue(line,chunkPos,2_pInt) + homogenization_RGC_angles(2,i) = IO_floatValue(line,chunkPos,3_pInt) + homogenization_RGC_angles(3,i) = IO_floatValue(line,chunkPos,4_pInt) + + end select + endif + endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! * assigning cluster orientations + elementLooping: do e = 1_pInt,mesh_NcpElems + if (homogenization_type(mesh_element(3,e)) == HOMOGENIZATION_RGC_ID) then + myInstance = homogenization_typeInstance(mesh_element(3,e)) + if (all (homogenization_RGC_angles(1:3,myInstance) >= 399.9_pReal)) then + homogenization_RGC_orientation(1:3,1:3,1,e) = math_EulerToR(math_sampleRandomOri()) + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + if (microstructure_elemhomo(mesh_element(4,e))) then + homogenization_RGC_orientation(1:3,1:3,i,e) = homogenization_RGC_orientation(1:3,1:3,1,e) + else + homogenization_RGC_orientation(1:3,1:3,i,e) = math_EulerToR(math_sampleRandomOri()) + endif + enddo + else + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + homogenization_RGC_orientation(1:3,1:3,i,e) = & + math_EulerToR(homogenization_RGC_angles(1:3,myInstance)*inRad) + enddo + endif + endif + enddo elementLooping + + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + do i = 1_pInt,maxNinstance + write(6,'(a15,1x,i4,/)') 'instance: ', i + write(6,'(a25,3(1x,i8))') 'cluster size: ',(homogenization_RGC_Ngrains(j,i),j=1_pInt,3_pInt) + write(6,'(a25,1x,e10.3)') 'scaling parameter: ', homogenization_RGC_xiAlpha(i) + write(6,'(a25,1x,e10.3)') 'over-proportionality: ', homogenization_RGC_ciAlpha(i) + write(6,'(a25,3(1x,e10.3))') 'grain size: ',(homogenization_RGC_dAlpha(j,i),j=1_pInt,3_pInt) + write(6,'(a25,3(1x,e10.3))') 'cluster orientation: ',(homogenization_RGC_angles(j,i),j=1_pInt,3_pInt) + enddo + endif +!-------------------------------------------------------------------------------------------------- + initializeInstances: do homog = 1_pInt, material_Nhomogenization + myHomog: if (homogenization_type(homog) == HOMOGENIZATION_RGC_ID) then + NofMyHomog = count(material_homog == homog) + instance = homogenization_typeInstance(homog) + +! * Determine size of postResults array + outputsLoop: do o = 1_pInt, homogenization_RGC_Noutput(instance) + select case(homogenization_RGC_outputID(o,instance)) + case(constitutivework_ID,penaltyenergy_ID,volumediscrepancy_ID, & + averagerelaxrate_ID,maximumrelaxrate_ID) + mySize = 1_pInt + case(ipcoords_ID,magnitudemismatch_ID) + mySize = 3_pInt + case(avgdefgrad_ID,avgfirstpiola_ID) + mySize = 9_pInt + case default + mySize = 0_pInt + end select + + outputFound: if (mySize > 0_pInt) then + homogenization_RGC_sizePostResult(o,instance) = mySize + homogenization_RGC_sizePostResults(instance) = & + homogenization_RGC_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop + + sizeHState = & + 3_pInt*(homogenization_RGC_Ngrains(1,instance)-1_pInt)* & + homogenization_RGC_Ngrains(2,instance)*homogenization_RGC_Ngrains(3,instance) & + + 3_pInt*homogenization_RGC_Ngrains(1,instance)*(homogenization_RGC_Ngrains(2,instance)-1_pInt)* & + homogenization_RGC_Ngrains(3,instance) & + + 3_pInt*homogenization_RGC_Ngrains(1,instance)*homogenization_RGC_Ngrains(2,instance)* & + (homogenization_RGC_Ngrains(3,instance)-1_pInt) & + + 8_pInt ! (1) Average constitutive work, (2-4) Overall mismatch, (5) Average penalty energy, + ! (6) Volume discrepancy, (7) Avg relaxation rate component, (8) Max relaxation rate component + +! allocate state arrays + homogState(homog)%sizeState = sizeHState + homogState(homog)%sizePostResults = homogenization_RGC_sizePostResults(instance) + allocate(homogState(homog)%state0 (sizeHState,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%subState0(sizeHState,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%state (sizeHState,NofMyHomog), source=0.0_pReal) + + endif myHomog + enddo initializeInstances + + + +end subroutine homogenization_RGC_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief partitions the deformation gradient onto the constituents +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_partitionDeformation(F,avgF,ip,el) + use debug, only: & + debug_level, & + debug_homogenization, & + debug_levelExtensive + use mesh, only: & + mesh_element + use material, only: & + homogenization_maxNgrains, & + homogenization_Ngrains,& + homogenization_typeInstance + + implicit none + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned F per grain + real(pReal), dimension (3,3), intent(in) :: avgF !< averaged F + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension (3) :: aVect,nVect + integer(pInt), dimension (4) :: intFace + integer(pInt), dimension (3) :: iGrain3 + integer(pInt) :: homID, iGrain,iFace,i,j + integer(pInt), parameter :: nFace = 6_pInt + +!-------------------------------------------------------------------------------------------------- +! compute the deformation gradient of individual grains due to relaxations + homID = homogenization_typeInstance(mesh_element(3,el)) + F = 0.0_pReal + do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) + iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) + do iFace = 1_pInt,nFace + intFace = homogenization_RGC_getInterface(iFace,iGrain3) ! identifying 6 interfaces of each grain + + aVect = homogenization_RGC_relaxationVector(intFace,homID, ip, el) ! get the relaxation vectors for each interface from global relaxation vector array + + nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the normal of each interface + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) & + 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 + +!-------------------------------------------------------------------------------------------------- +! debugging the grain deformation gradients + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a32,1x,i3)')'Deformation gradient of grain: ',iGrain + do i = 1_pInt,3_pInt + write(6,'(1x,3(e15.8,1x))')(F(i,j,iGrain), j = 1_pInt,3_pInt) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + + enddo + +end subroutine homogenization_RGC_partitionDeformation + + +!-------------------------------------------------------------------------------------------------- +!> @brief update the internal state of the homogenization scheme and tell whether "done" and +! "happy" with result +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) + use debug, only: & + debug_level, & + debug_homogenization,& + debug_levelExtensive, & + debug_e, & + debug_i + use math, only: & + math_invert + use mesh, only: & + mesh_element + use material, only: & + homogenization_maxNgrains, & + homogenization_typeInstance, & + homogState, & + mappingHomogenization, & + homogenization_Ngrains + use numerics, only: & + absTol_RGC, & + relTol_RGC, & + absMax_RGC, & + relMax_RGC, & + pPert_RGC, & + maxdRelax_RGC, & + viscPower_RGC, & + viscModus_RGC, & + refRelaxRate_RGC + + implicit none + + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: & + P,& !< array of P + F,& !< array of F + F0 !< array of initial F + real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffness + real(pReal), dimension (3,3), intent(in) :: avgF !< average F + real(pReal), intent(in) :: dt !< time increment + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + logical, dimension(2) :: homogenization_RGC_updateState + integer(pInt), dimension (4) :: intFaceN,intFaceP,faceID + integer(pInt), dimension (3) :: nGDim,iGr3N,iGr3P,stresLoc + integer(pInt), dimension (2) :: residLoc + integer(pInt) homID,iNum,i,j,nIntFaceTot,iGrN,iGrP,iMun,iFace,k,l,ipert,iGrain,nGrain + real(pReal), dimension (3,3,homogenization_maxNgrains) :: R,pF,pR,D,pD + real(pReal), dimension (3,homogenization_maxNgrains) :: NN,pNN + real(pReal), dimension (3) :: normP,normN,mornP,mornN + real(pReal) :: residMax,stresMax,constitutiveWork,penaltyEnergy,volDiscrep + logical error + + integer(pInt), parameter :: nFace = 6_pInt + + real(pReal), dimension(:,:), allocatable :: tract,jmatrix,jnverse,smatrix,pmatrix,rmatrix + real(pReal), dimension(:), allocatable :: resid,relax,p_relax,p_resid,drelax + + if(abs(dt) < tiny(0.0_pReal)) then ! zero time step + homogenization_RGC_updateState = .true. ! pretend everything is fine and return + return + endif + +!-------------------------------------------------------------------------------------------------- +! get the dimension of the cluster (grains and interfaces) + homID = homogenization_typeInstance(mesh_element(3,el)) + nGDim = homogenization_RGC_Ngrains(1:3,homID) + nGrain = homogenization_Ngrains(mesh_element(3,el)) + nIntFaceTot = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) + nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) & + + nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) + +!-------------------------------------------------------------------------------------------------- +! allocate the size of the global relaxation arrays/jacobian matrices depending on the size of the cluster + allocate(resid(3_pInt*nIntFaceTot), source=0.0_pReal) + allocate(tract(nIntFaceTot,3), source=0.0_pReal) + allocate(relax(3_pInt*nIntFaceTot)); relax= homogState(mappingHomogenization(2,ip,el))% & + state(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) + allocate(drelax(3_pInt*nIntFaceTot)); drelax= homogState(mappingHomogenization(2,ip,el))% & + state(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) - & + homogState(mappingHomogenization(2,ip,el))% & + state0(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) +!-------------------------------------------------------------------------------------------------- +! debugging the obtained state + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Obtained state: ' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,2(e15.8,1x))')homogState(mappingHomogenization(2,ip,el))%state(i,mappingHomogenization(1,ip,el)) + enddo + write(6,*)' ' + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! computing interface mismatch and stress penalty tensor for all interfaces of all grains + call homogenization_RGC_stressPenalty(R,NN,avgF,F,ip,el,homID) + +!-------------------------------------------------------------------------------------------------- +! calculating volume discrepancy and stress penalty related to overall volume discrepancy + call homogenization_RGC_volumePenalty(D,volDiscrep,F,avgF,ip,el) + +!-------------------------------------------------------------------------------------------------- +! debugging the mismatch, stress and penalties of grains + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + do iGrain = 1_pInt,nGrain + write(6,'(1x,a30,1x,i3,1x,a4,3(1x,e15.8))')'Mismatch magnitude of grain(',iGrain,') :',& + NN(1,iGrain),NN(2,iGrain),NN(3,iGrain) + write(6,'(/,1x,a30,1x,i3)')'Stress and penalties of grain: ',iGrain + do i = 1_pInt,3_pInt + write(6,'(1x,3(e15.8,1x),1x,3(e15.8,1x),1x,3(e15.8,1x))')(P(i,j,iGrain), j = 1_pInt,3_pInt), & + (R(i,j,iGrain), j = 1_pInt,3_pInt), & + (D(i,j,iGrain), j = 1_pInt,3_pInt) + enddo + write(6,*)' ' + enddo + !$OMP END CRITICAL (write2out) + endif + +!------------------------------------------------------------------------------------------------ +! computing the residual stress from the balance of traction at all (interior) interfaces + do iNum = 1_pInt,nIntFaceTot + faceID = homogenization_RGC_interface1to4(iNum,homID) ! identifying the interface ID in local coordinate system (4-dimensional index) + +!-------------------------------------------------------------------------------------------------- +! identify the left/bottom/back grain (-|N) + iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate system (3-dimensional index) + iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) + intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) + normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the interface normal + +!-------------------------------------------------------------------------------------------------- +! identify the right/up/front grain (+|P) + iGr3P = iGr3N + iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate system (3-dimensional index) + iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) + intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) + normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the interface normal + +!-------------------------------------------------------------------------------------------------- +! compute the residual of traction at the interface (in local system, 4-dimensional index) + do i = 1_pInt,3_pInt + tract(iNum,i) = sign(viscModus_RGC*(abs(drelax(i+3*(iNum-1_pInt)))/(refRelaxRate_RGC*dt))**viscPower_RGC, & + drelax(i+3*(iNum-1_pInt))) ! contribution from the relaxation viscosity + do j = 1_pInt,3_pInt + tract(iNum,i) = tract(iNum,i) + (P(i,j,iGrP) + R(i,j,iGrP) + D(i,j,iGrP))*normP(j) & ! contribution from material stress P, mismatch penalty R, and volume penalty D projected into the interface + + (P(i,j,iGrN) + R(i,j,iGrN) + D(i,j,iGrN))*normN(j) + resid(i+3_pInt*(iNum-1_pInt)) = tract(iNum,i) ! translate the local residual into global 1-dimensional residual array + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! debugging the residual stress + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30,1x,i3)')'Traction at interface: ',iNum + write(6,'(1x,3(e15.8,1x))')(tract(iNum,j), j = 1_pInt,3_pInt) + write(6,*)' ' + !$OMP END CRITICAL (write2out) + endif + enddo + +!-------------------------------------------------------------------------------------------------- +! convergence check for stress residual + stresMax = maxval(abs(P)) ! get the maximum of first Piola-Kirchhoff (material) stress + stresLoc = int(maxloc(abs(P)),pInt) ! get the location of the maximum stress + residMax = maxval(abs(tract)) ! get the maximum of the residual + residLoc = int(maxloc(abs(tract)),pInt) ! get the position of the maximum residual + +!-------------------------------------------------------------------------------------------------- +! Debugging the convergent criteria + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a)')' ' + write(6,'(1x,a,1x,i2,1x,i4)')'RGC residual check ...',ip,el + write(6,'(1x,a15,1x,e15.8,1x,a7,i3,1x,a12,i2,i2)')'Max stress: ',stresMax, & + '@ grain',stresLoc(3),'in component',stresLoc(1),stresLoc(2) + write(6,'(1x,a15,1x,e15.8,1x,a7,i3,1x,a12,i2)')'Max residual: ',residMax, & + '@ iface',residLoc(1),'in direction',residLoc(2) + flush(6) + !$OMP END CRITICAL (write2out) + endif + + homogenization_RGC_updateState = .false. + +!-------------------------------------------------------------------------------------------------- +! If convergence reached => done and happy + if (residMax < relTol_RGC*stresMax .or. residMax < absTol_RGC) then + homogenization_RGC_updateState = .true. + + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a55,/)')'... done and happy' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! compute/update the state for postResult, i.e., all energy densities computed by time-integration + constitutiveWork = homogState(mappingHomogenization(2,ip,el))%state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) + penaltyEnergy = homogState(mappingHomogenization(2,ip,el))%state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) + do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) ! time-integration loop for the calculating the work and energy + do i = 1_pInt,3_pInt + do j = 1_pInt,3_pInt + constitutiveWork = constitutiveWork + P(i,j,iGrain)*(F(i,j,iGrain) - F0(i,j,iGrain))/real(nGrain,pReal) + penaltyEnergy = penaltyEnergy + R(i,j,iGrain)*(F(i,j,iGrain) - F0(i,j,iGrain))/real(nGrain,pReal) + enddo + enddo + enddo + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) = constitutiveWork ! the bulk mechanical/constitutive work + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+2,mappingHomogenization(1,ip,el)) = sum(NN(1,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e1-direction + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+3,mappingHomogenization(1,ip,el)) = sum(NN(2,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e2-direction + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+4,mappingHomogenization(1,ip,el)) = sum(NN(3,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e3-direction + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) = penaltyEnergy ! the overall penalty energy + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+6,mappingHomogenization(1,ip,el)) = volDiscrep ! the overall volume discrepancy + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+7,mappingHomogenization(1,ip,el)) = & + sum(abs(drelax))/dt/real(3_pInt*nIntFaceTot,pReal) ! the average rate of relaxation vectors + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+8,mappingHomogenization(1,ip,el)) = maxval(abs(drelax))/dt ! the maximum rate of relaxation vectors + + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30,1x,e15.8)') 'Constitutive work: ',constitutiveWork + write(6,'(1x,a30,3(1x,e15.8))')'Magnitude mismatch: ',sum(NN(1,:))/real(nGrain,pReal), & + sum(NN(2,:))/real(nGrain,pReal), & + sum(NN(3,:))/real(nGrain,pReal) + write(6,'(1x,a30,1x,e15.8)') 'Penalty energy: ',penaltyEnergy + write(6,'(1x,a30,1x,e15.8,/)') 'Volume discrepancy: ',volDiscrep + write(6,'(1x,a30,1x,e15.8)') 'Maximum relaxation rate: ',maxval(abs(drelax))/dt + write(6,'(1x,a30,1x,e15.8,/)') 'Average relaxation rate: ',sum(abs(drelax))/dt/real(3_pInt*nIntFaceTot,pReal) + flush(6) + !$OMP END CRITICAL (write2out) + endif + + deallocate(tract,resid,relax,drelax) + return + +!-------------------------------------------------------------------------------------------------- +! if residual blows-up => done but unhappy + elseif (residMax > relMax_RGC*stresMax .or. residMax > absMax_RGC) then ! try to restart when residual blows up exceeding maximum bound + homogenization_RGC_updateState = [.true.,.false.] ! with direct cut-back + + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a55,/)')'... broken' + flush(6) + !$OMP END CRITICAL (write2out) + endif + + deallocate(tract,resid,relax,drelax) + return + else ! proceed with computing the Jacobian and state update + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a55,/)')'... not yet done' + flush(6) + !$OMP END CRITICAL (write2out) + endif + + endif + +!--------------------------------------------------------------------------------------------------- +! construct the global Jacobian matrix for updating the global relaxation vector array when +! convergence is not yet reached ... + +!-------------------------------------------------------------------------------------------------- +! ... of the constitutive stress tangent, assembled from dPdF or material constitutive model "smatrix" + allocate(smatrix(3*nIntFaceTot,3*nIntFaceTot), source=0.0_pReal) + do iNum = 1_pInt,nIntFaceTot + faceID = homogenization_RGC_interface1to4(iNum,homID) ! assembling of local dPdF into global Jacobian matrix + +!-------------------------------------------------------------------------------------------------- +! identify the left/bottom/back grain (-|N) + iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate sytem + iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate into global grain ID + intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) ! identifying the connecting interface in local coordinate system + normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the interface normal + do iFace = 1_pInt,nFace + intFaceN = homogenization_RGC_getInterface(iFace,iGr3N) ! identifying all interfaces that influence relaxation of the above interface + mornN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get normal of the interfaces + iMun = homogenization_RGC_interface4to1(intFaceN,homID) ! translate the interfaces ID into local 4-dimensional index + if (iMun > 0) then ! get the corresponding tangent + do i=1_pInt,3_pInt; do j=1_pInt,3_pInt; do k=1_pInt,3_pInt; do l=1_pInt,3_pInt + smatrix(3*(iNum-1)+i,3*(iMun-1)+j) = smatrix(3*(iNum-1)+i,3*(iMun-1)+j) + dPdF(i,k,j,l,iGrN)*normN(k)*mornN(l) + enddo;enddo;enddo;enddo +! projecting the material tangent dPdF into the interface +! to obtain the Jacobian matrix contribution of dPdF + endif + enddo + +!-------------------------------------------------------------------------------------------------- +! identify the right/up/front grain (+|P) + iGr3P = iGr3N + iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate sytem + iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate into global grain ID + intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) ! identifying the connecting interface in local coordinate system + normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the interface normal + do iFace = 1_pInt,nFace + intFaceP = homogenization_RGC_getInterface(iFace,iGr3P) ! identifying all interfaces that influence relaxation of the above interface + mornP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get normal of the interfaces + iMun = homogenization_RGC_interface4to1(intFaceP,homID) ! translate the interfaces ID into local 4-dimensional index + if (iMun > 0_pInt) then ! get the corresponding tangent + do i=1_pInt,3_pInt; do j=1_pInt,3_pInt; do k=1_pInt,3_pInt; do l=1_pInt,3_pInt + smatrix(3*(iNum-1)+i,3*(iMun-1)+j) = smatrix(3*(iNum-1)+i,3*(iMun-1)+j) + dPdF(i,k,j,l,iGrP)*normP(k)*mornP(l) + enddo;enddo;enddo;enddo + endif + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! debugging the global Jacobian matrix of stress tangent + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Jacobian matrix of stress' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,100(e11.4,1x))')(smatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! ... of the stress penalty tangent (mismatch penalty and volume penalty, computed using numerical +! perturbation method) "pmatrix" + allocate(pmatrix(3*nIntFaceTot,3*nIntFaceTot), source=0.0_pReal) + allocate(p_relax(3*nIntFaceTot), source=0.0_pReal) + allocate(p_resid(3*nIntFaceTot), source=0.0_pReal) + do ipert = 1_pInt,3_pInt*nIntFaceTot + p_relax = relax + p_relax(ipert) = relax(ipert) + pPert_RGC ! perturb the relaxation vector + homogState(mappingHomogenization(2,ip,el))%state(1:3*nIntFaceTot,mappingHomogenization(1,ip,el)) = p_relax + call homogenization_RGC_grainDeformation(pF,avgF,ip,el) ! compute the grains deformation from perturbed state + call homogenization_RGC_stressPenalty(pR,pNN,avgF,pF,ip,el,homID) ! compute stress penalty due to interface mismatch from perturbed state + call homogenization_RGC_volumePenalty(pD,volDiscrep,pF,avgF,ip,el) ! compute stress penalty due to volume discrepancy from perturbed state + +!-------------------------------------------------------------------------------------------------- +! computing the global stress residual array from the perturbed state + p_resid = 0.0_pReal + do iNum = 1_pInt,nIntFaceTot + faceID = homogenization_RGC_interface1to4(iNum,homID) ! identifying the interface ID in local coordinate system (4-dimensional index) + +!-------------------------------------------------------------------------------------------------- +! identify the left/bottom/back grain (-|N) + iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate system (3-dimensional index) + iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) + intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) ! identifying the interface ID of the grain + normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the corresponding interface normal + +!-------------------------------------------------------------------------------------------------- +! identify the right/up/front grain (+|P) + iGr3P = iGr3N + iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate system (3-dimensional index) + iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) + intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) ! identifying the interface ID of the grain + normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the corresponding normal + +!-------------------------------------------------------------------------------------------------- +! compute the residual stress (contribution of mismatch and volume penalties) from perturbed state +! at all interfaces + do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt + p_resid(i+3*(iNum-1)) = p_resid(i+3*(iNum-1)) + (pR(i,j,iGrP) - R(i,j,iGrP))*normP(j) & + + (pR(i,j,iGrN) - R(i,j,iGrN))*normN(j) & + + (pD(i,j,iGrP) - D(i,j,iGrP))*normP(j) & + + (pD(i,j,iGrN) - D(i,j,iGrN))*normN(j) + enddo; enddo + enddo + pmatrix(:,ipert) = p_resid/pPert_RGC + enddo + +!-------------------------------------------------------------------------------------------------- +! debugging the global Jacobian matrix of penalty tangent + if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Jacobian matrix of penalty' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,100(e11.4,1x))')(pmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! ... of the numerical viscosity traction "rmatrix" + allocate(rmatrix(3*nIntFaceTot,3*nIntFaceTot),source=0.0_pReal) + forall (i=1_pInt:3_pInt*nIntFaceTot) & + rmatrix(i,i) = viscModus_RGC*viscPower_RGC/(refRelaxRate_RGC*dt)* & ! tangent due to numerical viscosity traction appears + (abs(drelax(i))/(refRelaxRate_RGC*dt))**(viscPower_RGC - 1.0_pReal) ! only in the main diagonal term + + + +!-------------------------------------------------------------------------------------------------- +! debugging the global Jacobian matrix of numerical viscosity tangent + if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Jacobian matrix of penalty' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,100(e11.4,1x))')(rmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! The overall Jacobian matrix summarizing contributions of smatrix, pmatrix, rmatrix + allocate(jmatrix(3*nIntFaceTot,3*nIntFaceTot)); jmatrix = smatrix + pmatrix + rmatrix + + if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Jacobian matrix (total)' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,100(e11.4,1x))')(jmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! computing the update of the state variable (relaxation vectors) using the Jacobian matrix + allocate(jnverse(3_pInt*nIntFaceTot,3_pInt*nIntFaceTot),source=0.0_pReal) + call math_invert(size(jmatrix,1),jmatrix,jnverse,error) ! Compute the inverse of the overall Jacobian matrix + +!-------------------------------------------------------------------------------------------------- +! debugging the inverse Jacobian matrix + if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Jacobian inverse' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,100(e11.4,1x))')(jnverse(i,j), j = 1_pInt,3_pInt*nIntFaceTot) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! calculate the state update (global relaxation vectors) for the next Newton-Raphson iteration + drelax = 0.0_pReal + do i = 1_pInt,3_pInt*nIntFaceTot + do j = 1_pInt,3_pInt*nIntFaceTot + drelax(i) = drelax(i) - jnverse(i,j)*resid(j) ! Calculate the correction for the state variable + enddo + enddo + relax = relax + drelax ! Updateing the state variable for the next iteration + homogState(mappingHomogenization(2,ip,el))%state(1:3*nIntFaceTot,mappingHomogenization(1,ip,el)) = relax + if (any(abs(drelax) > maxdRelax_RGC)) then ! Forcing cutback when the incremental change of relaxation vector becomes too large + homogenization_RGC_updateState = [.true.,.false.] + !$OMP CRITICAL (write2out) + write(6,'(1x,a,1x,i3,1x,a,1x,i3,1x,a)')'RGC_updateState: ip',ip,'| el',el,'enforces cutback' + write(6,'(1x,a,1x,e15.8)')'due to large relaxation change =',maxval(abs(drelax)) + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! debugging the return state + if (iand(debug_homogenization, debug_levelExtensive) > 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Returned state: ' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,2(e15.8,1x))')homogState(mappingHomogenization(2,ip,el))%state(i,mappingHomogenization(1,ip,el)) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + + deallocate(tract,resid,jmatrix,jnverse,relax,drelax,pmatrix,smatrix,p_relax,p_resid) + +end function homogenization_RGC_updateState + + +!-------------------------------------------------------------------------------------------------- +!> @brief derive average stress and stiffness from constituent quantities +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,el) + use debug, only: & + debug_level, & + debug_homogenization,& + debug_levelExtensive + use mesh, only: mesh_element + use material, only: & + homogenization_maxNgrains, & + homogenization_Ngrains, & + homogenization_typeInstance + use math, only: math_Plain3333to99 + + implicit none + 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 (3,3,homogenization_maxNgrains), intent(in) :: P !< array of current grain stresses + real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffnesses + integer(pInt), intent(in) :: el !< element number + real(pReal), dimension (9,9) :: dPdF99 + + integer(pInt) :: homID, i, j, Ngrains, iGrain + + homID = homogenization_typeInstance(mesh_element(3,el)) + Ngrains = homogenization_Ngrains(mesh_element(3,el)) + +!-------------------------------------------------------------------------------------------------- +! debugging the grain tangent + if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + do iGrain = 1_pInt,Ngrains + dPdF99 = math_Plain3333to99(dPdF(1:3,1:3,1:3,1:3,iGrain)) + write(6,'(1x,a30,1x,i3)')'Stress tangent of grain: ',iGrain + do i = 1_pInt,9_pInt + write(6,'(1x,(e15.8,1x))') (dPdF99(i,j), j = 1_pInt,9_pInt) + enddo + write(6,*)' ' + enddo + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! computing the average first Piola-Kirchhoff stress P and the average tangent dPdF + avgP = sum(P,3)/real(Ngrains,pReal) + dAvgPdAvgF = sum(dPdF,5)/real(Ngrains,pReal) + +end subroutine homogenization_RGC_averageStressAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of homogenization results for post file inclusion +!-------------------------------------------------------------------------------------------------- +pure function homogenization_RGC_postResults(ip,el,avgP,avgF) + use mesh, only: & + mesh_element, & + mesh_ipCoordinates + use material, only: & + homogenization_typeInstance,& + homogState, & + mappingHomogenization, & + homogenization_Noutput + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3), intent(in) :: & + avgP, & !< average stress at material point + avgF !< average deformation gradient at material point + + integer(pInt) homID,o,c,nIntFaceTot + real(pReal), dimension(homogenization_RGC_sizePostResults(homogenization_typeInstance(mesh_element(3,el)))) :: & + homogenization_RGC_postResults + + homID = homogenization_typeInstance(mesh_element(3,el)) + nIntFaceTot=(homogenization_RGC_Ngrains(1,homID)-1_pInt)*homogenization_RGC_Ngrains(2,homID)*homogenization_RGC_Ngrains(3,homID)& + + homogenization_RGC_Ngrains(1,homID)*(homogenization_RGC_Ngrains(2,homID)-1_pInt)*homogenization_RGC_Ngrains(3,homID)& + + homogenization_RGC_Ngrains(1,homID)*homogenization_RGC_Ngrains(2,homID)*(homogenization_RGC_Ngrains(3,homID)-1_pInt) + + c = 0_pInt + homogenization_RGC_postResults = 0.0_pReal + do o = 1_pInt,homogenization_Noutput(mesh_element(3,el)) + select case(homogenization_RGC_outputID(o,homID)) + case (avgdefgrad_ID) + homogenization_RGC_postResults(c+1_pInt:c+9_pInt) = reshape(avgF,[9]) + c = c + 9_pInt + case (avgfirstpiola_ID) + homogenization_RGC_postResults(c+1_pInt:c+9_pInt) = reshape(avgP,[9]) + c = c + 9_pInt + case (ipcoords_ID) + homogenization_RGC_postResults(c+1_pInt:c+3_pInt) = mesh_ipCoordinates(1:3,ip,el) ! current ip coordinates + c = c + 3_pInt + case (constitutivework_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) + c = c + 1_pInt + case (magnitudemismatch_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+2,mappingHomogenization(1,ip,el)) + homogenization_RGC_postResults(c+2) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+3,mappingHomogenization(1,ip,el)) + homogenization_RGC_postResults(c+3) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+4,mappingHomogenization(1,ip,el)) + c = c + 3_pInt + case (penaltyenergy_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) + c = c + 1_pInt + case (volumediscrepancy_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+6,mappingHomogenization(1,ip,el)) + c = c + 1_pInt + case (averagerelaxrate_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+7,mappingHomogenization(1,ip,el)) + c = c + 1_pInt + case (maximumrelaxrate_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+8,mappingHomogenization(1,ip,el)) + c = c + 1_pInt + end select + enddo + +end function homogenization_RGC_postResults + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate stress-like penalty due to deformation mismatch +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_stressPenalty(rPen,nMis,avgF,fDef,ip,el,homID) + use debug, only: & + debug_level, & + debug_homogenization,& + debug_levelExtensive, & + debug_e, & + debug_i + use mesh, only: & + mesh_element + use constitutive, only: & + constitutive_homogenizedC + use math, only: & + math_civita + use material, only: & + homogenization_maxNgrains,& + homogenization_Ngrains + use numerics, only: & + xSmoo_RGC + + implicit none + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: rPen !< stress-like penalty + real(pReal), dimension (3,homogenization_maxNgrains), intent(out) :: nMis !< total amount of mismatch + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: fDef !< deformation gradients + real(pReal), dimension (3,3), intent(in) :: avgF !< initial effective stretch tensor + integer(pInt), intent(in) :: ip,el + integer(pInt), dimension (4) :: intFace + integer(pInt), dimension (3) :: iGrain3,iGNghb3,nGDim + real(pReal), dimension (3,3) :: gDef,nDef + real(pReal), dimension (3) :: nVect,surfCorr + real(pReal), dimension (2) :: Gmoduli + integer(pInt) :: homID,iGrain,iGNghb,iFace,i,j,k,l + real(pReal) :: muGrain,muGNghb,nDefNorm,bgGrain,bgGNghb + + integer(pInt), parameter :: nFace = 6_pInt + real(pReal), parameter :: nDefToler = 1.0e-10_pReal + + nGDim = homogenization_RGC_Ngrains(1:3,homID) + rPen = 0.0_pReal + nMis = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! get the correction factor the modulus of penalty stress representing the evolution of area of +! the interfaces due to deformations + surfCorr = homogenization_RGC_surfaceCorrection(avgF,ip,el) + +!-------------------------------------------------------------------------------------------------- +! debugging the surface correction factor + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a20,2(1x,i3))')'Correction factor: ',ip,el + write(6,'(1x,3(e11.4,1x))')(surfCorr(i), i = 1,3) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! computing the mismatch and penalty stress tensor of all grains + do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) + Gmoduli = homogenization_RGC_equivalentModuli(iGrain,ip,el) + muGrain = Gmoduli(1) ! collecting the equivalent shear modulus of grain + bgGrain = Gmoduli(2) ! and the lengthh of Burgers vector + iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) ! get the grain ID in local 3-dimensional index (x,y,z)-position + +!* Looping over all six interfaces of each grain + do iFace = 1_pInt,nFace + intFace = homogenization_RGC_getInterface(iFace,iGrain3) ! get the 4-dimensional index of the interface in local numbering system of the grain + nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the interface normal + iGNghb3 = iGrain3 ! identify the neighboring grain across the interface + iGNghb3(abs(intFace(1))) = iGNghb3(abs(intFace(1))) + int(real(intFace(1),pReal)/real(abs(intFace(1)),pReal),pInt) + if (iGNghb3(1) < 1) iGNghb3(1) = nGDim(1) ! with periodicity along e1 direction + if (iGNghb3(1) > nGDim(1)) iGNghb3(1) = 1_pInt + if (iGNghb3(2) < 1) iGNghb3(2) = nGDim(2) ! with periodicity along e2 direction + if (iGNghb3(2) > nGDim(2)) iGNghb3(2) = 1_pInt + if (iGNghb3(3) < 1) iGNghb3(3) = nGDim(3) ! with periodicity along e3 direction + if (iGNghb3(3) > nGDim(3)) iGNghb3(3) = 1_pInt + iGNghb = homogenization_RGC_grain3to1(iGNghb3,homID) ! get the ID of the neighboring grain + Gmoduli = homogenization_RGC_equivalentModuli(iGNghb,ip,el) ! collecting the shear modulus and Burgers vector of the neighbor + muGNghb = Gmoduli(1) + bgGNghb = Gmoduli(2) + gDef = 0.5_pReal*(fDef(1:3,1:3,iGNghb) - fDef(1:3,1:3,iGrain)) ! compute the difference/jump in deformation gradeint across the neighbor + +!-------------------------------------------------------------------------------------------------- +! compute the mismatch tensor of all interfaces + nDefNorm = 0.0_pReal + nDef = 0.0_pReal + do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt + do k = 1_pInt,3_pInt; do l = 1_pInt,3_pInt + nDef(i,j) = nDef(i,j) - nVect(k)*gDef(i,l)*math_civita(j,k,l) ! compute the interface mismatch tensor from the jump of deformation gradient + enddo; enddo + nDefNorm = nDefNorm + nDef(i,j)*nDef(i,j) ! compute the norm of the mismatch tensor + 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) + +!-------------------------------------------------------------------------------------------------- +! debuggin the mismatch tensor + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a20,i2,1x,a20,1x,i3)')'Mismatch to face: ',intFace(1),'neighbor grain: ',iGNghb + do i = 1,3 + write(6,'(1x,3(e11.4,1x))')(nDef(i,j), j = 1,3) + enddo + write(6,'(1x,a20,e11.4)')'with magnitude: ',nDefNorm + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! compute the stress penalty of all interfaces + do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt + do k = 1_pInt,3_pInt; do l = 1_pInt,3_pInt + rPen(i,j,iGrain) = rPen(i,j,iGrain) + 0.5_pReal*(muGrain*bgGrain + muGNghb*bgGNghb)*homogenization_RGC_xiAlpha(homID) & + *surfCorr(abs(intFace(1)))/homogenization_RGC_dAlpha(abs(intFace(1)),homID) & + *cosh(homogenization_RGC_ciAlpha(homID)*nDefNorm) & + *0.5_pReal*nVect(l)*nDef(i,k)/nDefNorm*math_civita(k,l,j) & + *tanh(nDefNorm/xSmoo_RGC) + enddo; enddo + enddo; enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! debugging the stress-like penalty + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a20,i2)')'Penalty of grain: ',iGrain + do i = 1,3 + write(6,'(1x,3(e11.4,1x))')(rPen(i,j,iGrain), j = 1,3) + enddo + !$OMP END CRITICAL (write2out) + endif + + enddo + +end subroutine homogenization_RGC_stressPenalty + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate stress-like penalty due to volume discrepancy +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_volumePenalty(vPen,vDiscrep,fDef,fAvg,ip,el) + use debug, only: & + debug_level, & + debug_homogenization,& + debug_levelExtensive, & + debug_e, & + debug_i + use mesh, only: & + mesh_element + use math, only: & + math_det33, & + math_inv33 + use material, only: & + homogenization_maxNgrains,& + homogenization_Ngrains + use numerics, only: & + maxVolDiscr_RGC,& + volDiscrMod_RGC,& + volDiscrPow_RGC + + implicit none + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: vPen ! stress-like penalty due to volume + real(pReal), intent(out) :: vDiscrep ! total volume discrepancy + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: fDef ! deformation gradients + real(pReal), dimension (3,3), intent(in) :: fAvg ! overall deformation gradient + integer(pInt), intent(in) :: ip,& ! integration point + el + real(pReal), dimension (homogenization_maxNgrains) :: gVol + integer(pInt) :: iGrain,nGrain,i,j + + nGrain = homogenization_Ngrains(mesh_element(3,el)) + +!-------------------------------------------------------------------------------------------------- +! compute the volumes of grains and of cluster + vDiscrep = math_det33(fAvg) ! compute the volume of the cluster + do iGrain = 1_pInt,nGrain + gVol(iGrain) = math_det33(fDef(1:3,1:3,iGrain)) ! compute the volume of individual grains + vDiscrep = vDiscrep - gVol(iGrain)/real(nGrain,pReal) ! calculate the difference/dicrepancy between + ! the volume of the cluster and the the total volume of grains + enddo + +!-------------------------------------------------------------------------------------------------- +! calculate the stress and penalty due to volume discrepancy + vPen = 0.0_pReal + do iGrain = 1_pInt,nGrain + vPen(:,:,iGrain) = -1.0_pReal/real(nGrain,pReal)*volDiscrMod_RGC*volDiscrPow_RGC/maxVolDiscr_RGC* & + sign((abs(vDiscrep)/maxVolDiscr_RGC)**(volDiscrPow_RGC - 1.0),vDiscrep)* & + gVol(iGrain)*transpose(math_inv33(fDef(:,:,iGrain))) + +!-------------------------------------------------------------------------------------------------- +! debugging the stress-like penalty + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30,i2)')'Volume penalty of grain: ',iGrain + do i = 1,3 + write(6,'(1x,3(e11.4,1x))')(vPen(i,j,iGrain), j = 1,3) + enddo + !$OMP END CRITICAL (write2out) + endif + enddo + +end subroutine homogenization_RGC_volumePenalty + + +!-------------------------------------------------------------------------------------------------- +!> @brief compute the correction factor accouted for surface evolution (area change) due to +! deformation +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_surfaceCorrection(avgF,ip,el) + use math, only: & + math_invert33, & + math_mul33x33 + + implicit none + real(pReal), dimension(3) :: homogenization_RGC_surfaceCorrection + real(pReal), dimension(3,3), intent(in) :: avgF !< average F + integer(pInt), intent(in) :: ip,& !< integration point number + el !< element number + real(pReal), dimension(3,3) :: invC,avgC + real(pReal), dimension(3) :: nVect + real(pReal) :: detF + integer(pInt), dimension(4) :: intFace + integer(pInt) :: i,j,iBase + logical :: error + + avgC = math_mul33x33(transpose(avgF),avgF) + call math_invert33(avgC,invC,detF,error) + homogenization_RGC_surfaceCorrection = 0.0_pReal + do iBase = 1_pInt,3_pInt + intFace = [iBase,1_pInt,1_pInt,1_pInt] + nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the normal of the interface + do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt + homogenization_RGC_surfaceCorrection(iBase) = & ! compute the component of (the inverse of) the stretch in the direction of the normal + homogenization_RGC_surfaceCorrection(iBase) + invC(i,j)*nVect(i)*nVect(j) + enddo; enddo + homogenization_RGC_surfaceCorrection(iBase) = & ! get the surface correction factor (area contraction/enlargement) + sqrt(homogenization_RGC_surfaceCorrection(iBase))*detF + enddo + +end function homogenization_RGC_surfaceCorrection + + +!-------------------------------------------------------------------------------------------------- +!> @brief compute the equivalent shear and bulk moduli from the elasticity tensor +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_equivalentModuli(grainID,ip,el) + use constitutive, only: & + constitutive_homogenizedC + + implicit none + integer(pInt), intent(in) :: & + grainID,& + ip, & !< integration point number + el !< element number + real(pReal), dimension (6,6) :: elasTens + real(pReal), dimension(2) :: homogenization_RGC_equivalentModuli + 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 + homogenization_RGC_equivalentModuli(1) = 0.2_pReal*(cEquiv_11 - cEquiv_12) + 0.6_pReal*cEquiv_44 + +!-------------------------------------------------------------------------------------------------- +! obtain the length of Burgers vector (could be model dependend) + homogenization_RGC_equivalentModuli(2) = 2.5e-10_pReal + +end function homogenization_RGC_equivalentModuli + + +!-------------------------------------------------------------------------------------------------- +!> @brief collect relaxation vectors of an interface +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_relaxationVector(intFace,homID, ip, el) + use material, only: & + homogState, & + mappingHomogenization + + implicit none + integer(pInt), intent(in) :: ip, el + real(pReal), dimension (3) :: homogenization_RGC_relaxationVector + integer(pInt), dimension (4), intent(in) :: intFace !< set of interface ID in 4D array (normal and position) + integer(pInt), dimension (3) :: nGDim + integer(pInt) :: & + iNum, & + homID !< homogenization ID + +!-------------------------------------------------------------------------------------------------- +! collect the interface relaxation vector from the global state array + homogenization_RGC_relaxationVector = 0.0_pReal + nGDim = homogenization_RGC_Ngrains(1:3,homID) + iNum = homogenization_RGC_interface4to1(intFace,homID) ! identify the position of the interface in global state array + if (iNum > 0_pInt) homogenization_RGC_relaxationVector = homogState(mappingHomogenization(2,ip,el))% & + state((3*iNum-2):(3*iNum),mappingHomogenization(1,ip,el)) ! get the corresponding entries + +end function homogenization_RGC_relaxationVector + + +!-------------------------------------------------------------------------------------------------- +!> @brief identify the normal of an interface +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_interfaceNormal(intFace,ip,el) + use debug, only: & + debug_homogenization,& + debug_levelExtensive + use math, only: & + math_mul33x3 + + implicit none + real(pReal), dimension (3) :: homogenization_RGC_interfaceNormal + integer(pInt), dimension (4), intent(in) :: intFace !< interface ID in 4D array (normal and position) + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + integer(pInt) :: nPos + +!-------------------------------------------------------------------------------------------------- +! get the normal of the interface, identified from the value of intFace(1) + homogenization_RGC_interfaceNormal = 0.0_pReal + nPos = abs(intFace(1)) ! identify the position of the interface in global state array + homogenization_RGC_interfaceNormal(nPos) = real(intFace(1)/abs(intFace(1)),pReal) ! get the normal vector w.r.t. cluster axis + + homogenization_RGC_interfaceNormal = & + math_mul33x3(homogenization_RGC_orientation(1:3,1:3,ip,el),homogenization_RGC_interfaceNormal) + ! map the normal vector into sample coordinate system (basis) + +end function homogenization_RGC_interfaceNormal + + +!-------------------------------------------------------------------------------------------------- +!> @brief collect six faces of a grain in 4D (normal and position) +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_getInterface(iFace,iGrain3) + + implicit none + integer(pInt), dimension (4) :: homogenization_RGC_getInterface + integer(pInt), dimension (3), intent(in) :: iGrain3 !< grain ID in 3D array + integer(pInt), intent(in) :: iFace !< face index (1..6) mapped like (-e1,-e2,-e3,+e1,+e2,+e3) or iDir = (-1,-2,-3,1,2,3) + integer(pInt) :: iDir + +!* Direction of interface normal + iDir = (int(real(iFace-1_pInt,pReal)/2.0_pReal,pInt)+1_pInt)*(-1_pInt)**iFace + homogenization_RGC_getInterface(1) = iDir + +!-------------------------------------------------------------------------------------------------- +! identify the interface position by the direction of its normal + homogenization_RGC_getInterface(2:4) = iGrain3 + if (iDir < 0_pInt) & ! to have a correlation with coordinate/position in real space + homogenization_RGC_getInterface(1_pInt-iDir) = homogenization_RGC_getInterface(1_pInt-iDir)-1_pInt + +end function homogenization_RGC_getInterface + +!-------------------------------------------------------------------------------------------------- +!> @brief map grain ID from in 1D (global array) to in 3D (local position) +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_grain1to3(grain1,homID) + + implicit none + integer(pInt), dimension (3) :: homogenization_RGC_grain1to3 + integer(pInt), intent(in) :: & + grain1,& !< grain ID in 1D array + homID !< homogenization ID + integer(pInt), dimension (3) :: nGDim + +!-------------------------------------------------------------------------------------------------- +! get the grain position + nGDim = homogenization_RGC_Ngrains(1:3,homID) + homogenization_RGC_grain1to3(3) = 1_pInt+(grain1-1_pInt)/(nGDim(1)*nGDim(2)) + homogenization_RGC_grain1to3(2) = 1_pInt+mod((grain1-1_pInt)/nGDim(1),nGDim(2)) + homogenization_RGC_grain1to3(1) = 1_pInt+mod((grain1-1_pInt),nGDim(1)) + +end function homogenization_RGC_grain1to3 + + +!-------------------------------------------------------------------------------------------------- +!> @brief map grain ID from in 3D (local position) to in 1D (global array) +!-------------------------------------------------------------------------------------------------- +pure function homogenization_RGC_grain3to1(grain3,homID) + + implicit none + integer(pInt), dimension (3), intent(in) :: grain3 !< grain ID in 3D array (pos.x,pos.y,pos.z) + integer(pInt) :: homogenization_RGC_grain3to1 + integer(pInt), dimension (3) :: nGDim + integer(pInt), intent(in) :: homID ! homogenization ID + +!-------------------------------------------------------------------------------------------------- +! get the grain ID + nGDim = homogenization_RGC_Ngrains(1:3,homID) + homogenization_RGC_grain3to1 = grain3(1) + nGDim(1)*(grain3(2)-1_pInt) + nGDim(1)*nGDim(2)*(grain3(3)-1_pInt) + +end function homogenization_RGC_grain3to1 + + +!-------------------------------------------------------------------------------------------------- +!> @brief maps interface ID from 4D (normal and local position) into 1D (global array) +!-------------------------------------------------------------------------------------------------- +integer(pInt) pure function homogenization_RGC_interface4to1(iFace4D, homID) + + implicit none + integer(pInt), dimension (4), intent(in) :: iFace4D !< interface ID in 4D array (n.dir,pos.x,pos.y,pos.z) + integer(pInt), dimension (3) :: nGDim,nIntFace + integer(pInt), intent(in) :: homID !< homogenization ID + + nGDim = homogenization_RGC_Ngrains(1:3,homID) + +!-------------------------------------------------------------------------------------------------- +! compute the total number of interfaces, which ... + nIntFace(1) = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) ! ... normal //e1 + nIntFace(2) = nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) ! ... normal //e2 + nIntFace(3) = nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) ! ... normal //e3 + + homogenization_RGC_interface4to1 = -1_pInt + +!-------------------------------------------------------------------------------------------------- +! get the corresponding interface ID in 1D global array + if (abs(iFace4D(1)) == 1_pInt) then ! interface with normal //e1 + homogenization_RGC_interface4to1 = iFace4D(3) + nGDim(2)*(iFace4D(4)-1_pInt) & + + nGDim(2)*nGDim(3)*(iFace4D(2)-1_pInt) + if ((iFace4D(2) == 0_pInt) .or. (iFace4D(2) == nGDim(1))) homogenization_RGC_interface4to1 = 0_pInt + elseif (abs(iFace4D(1)) == 2_pInt) then ! interface with normal //e2 + homogenization_RGC_interface4to1 = iFace4D(4) + nGDim(3)*(iFace4D(2)-1_pInt) & + + nGDim(3)*nGDim(1)*(iFace4D(3)-1_pInt) + nIntFace(1) + if ((iFace4D(3) == 0_pInt) .or. (iFace4D(3) == nGDim(2))) homogenization_RGC_interface4to1 = 0_pInt + elseif (abs(iFace4D(1)) == 3_pInt) then ! interface with normal //e3 + homogenization_RGC_interface4to1 = iFace4D(2) + nGDim(1)*(iFace4D(3)-1_pInt) & + + nGDim(1)*nGDim(2)*(iFace4D(4)-1_pInt) + nIntFace(1) + nIntFace(2) + if ((iFace4D(4) == 0_pInt) .or. (iFace4D(4) == nGDim(3))) homogenization_RGC_interface4to1 = 0_pInt + endif + +end function homogenization_RGC_interface4to1 + + +!-------------------------------------------------------------------------------------------------- +!> @brief maps interface ID from 1D (global array) into 4D (normal and local position) +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_interface1to4(iFace1D, homID) + + implicit none + integer(pInt), dimension (4) :: homogenization_RGC_interface1to4 + integer(pInt), intent(in) :: iFace1D !< interface ID in 1D array + integer(pInt), dimension (3) :: nGDim,nIntFace + integer(pInt), intent(in) :: homID !< homogenization ID + + nGDim = homogenization_RGC_Ngrains(:,homID) + +!-------------------------------------------------------------------------------------------------- +! compute the total number of interfaces, which ... + nIntFace(1) = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) ! ... normal //e1 + nIntFace(2) = nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) ! ... normal //e2 + nIntFace(3) = nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) ! ... normal //e3 + +!-------------------------------------------------------------------------------------------------- +! get the corresponding interface ID in 4D (normal and local position) + if (iFace1D > 0 .and. iFace1D <= nIntFace(1)) then ! interface with normal //e1 + homogenization_RGC_interface1to4(1) = 1_pInt + homogenization_RGC_interface1to4(3) = mod((iFace1D-1_pInt),nGDim(2))+1_pInt + homogenization_RGC_interface1to4(4) = mod(& + int(& + real(iFace1D-1_pInt,pReal)/& + real(nGDim(2),pReal)& + ,pInt)& + ,nGDim(3))+1_pInt + homogenization_RGC_interface1to4(2) = int(& + real(iFace1D-1_pInt,pReal)/& + real(nGDim(2),pReal)/& + real(nGDim(3),pReal)& + ,pInt)+1_pInt + elseif (iFace1D > nIntFace(1) .and. iFace1D <= (nIntFace(2) + nIntFace(1))) then ! interface with normal //e2 + homogenization_RGC_interface1to4(1) = 2_pInt + homogenization_RGC_interface1to4(4) = mod((iFace1D-nIntFace(1)-1_pInt),nGDim(3))+1_pInt + homogenization_RGC_interface1to4(2) = mod(& + int(& + real(iFace1D-nIntFace(1)-1_pInt,pReal)/& + real(nGDim(3),pReal)& + ,pInt)& + ,nGDim(1))+1_pInt + homogenization_RGC_interface1to4(3) = int(& + real(iFace1D-nIntFace(1)-1_pInt,pReal)/& + real(nGDim(3),pReal)/& + real(nGDim(1),pReal)& + ,pInt)+1_pInt + elseif (iFace1D > nIntFace(2) + nIntFace(1) .and. iFace1D <= (nIntFace(3) + nIntFace(2) + nIntFace(1))) then ! interface with normal //e3 + homogenization_RGC_interface1to4(1) = 3_pInt + homogenization_RGC_interface1to4(2) = mod((iFace1D-nIntFace(2)-nIntFace(1)-1_pInt),nGDim(1))+1_pInt + homogenization_RGC_interface1to4(3) = mod(& + int(& + real(iFace1D-nIntFace(2)-nIntFace(1)-1_pInt,pReal)/& + real(nGDim(1),pReal)& + ,pInt)& + ,nGDim(2))+1_pInt + homogenization_RGC_interface1to4(4) = int(& + real(iFace1D-nIntFace(2)-nIntFace(1)-1_pInt,pReal)/& + real(nGDim(1),pReal)/& + real(nGDim(2),pReal)& + ,pInt)+1_pInt + endif + +end function homogenization_RGC_interface1to4 + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculating the grain deformation gradient (the same with +! homogenization_RGC_partionDeformation, but used only for perturbation scheme) +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_grainDeformation(F, avgF, ip, el) + use mesh, only: & + mesh_element + use material, only: & + homogenization_maxNgrains,& + homogenization_Ngrains, & + homogenization_typeInstance + + implicit none + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned F per grain + real(pReal), dimension (3,3), intent(in) :: avgF !< + integer(pInt), intent(in) :: & + el, & !< element number + ip !< integration point number + real(pReal), dimension (3) :: aVect,nVect + integer(pInt), dimension (4) :: intFace + integer(pInt), dimension (3) :: iGrain3 + integer(pInt) :: homID, iGrain,iFace,i,j + integer(pInt), parameter :: nFace = 6_pInt + +!-------------------------------------------------------------------------------------------------- +! compute the deformation gradient of individual grains due to relaxations + homID = homogenization_typeInstance(mesh_element(3,el)) + F = 0.0_pReal + do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) + iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) + do iFace = 1_pInt,nFace + intFace = homogenization_RGC_getInterface(iFace,iGrain3) + aVect = homogenization_RGC_relaxationVector(intFace,homID, ip, el) + nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) & + F(i,j,iGrain) = F(i,j,iGrain) + aVect(i)*nVect(j) ! effective relaxations + enddo + F(1:3,1:3,iGrain) = F(1:3,1:3,iGrain) + avgF ! relaxed deformation gradient + enddo + +end subroutine homogenization_RGC_grainDeformation + +end module homogenization_RGC diff --git a/code/homogenization/homogenization_isostrain.f90 b/code/homogenization/homogenization_isostrain.f90 new file mode 100644 index 000000000..083107d9f --- /dev/null +++ b/code/homogenization/homogenization_isostrain.f90 @@ -0,0 +1,317 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Isostrain (full constraint Taylor assuption) homogenization scheme +!-------------------------------------------------------------------------------------------------- +module homogenization_isostrain + use prec, only: & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + homogenization_isostrain_sizePostResults + integer(pInt), dimension(:,:), allocatable, target, public :: & + homogenization_isostrain_sizePostResult + + character(len=64), dimension(:,:), allocatable, target, public :: & + homogenization_isostrain_output !< name of each post result output + integer(pInt), dimension(:), allocatable, target, public :: & + homogenization_isostrain_Noutput !< number of outputs per homog instance + integer(pInt), dimension(:), allocatable, private :: & + homogenization_isostrain_Ngrains + enum, bind(c) + enumerator :: undefined_ID, & + nconstituents_ID, & + ipcoords_ID, & + avgdefgrad_ID, & + avgfirstpiola_ID + end enum + enum, bind(c) + enumerator :: parallel_ID, & + average_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + homogenization_isostrain_outputID !< ID of each post result output + integer(kind(average_ID)), dimension(:), allocatable, private :: & + homogenization_isostrain_mapping !< mapping type + + + public :: & + homogenization_isostrain_init, & + homogenization_isostrain_partitionDeformation, & + homogenization_isostrain_averageStressAndItsTangent, & + homogenization_isostrain_postResults + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_isostrain_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal + use debug, only: & + debug_HOMOGENIZATION, & + debug_level, & + debug_levelBasic + use IO + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + section = 0_pInt, i, mySize, o + integer :: & + maxNinstance, & + homog, & + instance + integer :: & + NofMyHomog ! no pInt (stores a system dependen value from 'count' + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_ISOSTRAIN_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = count(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID) + if (maxNinstance == 0) return + + if (iand(debug_level(debug_HOMOGENIZATION),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + allocate(homogenization_isostrain_sizePostResults(maxNinstance), source=0_pInt) + allocate(homogenization_isostrain_sizePostResult(maxval(homogenization_Noutput),maxNinstance), & + source=0_pInt) + allocate(homogenization_isostrain_Noutput(maxNinstance), source=0_pInt) + allocate(homogenization_isostrain_Ngrains(maxNinstance), source=0_pInt) + allocate(homogenization_isostrain_mapping(maxNinstance), source=average_ID) + allocate(homogenization_isostrain_output(maxval(homogenization_Noutput),maxNinstance)) + homogenization_isostrain_output = '' + allocate(homogenization_isostrain_outputID(maxval(homogenization_Noutput),maxNinstance), & + source=undefined_ID) + + rewind(fileUnit) + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homogenization part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + cycle + endif + if (section > 0_pInt ) then ! do not short-circuit here (.and. with next if-statement). It's not safe in Fortran + if (homogenization_type(section) == HOMOGENIZATION_ISOSTRAIN_ID) then ! one of my sections + i = homogenization_typeInstance(section) ! which instance of my type is present homogenization + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case('nconstituents','ngrains') + homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt + homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = nconstituents_ID + homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('ipcoords') + homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt + homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = ipcoords_ID + homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('avgdefgrad','avgf') + homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt + homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = avgdefgrad_ID + homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('avgp','avgfirstpiola','avg1stpiola') + homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt + homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = avgfirstpiola_ID + homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + + end select + case ('nconstituents','ngrains') + homogenization_isostrain_Ngrains(i) = IO_intValue(line,chunkPos,2_pInt) + case ('mapping') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('parallel','sum') + homogenization_isostrain_mapping(i) = parallel_ID + case ('average','mean','avg') + homogenization_isostrain_mapping(i) = average_ID + case default + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//HOMOGENIZATION_isostrain_label//')') + end select + + end select + endif + endif + enddo parsingFile + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + myHomog: if (homogenization_type(homog) == HOMOGENIZATION_ISOSTRAIN_ID) then + NofMyHomog = count(material_homog == homog) + instance = homogenization_typeInstance(homog) + +! * Determine size of postResults array + outputsLoop: do o = 1_pInt, homogenization_isostrain_Noutput(instance) + select case(homogenization_isostrain_outputID(o,instance)) + case(nconstituents_ID) + mySize = 1_pInt + case(ipcoords_ID) + mySize = 3_pInt + case(avgdefgrad_ID, avgfirstpiola_ID) + mySize = 9_pInt + case default + mySize = 0_pInt + end select + + outputFound: if (mySize > 0_pInt) then + homogenization_isostrain_sizePostResult(o,instance) = mySize + homogenization_isostrain_sizePostResults(instance) = & + homogenization_isostrain_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop + +! allocate state arrays + homogState(homog)%sizeState = 0_pInt + homogState(homog)%sizePostResults = homogenization_isostrain_sizePostResults(instance) + allocate(homogState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) + + endif myHomog + enddo initializeInstances + +end subroutine homogenization_isostrain_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief partitions the deformation gradient onto the constituents +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_isostrain_partitionDeformation(F,avgF,el) + use prec, only: & + pReal + use mesh, only: & + mesh_element + use material, only: & + homogenization_maxNgrains, & + homogenization_Ngrains + + implicit none + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned def grad per grain + real(pReal), dimension (3,3), intent(in) :: avgF !< my average def grad + integer(pInt), intent(in) :: & + el !< element number + F=0.0_pReal + F(1:3,1:3,1:homogenization_Ngrains(mesh_element(3,el)))= & + spread(avgF,3,homogenization_Ngrains(mesh_element(3,el))) + +end subroutine homogenization_isostrain_partitionDeformation + + +!-------------------------------------------------------------------------------------------------- +!> @brief derive average stress and stiffness from constituent quantities +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_isostrain_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,el) + use prec, only: & + pReal + use mesh, only: & + mesh_element + use material, only: & + homogenization_maxNgrains, & + homogenization_Ngrains, & + homogenization_typeInstance + + implicit none + 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 (3,3,homogenization_maxNgrains), intent(in) :: P !< array of current grain stresses + real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffnesses + integer(pInt), intent(in) :: el !< element number + integer(pInt) :: & + homID, & + Ngrains + + homID = homogenization_typeInstance(mesh_element(3,el)) + Ngrains = homogenization_Ngrains(mesh_element(3,el)) + + select case (homogenization_isostrain_mapping(homID)) + case (parallel_ID) + avgP = sum(P,3) + dAvgPdAvgF = sum(dPdF,5) + case (average_ID) + avgP = sum(P,3) /real(Ngrains,pReal) + dAvgPdAvgF = sum(dPdF,5)/real(Ngrains,pReal) + end select + +end subroutine homogenization_isostrain_averageStressAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of homogenization results for post file inclusion +!-------------------------------------------------------------------------------------------------- +pure function homogenization_isostrain_postResults(ip,el,avgP,avgF) + use prec, only: & + pReal + use mesh, only: & + mesh_element, & + mesh_ipCoordinates + use material, only: & + homogenization_typeInstance, & + homogenization_Noutput + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3), intent(in) :: & + avgP, & !< average stress at material point + avgF !< average deformation gradient at material point + real(pReal), dimension(homogenization_isostrain_sizePostResults & + (homogenization_typeInstance(mesh_element(3,el)))) :: & + homogenization_isostrain_postResults + + integer(pInt) :: & + homID, & + o, c + + c = 0_pInt + homID = homogenization_typeInstance(mesh_element(3,el)) + homogenization_isostrain_postResults = 0.0_pReal + + do o = 1_pInt,homogenization_Noutput(mesh_element(3,el)) + select case(homogenization_isostrain_outputID(o,homID)) + case (nconstituents_ID) + homogenization_isostrain_postResults(c+1_pInt) = real(homogenization_isostrain_Ngrains(homID),pReal) + c = c + 1_pInt + case (avgdefgrad_ID) + homogenization_isostrain_postResults(c+1_pInt:c+9_pInt) = reshape(avgF,[9]) + c = c + 9_pInt + case (avgfirstpiola_ID) + homogenization_isostrain_postResults(c+1_pInt:c+9_pInt) = reshape(avgP,[9]) + c = c + 9_pInt + case (ipcoords_ID) + homogenization_isostrain_postResults(c+1_pInt:c+3_pInt) = mesh_ipCoordinates(1:3,ip,el) ! current ip coordinates + c = c + 3_pInt + end select + enddo + +end function homogenization_isostrain_postResults + +end module homogenization_isostrain diff --git a/code/homogenization/homogenization_none.f90 b/code/homogenization/homogenization_none.f90 new file mode 100644 index 000000000..59e483c27 --- /dev/null +++ b/code/homogenization/homogenization_none.f90 @@ -0,0 +1,60 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief dummy homogenization homogenization scheme +!-------------------------------------------------------------------------------------------------- +module homogenization_none + + implicit none + private + + public :: & + homogenization_none_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_none_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_NONE_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (homogenization_type(homog) == HOMOGENIZATION_none_ID) then + NofMyHomog = count(material_homog == homog) + homogState(homog)%sizeState = 0_pInt + homogState(homog)%sizePostResults = 0_pInt + allocate(homogState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) + + endif myhomog + enddo initializeInstances + + +end subroutine homogenization_none_init + +end module homogenization_none diff --git a/code/hydrogenflux/CMakeLists.txt b/code/hydrogenflux/CMakeLists.txt new file mode 100644 index 000000000..ef296400b --- /dev/null +++ b/code/hydrogenflux/CMakeLists.txt @@ -0,0 +1,9 @@ +# group sources +set (HYDROGENFLUX "hydrogenflux_isoconc" + "hydrogenflux_cahnhilliard" + ) + +# compile hydrogenflux modules +foreach (p ${HYDROGENFLUX}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) diff --git a/code/hydrogenflux/hydrogenflux_cahnhilliard.f90 b/code/hydrogenflux/hydrogenflux_cahnhilliard.f90 new file mode 100644 index 000000000..d8cb71edc --- /dev/null +++ b/code/hydrogenflux/hydrogenflux_cahnhilliard.f90 @@ -0,0 +1,513 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for conservative transport of solute hydrogen +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module hydrogenflux_cahnhilliard + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + hydrogenflux_cahnhilliard_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + hydrogenflux_cahnhilliard_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + hydrogenflux_cahnhilliard_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + hydrogenflux_cahnhilliard_Noutput !< number of outputs per instance of this damage + + real(pReal), parameter, private :: & + kB = 1.3806488e-23_pReal !< Boltzmann constant in J/Kelvin + + enum, bind(c) + enumerator :: undefined_ID, & + hydrogenConc_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + hydrogenflux_cahnhilliard_outputID !< ID of each post result output + + + public :: & + hydrogenflux_cahnhilliard_init, & + hydrogenflux_cahnhilliard_getMobility33, & + hydrogenflux_cahnhilliard_getDiffusion33, & + hydrogenflux_cahnhilliard_getFormationEnergy, & + hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent, & + hydrogenflux_cahnhilliard_getChemPotAndItsTangent, & + hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate, & + hydrogenflux_cahnhilliard_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine hydrogenflux_cahnhilliard_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + hydrogenflux_type, & + hydrogenflux_typeInstance, & + homogenization_Noutput, & + HYDROGENFLUX_cahnhilliard_label, & + HYDROGENFLUX_cahnhilliard_ID, & + material_homog, & + mappingHomogenization, & + hydrogenfluxState, & + hydrogenfluxMapping, & + hydrogenConc, & + hydrogenConcRate, & + hydrogenflux_initialCh, & + material_partHomogenization, & + material_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- hydrogenflux_'//HYDROGENFLUX_cahnhilliard_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(hydrogenflux_type == HYDROGENFLUX_cahnhilliard_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(hydrogenflux_cahnhilliard_sizePostResults(maxNinstance), source=0_pInt) + allocate(hydrogenflux_cahnhilliard_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(hydrogenflux_cahnhilliard_output (maxval(homogenization_Noutput),maxNinstance)) + hydrogenflux_cahnhilliard_output = '' + allocate(hydrogenflux_cahnhilliard_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(hydrogenflux_cahnhilliard_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (hydrogenflux_type(section) == HYDROGENFLUX_cahnhilliard_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = hydrogenflux_typeInstance(section) ! which instance of my hydrogenflux is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('hydrogenconc') + hydrogenflux_cahnhilliard_Noutput(instance) = hydrogenflux_cahnhilliard_Noutput(instance) + 1_pInt + hydrogenflux_cahnhilliard_outputID(hydrogenflux_cahnhilliard_Noutput(instance),instance) = hydrogenConc_ID + hydrogenflux_cahnhilliard_output(hydrogenflux_cahnhilliard_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingHomog + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + initializeInstances: do section = 1_pInt, size(hydrogenflux_type) + if (hydrogenflux_type(section) == HYDROGENFLUX_cahnhilliard_ID) then + NofMyHomog=count(material_homog==section) + instance = hydrogenflux_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,hydrogenflux_cahnhilliard_Noutput(instance) + select case(hydrogenflux_cahnhilliard_outputID(o,instance)) + case(hydrogenConc_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + hydrogenflux_cahnhilliard_sizePostResult(o,instance) = mySize + hydrogenflux_cahnhilliard_sizePostResults(instance) = hydrogenflux_cahnhilliard_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 0_pInt + hydrogenfluxState(section)%sizeState = sizeState + hydrogenfluxState(section)%sizePostResults = hydrogenflux_cahnhilliard_sizePostResults(instance) + allocate(hydrogenfluxState(section)%state0 (sizeState,NofMyHomog)) + allocate(hydrogenfluxState(section)%subState0(sizeState,NofMyHomog)) + allocate(hydrogenfluxState(section)%state (sizeState,NofMyHomog)) + + nullify(hydrogenfluxMapping(section)%p) + hydrogenfluxMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(hydrogenConc (section)%p) + deallocate(hydrogenConcRate(section)%p) + allocate (hydrogenConc (section)%p(NofMyHomog), source=hydrogenflux_initialCh(section)) + allocate (hydrogenConcRate(section)%p(NofMyHomog), source=0.0_pReal) + + endif + + enddo initializeInstances + +end subroutine hydrogenflux_cahnhilliard_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized solute mobility tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function hydrogenflux_cahnhilliard_getMobility33(ip,el) + use lattice, only: & + lattice_hydrogenfluxMobility33 + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + hydrogenflux_cahnhilliard_getMobility33 + integer(pInt) :: & + grain + + hydrogenflux_cahnhilliard_getMobility33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + hydrogenflux_cahnhilliard_getMobility33 = hydrogenflux_cahnhilliard_getMobility33 + & + crystallite_push33ToRef(grain,ip,el,lattice_hydrogenfluxMobility33(:,:,material_phase(grain,ip,el))) + enddo + + hydrogenflux_cahnhilliard_getMobility33 = & + hydrogenflux_cahnhilliard_getMobility33/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function hydrogenflux_cahnhilliard_getMobility33 + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized solute nonlocal diffusion tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function hydrogenflux_cahnhilliard_getDiffusion33(ip,el) + use lattice, only: & + lattice_hydrogenfluxDiffusion33 + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + hydrogenflux_cahnhilliard_getDiffusion33 + integer(pInt) :: & + grain + + hydrogenflux_cahnhilliard_getDiffusion33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + hydrogenflux_cahnhilliard_getDiffusion33 = hydrogenflux_cahnhilliard_getDiffusion33 + & + crystallite_push33ToRef(grain,ip,el,lattice_hydrogenfluxDiffusion33(:,:,material_phase(grain,ip,el))) + enddo + + hydrogenflux_cahnhilliard_getDiffusion33 = & + hydrogenflux_cahnhilliard_getDiffusion33/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function hydrogenflux_cahnhilliard_getDiffusion33 + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized solution energy +!-------------------------------------------------------------------------------------------------- +function hydrogenflux_cahnhilliard_getFormationEnergy(ip,el) + use lattice, only: & + lattice_hydrogenFormationEnergy, & + lattice_hydrogenVol, & + lattice_hydrogenSurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + hydrogenflux_cahnhilliard_getFormationEnergy + integer(pInt) :: & + grain + + hydrogenflux_cahnhilliard_getFormationEnergy = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + hydrogenflux_cahnhilliard_getFormationEnergy = hydrogenflux_cahnhilliard_getFormationEnergy + & + lattice_hydrogenFormationEnergy(material_phase(grain,ip,el))/ & + lattice_hydrogenVol(material_phase(grain,ip,el))/ & + lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) + enddo + + hydrogenflux_cahnhilliard_getFormationEnergy = & + hydrogenflux_cahnhilliard_getFormationEnergy/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function hydrogenflux_cahnhilliard_getFormationEnergy + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized hydrogen entropy coefficient +!-------------------------------------------------------------------------------------------------- +function hydrogenflux_cahnhilliard_getEntropicCoeff(ip,el) + use lattice, only: & + lattice_hydrogenVol, & + lattice_hydrogenSurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_homog, & + material_phase, & + temperature, & + thermalMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + hydrogenflux_cahnhilliard_getEntropicCoeff + integer(pInt) :: & + grain + + hydrogenflux_cahnhilliard_getEntropicCoeff = 0.0_pReal + do grain = 1, homogenization_Ngrains(material_homog(ip,el)) + hydrogenflux_cahnhilliard_getEntropicCoeff = hydrogenflux_cahnhilliard_getEntropicCoeff + & + kB/ & + lattice_hydrogenVol(material_phase(grain,ip,el))/ & + lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) + enddo + + hydrogenflux_cahnhilliard_getEntropicCoeff = & + hydrogenflux_cahnhilliard_getEntropicCoeff* & + temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))/ & + homogenization_Ngrains(material_homog(ip,el)) + +end function hydrogenflux_cahnhilliard_getEntropicCoeff + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized kinematic contribution to chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCh, Ch, ip, el) + use lattice, only: & + lattice_hydrogenSurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_homog, & + phase_kinematics, & + phase_Nkinematics, & + material_phase, & + KINEMATICS_hydrogen_strain_ID + use crystallite, only: & + crystallite_Tstar_v, & + crystallite_Fi0, & + crystallite_Fi + use kinematics_hydrogen_strain, only: & + kinematics_hydrogen_strain_ChemPotAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Ch + real(pReal), intent(out) :: & + KPot, dKPot_dCh + real(pReal) :: & + my_KPot, my_dKPot_dCh + integer(pInt) :: & + grain, kinematics + + KPot = 0.0_pReal + dKPot_dCh = 0.0_pReal + do grain = 1_pInt,homogenization_Ngrains(material_homog(ip,el)) + do kinematics = 1_pInt, phase_Nkinematics(material_phase(grain,ip,el)) + select case (phase_kinematics(kinematics,material_phase(grain,ip,el))) + case (KINEMATICS_hydrogen_strain_ID) + call kinematics_hydrogen_strain_ChemPotAndItsTangent(my_KPot, my_dKPot_dCh, & + crystallite_Tstar_v(1:6,grain,ip,el), & + crystallite_Fi0(1:3,1:3,grain,ip,el), & + crystallite_Fi (1:3,1:3,grain,ip,el), & + grain,ip, el) + + case default + my_KPot = 0.0_pReal + my_dKPot_dCh = 0.0_pReal + + end select + KPot = KPot + my_KPot/lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) + dKPot_dCh = dKPot_dCh + my_dKPot_dCh/lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) + enddo + enddo + + KPot = KPot/homogenization_Ngrains(material_homog(ip,el)) + dKPot_dCh = dKPot_dCh/homogenization_Ngrains(material_homog(ip,el)) + +end subroutine hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine hydrogenflux_cahnhilliard_getChemPotAndItsTangent(ChemPot,dChemPot_dCh,Ch,ip,el) + use numerics, only: & + hydrogenBoundPenalty, & + hydrogenPolyOrder + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Ch + real(pReal), intent(out) :: & + ChemPot, & + dChemPot_dCh + real(pReal) :: & + kBT, KPot, dKPot_dCh + integer(pInt) :: & + o + + ChemPot = hydrogenflux_cahnhilliard_getFormationEnergy(ip,el) + dChemPot_dCh = 0.0_pReal + kBT = hydrogenflux_cahnhilliard_getEntropicCoeff(ip,el) + do o = 1_pInt, hydrogenPolyOrder + ChemPot = ChemPot + kBT*((2.0_pReal*Ch - 1.0_pReal)**real(2_pInt*o-1_pInt,pReal))/ & + real(2_pInt*o-1_pInt,pReal) + dChemPot_dCh = dChemPot_dCh + 2.0_pReal*kBT*(2.0_pReal*Ch - 1.0_pReal)**real(2_pInt*o-2_pInt,pReal) + enddo + + call hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCh, Ch, ip, el) + ChemPot = ChemPot + KPot + dChemPot_dCh = dChemPot_dCh + dKPot_dCh + + if (Ch < 0.0_pReal) then + ChemPot = ChemPot - 3.0_pReal*hydrogenBoundPenalty*Ch*Ch + dChemPot_dCh = dChemPot_dCh - 6.0_pReal*hydrogenBoundPenalty*Ch + elseif (Ch > 1.0_pReal) then + ChemPot = ChemPot + 3.0_pReal*hydrogenBoundPenalty*(1.0_pReal - Ch)*(1.0_pReal - Ch) + dChemPot_dCh = dChemPot_dCh - 6.0_pReal*hydrogenBoundPenalty*(1.0_pReal - Ch) + endif + +end subroutine hydrogenflux_cahnhilliard_getChemPotAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief updates hydrogen concentration with solution from Cahn-Hilliard PDE for solute transport +!-------------------------------------------------------------------------------------------------- +subroutine hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate(Ch,Chdot,ip,el) + use material, only: & + mappingHomogenization, & + hydrogenConc, & + hydrogenConcRate, & + hydrogenfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Ch, & + Chdot + integer(pInt) :: & + homog, & + offset + + homog = mappingHomogenization(2,ip,el) + offset = hydrogenfluxMapping(homog)%p(ip,el) + hydrogenConc (homog)%p(offset) = Ch + hydrogenConcRate(homog)%p(offset) = Chdot + +end subroutine hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of hydrogen transport results +!-------------------------------------------------------------------------------------------------- +function hydrogenflux_cahnhilliard_postResults(ip,el) + use material, only: & + mappingHomogenization, & + hydrogenflux_typeInstance, & + hydrogenConc, & + hydrogenfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(hydrogenflux_cahnhilliard_sizePostResults(hydrogenflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & + hydrogenflux_cahnhilliard_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = hydrogenfluxMapping(homog)%p(ip,el) + instance = hydrogenflux_typeInstance(homog) + + c = 0_pInt + hydrogenflux_cahnhilliard_postResults = 0.0_pReal + + do o = 1_pInt,hydrogenflux_cahnhilliard_Noutput(instance) + select case(hydrogenflux_cahnhilliard_outputID(o,instance)) + + case (hydrogenConc_ID) + hydrogenflux_cahnhilliard_postResults(c+1_pInt) = hydrogenConc(homog)%p(offset) + c = c + 1 + end select + enddo +end function hydrogenflux_cahnhilliard_postResults + +end module hydrogenflux_cahnhilliard diff --git a/code/hydrogenflux/hydrogenflux_isoconc.f90 b/code/hydrogenflux/hydrogenflux_isoconc.f90 new file mode 100644 index 000000000..74759d4c3 --- /dev/null +++ b/code/hydrogenflux/hydrogenflux_isoconc.f90 @@ -0,0 +1,63 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for constant hydrogen concentration +!-------------------------------------------------------------------------------------------------- +module hydrogenflux_isoconc + + implicit none + private + + public :: & + hydrogenflux_isoconc_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine hydrogenflux_isoconc_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- hydrogenflux_'//HYDROGENFLUX_isoconc_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (hydrogenflux_type(homog) == HYDROGENFLUX_isoconc_ID) then + NofMyHomog = count(material_homog == homog) + hydrogenfluxState(homog)%sizeState = 0_pInt + hydrogenfluxState(homog)%sizePostResults = 0_pInt + allocate(hydrogenfluxState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) + allocate(hydrogenfluxState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) + allocate(hydrogenfluxState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) + + deallocate(hydrogenConc (homog)%p) + deallocate(hydrogenConcRate(homog)%p) + allocate (hydrogenConc (homog)%p(1), source=hydrogenflux_initialCh(homog)) + allocate (hydrogenConcRate(homog)%p(1), source=0.0_pReal) + + endif myhomog + enddo initializeInstances + + +end subroutine hydrogenflux_isoconc_init + +end module hydrogenflux_isoconc diff --git a/code/kinematics/CMakeLists.txt b/code/kinematics/CMakeLists.txt new file mode 100644 index 000000000..17e1a7dd7 --- /dev/null +++ b/code/kinematics/CMakeLists.txt @@ -0,0 +1,12 @@ +# group sources +set (KINEMATICS "kinematics_cleavage_opening" + "kinematics_slipplane_opening" + "kinematics_thermal_expansion" + "kinematics_vacancy_strain" + "kinematics_hydrogen_strain" + ) + +# compile kinamtic modules +foreach (p ${KINEMATICS}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) diff --git a/code/kinematics/kinematics_cleavage_opening.f90 b/code/kinematics/kinematics_cleavage_opening.f90 new file mode 100644 index 000000000..945e2d08a --- /dev/null +++ b/code/kinematics/kinematics_cleavage_opening.f90 @@ -0,0 +1,303 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from opening of cleavage planes +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_cleavage_opening + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_cleavage_opening_sizePostResults, & !< cumulative size of post results + kinematics_cleavage_opening_offset, & !< which kinematics is my current damage mechanism? + kinematics_cleavage_opening_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_cleavage_opening_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_cleavage_opening_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_cleavage_opening_Noutput !< number of outputs per instance of this damage + + integer(pInt), dimension(:), allocatable, private :: & + kinematics_cleavage_opening_totalNcleavage !< total number of cleavage systems + + integer(pInt), dimension(:,:), allocatable, private :: & + kinematics_cleavage_opening_Ncleavage !< number of cleavage systems per family + + real(pReal), dimension(:), allocatable, private :: & + kinematics_cleavage_opening_sdot_0, & + kinematics_cleavage_opening_N + + real(pReal), dimension(:,:), allocatable, private :: & + kinematics_cleavage_opening_critDisp, & + kinematics_cleavage_opening_critLoad + + public :: & + kinematics_cleavage_opening_init, & + kinematics_cleavage_opening_LiAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_cleavage_opening_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_cleavage_opening_label, & + KINEMATICS_cleavage_opening_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + use lattice, only: & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_cleavage_opening_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_cleavage_opening_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_cleavage_opening_offset(material_Nphase), source=0_pInt) + allocate(kinematics_cleavage_opening_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_cleavage_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_cleavage_opening_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_cleavage_opening_ID) & + kinematics_cleavage_opening_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_cleavage_opening_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_output(maxval(phase_Noutput),maxNinstance)) + kinematics_cleavage_opening_output = '' + allocate(kinematics_cleavage_opening_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(kinematics_cleavage_opening_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(kinematics_cleavage_opening_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_totalNcleavage(maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_sdot_0(maxNinstance), source=0.0_pReal) + allocate(kinematics_cleavage_opening_N(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_cleavage_opening_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('anisobrittle_sdot0') + kinematics_cleavage_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisobrittle_ratesensitivity') + kinematics_cleavage_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('ncleavage') ! + Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_CleavageFamilies + kinematics_cleavage_opening_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticaldisplacement') + do j = 1_pInt, Nchunks_CleavageFamilies + kinematics_cleavage_opening_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticalload') + do j = 1_pInt, Nchunks_CleavageFamilies + kinematics_cleavage_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then + instance = kinematics_cleavage_opening_instance(phase) + kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & + min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested + kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance)) + kinematics_cleavage_opening_totalNcleavage(instance) = sum(kinematics_cleavage_opening_Ncleavage(:,instance)) ! how many cleavage systems altogether + if (kinematics_cleavage_opening_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_cleavage_opening_LABEL//')') + if (any(kinematics_cleavage_opening_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//KINEMATICS_cleavage_opening_LABEL//')') + if (any(kinematics_cleavage_opening_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//KINEMATICS_cleavage_opening_LABEL//')') + if (kinematics_cleavage_opening_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_cleavage_opening_LABEL//')') + endif myPhase + enddo sanityChecks + +end subroutine kinematics_cleavage_opening_init + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) + use prec, only: & + tol_math_check + use material, only: & + phaseAt, phasememberAt, & + material_homog, & + damage, & + damageMapping + use lattice, only: & + lattice_Scleavage, & + lattice_Scleavage_v, & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola-Kirchhoff stress + real(pReal), intent(out), dimension(3,3) :: & + Ld !< damage velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) + integer(pInt) :: & + phase, & + constituent, & + instance, & + homog, damageOffset, & + f, i, index_myFamily, k, l, m, n + real(pReal) :: & + traction_d, traction_t, traction_n, traction_crit, & + udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = kinematics_cleavage_opening_instance(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + Ld = 0.0_pReal + dLd_dTstar3333 = 0.0_pReal + do f = 1_pInt,lattice_maxNcleavageFamily + index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family + do i = 1_pInt,kinematics_cleavage_opening_Ncleavage(f,instance) ! process each (active) cleavage system in family + traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) + traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) + traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) + traction_crit = kinematics_cleavage_opening_critLoad(f,instance)* & + damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) + udotd = & + sign(1.0_pReal,traction_d)* & + kinematics_cleavage_opening_sdot_0(instance)* & + (max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) + if (abs(udotd) > tol_math_check) then + Ld = Ld + udotd*lattice_Scleavage(1:3,1:3,1,index_myFamily+i,phase) + dudotd_dt = sign(1.0_pReal,traction_d)*udotd*kinematics_cleavage_opening_N(instance)/ & + max(0.0_pReal, abs(traction_d) - traction_crit) + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotd_dt*lattice_Scleavage(k,l,1,index_myFamily+i,phase)* & + lattice_Scleavage(m,n,1,index_myFamily+i,phase) + endif + + udott = & + sign(1.0_pReal,traction_t)* & + kinematics_cleavage_opening_sdot_0(instance)* & + (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) + if (abs(udott) > tol_math_check) then + Ld = Ld + udott*lattice_Scleavage(1:3,1:3,2,index_myFamily+i,phase) + dudott_dt = sign(1.0_pReal,traction_t)*udott*kinematics_cleavage_opening_N(instance)/ & + max(0.0_pReal, abs(traction_t) - traction_crit) + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudott_dt*lattice_Scleavage(k,l,2,index_myFamily+i,phase)* & + lattice_Scleavage(m,n,2,index_myFamily+i,phase) + endif + + udotn = & + sign(1.0_pReal,traction_n)* & + kinematics_cleavage_opening_sdot_0(instance)* & + (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) + if (abs(udotn) > tol_math_check) then + Ld = Ld + udotn*lattice_Scleavage(1:3,1:3,3,index_myFamily+i,phase) + dudotn_dt = sign(1.0_pReal,traction_n)*udotn*kinematics_cleavage_opening_N(instance)/ & + max(0.0_pReal, abs(traction_n) - traction_crit) + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotn_dt*lattice_Scleavage(k,l,3,index_myFamily+i,phase)* & + lattice_Scleavage(m,n,3,index_myFamily+i,phase) + endif + + enddo + enddo + +end subroutine kinematics_cleavage_opening_LiAndItsTangent + +end module kinematics_cleavage_opening diff --git a/code/kinematics/kinematics_hydrogen_strain.f90 b/code/kinematics/kinematics_hydrogen_strain.f90 new file mode 100644 index 000000000..ceb3b1ef3 --- /dev/null +++ b/code/kinematics/kinematics_hydrogen_strain.f90 @@ -0,0 +1,264 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from interstitial hydrogen +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_hydrogen_strain + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_hydrogen_strain_sizePostResults, & !< cumulative size of post results + kinematics_hydrogen_strain_offset, & !< which kinematics is my current damage mechanism? + kinematics_hydrogen_strain_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_hydrogen_strain_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_hydrogen_strain_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_hydrogen_strain_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + kinematics_hydrogen_strain_coeff + + public :: & + kinematics_hydrogen_strain_init, & + kinematics_hydrogen_strain_initialStrain, & + kinematics_hydrogen_strain_LiAndItsTangent, & + kinematics_hydrogen_strain_ChemPotAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_hydrogen_strain_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_hydrogen_strain_label, & + KINEMATICS_hydrogen_strain_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_hydrogen_strain_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_hydrogen_strain_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_hydrogen_strain_offset(material_Nphase), source=0_pInt) + allocate(kinematics_hydrogen_strain_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_hydrogen_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_hydrogen_strain_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_hydrogen_strain_ID) & + kinematics_hydrogen_strain_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_hydrogen_strain_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_hydrogen_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_hydrogen_strain_output(maxval(phase_Noutput),maxNinstance)) + kinematics_hydrogen_strain_output = '' + allocate(kinematics_hydrogen_strain_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_hydrogen_strain_coeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_hydrogen_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_hydrogen_strain_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('hydrogen_strain_coeff') + kinematics_hydrogen_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + +end subroutine kinematics_hydrogen_strain_init + +!-------------------------------------------------------------------------------------------------- +!> @brief report initial hydrogen strain based on current hydrogen conc deviation from +!> equillibrium (0) +!-------------------------------------------------------------------------------------------------- +pure function kinematics_hydrogen_strain_initialStrain(ipc, ip, el) + use math, only: & + math_I3 + use material, only: & + material_phase, & + material_homog, & + hydrogenConc, & + hydrogenfluxMapping + use lattice, only: & + lattice_equilibriumHydrogenConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + kinematics_hydrogen_strain_initialStrain !< initial thermal strain (should be small strain, though) + integer(pInt) :: & + phase, & + homog, offset, instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_hydrogen_strain_instance(phase) + homog = material_homog(ip,el) + offset = hydrogenfluxMapping(homog)%p(ip,el) + + kinematics_hydrogen_strain_initialStrain = & + (hydrogenConc(homog)%p(offset) - lattice_equilibriumHydrogenConcentration(phase)) * & + kinematics_hydrogen_strain_coeff(instance)* math_I3 + +end function kinematics_hydrogen_strain_initialStrain + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_hydrogen_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + hydrogenConc, & + hydrogenConcRate, & + hydrogenfluxMapping + use math, only: & + math_I3 + use lattice, only: & + lattice_equilibriumHydrogenConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out), dimension(3,3) :: & + Li !< thermal velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) + integer(pInt) :: & + phase, & + instance, & + homog, offset + real(pReal) :: & + Ch, ChEq, ChDot + + phase = material_phase(ipc,ip,el) + instance = kinematics_hydrogen_strain_instance(phase) + homog = material_homog(ip,el) + offset = hydrogenfluxMapping(homog)%p(ip,el) + Ch = hydrogenConc(homog)%p(offset) + ChDot = hydrogenConcRate(homog)%p(offset) + ChEq = lattice_equilibriumHydrogenConcentration(phase) + + Li = ChDot*math_I3* & + kinematics_hydrogen_strain_coeff(instance)/ & + (1.0_pReal + kinematics_hydrogen_strain_coeff(instance)*(Ch - ChEq)) + dLi_dTstar3333 = 0.0_pReal + +end subroutine kinematics_hydrogen_strain_LiAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the kinematic contribution to hydrogen chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCh, Tstar_v, Fi0, Fi, ipc, ip, el) + use material, only: & + material_phase + use math, only: & + math_inv33, & + math_mul33x33, & + math_Mandel6to33, & + math_transpose33 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v + real(pReal), intent(in), dimension(3,3) :: & + Fi0, Fi + real(pReal), intent(out) :: & + ChemPot, dChemPot_dCh + integer(pInt) :: & + phase, & + instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_hydrogen_strain_instance(phase) + + ChemPot = -kinematics_hydrogen_strain_coeff(instance)* & + sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & + math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) + dChemPot_dCh = 0.0_pReal + +end subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent + +end module kinematics_hydrogen_strain diff --git a/code/kinematics/kinematics_slipplane_opening.f90 b/code/kinematics/kinematics_slipplane_opening.f90 new file mode 100644 index 000000000..8b49e1cf3 --- /dev/null +++ b/code/kinematics/kinematics_slipplane_opening.f90 @@ -0,0 +1,323 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from opening of slip planes +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_slipplane_opening + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_slipplane_opening_sizePostResults, & !< cumulative size of post results + kinematics_slipplane_opening_offset, & !< which kinematics is my current damage mechanism? + kinematics_slipplane_opening_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_slipplane_opening_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_slipplane_opening_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_slipplane_opening_Noutput !< number of outputs per instance of this damage + + integer(pInt), dimension(:), allocatable, private :: & + kinematics_slipplane_opening_totalNslip !< total number of slip systems + + integer(pInt), dimension(:,:), allocatable, private :: & + kinematics_slipplane_opening_Nslip !< number of slip systems per family + + real(pReal), dimension(:), allocatable, private :: & + kinematics_slipplane_opening_sdot_0, & + kinematics_slipplane_opening_N + + real(pReal), dimension(:,:), allocatable, private :: & + kinematics_slipplane_opening_critPlasticStrain, & + kinematics_slipplane_opening_critLoad + + public :: & + kinematics_slipplane_opening_init, & + kinematics_slipplane_opening_LiAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_slipplane_opening_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_slipplane_opening_label, & + KINEMATICS_slipplane_opening_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + use lattice, only: & + lattice_maxNslipFamily, & + lattice_NslipSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_slipplane_opening_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_slipplane_opening_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_slipplane_opening_offset(material_Nphase), source=0_pInt) + allocate(kinematics_slipplane_opening_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_slipplane_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_slipplane_opening_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_slipplane_opening_ID) & + kinematics_slipplane_opening_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_slipplane_opening_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_slipplane_opening_output(maxval(phase_Noutput),maxNinstance)) + kinematics_slipplane_opening_output = '' + allocate(kinematics_slipplane_opening_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(kinematics_slipplane_opening_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(kinematics_slipplane_opening_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_totalNslip(maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_N(maxNinstance), source=0.0_pReal) + allocate(kinematics_slipplane_opening_sdot_0(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_slipplane_opening_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('nslip') ! + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + kinematics_slipplane_opening_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_sdot0') + kinematics_slipplane_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalplasticstrain') + do j = 1_pInt, Nchunks_SlipFamilies + kinematics_slipplane_opening_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_ratesensitivity') + kinematics_slipplane_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalload') + do j = 1_pInt, Nchunks_SlipFamilies + kinematics_slipplane_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then + instance = kinematics_slipplane_opening_instance(phase) + kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested + kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance)) + kinematics_slipplane_opening_totalNslip(instance) = sum(kinematics_slipplane_opening_Nslip(:,instance)) + if (kinematics_slipplane_opening_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_slipplane_opening_LABEL//')') + if (any(kinematics_slipplane_opening_critPlasticStrain(:,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//KINEMATICS_slipplane_opening_LABEL//')') + if (kinematics_slipplane_opening_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_slipplane_opening_LABEL//')') + endif myPhase + enddo sanityChecks + + +end subroutine kinematics_slipplane_opening_init + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) + use prec, only: & + tol_math_check + use lattice, only: & + lattice_maxNslipFamily, & + lattice_NslipSystem, & + lattice_sd, & + lattice_st, & + lattice_sn + use material, only: & + phaseAt, phasememberAt, & + material_homog, & + damage, & + damageMapping + use math, only: & + math_Plain3333to99, & + math_I3, & + math_identity4th, & + math_symmetric33, & + math_Mandel33to6, & + math_tensorproduct33, & + math_det33, & + math_mul33x33 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola-Kirchhoff stress + real(pReal), intent(out), dimension(3,3) :: & + Ld !< damage velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) + real(pReal), dimension(3,3) :: & + projection_d, projection_t, projection_n !< projection modes 3x3 tensor + real(pReal), dimension(6) :: & + projection_d_v, projection_t_v, projection_n_v !< projection modes 3x3 vector + integer(pInt) :: & + phase, & + constituent, & + instance, & + homog, damageOffset, & + f, i, index_myFamily, k, l, m, n + real(pReal) :: & + traction_d, traction_t, traction_n, traction_crit, & + udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = kinematics_slipplane_opening_instance(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + Ld = 0.0_pReal + dLd_dTstar3333 = 0.0_pReal + do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,phase)) ! at which index starts my family + do i = 1_pInt,kinematics_slipplane_opening_Nslip(f,instance) ! process each (active) slip system in family + projection_d = math_tensorproduct33(lattice_sd(1:3,index_myFamily+i,phase),& + lattice_sn(1:3,index_myFamily+i,phase)) + projection_t = math_tensorproduct33(lattice_st(1:3,index_myFamily+i,phase),& + lattice_sn(1:3,index_myFamily+i,phase)) + projection_n = math_tensorproduct33(lattice_sn(1:3,index_myFamily+i,phase),& + lattice_sn(1:3,index_myFamily+i,phase)) + + projection_d_v(1:6) = math_Mandel33to6(math_symmetric33(projection_d(1:3,1:3))) + projection_t_v(1:6) = math_Mandel33to6(math_symmetric33(projection_t(1:3,1:3))) + projection_n_v(1:6) = math_Mandel33to6(math_symmetric33(projection_n(1:3,1:3))) + + traction_d = dot_product(Tstar_v,projection_d_v(1:6)) + traction_t = dot_product(Tstar_v,projection_t_v(1:6)) + traction_n = dot_product(Tstar_v,projection_n_v(1:6)) + + traction_crit = kinematics_slipplane_opening_critLoad(f,instance)* & + damage(homog)%p(damageOffset) ! degrading critical load carrying capacity by damage + + udotd = & + sign(1.0_pReal,traction_d)* & + kinematics_slipplane_opening_sdot_0(instance)* & + (abs(traction_d)/traction_crit - & + abs(traction_d)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) + if (abs(udotd) > tol_math_check) then + Ld = Ld + udotd*projection_d + dudotd_dt = udotd*kinematics_slipplane_opening_N(instance)/traction_d + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotd_dt*projection_d(k,l)*projection_d(m,n) + endif + + udott = & + sign(1.0_pReal,traction_t)* & + kinematics_slipplane_opening_sdot_0(instance)* & + (abs(traction_t)/traction_crit - & + abs(traction_t)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) + if (abs(udott) > tol_math_check) then + Ld = Ld + udott*projection_t + dudott_dt = udott*kinematics_slipplane_opening_N(instance)/traction_t + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudott_dt*projection_t(k,l)*projection_t(m,n) + endif + udotn = & + kinematics_slipplane_opening_sdot_0(instance)* & + (max(0.0_pReal,traction_n)/traction_crit - & + max(0.0_pReal,traction_n)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) + if (abs(udotn) > tol_math_check) then + Ld = Ld + udotn*projection_n + dudotn_dt = udotn*kinematics_slipplane_opening_N(instance)/traction_n + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotn_dt*projection_n(k,l)*projection_n(m,n) + endif + enddo + enddo + +end subroutine kinematics_slipplane_opening_LiAndItsTangent + +end module kinematics_slipplane_opening diff --git a/code/kinematics/kinematics_thermal_expansion.f90 b/code/kinematics/kinematics_thermal_expansion.f90 new file mode 100644 index 000000000..b99c499f3 --- /dev/null +++ b/code/kinematics/kinematics_thermal_expansion.f90 @@ -0,0 +1,228 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from thermal expansion +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_thermal_expansion + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_thermal_expansion_sizePostResults, & !< cumulative size of post results + kinematics_thermal_expansion_offset, & !< which kinematics is my current damage mechanism? + kinematics_thermal_expansion_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_thermal_expansion_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_thermal_expansion_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_thermal_expansion_Noutput !< number of outputs per instance of this damage + +! enum, bind(c) ! ToDo kinematics need state machinery to deal with sizePostResult +! enumerator :: undefined_ID, & ! possible remedy is to decouple having state vars from having output +! thermalexpansionrate_ID ! which means to separate user-defined types tState + tOutput... +! end enum + public :: & + kinematics_thermal_expansion_init, & + kinematics_thermal_expansion_initialStrain, & + kinematics_thermal_expansion_LiAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_thermal_expansion_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_thermal_expansion_label, & + KINEMATICS_thermal_expansion_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + character(len=65536) :: & + tag = '', & + output = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_thermal_expansion_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_thermal_expansion_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_thermal_expansion_offset(material_Nphase), source=0_pInt) + allocate(kinematics_thermal_expansion_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_thermal_expansion_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_thermal_expansion_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_thermal_expansion_ID) & + kinematics_thermal_expansion_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_thermal_expansion_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_thermal_expansion_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_thermal_expansion_output(maxval(phase_Noutput),maxNinstance)) + kinematics_thermal_expansion_output = '' + allocate(kinematics_thermal_expansion_Noutput(maxNinstance), source=0_pInt) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_thermal_expansion_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_thermal_expansion_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key... + select case(tag) +! case ('(output)') +! output = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) ! ...and corresponding output +! select case(output) +! case ('thermalexpansionrate') +! kinematics_thermal_expansion_Noutput(instance) = kinematics_thermal_expansion_Noutput(instance) + 1_pInt +! kinematics_thermal_expansion_outputID(kinematics_thermal_expansion_Noutput(instance),instance) = & +! thermalexpansionrate_ID +! kinematics_thermal_expansion_output(kinematics_thermal_expansion_Noutput(instance),instance) = output +! ToDo add sizePostResult loop afterwards... + + end select + endif; endif + enddo parsingFile + +end subroutine kinematics_thermal_expansion_init + +!-------------------------------------------------------------------------------------------------- +!> @brief report initial thermal strain based on current temperature deviation from reference +!-------------------------------------------------------------------------------------------------- +pure function kinematics_thermal_expansion_initialStrain(ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + temperature, & + thermalMapping + use lattice, only: & + lattice_thermalExpansion33, & + lattice_referenceTemperature + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + kinematics_thermal_expansion_initialStrain !< initial thermal strain (should be small strain, though) + integer(pInt) :: & + phase, & + homog, offset + + phase = material_phase(ipc,ip,el) + homog = material_homog(ip,el) + offset = thermalMapping(homog)%p(ip,el) + + kinematics_thermal_expansion_initialStrain = & + (temperature(homog)%p(offset) - lattice_referenceTemperature(phase)) * & + lattice_thermalExpansion33(1:3,1:3,phase) + +end function kinematics_thermal_expansion_initialStrain + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + temperature, & + temperatureRate, & + thermalMapping + use lattice, only: & + lattice_thermalExpansion33, & + lattice_referenceTemperature + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out), dimension(3,3) :: & + Li !< thermal velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor defined to be zero) + integer(pInt) :: & + phase, & + homog, offset + real(pReal) :: & + T, TRef, TDot + + phase = material_phase(ipc,ip,el) + homog = material_homog(ip,el) + offset = thermalMapping(homog)%p(ip,el) + T = temperature(homog)%p(offset) + TDot = temperatureRate(homog)%p(offset) + TRef = lattice_referenceTemperature(phase) + + Li = TDot* & + lattice_thermalExpansion33(1:3,1:3,phase)/ & + (1.0_pReal + lattice_thermalExpansion33(1:3,1:3,phase)*(T - TRef)) + dLi_dTstar3333 = 0.0_pReal + +end subroutine kinematics_thermal_expansion_LiAndItsTangent + +end module kinematics_thermal_expansion diff --git a/code/kinematics/kinematics_vacancy_strain.f90 b/code/kinematics/kinematics_vacancy_strain.f90 new file mode 100644 index 000000000..899bccd9f --- /dev/null +++ b/code/kinematics/kinematics_vacancy_strain.f90 @@ -0,0 +1,265 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from vacancy point defects +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_vacancy_strain + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_vacancy_strain_sizePostResults, & !< cumulative size of post results + kinematics_vacancy_strain_offset, & !< which kinematics is my current damage mechanism? + kinematics_vacancy_strain_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_vacancy_strain_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_vacancy_strain_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_vacancy_strain_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + kinematics_vacancy_strain_coeff + + public :: & + kinematics_vacancy_strain_init, & + kinematics_vacancy_strain_initialStrain, & + kinematics_vacancy_strain_LiAndItsTangent, & + kinematics_vacancy_strain_ChemPotAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_vacancy_strain_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_vacancy_strain_label, & + KINEMATICS_vacancy_strain_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_vacancy_strain_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_vacancy_strain_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_vacancy_strain_offset(material_Nphase), source=0_pInt) + allocate(kinematics_vacancy_strain_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_vacancy_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_vacancy_strain_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_vacancy_strain_ID) & + kinematics_vacancy_strain_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_vacancy_strain_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_vacancy_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_vacancy_strain_output(maxval(phase_Noutput),maxNinstance)) + kinematics_vacancy_strain_output = '' + allocate(kinematics_vacancy_strain_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_vacancy_strain_coeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_vacancy_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_vacancy_strain_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('vacancy_strain_coeff') + kinematics_vacancy_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + +end subroutine kinematics_vacancy_strain_init + +!-------------------------------------------------------------------------------------------------- +!> @brief report initial vacancy strain based on current vacancy conc deviation from equillibrium +!-------------------------------------------------------------------------------------------------- +pure function kinematics_vacancy_strain_initialStrain(ipc, ip, el) + use math, only: & + math_I3 + use material, only: & + material_phase, & + material_homog, & + vacancyConc, & + vacancyfluxMapping + use lattice, only: & + lattice_equilibriumVacancyConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + kinematics_vacancy_strain_initialStrain !< initial thermal strain (should be small strain, though) + integer(pInt) :: & + phase, & + homog, offset, instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_vacancy_strain_instance(phase) + homog = material_homog(ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + + kinematics_vacancy_strain_initialStrain = & + (vacancyConc(homog)%p(offset) - lattice_equilibriumVacancyConcentration(phase)) * & + kinematics_vacancy_strain_coeff(instance)* math_I3 + +end function kinematics_vacancy_strain_initialStrain + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_vacancy_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + vacancyConc, & + vacancyConcRate, & + vacancyfluxMapping + use math, only: & + math_I3 + use lattice, only: & + lattice_equilibriumVacancyConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out), dimension(3,3) :: & + Li !< thermal velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) + integer(pInt) :: & + phase, & + instance, & + homog, offset + real(pReal) :: & + Cv, CvEq, CvDot + + phase = material_phase(ipc,ip,el) + instance = kinematics_vacancy_strain_instance(phase) + homog = material_homog(ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + + Cv = vacancyConc(homog)%p(offset) + CvDot = vacancyConcRate(homog)%p(offset) + CvEq = lattice_equilibriumvacancyConcentration(phase) + + Li = CvDot*math_I3* & + kinematics_vacancy_strain_coeff(instance)/ & + (1.0_pReal + kinematics_vacancy_strain_coeff(instance)*(Cv - CvEq)) + + dLi_dTstar3333 = 0.0_pReal + +end subroutine kinematics_vacancy_strain_LiAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the kinematic contribution to vacancy chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_vacancy_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCv, Tstar_v, Fi0, Fi, ipc, ip, el) + use material, only: & + material_phase + use math, only: & + math_inv33, & + math_mul33x33, & + math_Mandel6to33, & + math_transpose33 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v + real(pReal), intent(in), dimension(3,3) :: & + Fi0, Fi + real(pReal), intent(out) :: & + ChemPot, dChemPot_dCv + integer(pInt) :: & + phase, & + instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_vacancy_strain_instance(phase) + + ChemPot = -kinematics_vacancy_strain_coeff(instance)* & + sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & + math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) + dChemPot_dCv = 0.0_pReal + +end subroutine kinematics_vacancy_strain_ChemPotAndItsTangent + +end module kinematics_vacancy_strain diff --git a/code/plastic/CMakeLists.txt b/code/plastic/CMakeLists.txt new file mode 100644 index 000000000..6c65481c3 --- /dev/null +++ b/code/plastic/CMakeLists.txt @@ -0,0 +1,16 @@ +# group sources +set (PLASTIC "plastic_dislotwin" + "plastic_disloUCLA" + "plastic_isotropic" + "plastic_j2" + "plastic_phenopowerlaw" + "plastic_titanmod" + "plastic_nonlocal" + "plastic_none" + "plastic_phenoplus" + ) + +# compile module +foreach (p ${PLASTIC}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) diff --git a/code/plastic/plastic_disloUCLA.f90 b/code/plastic/plastic_disloUCLA.f90 new file mode 100644 index 000000000..d95a5e6a4 --- /dev/null +++ b/code/plastic/plastic_disloUCLA.f90 @@ -0,0 +1,2116 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author David Cereceda, Lawrence Livermore National Laboratory +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incoprorating dislocation and twinning physics +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module plastic_disloUCLA + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_disloUCLA_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_disloUCLA_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_disloUCLA_output !< name of each post result output + + real(pReal), parameter, private :: & + kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_disloUCLA_Noutput !< number of outputs per instance of this plasticity + + integer(pInt), dimension(:), allocatable, private :: & + plastic_disloUCLA_totalNslip, & !< total number of active slip systems for each instance + plastic_disloUCLA_totalNtwin !< total number of active twin systems for each instance + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_disloUCLA_Nslip, & !< number of active slip systems for each family and instance + plastic_disloUCLA_Ntwin !< number of active twin systems for each family and instance + + real(pReal), dimension(:), allocatable, private :: & + plastic_disloUCLA_CAtomicVolume, & !< atomic volume in Bugers vector unit + plastic_disloUCLA_D0, & !< prefactor for self-diffusion coefficient + plastic_disloUCLA_Qsd, & !< activation energy for dislocation climb + plastic_disloUCLA_GrainSize, & !< grain size + plastic_disloUCLA_MaxTwinFraction, & !< maximum allowed total twin volume fraction + plastic_disloUCLA_CEdgeDipMinDistance, & !< + plastic_disloUCLA_Cmfptwin, & !< + plastic_disloUCLA_Cthresholdtwin, & !< + plastic_disloUCLA_SolidSolutionStrength, & !< Strength due to elements in solid solution + plastic_disloUCLA_L0, & !< Length of twin nuclei in Burgers vectors + plastic_disloUCLA_xc, & !< critical distance for formation of twin nucleus + plastic_disloUCLA_VcrossSlip, & !< cross slip volume + plastic_disloUCLA_SFE_0K, & !< stacking fault energy at zero K + plastic_disloUCLA_dSFE_dT, & !< temperature dependance of stacking fault energy + plastic_disloUCLA_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful + plastic_disloUCLA_aTolRho, & !< absolute tolerance for integration of dislocation density + plastic_disloUCLA_aTolTwinFrac !< absolute tolerance for integration of twin volume fraction + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_disloUCLA_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_disloUCLA_Ctwin3333 !< twin elasticity matrix for each instance + real(pReal), dimension(:,:), allocatable, private :: & + plastic_disloUCLA_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance + plastic_disloUCLA_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance + plastic_disloUCLA_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance + plastic_disloUCLA_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance + plastic_disloUCLA_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance + plastic_disloUCLA_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance + plastic_disloUCLA_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance + plastic_disloUCLA_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance + plastic_disloUCLA_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance + plastic_disloUCLA_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance + plastic_disloUCLA_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance + plastic_disloUCLA_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance + plastic_disloUCLA_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance + plastic_disloUCLA_tau_r, & !< stress to bring partial close together for each twin system and instance + plastic_disloUCLA_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance + plastic_disloUCLA_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance + plastic_disloUCLA_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_disloUCLA_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_disloUCLA_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance + plastic_disloUCLA_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance + plastic_disloUCLA_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_disloUCLA_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance + plastic_disloUCLA_pPerSlipFamily, & !< p-exponent in glide velocity + plastic_disloUCLA_qPerSlipFamily, & !< q-exponent in glide velocity + !* mobility law parameters + plastic_disloUCLA_kinkheight, & !< height of the kink pair + plastic_disloUCLA_omega, & !< attempt frequency for kink pair nucleation + plastic_disloUCLA_kinkwidth, & !< width of the kink pair + plastic_disloUCLA_dislolength, & !< dislocation length (lamda) + plastic_disloUCLA_friction, & !< friction coeff. B (kMC) + !* + plastic_disloUCLA_rPerTwinFamily, & !< r-exponent in twin nucleation rate + plastic_disloUCLA_nonSchmidCoeff !< non-Schmid coefficients (bcc) + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_disloUCLA_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance + plastic_disloUCLA_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance + plastic_disloUCLA_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance + plastic_disloUCLA_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance + plastic_disloUCLA_forestProjectionEdge !< matrix of forest projections of edge dislocations for each instance + + enum, bind(c) + enumerator :: undefined_ID, & + edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID, & + twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_disloUCLA_outputID !< ID of each post result output + + type, private :: tDisloUCLAState + real(pReal), pointer, dimension(:,:) :: & + rhoEdge, & + rhoEdgeDip, & + accshear_slip, & + twinFraction, & + accshear_twin, & + invLambdaSlip, & + invLambdaSlipTwin, & + invLambdaTwin, & + mfp_slip, & + mfp_twin, & + threshold_stress_slip, & + threshold_stress_twin, & + twinVolume + end type + type(tDisloUCLAState ), allocatable, dimension(:), private :: & + state, & + state0, & + dotState + + public :: & + plastic_disloUCLA_init, & + plastic_disloUCLA_homogenizedC, & + plastic_disloUCLA_microstructure, & + plastic_disloUCLA_LpAndItsTangent, & + plastic_disloUCLA_dotState, & + plastic_disloUCLA_postResults + private :: & + plastic_disloUCLA_stateInit, & + plastic_disloUCLA_aTolState + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333, & + math_mul3x3 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_DISLOUCLA_label, & + PLASTICITY_DISLOUCLA_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,& + f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & + offset_slip, index_myFamily, index_otherFamily, & + startIndex, endIndex + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOUCLA_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOUCLA_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_disloUCLA_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(plastic_disloUCLA_output(maxval(phase_Noutput),maxNinstance)) + plastic_disloUCLA_output = '' + allocate(plastic_disloUCLA_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_disloUCLA_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_CAtomicVolume(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_D0(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Qsd(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_GrainSize(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_MaxTwinFraction(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Cmfptwin(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Cthresholdtwin(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_SolidSolutionStrength(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_L0(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_xc(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_VcrossSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_aTolRho(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_aTolTwinFrac(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_SFE_0K(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_dSFE_dT(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default + allocate(plastic_disloUCLA_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_kinkheight(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_omega(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_kinkwidth(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_dislolength(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_friction(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_disloUCLA_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_disloUCLA_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), source=0.0_pReal) + + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + if(allocated(tempPerTwin)) deallocate(tempPerTwin) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + allocate(tempPerTwin(Nchunks_TwinFamilies)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('edge_density') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_density_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('dipole_density') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = dipole_density_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_slip','shearrate_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('edge_dipole_distance') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_dipole_distance_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stress_exponent') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = stress_exponent_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('twin_fraction') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = twin_fraction_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_twin','shearrate_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip system families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + plastic_disloUCLA_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip',& + 'kink_height','omega','kink_width','dislolength','friction_coeff') + do j = 1_pInt, Nchunks_SlipFamilies + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('rhoedge0') + plastic_disloUCLA_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('rhoedgedip0') + plastic_disloUCLA_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('slipburgers') + plastic_disloUCLA_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('qedge') + plastic_disloUCLA_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('v0') + plastic_disloUCLA_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('clambdaslip') + plastic_disloUCLA_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau_peierls') + if (lattice_structure(phase) /= LATTICE_bcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOUCLA_label//')') + plastic_disloUCLA_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('p_slip') + plastic_disloUCLA_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('q_slip') + plastic_disloUCLA_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('kink_height') + plastic_disloUCLA_kinkheight(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('omega') + plastic_disloUCLA_omega(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('kink_width') + plastic_disloUCLA_kinkwidth(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('dislolength') + plastic_disloUCLA_dislolength(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('friction_coeff') + plastic_disloUCLA_friction(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on slip number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_disloUCLA_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ndot0','twinsize','twinburgers','r_twin') + do j = 1_pInt, Nchunks_TwinFamilies + tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('ndot0') + if (lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOUCLA_label//')') + plastic_disloUCLA_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinsize') + plastic_disloUCLA_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinburgers') + plastic_disloUCLA_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('r_twin') + plastic_disloUCLA_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip','interactionslipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_disloUCLA_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin','interactionsliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_disloUCLA_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip','interactiontwinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_disloUCLA_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin','interactiontwintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_disloUCLA_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt,Nchunks_nonSchmid + plastic_disloUCLA_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin systems + case ('grainsize') + plastic_disloUCLA_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('maxtwinfraction') + plastic_disloUCLA_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('d0') + plastic_disloUCLA_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('qsd') + plastic_disloUCLA_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_rho') + plastic_disloUCLA_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_disloUCLA_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cmfptwin') + plastic_disloUCLA_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cthresholdtwin') + plastic_disloUCLA_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('solidsolutionstrength') + plastic_disloUCLA_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('l0') + plastic_disloUCLA_L0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('xc') + plastic_disloUCLA_xc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('vcrossslip') + plastic_disloUCLA_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cedgedipmindistance') + plastic_disloUCLA_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('catomicvolume') + plastic_disloUCLA_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('sfe_0k') + plastic_disloUCLA_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dsfe_dt') + plastic_disloUCLA_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dipoleformationfactor') + plastic_disloUCLA_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then + instance = phase_plasticityInstance(phase) + if (sum(plastic_disloUCLA_Nslip(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOUCLA_label//')') + if (sum(plastic_disloUCLA_Ntwin(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOUCLA_label//')') + do f = 1_pInt,lattice_maxNslipFamily + if (plastic_disloUCLA_Nslip(f,instance) > 0_pInt) then + if (plastic_disloUCLA_rhoEdge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_rhoEdgeDip0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_v0PerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOUCLA_label//')') + endif + enddo + do f = 1_pInt,lattice_maxNtwinFamily + if (plastic_disloUCLA_Ntwin(f,instance) > 0_pInt) then + if (plastic_disloUCLA_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='ndot0 ('//PLASTICITY_DISLOUCLA_label//')') + endif + enddo + if (plastic_disloUCLA_CAtomicVolume(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_D0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_Qsd(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOUCLA_label//')') + if (sum(plastic_disloUCLA_Ntwin(:,instance)) > 0_pInt) then + if (abs(plastic_disloUCLA_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & + abs(plastic_disloUCLA_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & + lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_aTolTwinFrac(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOUCLA_label//')') + endif + if (abs(plastic_disloUCLA_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & + plastic_disloUCLA_dipoleFormationFactor(instance) /= 1.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOUCLA_label//')') + +!-------------------------------------------------------------------------------------------------- +! Determine total number of active slip or twin systems + plastic_disloUCLA_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_disloUCLA_Nslip(:,instance)) + plastic_disloUCLA_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_disloUCLA_Ntwin(:,instance)) + plastic_disloUCLA_totalNslip(instance) = sum(plastic_disloUCLA_Nslip(:,instance)) + plastic_disloUCLA_totalNtwin(instance) = sum(plastic_disloUCLA_Ntwin(:,instance)) + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + maxTotalNslip = maxval(plastic_disloUCLA_totalNslip) + maxTotalNtwin = maxval(plastic_disloUCLA_totalNtwin) + + allocate(plastic_disloUCLA_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_tau_r(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) + + allocate(plastic_disloUCLA_interactionMatrix_SlipSlip(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from slip activity + maxval(plastic_disloUCLA_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_interactionMatrix_SlipTwin(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from twin activity + maxval(plastic_disloUCLA_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_interactionMatrix_TwinSlip(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_disloUCLA_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_interactionMatrix_TwinTwin(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_disloUCLA_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & + source=0.0_pReal) + allocate(plastic_disloUCLA_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) + + allocate(state(maxNinstance)) + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + myPhase2: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then + NofMyPhase=count(material_phase==phase) + instance = phase_plasticityInstance(phase) + + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputs: do o = 1_pInt,plastic_disloUCLA_Noutput(instance) + select case(plastic_disloUCLA_outputID(o,instance)) + case(edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID & + ) + mySize = ns + case(twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID & + ) + mySize = nt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + plastic_disloUCLA_sizePostResult(o,instance) = mySize + plastic_disloUCLA_sizePostResults(instance) = plastic_disloUCLA_sizePostResults(instance) + mySize + endif + enddo outputs + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + + sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & + + int(size(['twinFraction','accsheartwin']),pInt) * nt + sizeDeltaState = 0_pInt + sizeState = sizeDotState & + + int(size(['invLambdaSlip ','invLambdaSlipTwin ',& + 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & + + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& + 'twinVolume ']),pInt) * nt + + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_disloUCLA_sizePostResults(instance) + plasticState(phase)%nSlip = plastic_disloucla_totalNslip(instance) + plasticState(phase)%nTwin = plastic_disloucla_totalNtwin(instance) + plasticState(phase)%nTrans= 0_pInt + allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + offset_slip = 2_pInt*plasticState(phase)%nSlip + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) + !* Process slip related parameters ------------------------------------------------ + + mySlipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + mySlipSystems: do j = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + + !* Burgers vector, + ! dislocation velocity prefactor, + ! mean free path prefactor, + ! and minimum dipole distance + + plastic_disloUCLA_burgersPerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_burgersPerSlipFamily(f,instance) + + plastic_disloUCLA_QedgePerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_QedgePerSlipFamily(f,instance) + + plastic_disloUCLA_v0PerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_v0PerSlipFamily(f,instance) + + plastic_disloUCLA_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_CLambdaSlipPerSlipFamily(f,instance) + + !* Calculation of forest projections for edge dislocations + !* Interaction matrices + + otherSlipFamilies: do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) + otherSlipSystems: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) + plastic_disloUCLA_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & + abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & + lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) + plastic_disloUCLA_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo otherSlipSystems; enddo otherSlipFamilies + + otherTwinFamilies: do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) + otherTwinSystems: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) + plastic_disloUCLA_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo otherTwinSystems; enddo otherTwinFamilies + + enddo mySlipSystems + enddo mySlipFamilies + + !* Process twin related parameters ------------------------------------------------ + + myTwinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(plastic_disloUCLA_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list + myTwinSystems: do j = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) + + !* Burgers vector, + ! nucleation rate prefactor, + ! and twin size + + plastic_disloUCLA_burgersPerTwinSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_burgersPerTwinFamily(f,instance) + + plastic_disloUCLA_Ndot0PerTwinSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) + + plastic_disloUCLA_twinsizePerTwinSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_twinsizePerTwinFamily(f,instance) + + !* Rotate twin elasticity matrices + index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list + do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt + do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt + plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & + plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & + lattice_C3333(p,q,r,s,instance) * & + lattice_Qtwin(l,p,index_otherFamily+j,phase) * & + lattice_Qtwin(m,q,index_otherFamily+j,phase) * & + lattice_Qtwin(n,r,index_otherFamily+j,phase) * & + lattice_Qtwin(o,s,index_otherFamily+j,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo; enddo + plastic_disloUCLA_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & + math_Mandel3333to66(plastic_disloUCLA_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) + + !* Interaction matrices + otherSlipFamilies2: do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) + otherSlipSystems2: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) + plastic_disloUCLA_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo otherSlipSystems2; enddo otherSlipFamilies2 + + otherTwinFamilies2: do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) + otherTwinSystems2: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) + plastic_disloUCLA_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo otherTwinSystems2; enddo otherTwinFamilies2 + + enddo myTwinSystems + enddo myTwinFamilies + + startIndex=1_pInt + endIndex=ns + state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+ns + state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+ns + state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+nt + state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+nt + state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+ns + state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) + + call plastic_disloUCLA_stateInit(phase,instance) + call plastic_disloUCLA_aTolState(phase,instance) + endif myPhase2 + + enddo initializeInstances + +end subroutine plastic_disloUCLA_init + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_stateInit(ph,instance) + use math, only: & + pi + use lattice, only: & + lattice_maxNslipFamily, & + lattice_mu + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + real(pReal), dimension(plasticState(ph)%sizeState) :: tempState + + integer(pInt) :: i,j,f,ns,nt, index_myFamily + real(pReal), dimension(plastic_disloUCLA_totalNslip(instance)) :: & + rhoEdge0, & + rhoEdgeDip0, & + invLambdaSlip0, & + MeanFreePathSlip0, & + tauSlipThreshold0 + real(pReal), dimension(plastic_disloUCLA_totalNtwin(instance)) :: & + MeanFreePathTwin0,TwinVolume0 + tempState = 0.0_pReal + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables + do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + rhoEdge0(index_myFamily+1_pInt: & + index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & + plastic_disloUCLA_rhoEdge0(f,instance) + rhoEdgeDip0(index_myFamily+1_pInt: & + index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & + plastic_disloUCLA_rhoEdgeDip0(f,instance) + enddo + + tempState(1_pInt:ns) = rhoEdge0 + tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent slip microstructural variables + forall (i = 1_pInt:ns) & + invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_forestProjectionEdge(1:ns,i,instance)))/ & + plastic_disloUCLA_CLambdaSlipPerSlipSystem(i,instance) + tempState(3_pInt*ns+2_pInt*nt+1:4_pInt*ns+2_pInt*nt) = invLambdaSlip0 + + forall (i = 1_pInt:ns) & + MeanFreePathSlip0(i) = & + plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_disloUCLA_GrainSize(instance)) + tempState(5_pInt*ns+3_pInt*nt+1:6_pInt*ns+3_pInt*nt) = MeanFreePathSlip0 + + forall (i = 1_pInt:ns) & + tauSlipThreshold0(i) = & + lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(i,instance) * & + sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_interactionMatrix_SlipSlip(i,1:ns,instance))) + + tempState(6_pInt*ns+4_pInt*nt+1:7_pInt*ns+4_pInt*nt) = tauSlipThreshold0 + + + +!-------------------------------------------------------------------------------------------------- +! initialize dependent twin microstructural variables + forall (j = 1_pInt:nt) & + MeanFreePathTwin0(j) = plastic_disloUCLA_GrainSize(instance) + tempState(6_pInt*ns+3_pInt*nt+1_pInt:6_pInt*ns+4_pInt*nt) = MeanFreePathTwin0 + + forall (j = 1_pInt:nt) & + TwinVolume0(j) = & + (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) + tempState(7_pInt*ns+5_pInt*nt+1_pInt:7_pInt*ns+6_pInt*nt) = TwinVolume0 + +plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) + +end subroutine plastic_disloUCLA_stateInit + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + ph, & + instance ! number specifying the current instance of the plasticity + + ! Tolerance state for dislocation densities + plasticState(ph)%aTolState(1_pInt:2_pInt*plastic_disloUCLA_totalNslip(instance)) = & + plastic_disloUCLA_aTolRho(instance) + + ! Tolerance state for accumulated shear due to slip + plasticState(ph)%aTolState(2_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & + 3_pInt*plastic_disloUCLA_totalNslip(instance))=1e6_pReal + + + ! Tolerance state for twin volume fraction + plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & + 3_pInt*plastic_disloUCLA_totalNslip(instance)+& + plastic_disloUCLA_totalNtwin(instance)) = & + plastic_disloUCLA_aTolTwinFrac(instance) + +! Tolerance state for accumulated shear due to twin + plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+ & + plastic_disloUCLA_totalNtwin(instance)+1_pInt: & + 3_pInt*plastic_disloUCLA_totalNslip(instance)+ & + 2_pInt*plastic_disloUCLA_totalNtwin(instance)) = 1e6_pReal + +end subroutine plastic_disloUCLA_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenized elasticity matrix +!-------------------------------------------------------------------------------------------------- +function plastic_disloUCLA_homogenizedC(ipc,ip,el) + use material, only: & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_C66 + + implicit none + real(pReal), dimension(6,6) :: & + plastic_disloUCLA_homogenizedC + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,i, & + ph, & + of + real(pReal) :: sumf + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + !* Homogenized elasticity matrix + plastic_disloUCLA_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) + do i=1_pInt,nt + plastic_disloUCLA_homogenizedC = plastic_disloUCLA_homogenizedC & + + state(instance)%twinFraction(i,of)*plastic_disloUCLA_Ctwin66(1:6,1:6,i,instance) + enddo + +end function plastic_disloUCLA_homogenizedC + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_microstructure(temperature,ipc,ip,el) + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + phaseAt, phasememberAt + use lattice, only: & + lattice_mu, & + lattice_nu + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + temperature !< temperature at IP + + integer(pInt) :: & + instance, & + ns,nt,s,t, & + ph, & + of + real(pReal) :: & + sumf,sfe,x0 + real(pReal), dimension(plastic_disloUCLA_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Stacking fault energy + sfe = plastic_disloUCLA_SFE_0K(instance) + & + plastic_disloUCLA_dSFE_dT(instance) * Temperature + + !* rescaled twin volume fraction for topology + forall (t = 1_pInt:nt) & + fOverStacksize(t) = & + state(instance)%twinFraction(t,of)/plastic_disloUCLA_twinsizePerTwinSystem(t,instance) + + !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation + forall (s = 1_pInt:ns) & + state(instance)%invLambdaSlip(s,of) = & + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_disloUCLA_forestProjectionEdge(1:ns,s,instance)))/ & + plastic_disloUCLA_CLambdaSlipPerSlipSystem(s,instance) + !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation + !$OMP CRITICAL (evilmatmul) + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal + if (nt > 0_pInt .and. ns > 0_pInt) & + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & + matmul(plastic_disloUCLA_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin + !$OMP CRITICAL (evilmatmul) + if (nt > 0_pInt) & + state(instance)%invLambdaTwin(1_pInt:nt,of) = & + matmul(plastic_disloUCLA_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* mean free path between 2 obstacles seen by a moving dislocation + do s = 1_pInt,ns + if (nt > 0_pInt) then + state(instance)%mfp_slip(s,of) = & + plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+plastic_disloUCLA_GrainSize(instance)*& + (state(instance)%invLambdaSlip(s,of)+state(instance)%invLambdaSlipTwin(s,of))) + else + state(instance)%mfp_slip(s,of) = & + plastic_disloUCLA_GrainSize(instance)/& + (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) + endif + enddo + + !* mean free path between 2 obstacles seen by a growing twin + forall (t = 1_pInt:nt) & + state(instance)%mfp_twin(t,of) = & + (plastic_disloUCLA_Cmfptwin(instance)*plastic_disloUCLA_GrainSize(instance))/& + (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*state(instance)%invLambdaTwin(t,of)) + + !* threshold stress for dislocation motion + forall (s = 1_pInt:ns) & + state(instance)%threshold_stress_slip(s,of) = & + lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(s,instance)*& + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_disloUCLA_interactionMatrix_SlipSlip(s,1:ns,instance))) + + !* threshold stress for growing twin + forall (t = 1_pInt:nt) & + state(instance)%threshold_stress_twin(t,of) = & + plastic_disloUCLA_Cthresholdtwin(instance)*& + (sfe/(3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance))+& + 3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& + (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(t,instance))) + + !* final twin volume after growth + forall (t = 1_pInt:nt) & + state(instance)%twinVolume(t,of) = & + (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(t,instance)*state(instance)%mfp_twin(t,of)**(2.0_pReal) + + !* equilibrium seperation of partial dislocations + do t = 1_pInt,nt + x0 = lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& + (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) + plastic_disloUCLA_tau_r(t,instance)= & + lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& + (1/(x0+plastic_disloUCLA_xc(instance))+cos(pi/3.0_pReal)/x0) !!! used where?? + enddo + +end subroutine plastic_disloUCLA_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + math_Plain3333to99, & + math_Mandel6to33, & + math_Mandel33to6, & + math_spectralDecompositionSym33, & + math_symmetric33, & + math_mul33x3 + use material, only: & + material_phase, & + phase_plasticityInstance, & + !plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily,& + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid, & + lattice_shearTwin, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + integer(pInt), intent(in) :: ipc,ip,el + real(pReal), intent(in) :: Temperature + real(pReal), dimension(6), intent(in) :: Tstar_v + real(pReal), dimension(3,3), intent(out) :: Lp + real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 + + integer(pInt) :: instance,ph,of,ns,nt,f,i,j,k,l,m,n,index_myFamily,s1,s2 + real(pReal) :: sumf,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0, & + tau_slip_pos,tau_slip_neg,vel_slip,dvel_slip,& + dgdot_dtauslip_pos,dgdot_dtauslip_neg,dgdot_dtautwin,tau_twin,gdot_twin,stressRatio + real(pReal), dimension(3,3,2) :: & + nonSchmid_tensor + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar3333 + real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip_pos,gdot_slip_neg + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Dislocation glide part + gdot_slip_pos = 0.0_pReal + gdot_slip_neg = 0.0_pReal + dgdot_dtauslip_pos = 0.0_pReal + dgdot_dtauslip_neg = 0.0_pReal + + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j+1_pInt + !* Boltzmann ratio + BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& + plastic_disloUCLA_v0PerSlipSystem(j,instance) + !* Resolved shear stress on slip system + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k, index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) + enddo nonSchmidSystems + + significantPostitiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratio + stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_pos & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_pos(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_pos) + + !* Derivatives of shear rates + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_pos & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_pos & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + dgdot_dtauslip_pos = DotGamma0 * dvel_slip + + endif significantPostitiveStress + significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratio + stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_neg & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_neg(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_neg) + + !* Derivatives of shear rates + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_neg & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_neg & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + + dgdot_dtauslip_neg = DotGamma0 * dvel_slip + + endif significantNegativeStress + !* Plastic velocity gradient for dislocation glide + Lp = Lp + (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + (dgdot_dtauslip_pos*nonSchmid_tensor(m,n,1)+& + dgdot_dtauslip_neg*nonSchmid_tensor(m,n,2))*0.5_pReal*& + lattice_Sslip(k,l,1,index_myFamily+i,ph) + enddo slipSystems + enddo slipFamilies + +!-------------------------------------------------------------------------------------------------- +! correct Lp and dLp_dTstar3333 for twinned fraction + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + Lp = Lp * (1.0_pReal - sumf) + dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf) + +!-------------------------------------------------------------------------------------------------- +! Mechanical twinning part + gdot_twin = 0.0_pReal + dgdot_dtautwin = 0.0_pReal + j = 0_pInt + twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) + j = j+1_pInt + !* Resolved shear stress on twin system + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_twin > tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then + Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive gdot_slip_pos (= gdot_slip_neg) + abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) + else + Ndot0=0.0_pReal + end if + case default + Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) + end select + gdot_twin = & + (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) + dgdot_dtautwin = ((gdot_twin*plastic_disloUCLA_rPerTwinFamily(f,instance))/tau_twin)*StressRatio_r + endif + + !* Plastic velocity gradient for mechanical twinning + Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin*& + lattice_Stwin(k,l,index_myFamily+i,ph)*& + lattice_Stwin(m,n,index_myFamily+i,ph) + enddo twinSystems + enddo twinFamilies + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + +end subroutine plastic_disloUCLA_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_dotState(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid, & + lattice_sheartwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,f,i,j,k,index_myFamily,s1,s2, & + ph, & + of + real(pReal) :: & + sumf, & + stressRatio_p,& + BoltzmannRatio,& + DotGamma0,& + stressRatio, & + EdgeDipMinDistance,& + AtomicVolume,& + VacancyDiffusion,& + StressRatio_r,& + Ndot0,& + tau_slip_pos,& + tau_slip_neg,& + DotRhoMultiplication,& + EdgeDipDistance, & + DotRhoEdgeDipAnnihilation, & + DotRhoEdgeEdgeAnnihilation, & + ClimbVelocity, & + DotRhoEdgeDipClimb, & + DotRhoDipFormation, & + tau_twin, & + vel_slip, & + gdot_slip + real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip_pos, gdot_slip_neg + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + plasticState(ph)%dotState(:,of) = 0.0_pReal + + !* Dislocation density evolution + gdot_slip_pos = 0.0_pReal + gdot_slip_neg = 0.0_pReal + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j+1_pInt + !* Boltzmann ratio + BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& + plastic_disloUCLA_v0PerSlipSystem(j,instance) + !* Resolved shear stress on slip system + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + + significantPositiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_pos & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_pos(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_pos) + endif significantPositiveStress + significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_neg & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_neg(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_neg) + endif significantNegativeStress + gdot_slip = (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal + !* Multiplication + DotRhoMultiplication = abs(gdot_slip)/& + (plastic_disloUCLA_burgersPerSlipSystem(j,instance)* & + state(instance)%mfp_slip(j,of)) + + !* Dipole formation + EdgeDipMinDistance = & + plastic_disloUCLA_CEdgeDipMinDistance(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance) + if (abs(tau_slip_pos) <= tiny(0.0_pReal)) then + DotRhoDipFormation = 0.0_pReal + else + EdgeDipDistance = & + (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(tau_slip_pos)) + if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) + if (EdgeDipDistance tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then + Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) + abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) + else + Ndot0=0.0_pReal + end if + case default + Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) + end select + + dotState(instance)%twinFraction(j, of) = & + (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*& + state(instance)%twinVolume(j, of)*Ndot0*exp(-StressRatio_r) + !* Dotstate for accumulated shear due to twin + dotState(instance)%accshear_twin(j,of) = dotState(ph)%twinFraction(j,of) * & + lattice_sheartwin(index_myfamily+i,ph) + endif + enddo twinSystems + enddo twinFamilies + +end subroutine plastic_disloUCLA_dotState + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_disloUCLA_postResults(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance,& + !plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid, & + lattice_shearTwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(plastic_disloUCLA_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_disloUCLA_postResults + + integer(pInt) :: & + instance,& + ns,nt,& + f,o,i,c,j,k,index_myFamily,& + s1,s2, & + ph, & + of + real(pReal) :: sumf,tau_twin,StressRatio_p,StressRatio_pminus1,& + BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0,stressRatio + real(pReal) :: dvel_slip, vel_slip + real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip_pos,dgdot_dtauslip_pos,tau_slip_pos,gdot_slip_neg,dgdot_dtauslip_neg,tau_slip_neg + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(ph)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Required output + c = 0_pInt + plastic_disloUCLA_postResults = 0.0_pReal + + do o = 1_pInt,plastic_disloUCLA_Noutput(instance) + select case(plastic_disloUCLA_outputID(o,instance)) + + case (edge_density_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) + c = c + ns + case (dipole_density_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) + c = c + ns + case (shear_rate_slip_ID,shear_rate_twin_ID,stress_exponent_ID) + gdot_slip_pos = 0.0_pReal + gdot_slip_neg = 0.0_pReal + dgdot_dtauslip_pos = 0.0_pReal + dgdot_dtauslip_neg = 0.0_pReal + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j + 1_pInt + !* Boltzmann ratio + BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& + plastic_disloUCLA_v0PerSlipSystem(j,instance) + !* Resolved shear stress on slip system + tau_slip_pos(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + tau_slip_neg(j) = tau_slip_pos(j) + + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + + significantPositiveTau: if((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then + !* Stress ratio + stressRatio = ((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_pos(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_pos(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_pos(j)) + !* Derivatives of shear rates + + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_pos(j) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_pos(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + + dgdot_dtauslip_pos(j) = DotGamma0 * dvel_slip + + endif significantPositiveTau + significantNegativeTau: if((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_neg(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_neg(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_neg(j)) + !* Derivatives of shear rates + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_neg(j) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_neg(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + + + dgdot_dtauslip_neg(j) = DotGamma0 * dvel_slip + + endif significantNegativeTau + enddo slipSystems + enddo slipFamilies + + if (plastic_disloUCLA_outputID(o,instance) == shear_rate_slip_ID) then + plastic_disloUCLA_postResults(c+1:c+ns) = (gdot_slip_pos + gdot_slip_neg)*0.5_pReal + c = c + ns + elseif (plastic_disloUCLA_outputID(o,instance) == shear_rate_twin_ID) then + if (nt > 0_pInt) then + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1,plastic_disloUCLA_Ntwin(f,instance) + j = j + 1_pInt + + !* Resolved shear stress on twin system + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + !* Stress ratios + StressRatio_r = (state(instance)%threshold_stress_twin(j, of)/ & + tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) + + !* Shear rates due to twin + if ( tau_twin > 0.0_pReal ) then + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then + Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) + abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_disloUCLA_L0(instance)*& + plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) + else + Ndot0=0.0_pReal + end if + + case default + Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) + end select + plastic_disloUCLA_postResults(c+j) = & + (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) + endif + enddo twinSystems1 + enddo twinFamilies1 + endif + c = c + nt + elseif(plastic_disloUCLA_outputID(o,instance) == stress_exponent_ID) then + do j = 1_pInt, ns + if (abs(gdot_slip_pos(j)+gdot_slip_neg(j))<=tiny(0.0_pReal)) then + plastic_disloUCLA_postResults(c+j) = 0.0_pReal + else + plastic_disloUCLA_postResults(c+j) = (tau_slip_pos(j)+tau_slip_neg(j))/& + (gdot_slip_pos(j)+gdot_slip_neg(j))*& + (dgdot_dtauslip_pos(j)+dgdot_dtauslip_neg(j))* 0.5_pReal + endif + enddo + c = c + ns + endif + + case (accumulated_shear_slip_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & + state(instance)%accshear_slip(1_pInt:ns, of) + c = c + ns + case (mfp_slip_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) =& + state(instance)%mfp_slip(1_pInt:ns, of) + c = c + ns + case (resolved_stress_slip_ID) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j + 1_pInt + plastic_disloUCLA_postResults(c+j) =& + dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + enddo slipSystems1; enddo slipFamilies1 + c = c + ns + case (threshold_stress_slip_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & + state(instance)%threshold_stress_slip(1_pInt:ns,of) + c = c + ns + case (edge_dipole_distance_ID) + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems2: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j + 1_pInt + plastic_disloUCLA_postResults(c+j) = & + (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) + plastic_disloUCLA_postResults(c+j)=min(plastic_disloUCLA_postResults(c+j),& + state(instance)%mfp_slip(j,of)) + enddo slipSystems2; enddo slipFamilies2 + c = c + ns + case (twin_fraction_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt, of) + c = c + nt + + case (accumulated_shear_twin_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt, of) + c = c + nt + + case (mfp_twin_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt, of) + c = c + nt + + case (resolved_stress_twin_ID) + if (nt > 0_pInt) then + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) + j = j + 1_pInt + plastic_disloUCLA_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + enddo twinSystems2; enddo twinFamilies2 + endif + c = c + nt + case (threshold_stress_twin_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt, of) + c = c + nt + end select + enddo +end function plastic_disloUCLA_postResults + +end module plastic_disloUCLA diff --git a/code/plastic/plastic_dislotwin.f90 b/code/plastic/plastic_dislotwin.f90 new file mode 100644 index 000000000..532312bfd --- /dev/null +++ b/code/plastic/plastic_dislotwin.f90 @@ -0,0 +1,2542 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incoprorating dislocation and twinning physics +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module plastic_dislotwin + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_dislotwin_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_dislotwin_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_dislotwin_output !< name of each post result output + + real(pReal), parameter, private :: & + kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_dislotwin_Noutput !< number of outputs per instance of this plasticity + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_dislotwin_totalNslip, & !< total number of active slip systems for each instance + plastic_dislotwin_totalNtwin, & !< total number of active twin systems for each instance + plastic_dislotwin_totalNtrans !< number of active transformation systems + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_dislotwin_Nslip, & !< number of active slip systems for each family and instance + plastic_dislotwin_Ntwin, & !< number of active twin systems for each family and instance + plastic_dislotwin_Ntrans !< number of active transformation systems for each family and instance + + real(pReal), dimension(:), allocatable, private :: & + plastic_dislotwin_CAtomicVolume, & !< atomic volume in Bugers vector unit + plastic_dislotwin_D0, & !< prefactor for self-diffusion coefficient + plastic_dislotwin_Qsd, & !< activation energy for dislocation climb + plastic_dislotwin_GrainSize, & !< grain size + plastic_dislotwin_pShearBand, & !< p-exponent in shearband velocity + plastic_dislotwin_qShearBand, & !< q-exponent in shearband velocity + plastic_dislotwin_MaxTwinFraction, & !< maximum allowed total twin volume fraction + plastic_dislotwin_CEdgeDipMinDistance, & !< + plastic_dislotwin_Cmfptwin, & !< + plastic_dislotwin_Cthresholdtwin, & !< + plastic_dislotwin_SolidSolutionStrength, & !< Strength due to elements in solid solution + plastic_dislotwin_L0_twin, & !< Length of twin nuclei in Burgers vectors + plastic_dislotwin_L0_trans, & !< Length of trans nuclei in Burgers vectors + plastic_dislotwin_xc_twin, & !< critical distance for formation of twin nucleus + plastic_dislotwin_xc_trans, & !< critical distance for formation of trans nucleus + plastic_dislotwin_VcrossSlip, & !< cross slip volume + plastic_dislotwin_sbResistance, & !< value for shearband resistance (might become an internal state variable at some point) + plastic_dislotwin_sbVelocity, & !< value for shearband velocity_0 + plastic_dislotwin_sbQedge, & !< value for shearband systems Qedge + plastic_dislotwin_SFE_0K, & !< stacking fault energy at zero K + plastic_dislotwin_dSFE_dT, & !< temperature dependance of stacking fault energy + plastic_dislotwin_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful + plastic_dislotwin_aTolRho, & !< absolute tolerance for integration of dislocation density + plastic_dislotwin_aTolTwinFrac, & !< absolute tolerance for integration of twin volume fraction + plastic_dislotwin_aTolTransFrac, & !< absolute tolerance for integration of trans volume fraction + plastic_dislotwin_deltaG, & !< Free energy difference between austensite and martensite + plastic_dislotwin_Cmfptrans, & !< + plastic_dislotwin_Cthresholdtrans, & !< + plastic_dislotwin_transStackHeight !< Stack height of hex nucleus + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctwin3333 !< twin elasticity matrix for each instance + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctrans66 !< trans elasticity matrix in Mandel notation for each instance + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctrans3333 !< trans elasticity matrix for each instance + real(pReal), dimension(:,:), allocatable, private :: & + plastic_dislotwin_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance + plastic_dislotwin_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance + plastic_dislotwin_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance + plastic_dislotwin_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance + plastic_dislotwin_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance + plastic_dislotwin_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance + plastic_dislotwin_burgersPerTransFamily, & !< absolute length of burgers vector [m] for each trans family and instance + plastic_dislotwin_burgersPerTransSystem, & !< absolute length of burgers vector [m] for each trans system and instance + plastic_dislotwin_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance + plastic_dislotwin_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance + plastic_dislotwin_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance + plastic_dislotwin_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance + plastic_dislotwin_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance + plastic_dislotwin_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance + plastic_dislotwin_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance + plastic_dislotwin_Ndot0PerTransFamily, & !< trans nucleation rate [1/m³s] for each trans family and instance + plastic_dislotwin_Ndot0PerTransSystem, & !< trans nucleation rate [1/m³s] for each trans system and instance + plastic_dislotwin_tau_r_twin, & !< stress to bring partial close together for each twin system and instance + plastic_dislotwin_tau_r_trans, & !< stress to bring partial close together for each trans system and instance + plastic_dislotwin_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance + plastic_dislotwin_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance + plastic_dislotwin_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_dislotwin_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_dislotwin_lamellarsizePerTransFamily, & !< martensite lamellar thickness [m] for each trans family and instance + plastic_dislotwin_lamellarsizePerTransSystem, & !< martensite lamellar thickness [m] for each trans system and instance + plastic_dislotwin_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance + plastic_dislotwin_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance + plastic_dislotwin_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_dislotwin_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance + plastic_dislotwin_interaction_SlipTrans, & !< coefficients for slip-trans interaction for each interaction type and instance + plastic_dislotwin_interaction_TransSlip, & !< coefficients for trans-slip interaction for each interaction type and instance + plastic_dislotwin_interaction_TransTrans, & !< coefficients for trans-trans interaction for each interaction type and instance + plastic_dislotwin_pPerSlipFamily, & !< p-exponent in glide velocity + plastic_dislotwin_qPerSlipFamily, & !< q-exponent in glide velocity + plastic_dislotwin_rPerTwinFamily, & !< r-exponent in twin nucleation rate + plastic_dislotwin_sPerTransFamily !< s-exponent in trans nucleation rate + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_dislotwin_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance + plastic_dislotwin_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance + plastic_dislotwin_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance + plastic_dislotwin_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance + plastic_dislotwin_interactionMatrix_SlipTrans, & !< interaction matrix of slip systems with trans systems for each instance + plastic_dislotwin_interactionMatrix_TransSlip, & !< interaction matrix of trans systems with slip systems for each instance + plastic_dislotwin_interactionMatrix_TransTrans, & !< interaction matrix of the different trans systems for each instance + plastic_dislotwin_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance + plastic_dislotwin_projectionMatrix_Trans !< matrix for projection of slip system shear on fault band (twin) systems for each instance + + real(pReal), dimension(:,:,:,:,:), allocatable, private :: & + plastic_dislotwin_sbSv + + enum, bind(c) + enumerator :: undefined_ID, & + edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID, & + twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID, & + resolved_stress_shearband_ID, & + shear_rate_shearband_ID, & + sb_eigenvalues_ID, & + sb_eigenvectors_ID, & + stress_trans_fraction_ID, & + strain_trans_fraction_ID, & + trans_fraction_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_dislotwin_outputID !< ID of each post result output + type, private :: tDislotwinState + real(pReal), pointer, dimension(:,:) :: & + rhoEdge, & + rhoEdgeDip, & + accshear_slip, & + twinFraction, & + accshear_twin, & + stressTransFraction, & + strainTransFraction , & + invLambdaSlip, & + invLambdaSlipTwin, & + invLambdaTwin, & + invLambdaSlipTrans, & + invLambdaTrans, & + mfp_slip, & + mfp_twin, & + mfp_trans, & + threshold_stress_slip, & + threshold_stress_twin, & + threshold_stress_trans, & + twinVolume, & + martensiteVolume + end type + type(tDislotwinState), allocatable, dimension(:), private :: & + state, & + state0, & + dotState + + public :: & + plastic_dislotwin_init, & + plastic_dislotwin_homogenizedC, & + plastic_dislotwin_microstructure, & + plastic_dislotwin_LpAndItsTangent, & + plastic_dislotwin_dotState, & + plastic_dislotwin_postResults + private :: & + plastic_dislotwin_stateInit, & + plastic_dislotwin_aTolState + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333, & + math_mul3x3 + use mesh, only: & + mesh_maxNips, & + mesh_NcpElems + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + homogenization_maxNgrains, & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_DISLOTWIN_label, & + PLASTICITY_DISLOTWIN_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,maxTotalNtrans,& + f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt,nr, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipTrans = 0_pInt, Nchunks_TransSlip = 0_pInt, Nchunks_TransTrans = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_TransFamilies = 0_pInt, & + offset_slip, index_myFamily, index_otherFamily, & + startIndex, endIndex + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin, tempPerTrans + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOTWIN_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOTWIN_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_dislotwin_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(plastic_dislotwin_output(maxval(phase_Noutput),maxNinstance)) + plastic_dislotwin_output = '' + allocate(plastic_dislotwin_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_dislotwin_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_totalNtrans(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_CAtomicVolume(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_D0(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Qsd(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_GrainSize(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_pShearBand(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_qShearBand(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_MaxTwinFraction(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cmfptwin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cthresholdtwin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_SolidSolutionStrength(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_L0_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_L0_trans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_xc_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_xc_trans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_VcrossSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_aTolRho(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_aTolTwinFrac(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_aTolTransFrac(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_sbResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_sbVelocity(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_sbQedge(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_SFE_0K(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_dSFE_dT(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default + allocate(plastic_dislotwin_deltaG(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cmfptrans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cthresholdtrans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_transStackHeight(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTransFamily(lattice_maxNtransFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTransFamily(lattice_maxNtransFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_SlipTrans(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TransSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TransTrans(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_sbSv(6,6,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) + allocate(plastic_dislotwin_lamellarsizePerTransFamily(lattice_maxNtransFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_sPerTransFamily(lattice_maxNtransFamily,maxNinstance),source=0.0_pReal) + + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) + Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase)> 0_pInt) + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_SlipTrans = maxval(lattice_interactionSlipTrans(:,:,phase)) + Nchunks_TransSlip = maxval(lattice_interactionTransSlip(:,:,phase)) + Nchunks_TransTrans = maxval(lattice_interactionTransTrans(:,:,phase)) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + if(allocated(tempPerTwin)) deallocate(tempPerTwin) + if(allocated(tempPerTrans)) deallocate(tempPerTrans) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + allocate(tempPerTwin(Nchunks_TwinFamilies)) + allocate(tempPerTrans(Nchunks_TransFamilies)) + endif + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('edge_density') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_density_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('dipole_density') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = dipole_density_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_slip','shearrate_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('edge_dipole_distance') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_dipole_distance_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stress_exponent') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_exponent_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('twin_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = twin_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_twin','shearrate_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_shearband') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_shearband_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_shearband','shearrate_shearband') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_shearband_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('sb_eigenvalues') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvalues_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('sb_eigenvectors') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvectors_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stress_trans_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_trans_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('strain_trans_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = strain_trans_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('trans_fraction','total_trans_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = trans_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip system families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + plastic_dislotwin_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip') + do j = 1_pInt, Nchunks_SlipFamilies + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('rhoedge0') + plastic_dislotwin_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('rhoedgedip0') + plastic_dislotwin_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('slipburgers') + plastic_dislotwin_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('qedge') + plastic_dislotwin_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('v0') + plastic_dislotwin_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('clambdaslip') + plastic_dislotwin_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau_peierls') + if (lattice_structure(phase) /= LATTICE_bcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOTWIN_label//')') + plastic_dislotwin_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('p_slip') + plastic_dislotwin_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('q_slip') + plastic_dislotwin_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on slip number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_dislotwin_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ndot0_twin','twinsize','twinburgers','r_twin') + do j = 1_pInt, Nchunks_TwinFamilies + tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('ndot0_twin') + if (lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') + plastic_dislotwin_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinsize') + plastic_dislotwin_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinburgers') + plastic_dislotwin_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('r_twin') + plastic_dislotwin_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of transformation system families + case ('ntrans') + if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & + call IO_warning(53_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + Nchunks_TransFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TransFamilies + plastic_dislotwin_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ndot0_trans','lamellarsize','transburgers','s_trans') + do j = 1_pInt, Nchunks_TransFamilies + tempPerTrans(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('ndot0_trans') + if (lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') + plastic_dislotwin_Ndot0PerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + case ('lamellarsize') + plastic_dislotwin_lamellarsizePerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + case ('transburgers') + plastic_dislotwin_burgersPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + case ('s_trans') + plastic_dislotwin_sPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip','interactionslipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_dislotwin_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin','interactionsliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_dislotwin_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip','interactiontwinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_dislotwin_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin','interactiontwintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_dislotwin_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptrans','interactionsliptrans') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTrans) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_SlipTrans + plastic_dislotwin_interaction_SlipTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_transslip','interactiontransslip') + if (chunkPos(1) < 1_pInt + Nchunks_TransSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TransSlip + plastic_dislotwin_interaction_TransSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_transtrans','interactiontranstrans') + if (chunkPos(1) < 1_pInt + Nchunks_TransTrans) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TransTrans + plastic_dislotwin_interaction_TransTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin/trans systems + case ('grainsize') + plastic_dislotwin_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('maxtwinfraction') + plastic_dislotwin_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('p_shearband') + plastic_dislotwin_pShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('q_shearband') + plastic_dislotwin_qShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('d0') + plastic_dislotwin_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('qsd') + plastic_dislotwin_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_rho') + plastic_dislotwin_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_dislotwin_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_transfrac') + plastic_dislotwin_aTolTransFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cmfptwin') + plastic_dislotwin_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cthresholdtwin') + plastic_dislotwin_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('solidsolutionstrength') + plastic_dislotwin_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('l0_twin') + plastic_dislotwin_L0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('l0_trans') + plastic_dislotwin_L0_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('xc_twin') + plastic_dislotwin_xc_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('xc_trans') + plastic_dislotwin_xc_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('vcrossslip') + plastic_dislotwin_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cedgedipmindistance') + plastic_dislotwin_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('catomicvolume') + plastic_dislotwin_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('sfe_0k') + plastic_dislotwin_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dsfe_dt') + plastic_dislotwin_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dipoleformationfactor') + plastic_dislotwin_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('shearbandresistance') + plastic_dislotwin_sbResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('shearbandvelocity') + plastic_dislotwin_sbVelocity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('qedgepersbsystem') + plastic_dislotwin_sbQedge(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('deltag') + plastic_dislotwin_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cmfptrans') + plastic_dislotwin_Cmfptrans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cthresholdtrans') + plastic_dislotwin_Cthresholdtrans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('transstackheight') + plastic_dislotwin_transStackHeight(instance) = IO_floatValue(line,chunkPos,2_pInt) + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then + instance = phase_plasticityInstance(phase) + + if (sum(plastic_dislotwin_Nslip(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOTWIN_label//')') + if (sum(plastic_dislotwin_Ntwin(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOTWIN_label//')') + if (sum(plastic_dislotwin_Ntrans(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Ntrans ('//PLASTICITY_DISLOTWIN_label//')') + do f = 1_pInt,lattice_maxNslipFamily + if (plastic_dislotwin_Nslip(f,instance) > 0_pInt) then + if (plastic_dislotwin_rhoEdge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_rhoEdgeDip0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_v0PerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOTWIN_label//')') + endif + enddo + do f = 1_pInt,lattice_maxNtwinFamily + if (plastic_dislotwin_Ntwin(f,instance) > 0_pInt) then + if (plastic_dislotwin_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='ndot0_twin ('//PLASTICITY_DISLOTWIN_label//')') + endif + enddo + if (plastic_dislotwin_CAtomicVolume(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_D0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_Qsd(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOTWIN_label//')') + if (sum(plastic_dislotwin_Ntwin(:,instance)) > 0_pInt) then + if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & + abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & + lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_aTolTwinFrac(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOTWIN_label//')') + endif + if (sum(plastic_dislotwin_Ntrans(:,instance)) > 0_pInt) then + if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & + abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & + lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_aTolTransFrac(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolTransFrac ('//PLASTICITY_DISLOTWIN_label//')') + endif + if (plastic_dislotwin_sbResistance(instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sbResistance ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_sbVelocity(instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sbVelocity ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & + plastic_dislotwin_pShearBand(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='pShearBand ('//PLASTICITY_DISLOTWIN_label//')') + if (abs(plastic_dislotwin_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & + plastic_dislotwin_dipoleFormationFactor(instance) /= 1.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & + plastic_dislotwin_qShearBand(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='qShearBand ('//PLASTICITY_DISLOTWIN_label//')') + +!-------------------------------------------------------------------------------------------------- +! Determine total number of active slip or twin systems + plastic_dislotwin_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_dislotwin_Nslip(:,instance)) + plastic_dislotwin_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_dislotwin_Ntwin(:,instance)) + plastic_dislotwin_Ntrans(:,instance)= min(lattice_NtransSystem(:,phase),plastic_dislotwin_Ntrans(:,instance)) + plastic_dislotwin_totalNslip(instance) = sum(plastic_dislotwin_Nslip(:,instance)) + plastic_dislotwin_totalNtwin(instance) = sum(plastic_dislotwin_Ntwin(:,instance)) + plastic_dislotwin_totalNtrans(instance) = sum(plastic_dislotwin_Ntrans(:,instance)) + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + maxTotalNslip = maxval(plastic_dislotwin_totalNslip) + maxTotalNtwin = maxval(plastic_dislotwin_totalNtwin) + maxTotalNtrans = maxval(plastic_dislotwin_totalNtrans) + + allocate(plastic_dislotwin_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_tau_r_twin(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_tau_r_trans(maxTotalNtrans, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_lamellarsizePerTransSystem(maxTotalNtrans, maxNinstance),source=0.0_pReal) + + allocate(plastic_dislotwin_interactionMatrix_SlipSlip(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from slip activity + maxval(plastic_dislotwin_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_SlipTwin(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from twin activity + maxval(plastic_dislotwin_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TwinSlip(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_dislotwin_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TwinTwin(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_dislotwin_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_SlipTrans(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from trans activity + maxval(plastic_dislotwin_totalNtrans),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TransSlip(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from slip activity + maxval(plastic_dislotwin_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TransTrans(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from trans activity + maxval(plastic_dislotwin_totalNtrans),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_projectionMatrix_Trans(maxTotalNtrans,maxTotalNslip,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ctrans66(6,6,maxTotalNtrans,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ctrans3333(3,3,3,3,maxTotalNtrans,maxNinstance), source=0.0_pReal) + + allocate(state(maxNinstance)) + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + myPhase2: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then + NofMyPhase=count(material_phase==phase) + instance = phase_plasticityInstance(phase) + + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_dislotwin_Noutput(instance) + select case(plastic_dislotwin_outputID(o,instance)) + case(edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID & + ) + mySize = ns + case(twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID & + ) + mySize = nt + case(resolved_stress_shearband_ID, & + shear_rate_shearband_ID & + ) + mySize = 6_pInt + case(sb_eigenvalues_ID) + mySize = 3_pInt + case(sb_eigenvectors_ID) + mySize = 9_pInt + case(stress_trans_fraction_ID, & + strain_trans_fraction_ID, & + trans_fraction_ID & + ) + mySize = nr + end select + + if (mySize > 0_pInt) then ! any meaningful output found + plastic_dislotwin_sizePostResult(o,instance) = mySize + plastic_dislotwin_sizePostResults(instance) = plastic_dislotwin_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + + sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & + + int(size(['twinFraction','accsheartwin']),pInt) * nt & + + int(size(['stressTransFraction','strainTransFraction']),pInt) * nr + sizeDeltaState = 0_pInt + sizeState = sizeDotState & + + int(size(['invLambdaSlip ','invLambdaSlipTwin ','invLambdaSlipTrans',& + 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & + + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& + 'twinVolume ']),pInt) * nt & + + int(size(['invLambdaTrans ','meanFreePathTrans','tauTransThreshold', & + 'martensiteVolume ']),pInt) * nr + + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_dislotwin_sizePostResults(instance) + plasticState(phase)%nSlip = plastic_dislotwin_totalNslip(instance) + plasticState(phase)%nTwin = plastic_dislotwin_totalNtwin(instance) + plasticState(phase)%nTrans= plastic_dislotwin_totalNtrans(instance) + allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + offset_slip = 2_pInt*plasticState(phase)%nslip + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) + + !* Process slip related parameters ------------------------------------------------ + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + slipSystemsLoop: do j = 1_pInt,plastic_dislotwin_Nslip(f,instance) + + !* Burgers vector, + ! dislocation velocity prefactor, + ! mean free path prefactor, + ! and minimum dipole distance + + plastic_dislotwin_burgersPerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_burgersPerSlipFamily(f,instance) + + plastic_dislotwin_QedgePerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_QedgePerSlipFamily(f,instance) + + plastic_dislotwin_v0PerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_v0PerSlipFamily(f,instance) + + plastic_dislotwin_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_CLambdaSlipPerSlipFamily(f,instance) + + !* Calculation of forest projections for edge dislocations + !* Interaction matrices + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_dislotwin_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & + abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & + lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) + plastic_dislotwin_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_dislotwin_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtransFamily + index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) + plastic_dislotwin_interactionMatrix_SlipTrans(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_SlipTrans(lattice_interactionSlipTrans( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo slipSystemsLoop + enddo slipFamiliesLoop + + !* Process twin related parameters ------------------------------------------------ + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(plastic_dislotwin_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list + twinSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntwin(f,instance) + + !* Burgers vector, + ! nucleation rate prefactor, + ! and twin size + + plastic_dislotwin_burgersPerTwinSystem(index_myFamily+j,instance) = & + plastic_dislotwin_burgersPerTwinFamily(f,instance) + + plastic_dislotwin_Ndot0PerTwinSystem(index_myFamily+j,instance) = & + plastic_dislotwin_Ndot0PerTwinFamily(f,instance) + + plastic_dislotwin_twinsizePerTwinSystem(index_myFamily+j,instance) = & + plastic_dislotwin_twinsizePerTwinFamily(f,instance) + + !* Rotate twin elasticity matrices + index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list + do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt + do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt + plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & + plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & + lattice_C3333(p,q,r,s,instance) * & + lattice_Qtwin(l,p,index_otherFamily+j,phase) * & + lattice_Qtwin(m,q,index_otherFamily+j,phase) * & + lattice_Qtwin(n,r,index_otherFamily+j,phase) * & + lattice_Qtwin(o,s,index_otherFamily+j,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo; enddo + plastic_dislotwin_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & + math_Mandel3333to66(plastic_dislotwin_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) + + !* Interaction matrices + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_dislotwin_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_dislotwin_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo twinSystemsLoop + enddo twinFamiliesLoop + + !* Process transformation related parameters ------------------------------------------------ + transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily + index_myFamily = sum(plastic_dislotwin_Ntrans(1:f-1_pInt,instance)) ! index in truncated trans system list + transSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntrans(f,instance) + + !* Burgers vector, + ! nucleation rate prefactor, + ! and martensite size + + plastic_dislotwin_burgersPerTransSystem(index_myFamily+j,instance) = & + plastic_dislotwin_burgersPerTransFamily(f,instance) + + plastic_dislotwin_Ndot0PerTransSystem(index_myFamily+j,instance) = & + plastic_dislotwin_Ndot0PerTransFamily(f,instance) + + plastic_dislotwin_lamellarsizePerTransSystem(index_myFamily+j,instance) = & + plastic_dislotwin_lamellarsizePerTransFamily(f,instance) + + !* Rotate trans elasticity matrices + index_otherFamily = sum(lattice_NtransSystem(1:f-1_pInt,phase)) ! index in full lattice trans list + do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt + do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt + plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) = & + plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) + & + lattice_trans_C3333(p,q,r,s,instance) * & + lattice_Qtrans(l,p,index_otherFamily+j,phase) * & + lattice_Qtrans(m,q,index_otherFamily+j,phase) * & + lattice_Qtrans(n,r,index_otherFamily+j,phase) * & + lattice_Qtrans(o,s,index_otherFamily+j,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo; enddo + plastic_dislotwin_Ctrans66(1:6,1:6,index_myFamily+j,instance) = & + math_Mandel3333to66(plastic_dislotwin_Ctrans3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) + + !* Interaction matrices + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_dislotwin_interactionMatrix_TransSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TransSlip(lattice_interactionTransSlip( & + sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtransFamily + index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) + plastic_dislotwin_interactionMatrix_TransTrans(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TransTrans(lattice_interactionTransTrans( & + sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + !* Projection matrices for shear from slip systems to fault-band (twin) systems for strain-induced martensite nucleation + select case(trans_lattice_structure(phase)) + case (LATTICE_bcc_ID) + do o = 1_pInt,lattice_maxNtransFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (trans) + plastic_dislotwin_projectionMatrix_Trans(index_myFamily+j,index_otherFamily+k,instance) = & + lattice_projectionTrans( sum(lattice_NtransSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, phase) + enddo; enddo + end select + + enddo transSystemsLoop + enddo transFamiliesLoop + + startIndex=1_pInt + endIndex=ns + state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%stressTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%stressTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%stressTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%strainTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%strainTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%strainTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlipTrans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlipTrans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%invLambdaTrans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaTrans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%mfp_trans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_trans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%threshold_stress_trans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_trans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%martensiteVolume=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%martensiteVolume=>plasticState(phase)%state0(startIndex:endIndex,:) + + call plastic_dislotwin_stateInit(phase,instance) + call plastic_dislotwin_aTolState(phase,instance) + endif myPhase2 + + enddo initializeInstances +end subroutine plastic_dislotwin_init + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_stateInit(ph,instance) + use math, only: & + pi + use lattice, only: & + lattice_maxNslipFamily, & + lattice_mu + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + real(pReal), dimension(plasticState(ph)%sizeState) :: tempState + + integer(pInt) :: i,j,f,ns,nt,nr, index_myFamily + real(pReal), dimension(plastic_dislotwin_totalNslip(instance)) :: & + rhoEdge0, & + rhoEdgeDip0, & + invLambdaSlip0, & + MeanFreePathSlip0, & + tauSlipThreshold0 + real(pReal), dimension(plastic_dislotwin_totalNtwin(instance)) :: & + MeanFreePathTwin0,TwinVolume0 + real(pReal), dimension(plastic_dislotwin_totalNtrans(instance)) :: & + MeanFreePathTrans0,MartensiteVolume0 + tempState = 0.0_pReal + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables + do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + rhoEdge0(index_myFamily+1_pInt: & + index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & + plastic_dislotwin_rhoEdge0(f,instance) + rhoEdgeDip0(index_myFamily+1_pInt: & + index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & + plastic_dislotwin_rhoEdgeDip0(f,instance) + enddo + + tempState(1_pInt:ns) = rhoEdge0 + tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent slip microstructural variables + forall (i = 1_pInt:ns) & + invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_forestProjectionEdge(1:ns,i,instance)))/ & + plastic_dislotwin_CLambdaSlipPerSlipSystem(i,instance) + tempState(3_pInt*ns+2_pInt*nt+2_pInt*nr+1:4_pInt*ns+2_pInt*nt+2_pInt*nr) = invLambdaSlip0 + + forall (i = 1_pInt:ns) & + MeanFreePathSlip0(i) = & + plastic_dislotwin_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_dislotwin_GrainSize(instance)) + tempState(6_pInt*ns+3_pInt*nt+3_pInt*nr+1:7_pInt*ns+3_pInt*nt+3_pInt*nr) = MeanFreePathSlip0 + + forall (i = 1_pInt:ns) & + tauSlipThreshold0(i) = & + lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(i,instance) * & + sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_interactionMatrix_SlipSlip(i,1:ns,instance))) + + tempState(7_pInt*ns+4_pInt*nt+4_pInt*nr+1:8_pInt*ns+4_pInt*nt+4_pInt*nr) = tauSlipThreshold0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent twin microstructural variables + forall (j = 1_pInt:nt) & + MeanFreePathTwin0(j) = plastic_dislotwin_GrainSize(instance) + tempState(7_pInt*ns+3_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+3_pInt*nr) = MeanFreePathTwin0 + + forall (j = 1_pInt:nt) & + TwinVolume0(j) = & + (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) + tempState(8_pInt*ns+5_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+5_pInt*nr) = TwinVolume0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent trans microstructural variables + forall (j = 1_pInt:nr) & + MeanFreePathTrans0(j) = plastic_dislotwin_GrainSize(instance) + tempState(7_pInt*ns+4_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+4_pInt*nr) = MeanFreePathTrans0 + + forall (j = 1_pInt:nr) & + MartensiteVolume0(j) = & + (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(j,instance)*MeanFreePathTrans0(j)**(2.0_pReal) + tempState(8_pInt*ns+6_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+6_pInt*nr) = MartensiteVolume0 + +plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) + +end subroutine plastic_dislotwin_stateInit + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + ph, & + instance ! number specifying the current instance of the plasticity + + integer(pInt) :: ns, nt, nr + + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + ! Tolerance state for dislocation densities + plasticState(ph)%aTolState(1_pInt: & + 2_pInt*ns) = plastic_dislotwin_aTolRho(instance) + + ! Tolerance state for accumulated shear due to slip + plasticState(ph)%aTolState(2_pInt*ns+1_pInt: & + 3_pInt*ns)=1.0e6_pReal + + ! Tolerance state for twin volume fraction + plasticState(ph)%aTolState(3_pInt*ns+1_pInt: & + 3_pInt*ns+nt) = plastic_dislotwin_aTolTwinFrac(instance) + + ! Tolerance state for accumulated shear due to twin + plasticState(ph)%aTolState(3_pInt*ns+nt+1_pInt: & + 3_pInt*ns+2_pInt*nt) = 1.0e6_pReal + +! Tolerance state for stress-assisted martensite volume fraction + plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+1_pInt: & + 3_pInt*ns+2_pInt*nt+nr) = plastic_dislotwin_aTolTransFrac(instance) + +! Tolerance state for strain-induced martensite volume fraction + plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+nr+1_pInt: & + 3_pInt*ns+2_pInt*nt+2_pInt*nr) = plastic_dislotwin_aTolTransFrac(instance) + +end subroutine plastic_dislotwin_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenized elasticity matrix +!-------------------------------------------------------------------------------------------------- +function plastic_dislotwin_homogenizedC(ipc,ip,el) + use material, only: & + phase_plasticityInstance, & + phaseAt, phasememberAt + use lattice, only: & + lattice_C66 + + implicit none + real(pReal), dimension(6,6) :: & + plastic_dislotwin_homogenizedC + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,nr,i, & + ph, & + of + real(pReal) :: sumf, sumftr + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + + !* Homogenized elasticity matrix + plastic_dislotwin_homogenizedC = (1.0_pReal-sumf-sumftr)*lattice_C66(1:6,1:6,ph) + do i=1_pInt,nt + plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & + + state(instance)%twinFraction(i,of)*plastic_dislotwin_Ctwin66(1:6,1:6,i,instance) + enddo + do i=1_pInt,nr + plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & + + (state(instance)%stressTransFraction(i,of) + state(instance)%strainTransFraction(i,of))*& + plastic_dislotwin_Ctrans66(1:6,1:6,i,instance) + enddo + + end function plastic_dislotwin_homogenizedC + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_microstructure(temperature,ipc,ip,el) + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + !plasticState, & !!!!delete + phaseAt, phasememberAt + use lattice, only: & + lattice_mu, & + lattice_nu + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + temperature !< temperature at IP + + integer(pInt) :: & + instance, & + ns,nt,nr,s,t,r, & + ph, & + of + real(pReal) :: & + sumf,sfe,x0,sumftr + real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize + real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + ftransOverLamellarSize + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + + !* Stacking fault energy + sfe = plastic_dislotwin_SFE_0K(instance) + & + plastic_dislotwin_dSFE_dT(instance) * Temperature + + !* rescaled twin volume fraction for topology + forall (t = 1_pInt:nt) & + fOverStacksize(t) = & + state(instance)%twinFraction(t,of)/plastic_dislotwin_twinsizePerTwinSystem(t,instance) + + !* rescaled trans volume fraction for topology + forall (r = 1_pInt:nr) & + ftransOverLamellarSize(r) = & + (state(instance)%stressTransFraction(r,of)+state(instance)%strainTransFraction(r,of))/& + plastic_dislotwin_lamellarsizePerTransSystem(r,instance) + + !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation + forall (s = 1_pInt:ns) & + state(instance)%invLambdaSlip(s,of) = & + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_dislotwin_forestProjectionEdge(1:ns,s,instance)))/ & + plastic_dislotwin_CLambdaSlipPerSlipSystem(s,instance) + + !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation + !$OMP CRITICAL (evilmatmul) + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal + if (nt > 0_pInt .and. ns > 0_pInt) & + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & + matmul(plastic_dislotwin_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin + !$OMP CRITICAL (evilmatmul) + if (nt > 0_pInt) & + state(instance)%invLambdaTwin(1_pInt:nt,of) = & + matmul(plastic_dislotwin_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* 1/mean free distance between 2 martensite lamellar from different systems seen by a moving dislocation + state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = 0.0_pReal + if (nr > 0_pInt .and. ns > 0_pInt) & + state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = & + matmul(plastic_dislotwin_interactionMatrix_SlipTrans(1:ns,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) + + !* 1/mean free distance between 2 martensite stacks from different systems seen by a growing martensite (1/lambda_trans) + if (nr > 0_pInt) & + state(instance)%invLambdaTrans(1_pInt:nr,of) = & + matmul(plastic_dislotwin_interactionMatrix_TransTrans(1:nr,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) + + !* mean free path between 2 obstacles seen by a moving dislocation + do s = 1_pInt,ns + if ((nt > 0_pInt) .or. (nr > 0_pInt)) then + state(instance)%mfp_slip(s,of) = & + plastic_dislotwin_GrainSize(instance)/(1.0_pReal+plastic_dislotwin_GrainSize(instance)*& + (state(instance)%invLambdaSlip(s,of) + & + state(instance)%invLambdaSlipTwin(s,of) + & + state(instance)%invLambdaSlipTrans(s,of))) + else + state(instance)%mfp_slip(s,of) = & + plastic_dislotwin_GrainSize(instance)/& + (1.0_pReal+plastic_dislotwin_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) !!!!!! correct? + endif + enddo + + !* mean free path between 2 obstacles seen by a growing twin + forall (t = 1_pInt:nt) & + state(instance)%mfp_twin(t,of) = & + plastic_dislotwin_Cmfptwin(instance)*plastic_dislotwin_GrainSize(instance)/& + (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(ph)%invLambdaTwin(t,of)) + + !* mean free path between 2 obstacles seen by a growing martensite + forall (r = 1_pInt:nr) & + state(instance)%mfp_trans(r,of) = & + plastic_dislotwin_Cmfptrans(instance)*plastic_dislotwin_GrainSize(instance)/& + (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(instance)%invLambdaTrans(r,of)) + + !* threshold stress for dislocation motion + forall (s = 1_pInt:ns) & + state(instance)%threshold_stress_slip(s,of) = & + lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(s,instance)*& + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_dislotwin_interactionMatrix_SlipSlip(s,1:ns,instance))) + + !* threshold stress for growing twin + forall (t = 1_pInt:nt) & + state(instance)%threshold_stress_twin(t,of) = & + plastic_dislotwin_Cthresholdtwin(instance)* & + (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)) & + + 3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& + (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(t,instance)) & + ) + + !* threshold stress for growing martensite + forall (r = 1_pInt:nr) & + state(instance)%threshold_stress_trans(r,of) = & + plastic_dislotwin_Cthresholdtrans(instance)* & + (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & + + 3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)*lattice_mu(ph)/& + (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(r,instance))& + + plastic_dislotwin_transStackHeight(instance)*plastic_dislotwin_deltaG(instance)/ & + (3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & + ) + + !* final twin volume after growth + forall (t = 1_pInt:nt) & + state(instance)%twinVolume(t,of) = & + (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(t,instance)*& + state(instance)%mfp_twin(t,of)**(2.0_pReal) + + !* final martensite volume after growth + forall (r = 1_pInt:nr) & + state(instance)%martensiteVolume(r,of) = & + (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(r,instance)*& + state(instance)%mfp_trans(r,of)**(2.0_pReal) + + !* equilibrium separation of partial dislocations (twin) + do t = 1_pInt,nt + x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& + (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) + plastic_dislotwin_tau_r_twin(t,instance)= & + lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& + (1/(x0+plastic_dislotwin_xc_twin(instance))+cos(pi/3.0_pReal)/x0) + enddo + + !* equilibrium separation of partial dislocations (trans) + do r = 1_pInt,nr + x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)**(2.0_pReal)/& + (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) + plastic_dislotwin_tau_r_trans(r,instance)= & + lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)/(2.0_pReal*pi)*& + (1/(x0+plastic_dislotwin_xc_trans(instance))+cos(pi/3.0_pReal)/x0) + enddo + +end subroutine plastic_dislotwin_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + math_Plain3333to99, & + math_Mandel6to33, & + math_Mandel33to6, & + math_spectralDecompositionSym, & + math_tensorproduct33, & + math_symmetric33, & + math_mul33x3 + use material, only: & + material_phase, & + phase_plasticityInstance, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_Strans, & + lattice_Strans_v, & + lattice_maxNslipFamily,& + lattice_maxNtwinFamily, & + lattice_maxNtransFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NtransSystem, & + lattice_shearTwin, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + integer(pInt), intent(in) :: ipc,ip,el + real(pReal), intent(in) :: Temperature + real(pReal), dimension(6), intent(in) :: Tstar_v + real(pReal), dimension(3,3), intent(out) :: Lp + real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 + + integer(pInt) :: instance,ph,of,ns,nt,nr,f,i,j,k,l,m,n,index_myFamily,s1,s2 + real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0_twin,stressRatio, & + Ndot0_trans,StressRatio_s + real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 + real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,dgdot_dtauslip,tau_slip + real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,dgdot_dtautwin,tau_twin + real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_trans,dgdot_dtautrans,tau_trans + real(pReal), dimension(6) :: gdot_sb,dgdot_dtausb,tau_sb + real(pReal), dimension(3,3) :: eigVectors, sb_Smatrix + real(pReal), dimension(3) :: eigValues, sb_s, sb_m + logical :: error + real(pReal), dimension(3,6), parameter :: & + sb_sComposition = & + reshape(real([& + 1, 0, 1, & + 1, 0,-1, & + 1, 1, 0, & + 1,-1, 0, & + 0, 1, 1, & + 0, 1,-1 & + ],pReal),[ 3,6]), & + sb_mComposition = & + reshape(real([& + 1, 0,-1, & + 1, 0,+1, & + 1,-1, 0, & + 1, 1, 0, & + 0, 1,-1, & + 0, 1, 1 & + ],pReal),[ 3,6]) + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Dislocation glide part + gdot_slip = 0.0_pReal + dgdot_dtauslip = 0.0_pReal + j = 0_pInt + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystemsLoop: do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on slip system + tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + + if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) + StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0 & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_dislotwin_qPerSlipFamily(f,instance)) & + * sign(1.0_pReal,tau_slip(j)) + + !* Derivatives of shear rates + dgdot_dtauslip(j) = & + abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& + *plastic_dislotwin_qPerSlipFamily(f,instance)/& + (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) + endif + + !* Plastic velocity gradient for dislocation glide + Lp = Lp + gdot_slip(j)*lattice_Sslip(:,:,1,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& + lattice_Sslip(k,l,1,index_myFamily+i,ph)*& + lattice_Sslip(m,n,1,index_myFamily+i,ph) + enddo slipSystemsLoop + enddo slipFamiliesLoop + +!-------------------------------------------------------------------------------------------------- +! correct Lp and dLp_dTstar3333 for twinned and transformed fraction + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + Lp = Lp * (1.0_pReal - sumf - sumftr) + dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf - sumftr) + +!-------------------------------------------------------------------------------------------------- +! Shear banding (shearband) part + if(abs(plastic_dislotwin_sbVelocity(instance)) > tiny(0.0_pReal) .and. & + abs(plastic_dislotwin_sbResistance(instance)) > tiny(0.0_pReal)) then + gdot_sb = 0.0_pReal + dgdot_dtausb = 0.0_pReal + call math_spectralDecompositionSym(math_Mandel6to33(Tstar_v),eigValues,eigVectors,error) + do j = 1_pInt,6_pInt + sb_s = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_sComposition(1:3,j)) + sb_m = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_mComposition(1:3,j)) + sb_Smatrix = math_tensorproduct33(sb_s,sb_m) + plastic_dislotwin_sbSv(1:6,j,ipc,ip,el) = math_Mandel33to6(math_symmetric33(sb_Smatrix)) + + !* Calculation of Lp + !* Resolved shear stress on shear banding system + tau_sb(j) = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) + + !* Stress ratios + if (abs(tau_sb(j)) < tol_math_check) then + StressRatio_p = 0.0_pReal + StressRatio_pminus1 = 0.0_pReal + else + StressRatio_p = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& + **plastic_dislotwin_pShearBand(instance) + StressRatio_pminus1 = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& + **(plastic_dislotwin_pShearBand(instance)-1.0_pReal) + endif + + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = plastic_dislotwin_sbVelocity(instance) + + !* Shear rates due to shearband + gdot_sb(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qShearBand(instance))*sign(1.0_pReal,tau_sb(j)) + + !* Derivatives of shear rates + dgdot_dtausb(j) = & + ((abs(gdot_sb(j))*BoltzmannRatio*& + plastic_dislotwin_pShearBand(instance)*plastic_dislotwin_qShearBand(instance))/& + plastic_dislotwin_sbResistance(instance))*& + StressRatio_pminus1*(1_pInt-StressRatio_p)**(plastic_dislotwin_qShearBand(instance)-1.0_pReal) + + !* Plastic velocity gradient for shear banding + Lp = Lp + gdot_sb(j)*sb_Smatrix + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtausb(j)*& + sb_Smatrix(k,l)*& + sb_Smatrix(m,n) + enddo + end if + +!-------------------------------------------------------------------------------------------------- +! Mechanical twinning part + gdot_twin = 0.0_pReal + dgdot_dtautwin = 0.0_pReal + j = 0_pInt + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on twin system + tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_twin(j) > tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then + Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(ph)%rhoEdgeDip(s2,of))+& !!!!! correct? + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) + else + Ndot0_twin=0.0_pReal + end if + case default + Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) + end select + gdot_twin(j) = & + (1.0_pReal-sumf-sumftr)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) + dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_dislotwin_rPerTwinFamily(f,instance))/tau_twin(j))*StressRatio_r + endif + + !* Plastic velocity gradient for mechanical twinning + Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& + lattice_Stwin(k,l,index_myFamily+i,ph)*& + lattice_Stwin(m,n,index_myFamily+i,ph) + enddo twinSystemsLoop + enddo twinFamiliesLoop + + !* Phase transformation part + gdot_trans = 0.0_pReal + dgdot_dtautrans = 0.0_pReal + j = 0_pInt + transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily + index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family + transSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) + j = j+1_pInt + + !* Resolved shear stress on transformation system + tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_trans(j) > tol_math_check) then + StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) + !* Shear rates and their derivatives due to transformation + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then + Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !!!!! correct? + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) + else + Ndot0_trans=0.0_pReal + end if + case default + Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) + end select + gdot_trans(j) = & + (1.0_pReal-sumf-sumftr)*& + state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) + dgdot_dtautrans(j) = ((gdot_trans(j)*plastic_dislotwin_sPerTransFamily(f,instance))/tau_trans(j))*StressRatio_s + endif + + !* Plastic velocity gradient for phase transformation + Lp = Lp + gdot_trans(j)*lattice_Strans(:,:,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautrans(j)*& + lattice_Strans(k,l,index_myFamily+i,ph)*& + lattice_Strans(m,n,index_myFamily+i,ph) + + enddo transSystemsLoop + enddo transFamiliesLoop + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + +end subroutine plastic_dislotwin_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_dotState(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_Strans_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_maxNtransFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NtransSystem, & + lattice_sheartwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + lattice_fccTobcc_transNucleationTwinPair, & + lattice_fccTobcc_shearCritTrans, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,nr,f,i,j,index_myFamily,s1,s2, & + ph, & + of + real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,& + EdgeDipMinDistance,AtomicVolume,VacancyDiffusion,StressRatio_r,Ndot0_twin,stressRatio,& + Ndot0_trans,StressRatio_s,EdgeDipDistance, ClimbVelocity,DotRhoEdgeDipClimb,DotRhoEdgeDipAnnihilation, & + DotRhoDipFormation,DotRhoMultiplication,DotRhoEdgeEdgeAnnihilation + real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,tau_slip + + real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + tau_twin + real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + tau_trans + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + plasticState(instance)%dotState(:,of) = 0.0_pReal + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + + !* Dislocation density evolution + gdot_slip = 0.0_pReal + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + !* Resolved shear stress on slip system + tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + + if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) + StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + plasticState(ph)%state(j, of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)** & + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau_slip(j)) + endif + !* Multiplication + DotRhoMultiplication = abs(gdot_slip(j))/& + (plastic_dislotwin_burgersPerSlipSystem(j,instance)*state(instance)%mfp_slip(j,of)) + !* Dipole formation + EdgeDipMinDistance = & + plastic_dislotwin_CEdgeDipMinDistance(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance) + if (abs(tau_slip(j)) <= tiny(0.0_pReal)) then + DotRhoDipFormation = 0.0_pReal + else + EdgeDipDistance = & + (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(tau_slip(j))) + if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) + if (EdgeDipDistance tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/& + tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then + Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) + else + Ndot0_twin=0.0_pReal + end if + case default + Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) + end select + dotState(instance)%twinFraction(j,of) = & + (1.0_pReal-sumf-sumftr)*& + state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) + !* Dotstate for accumulated shear due to twin + dotState(instance)%accshear_twin(j,of) = dotState(instance)%twinFraction(j,of) * & + lattice_sheartwin(index_myfamily+i,ph) + endif + enddo + enddo + + !* Transformation volume fraction evolution + j = 0_pInt + do f = 1_pInt,lattice_maxNtransFamily ! loop over all trans families + index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) ! process each (active) trans system in family + j = j+1_pInt + + !* Resolved shear stress on transformation system + tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_trans(j) > tol_math_check) then + StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/& + tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) + !* Shear rates and their derivatives due to transformation + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then + Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) + else + Ndot0_trans=0.0_pReal + end if + case default + Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) + end select + dotState(instance)%strainTransFraction(j,of) = & + (1.0_pReal-sumf-sumftr)*& + state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) + !* Dotstate for accumulated shear due to transformation + !dotState(instance)%accshear_trans(j,of) = dotState(instance)%strainTransFraction(j,of) * & + ! lattice_sheartrans(index_myfamily+i,ph) + endif + + enddo + enddo + +end subroutine plastic_dislotwin_dotState + + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_dislotwin_postResults(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi, & + math_Mandel6to33, & + math_eigenvaluesSym33, & + math_spectralDecompositionSym33 + use material, only: & + material_phase, & + phase_plasticityInstance,& + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_shearTwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(plastic_dislotwin_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_dislotwin_postResults + integer(pInt) :: & + instance,& + ns,nt,nr,& + f,o,i,c,j,index_myFamily,& + s1,s2, & + ph, & + of + real(pReal) :: sumf,tau,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0_twin,dgdot_dtauslip, & + stressRatio + real(preal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip + real(pReal), dimension(3,3) :: eigVectors + real(pReal), dimension (3) :: eigValues + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Required output + c = 0_pInt + plastic_dislotwin_postResults = 0.0_pReal + do o = 1_pInt,plastic_dislotwin_Noutput(instance) + select case(plastic_dislotwin_outputID(o,instance)) + + case (edge_density_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) + c = c + ns + case (dipole_density_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) + c = c + ns + case (shear_rate_slip_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt ! could be taken from state by now! + + !* Resolved shear stress on slip system + tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + !* Stress ratios + if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau)-state(ph)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) + StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + plastic_dislotwin_postResults(c+j) = & + DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) + else + plastic_dislotwin_postResults(c+j) = 0.0_pReal + endif + + enddo ; enddo + c = c + ns + case (accumulated_shear_slip_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = & + state(instance)%accshear_slip(1_pInt:ns,of) + c = c + ns + case (mfp_slip_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) =& + state(instance)%mfp_slip(1_pInt:ns,of) + c = c + ns + case (resolved_stress_slip_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + plastic_dislotwin_postResults(c+j) =& + dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + enddo; enddo + c = c + ns + case (threshold_stress_slip_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = & + state(instance)%threshold_stress_slip(1_pInt:ns,of) + c = c + ns + case (edge_dipole_distance_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + plastic_dislotwin_postResults(c+j) = & + (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) + plastic_dislotwin_postResults(c+j)=min(plastic_dislotwin_postResults(c+j),& + state(instance)%mfp_slip(j,of)) + ! plastic_dislotwin_postResults(c+j)=max(plastic_dislotwin_postResults(c+j),& + ! plasticState(ph)%state(4*ns+2*nt+2*nr+j, of)) + enddo; enddo + c = c + ns + case (resolved_stress_shearband_ID) + do j = 1_pInt,6_pInt ! loop over all shearband families + plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v, & + plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) + enddo + c = c + 6_pInt + case (shear_rate_shearband_ID) + do j = 1_pInt,6_pInt ! loop over all shearbands + !* Resolved shear stress on shearband system + tau = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) + !* Stress ratios + if (abs(tau) < tol_math_check) then + StressRatio_p = 0.0_pReal + StressRatio_pminus1 = 0.0_pReal + else + StressRatio_p = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& + plastic_dislotwin_pShearBand(instance) + StressRatio_pminus1 = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& + (plastic_dislotwin_pShearBand(instance)-1.0_pReal) + endif + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = plastic_dislotwin_sbVelocity(instance) + ! Shear rate due to shear band + plastic_dislotwin_postResults(c+j) = & + DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**plastic_dislotwin_qShearBand(instance))*& + sign(1.0_pReal,tau) + enddo + c = c + 6_pInt + case (twin_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt,of) + c = c + nt + case (shear_rate_twin_ID) + if (nt > 0_pInt) then + + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + + !* Resolved shear stress on slip system + tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + !* Stress ratios + if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) + else + gdot_slip(j) = 0.0_pReal + endif + enddo;enddo + + j = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily ! loop over all twin families + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1,plastic_dislotwin_Ntwin(f,instance) ! process each (active) twin system in family + j = j + 1_pInt + + tau = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + + !* Shear rates due to twin + if ( tau > 0.0_pReal ) then + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau < plastic_dislotwin_tau_r_twin(j,instance)) then + Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_twin(instance)*& + plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_twin(j,instance)-tau))) + else + Ndot0_twin=0.0_pReal + end if + case default + Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) + end select + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau) & + **plastic_dislotwin_rPerTwinFamily(f,instance) + plastic_dislotwin_postResults(c+j) = & + (plastic_dislotwin_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) + endif + + enddo ; enddo + endif + c = c + nt + case (accumulated_shear_twin_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt,of) + c = c + nt + case (mfp_twin_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt,of) + c = c + nt + case (resolved_stress_twin_ID) + if (nt > 0_pInt) then + j = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily ! loop over all slip families + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + enddo; enddo + endif + c = c + nt + case (threshold_stress_twin_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt,of) + c = c + nt + case (stress_exponent_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + + !* Resolved shear stress on slip system + tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) + + !* Derivatives of shear rates + dgdot_dtauslip = & + abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& + *plastic_dislotwin_qPerSlipFamily(f,instance)/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) + + else + gdot_slip(j) = 0.0_pReal + dgdot_dtauslip = 0.0_pReal + endif + + !* Stress exponent + if (abs(gdot_slip(j))<=tiny(0.0_pReal)) then + plastic_dislotwin_postResults(c+j) = 0.0_pReal + else + plastic_dislotwin_postResults(c+j) = (tau/gdot_slip(j))*dgdot_dtauslip + endif + enddo ; enddo + c = c + ns + case (sb_eigenvalues_ID) + plastic_dislotwin_postResults(c+1_pInt:c+3_pInt) = math_eigenvaluesSym33(math_Mandel6to33(Tstar_v)) + c = c + 3_pInt + case (sb_eigenvectors_ID) + call math_spectralDecompositionSym33(math_Mandel6to33(Tstar_v),eigValues,eigVectors) + plastic_dislotwin_postResults(c+1_pInt:c+9_pInt) = reshape(eigVectors,[9]) + c = c + 9_pInt + case (stress_trans_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nr) = & + state(instance)%stressTransFraction(1_pInt:nr,of) + c = c + nr + case (strain_trans_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nr) = & + state(instance)%strainTransFraction(1_pInt:nr,of) + c = c + nr + case (trans_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nr) = & + state(instance)%stressTransFraction(1_pInt:nr,of) + & + state(instance)%strainTransFraction(1_pInt:nr,of) + c = c + nr + end select + enddo +end function plastic_dislotwin_postResults + +end module plastic_dislotwin \ No newline at end of file diff --git a/code/plastic/plastic_isotropic.f90 b/code/plastic/plastic_isotropic.f90 new file mode 100644 index 000000000..13481b9a7 --- /dev/null +++ b/code/plastic/plastic_isotropic.f90 @@ -0,0 +1,678 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for isotropic (ISOTROPIC) plasticity +!> @details Isotropic (ISOTROPIC) Plasticity which resembles the phenopowerlaw plasticity without +!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an +!! untextured polycrystal +!-------------------------------------------------------------------------------------------------- +module plastic_isotropic +#ifdef HDF + use hdf5, only: & + HID_T +#endif + + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_isotropic_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_isotropic_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_isotropic_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_isotropic_Noutput !< number of outputs per instance + + enum, bind(c) + enumerator :: undefined_ID, & + flowstress_ID, & + strainrate_ID + end enum + + type, private :: tParameters !< container type for internal constitutive parameters + integer(kind(undefined_ID)), allocatable, dimension(:) :: & + outputID + real(pReal) :: & + fTaylor, & + tau0, & + gdot0, & + n, & + h0, & + h0_slopeLnRate, & + tausat, & + a, & + aTolFlowstress, & + aTolShear , & + tausat_SinhFitA, & + tausat_SinhFitB, & + tausat_SinhFitC, & + tausat_SinhFitD + logical :: & + dilatation + end type + + type(tParameters), dimension(:), allocatable, private :: param !< containers of constitutive parameters (len Ninstance) + + type, private :: tIsotropicState !< internal state aliases + real(pReal), pointer, dimension(:) :: & ! scalars along NipcMyInstance + flowstress, & + accumulatedShear + end type + type, private :: tIsotropicAbsTol !< internal alias for abs tolerance in state + real(pReal), pointer :: & ! scalars along NipcMyInstance + flowstress, & + accumulatedShear + end type + type(tIsotropicState), allocatable, dimension(:), private :: & !< state aliases per instance + state, & + state0, & + dotState + type(tIsotropicAbsTol), allocatable, dimension(:), private :: & !< state aliases per instance + stateAbsTol + + public :: & + plastic_isotropic_init, & + plastic_isotropic_LpAndItsTangent, & + plastic_isotropic_LiAndItsTangent, & + plastic_isotropic_dotState, & + plastic_isotropic_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic + use numerics, only: & + analyticJaco, & + worldrank, & + numerics_integrator + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_ISOTROPIC_label, & + PLASTICITY_ISOTROPIC_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + + use lattice + + implicit none + integer(pInt), intent(in) :: fileUnit + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + o, & + phase, & + instance, & + maxNinstance, & + mySize, & + sizeDotState, & + sizeState, & + sizeDeltaState + character(len=65536) :: & + tag = '', & + outputtag = '', & + line = '', & + extmsg = '' + integer(pInt) :: NipcMyPhase + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_ISOTROPIC_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_ISOTROPIC_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_isotropic_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_isotropic_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) + allocate(plastic_isotropic_output(maxval(phase_Noutput), maxNinstance)) + plastic_isotropic_output = '' + allocate(plastic_isotropic_Noutput(maxNinstance), source=0_pInt) + + allocate(param(maxNinstance)) ! one container of parameters per instance + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + phase = phase + 1_pInt ! advance section counter + if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then + instance = phase_plasticityInstance(phase) + + endif + cycle ! skip to next line + endif + if (phase > 0_pInt) then; if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + allocate(param(instance)%outputID(phase_Noutput(phase))) ! allocate space for IDs of every requested output + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + extmsg = trim(tag)//' ('//PLASTICITY_ISOTROPIC_label//')' ! prepare error message identifier + + select case(tag) + case ('(output)') + outputtag = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + select case(outputtag) + case ('flowstress') + plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt + param(instance)%outputID (plastic_isotropic_Noutput(instance)) = flowstress_ID + plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag + case ('strainrate') + plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt + param(instance)%outputID (plastic_isotropic_Noutput(instance)) = strainrate_ID + plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag + + end select + + case ('/dilatation/') + param(instance)%dilatation = .true. + + case ('tau0') + param(instance)%tau0 = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%tau0 < 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('gdot0') + param(instance)%gdot0 = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%gdot0 <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('n') + param(instance)%n = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%n <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('h0') + param(instance)%h0 = IO_floatValue(line,chunkPos,2_pInt) + + case ('h0_slope','slopelnrate') + param(instance)%h0_slopeLnRate = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat') + param(instance)%tausat = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%tausat <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('tausat_sinhfita') + param(instance)%tausat_SinhFitA = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat_sinhfitb') + param(instance)%tausat_SinhFitB = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat_sinhfitc') + param(instance)%tausat_SinhFitC = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat_sinhfitd') + param(instance)%tausat_SinhFitD = IO_floatValue(line,chunkPos,2_pInt) + + case ('a', 'w0') + param(instance)%a = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%a <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('taylorfactor') + param(instance)%fTaylor = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%fTaylor <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('atol_flowstress') + param(instance)%aTolFlowstress = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%aTolFlowstress <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('atol_shear') + param(instance)%aTolShear = IO_floatValue(line,chunkPos,2_pInt) + + case default + + end select + endif; endif + enddo parsingFile + + allocate(state(maxNinstance)) ! internal state aliases + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + allocate(stateAbsTol(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop over every plasticity + myPhase: if (phase_plasticity(phase) == PLASTICITY_isotropic_ID) then ! isolate instances of own constitutive description + NipcMyPhase = count(material_phase == phase) ! number of own material points (including point components ipc) + instance = phase_plasticityInstance(phase) +!-------------------------------------------------------------------------------------------------- +! sanity checks + if (param(instance)%aTolShear <= 0.0_pReal) & + param(instance)%aTolShear = 1.0e-6_pReal ! default absolute tolerance 1e-6 + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) + select case(param(instance)%outputID(o)) + case(flowstress_ID,strainrate_ID) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_isotropic_sizePostResult(o,instance) = mySize + plastic_isotropic_sizePostResults(instance) = & + plastic_isotropic_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = 2_pInt ! flowstress, accumulated_shear + sizeDotState = sizeState ! both evolve + sizeDeltaState = 0_pInt ! no sudden jumps in state + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_isotropic_sizePostResults(instance) + plasticState(phase)%nSlip = 1 + plasticState(phase)%nTwin = 0 + plasticState(phase)%nTrans= 0 + allocate(plasticState(phase)%aTolState ( sizeState)) + + allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase),source=0.0_pReal) + + allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase),source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase),source=0.0_pReal) + +!-------------------------------------------------------------------------------------------------- +! globally required state aliases + plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NipcMyPhase) + plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NipcMyPhase) + +!-------------------------------------------------------------------------------------------------- +! locally defined state aliases + state(instance)%flowstress => plasticState(phase)%state (1,1:NipcMyPhase) + state0(instance)%flowstress => plasticState(phase)%state0 (1,1:NipcMyPhase) + dotState(instance)%flowstress => plasticState(phase)%dotState (1,1:NipcMyPhase) + stateAbsTol(instance)%flowstress => plasticState(phase)%aTolState(1) + + state(instance)%accumulatedShear => plasticState(phase)%state (2,1:NipcMyPhase) + state0(instance)%accumulatedShear => plasticState(phase)%state0 (2,1:NipcMyPhase) + dotState(instance)%accumulatedShear => plasticState(phase)%dotState (2,1:NipcMyPhase) + stateAbsTol(instance)%accumulatedShear => plasticState(phase)%aTolState(2) + +!-------------------------------------------------------------------------------------------------- +! init state + state0(instance)%flowstress = param(instance)%tau0 + state0(instance)%accumulatedShear = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! init absolute state tolerances + stateAbsTol(instance)%flowstress = param(instance)%aTolFlowstress + stateAbsTol(instance)%accumulatedShear = param(instance)%aTolShear + + endif myPhase + enddo initializeInstances + +end subroutine plastic_isotropic_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_g + use math, only: & + math_mul6x6, & + math_Mandel6to33, & + math_Plain3333to99, & + math_deviatoric33, & + math_mul33xx33, & + math_transpose33 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(3,3) :: & + Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal) :: & + gamma_dot, & !< strainrate + norm_Tstar_dev, & !< euclidean norm of Tstar_dev + squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev + integer(pInt) :: & + instance, of, & + k, l, m, n + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + + Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress + squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) + norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) + + if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero + Lp = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + else + gamma_dot = param(instance)%gdot0 & + * ( sqrt(1.5_pReal) * norm_Tstar_dev / param(instance)%fTaylor / state(instance)%flowstress(of) ) & + **param(instance)%n + + Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/param(instance)%fTaylor + + if (iand(debug_level(debug_constitutive), debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i8,1x,i2,1x,i3)') '<< CONST isotropic >> at el ip g ',el,ip,ipc + write(6,'(/,a,/,3(12x,3(f12.4,1x)/))') '<< CONST isotropic >> Tstar (dev) / MPa', & + math_transpose33(Tstar_dev_33(1:3,1:3))*1.0e-6_pReal + write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> norm Tstar / MPa', norm_Tstar_dev*1.0e-6_pReal + write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> gdot', gamma_dot + end if +!-------------------------------------------------------------------------------------------------- +! Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & + Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal + forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & + dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal + dLp_dTstar99 = math_Plain3333to99(gamma_dot / param(instance)%fTaylor * & + dLp_dTstar_3333 / norm_Tstar_dev) + end if +end subroutine plastic_isotropic_LpAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_LiAndItsTangent(Li,dLi_dTstar_3333,Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6, & + math_Mandel6to33, & + math_Plain3333to99, & + math_spherical33, & + math_mul33xx33 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Li !< plastic velocity gradient + + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(3,3) :: & + Tstar_sph_33 !< sphiatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor + real(pReal), dimension(3,3,3,3), intent(out) :: & + dLi_dTstar_3333 !< derivative of Li with respect to Tstar as 4th order tensor + real(pReal) :: & + gamma_dot, & !< strainrate + norm_Tstar_sph, & !< euclidean norm of Tstar_sph + squarenorm_Tstar_sph !< square of the euclidean norm of Tstar_sph + integer(pInt) :: & + instance, of, & + k, l, m, n + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + + Tstar_sph_33 = math_spherical33(math_Mandel6to33(Tstar_v)) ! spherical part of 2nd Piola-Kirchhoff stress + squarenorm_Tstar_sph = math_mul33xx33(Tstar_sph_33,Tstar_sph_33) + norm_Tstar_sph = sqrt(squarenorm_Tstar_sph) + + if (param(instance)%dilatation) then + if (norm_Tstar_sph <= 0.0_pReal) then ! Tstar == 0 --> both Li and dLi_dTstar are zero + Li = 0.0_pReal + dLi_dTstar_3333 = 0.0_pReal + else + gamma_dot = param(instance)%gdot0 & + * (sqrt(1.5_pReal) * norm_Tstar_sph / param(instance)%fTaylor / state(instance)%flowstress(of) ) & + **param(instance)%n + + Li = Tstar_sph_33/norm_Tstar_sph * gamma_dot/param(instance)%fTaylor + + !-------------------------------------------------------------------------------------------------- + ! Calculation of the tangent of Li + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLi_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & + Tstar_sph_33(k,l)*Tstar_sph_33(m,n) / squarenorm_Tstar_sph + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLi_dTstar_3333(k,l,k,l) = dLi_dTstar_3333(k,l,k,l) + 1.0_pReal + + dLi_dTstar_3333 = gamma_dot / param(instance)%fTaylor * & + dLi_dTstar_3333 / norm_Tstar_sph + endif + endif + +end subroutine plastic_isotropic_LiAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_dotState(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6) :: & + Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + gamma_dot, & !< strainrate + hardening, & !< hardening coefficient + saturation, & !< saturation flowstress + norm_Tstar_v !< euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of !< shortcut notation for offset position in state array + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + +!-------------------------------------------------------------------------------------------------- +! norm of (deviatoric) 2nd Piola-Kirchhoff stress + if (param(instance)%dilatation) then + norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) + else + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + end if +!-------------------------------------------------------------------------------------------------- +! strain rate + gamma_dot = param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & + / &!----------------------------------------------------------------------------------- + (param(instance)%fTaylor*state(instance)%flowstress(of) ))**param(instance)%n + +!-------------------------------------------------------------------------------------------------- +! hardening coefficient + if (abs(gamma_dot) > 1e-12_pReal) then + if (abs(param(instance)%tausat_SinhFitA) <= tiny(0.0_pReal)) then + saturation = param(instance)%tausat + else + saturation = ( param(instance)%tausat & + + ( log( ( gamma_dot / param(instance)%tausat_SinhFitA& + )**(1.0_pReal / param(instance)%tausat_SinhFitD)& + + sqrt( ( gamma_dot / param(instance)%tausat_SinhFitA & + )**(2.0_pReal / param(instance)%tausat_SinhFitD) & + + 1.0_pReal ) & + ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) + )**(1.0_pReal / param(instance)%tausat_SinhFitC) & + / ( param(instance)%tausat_SinhFitB & + * (gamma_dot / param(instance)%gdot0)**(1.0_pReal / param(instance)%n) & + ) & + ) + endif + hardening = ( param(instance)%h0 + param(instance)%h0_slopeLnRate * log(gamma_dot) ) & + * abs( 1.0_pReal - state(instance)%flowstress(of)/saturation )**param(instance)%a & + * sign(1.0_pReal, 1.0_pReal - state(instance)%flowstress(of)/saturation) + else + hardening = 0.0_pReal + endif + + dotState(instance)%flowstress (of) = hardening * gamma_dot + dotState(instance)%accumulatedShear(of) = gamma_dot + +end subroutine plastic_isotropic_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_isotropic_postResults(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(plastic_isotropic_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_isotropic_postResults + + real(pReal), dimension(6) :: & + Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + norm_Tstar_v ! euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of, & !< shortcut notation for offset position in state array + c, & + o + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + +!-------------------------------------------------------------------------------------------------- +! norm of (deviatoric) 2nd Piola-Kirchhoff stress + if (param(instance)%dilatation) then + norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) + else + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + end if + + c = 0_pInt + plastic_isotropic_postResults = 0.0_pReal + + outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) + select case(param(instance)%outputID(o)) + case (flowstress_ID) + plastic_isotropic_postResults(c+1_pInt) = state(instance)%flowstress(of) + c = c + 1_pInt + case (strainrate_ID) + plastic_isotropic_postResults(c+1_pInt) = & + param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & + / &!---------------------------------------------------------------------------------- + (param(instance)%fTaylor * state(instance)%flowstress(of)) ) ** param(instance)%n + c = c + 1_pInt + end select + enddo outputsLoop + +end function plastic_isotropic_postResults + + +end module plastic_isotropic diff --git a/code/plastic/plastic_j2.f90 b/code/plastic/plastic_j2.f90 new file mode 100644 index 000000000..89c022cc9 --- /dev/null +++ b/code/plastic/plastic_j2.f90 @@ -0,0 +1,579 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for isotropic (J2) plasticity +!> @details Isotropic (J2) Plasticity which resembles the phenopowerlaw plasticity without +!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an +!! untextured polycrystal +!-------------------------------------------------------------------------------------------------- +module plastic_j2 +#ifdef HDF + use hdf5, only: & + HID_T +#endif + + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_j2_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_j2_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_j2_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_j2_Noutput !< number of outputs per instance + real(pReal), dimension(:), allocatable, private :: & + plastic_j2_fTaylor, & !< Taylor factor + plastic_j2_tau0, & !< initial plastic stress + plastic_j2_gdot0, & !< reference velocity + plastic_j2_n, & !< Visco-plastic parameter +!-------------------------------------------------------------------------------------------------- +! h0 as function of h0 = A + B log (gammadot) + plastic_j2_h0, & + plastic_j2_h0_slopeLnRate, & + plastic_j2_tausat, & !< final plastic stress + plastic_j2_a, & + plastic_j2_aTolResistance, & + plastic_j2_aTolShear, & +!-------------------------------------------------------------------------------------------------- +! tausat += (asinh((gammadot / SinhFitA)**(1 / SinhFitD)))**(1 / SinhFitC) / (SinhFitB * (gammadot / gammadot0)**(1/n)) + plastic_j2_tausat_SinhFitA, & !< fitting parameter for normalized strain rate vs. stress function + plastic_j2_tausat_SinhFitB, & !< fitting parameter for normalized strain rate vs. stress function + plastic_j2_tausat_SinhFitC, & !< fitting parameter for normalized strain rate vs. stress function + plastic_j2_tausat_SinhFitD !< fitting parameter for normalized strain rate vs. stress function + + enum, bind(c) + enumerator :: undefined_ID, & + flowstress_ID, & + strainrate_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_j2_outputID !< ID of each post result output + + +#ifdef HDF + type plastic_j2_tOutput + real(pReal), dimension(:), allocatable, private :: & + flowstress, & + strainrate + logical :: flowstressActive = .false., strainrateActive = .false. ! if we can write the output block wise, this is not needed anymore because we can do an if(allocated(xxx)) + end type plastic_j2_tOutput + type(plastic_j2_tOutput), allocatable, dimension(:) :: plastic_j2_Output2 +integer(HID_T), allocatable, dimension(:) :: outID +#endif + + + public :: & + plastic_j2_init, & + plastic_j2_LpAndItsTangent, & + plastic_j2_dotState, & + plastic_j2_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_j2_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) +#ifdef HDF + use hdf5 +#endif + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic + use numerics, only: & + analyticJaco, & + worldrank, & + numerics_integrator + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_error, & + IO_timeStamp, & +#ifdef HDF + tempResults, & + HDF5_addGroup, & + HDF5_addScalarDataset,& +#endif + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_J2_label, & + PLASTICITY_J2_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + + use lattice + + implicit none + integer(pInt), intent(in) :: fileUnit + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + o, & + phase, & + maxNinstance, & + instance, & + mySize, & + sizeDotState, & + sizeState, & + sizeDeltaState + character(len=65536) :: & + tag = '', & + line = '' + integer(pInt) :: NofMyPhase + +#ifdef HDF + character(len=5) :: & + str1 + integer(HID_T) :: ID,ID2,ID4 +#endif + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_J2_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_J2_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + +#ifdef HDF + allocate(plastic_j2_Output2(maxNinstance)) + allocate(outID(maxNinstance)) +#endif + + allocate(plastic_j2_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_j2_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) + allocate(plastic_j2_output(maxval(phase_Noutput), maxNinstance)) + plastic_j2_output = '' + allocate(plastic_j2_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_j2_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_j2_fTaylor(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tau0(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_gdot0(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_n(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_h0(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_h0_slopeLnRate(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_a(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_aTolResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_aTolShear (maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitA(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitB(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitC(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitD(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + phase = phase + 1_pInt ! advance section counter + if (phase_plasticity(phase) == PLASTICITY_J2_ID) then + instance = phase_plasticityInstance(phase) +#ifdef HDF + outID(instance)=HDF5_addGroup(str1,tempResults) +#endif + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_J2_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('flowstress') + plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt + plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = flowstress_ID + plastic_j2_output(plastic_j2_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) +#ifdef HDF + call HDF5_addScalarDataset(outID(instance),myConstituents,'flowstress','MPa') + allocate(plastic_j2_Output2(instance)%flowstress(myConstituents)) + plastic_j2_Output2(instance)%flowstressActive = .true. +#endif + case ('strainrate') + plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt + plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = strainrate_ID + plastic_j2_output(plastic_j2_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) +#ifdef HDF + call HDF5_addScalarDataset(outID(instance),myConstituents,'strainrate','1/s') + allocate(plastic_j2_Output2(instance)%strainrate(myConstituents)) + plastic_j2_Output2(instance)%strainrateActive = .true. +#endif + case default + + end select + case ('tau0') + plastic_j2_tau0(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_tau0(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('gdot0') + plastic_j2_gdot0(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_gdot0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('n') + plastic_j2_n(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_n(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('h0') + plastic_j2_h0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_slope','slopelnrate') + plastic_j2_h0_slopeLnRate(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat') + plastic_j2_tausat(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_tausat(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('tausat_sinhfita') + plastic_j2_tausat_SinhFitA(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat_sinhfitb') + plastic_j2_tausat_SinhFitB(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat_sinhfitc') + plastic_j2_tausat_SinhFitC(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat_sinhfitd') + plastic_j2_tausat_SinhFitD(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('a', 'w0') + plastic_j2_a(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_a(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('taylorfactor') + plastic_j2_fTaylor(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_fTaylor(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('atol_resistance') + plastic_j2_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_aTolResistance(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('atol_shear') + plastic_j2_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case default + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_j2_ID) then + NofMyPhase=count(material_phase==phase) + instance = phase_plasticityInstance(phase) +!-------------------------------------------------------------------------------------------------- +! sanity checks + if (plastic_j2_aTolShear(instance) <= 0.0_pReal) & + plastic_j2_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) + select case(plastic_j2_outputID(o,instance)) + case(flowstress_ID,strainrate_ID) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_j2_sizePostResult(o,instance) = mySize + plastic_j2_sizePostResults(instance) = & + plastic_j2_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = 2_pInt + sizeDotState = sizeState + sizeDeltaState = 0_pInt + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_j2_sizePostResults(instance) + plasticState(phase)%nSlip = 1 + plasticState(phase)%nTwin = 0 + plasticState(phase)%nTrans= 0 + allocate(plasticState(phase)%aTolState ( sizeState)) + plasticState(phase)%aTolState(1) = plastic_j2_aTolResistance(instance) + plasticState(phase)%aTolState(2) = plastic_j2_aTolShear(instance) + allocate(plasticState(phase)%state0 ( sizeState,NofMyPhase)) + plasticState(phase)%state0(1,1:NofMyPhase) = plastic_j2_tau0(instance) + plasticState(phase)%state0(2,1:NofMyPhase) = 0.0_pReal + allocate(plasticState(phase)%partionedState0 ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase),source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase),source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NofMyPhase) + endif myPhase + enddo initializeInstances + +end subroutine plastic_j2_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_j2_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6, & + math_Mandel6to33, & + math_Plain3333to99, & + math_deviatoric33, & + math_mul33xx33 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(3,3) :: & + Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal) :: & + gamma_dot, & !< strainrate + norm_Tstar_dev, & !< euclidean norm of Tstar_dev + squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & + k, l, m, n + + instance = phase_plasticityInstance(material_phase(ipc,ip,el)) + Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress + squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) + norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) + + if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero + Lp = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + else + gamma_dot = plastic_j2_gdot0(instance) & + * (sqrt(1.5_pReal) * norm_Tstar_dev / (plastic_j2_fTaylor(instance) * & + plasticState(phaseAt(ipc,ip,el))%state(1,phasememberAt(ipc,ip,el)))) & + **plastic_j2_n(instance) + + Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/plastic_j2_fTaylor(instance) + +!-------------------------------------------------------------------------------------------------- +! Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,m,n) = (plastic_j2_n(instance)-1.0_pReal) * & + Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal + forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & + dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal + dLp_dTstar99 = math_Plain3333to99(gamma_dot / plastic_j2_fTaylor(instance) * & + dLp_dTstar_3333 / norm_Tstar_dev) + end if +end subroutine plastic_j2_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_j2_dotState(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6) :: & + Tstar_dev_v !< deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + gamma_dot, & !< strainrate + hardening, & !< hardening coefficient + saturation, & !< saturation resistance + norm_Tstar_dev !< euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of, & !< shortcut notation for offset position in state array + ph !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(material_phase(ipc,ip,el)) + +!-------------------------------------------------------------------------------------------------- +! norm of deviatoric part of 2nd Piola-Kirchhoff stress + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + +!-------------------------------------------------------------------------------------------------- +! strain rate + gamma_dot = plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & + / &!----------------------------------------------------------------------------------- + (plastic_j2_fTaylor(instance)*plasticState(ph)%state(1,of)) )**plastic_j2_n(instance) + +!-------------------------------------------------------------------------------------------------- +! hardening coefficient + if (abs(gamma_dot) > 1e-12_pReal) then + if (abs(plastic_j2_tausat_SinhFitA(instance)) <= tiny(0.0_pReal)) then + saturation = plastic_j2_tausat(instance) + else + saturation = ( plastic_j2_tausat(instance) & + + ( log( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance)& + )**(1.0_pReal / plastic_j2_tausat_SinhFitD(instance))& + + sqrt( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance) & + )**(2.0_pReal / plastic_j2_tausat_SinhFitD(instance)) & + + 1.0_pReal ) & + ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) + )**(1.0_pReal / plastic_j2_tausat_SinhFitC(instance)) & + / ( plastic_j2_tausat_SinhFitB(instance) & + * (gamma_dot / plastic_j2_gdot0(instance))**(1.0_pReal / plastic_j2_n(instance)) & + ) & + ) + endif + hardening = ( plastic_j2_h0(instance) + plastic_j2_h0_slopeLnRate(instance) * log(gamma_dot) ) & + * abs( 1.0_pReal - plasticState(ph)%state(1,of)/saturation )**plastic_j2_a(instance) & + * sign(1.0_pReal, 1.0_pReal - plasticState(ph)%state(1,of)/saturation) + else + hardening = 0.0_pReal + endif + + plasticState(ph)%dotState(1,of) = hardening * gamma_dot + plasticState(ph)%dotState(2,of) = gamma_dot + +end subroutine plastic_j2_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_j2_postResults(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(plastic_j2_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_j2_postResults + + real(pReal), dimension(6) :: & + Tstar_dev_v ! deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + norm_Tstar_dev ! euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of, & !< shortcut notation for offset position in state array + ph, & !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) + c, & + o + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(material_phase(ipc,ip,el)) + +!-------------------------------------------------------------------------------------------------- +! calculate deviatoric part of 2nd Piola-Kirchhoff stress and its norm + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + + c = 0_pInt + plastic_j2_postResults = 0.0_pReal + + outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) + select case(plastic_j2_outputID(o,instance)) + case (flowstress_ID) + plastic_j2_postResults(c+1_pInt) = plasticState(ph)%state(1,of) + c = c + 1_pInt + case (strainrate_ID) + plastic_j2_postResults(c+1_pInt) = & + plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & + / &!---------------------------------------------------------------------------------- + (plastic_j2_fTaylor(instance) * plasticState(ph)%state(1,of)) ) ** plastic_j2_n(instance) + c = c + 1_pInt + end select + enddo outputsLoop + +end function plastic_j2_postResults + + +end module plastic_j2 diff --git a/code/plastic/plastic_none.f90 b/code/plastic/plastic_none.f90 new file mode 100644 index 000000000..f624a80a2 --- /dev/null +++ b/code/plastic/plastic_none.f90 @@ -0,0 +1,109 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for purely elastic material +!-------------------------------------------------------------------------------------------------- +module plastic_none + use prec, only: & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_none_sizePostResults + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_none_sizePostResult !< size of each post result output + + public :: & + plastic_none_init + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_none_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic + use IO, only: & + IO_timeStamp + use numerics, only: & + worldrank, & + numerics_integrator + use material, only: & + phase_plasticity, & + PLASTICITY_NONE_label, & + material_phase, & + plasticState, & + PLASTICITY_none_ID + + implicit none + + integer(pInt) :: & + maxNinstance, & + phase, & + NofMyPhase, & + sizeState, & + sizeDotState, & + sizeDeltaState + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONE_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_none_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + if (phase_plasticity(phase) == PLASTICITY_none_ID) then + NofMyPhase=count(material_phase==phase) + + sizeState = 0_pInt + plasticState(phase)%sizeState = sizeState + sizeDotState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + sizeDeltaState = 0_pInt + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = 0_pInt + plasticState(phase)%nSlip = 0_pInt + plasticState(phase)%nTwin = 0_pInt + plasticState(phase)%nTrans = 0_pInt + allocate(plasticState(phase)%aTolState (sizeState)) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase)) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase)) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase)) + allocate(plasticState(phase)%state (sizeState,NofMyPhase)) + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase)) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase)) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase)) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase)) + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase)) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase)) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase)) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase)) + endif + enddo initializeInstances + + allocate(plastic_none_sizePostResults(maxNinstance), source=0_pInt) + +end subroutine plastic_none_init + +end module plastic_none diff --git a/code/plastic/plastic_nonlocal.f90 b/code/plastic/plastic_nonlocal.f90 new file mode 100644 index 000000000..1922c08e2 --- /dev/null +++ b/code/plastic/plastic_nonlocal.f90 @@ -0,0 +1,4031 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Christoph Kords, 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 +!> @brief material subroutine for plasticity including dislocation flux +!-------------------------------------------------------------------------------------------------- +module plastic_nonlocal + use prec, only: & + pReal, & + pInt + + implicit none + private + character(len=22), dimension(11), parameter, private :: & + BASICSTATES = ['rhoSglEdgePosMobile ', & + 'rhoSglEdgeNegMobile ', & + 'rhoSglScrewPosMobile ', & + 'rhoSglScrewNegMobile ', & + 'rhoSglEdgePosImmobile ', & + 'rhoSglEdgeNegImmobile ', & + 'rhoSglScrewPosImmobile', & + 'rhoSglScrewNegImmobile', & + 'rhoDipEdge ', & + 'rhoDipScrew ', & + 'accumulatedshear ' ] !< list of "basic" microstructural state variables that are independent from other state variables + + character(len=16), dimension(3), parameter, private :: & + DEPENDENTSTATES = ['rhoForest ', & + 'tauThreshold ', & + 'tauBack ' ] !< list of microstructural state variables that depend on other state variables + + character(len=20), dimension(6), parameter, private :: & + OTHERSTATES = ['velocityEdgePos ', & + 'velocityEdgeNeg ', & + 'velocityScrewPos ', & + 'velocityScrewNeg ', & + 'maxDipoleHeightEdge ', & + 'maxDipoleHeightScrew' ] !< list of other dependent state variables that are not updated by microstructure + + real(pReal), parameter, private :: & + KB = 1.38e-23_pReal !< Physical parameter, Boltzmann constant in J/Kelvin + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_nonlocal_sizeDotState, & !< number of dotStates = number of basic state variables + plastic_nonlocal_sizeDependentState, & !< number of dependent state variables + plastic_nonlocal_sizeState, & !< total number of state variables + plastic_nonlocal_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_nonlocal_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_nonlocal_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_nonlocal_Noutput !< number of outputs per instance of this plasticity + + integer(pInt), dimension(:,:), allocatable, private :: & + iGamma, & !< state indices for accumulated shear + iRhoF, & !< state indices for forest density + iTauF, & !< state indices for critical resolved shear stress + iTauB !< state indices for backstress + integer(pInt), dimension(:,:,:), allocatable, private :: & + iRhoU, & !< state indices for unblocked density + iRhoB, & !< state indices for blocked density + iRhoD, & !< state indices for dipole density + iV, & !< state indices for dislcation velocities + iD !< state indices for stable dipole height + + integer(pInt), dimension(:), allocatable, public, protected :: & + totalNslip !< total number of active slip systems for each instance + + integer(pInt), dimension(:,:), allocatable, private :: & + Nslip, & !< number of active slip systems for each family and instance + slipFamily, & !< lookup table relating active slip system to slip family for each instance + slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance + colinearSystem !< colinear system to the active slip system (only valid for fcc!) + + real(pReal), dimension(:), allocatable, private :: & + atomicVolume, & !< atomic volume + Dsd0, & !< prefactor for self-diffusion coefficient + selfDiffusionEnergy, & !< activation enthalpy for diffusion + aTolRho, & !< absolute tolerance for dislocation density in state integration + aTolShear, & !< absolute tolerance for accumulated shear in state integration + significantRho, & !< density considered significant + significantN, & !< number of dislocations considered significant + cutoffRadius, & !< cutoff radius for dislocation stress + doublekinkwidth, & !< width of a doubkle kink in multiples of the burgers vector length b + solidSolutionEnergy, & !< activation energy for solid solution in J + solidSolutionSize, & !< solid solution obstacle size in multiples of the burgers vector length + solidSolutionConcentration, & !< concentration of solid solution in atomic parts + pParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) + qParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) + viscosity, & !< viscosity for dislocation glide in Pa s + fattack, & !< attack frequency in Hz + rhoSglScatter, & !< standard deviation of scatter in initial dislocation density + surfaceTransmissivity, & !< transmissivity at free surface + grainboundaryTransmissivity, & !< transmissivity at grain boundary (identified by different texture) + CFLfactor, & !< safety factor for CFL flux condition + fEdgeMultiplication, & !< factor that determines how much edge dislocations contribute to multiplication (0...1) + rhoSglRandom, & + rhoSglRandomBinning, & + linetensionEffect, & + edgeJogFactor + + real(pReal), dimension(:,:), allocatable, private :: & + rhoSglEdgePos0, & !< initial edge_pos dislocation density per slip system for each family and instance + rhoSglEdgeNeg0, & !< initial edge_neg dislocation density per slip system for each family and instance + rhoSglScrewPos0, & !< initial screw_pos dislocation density per slip system for each family and instance + rhoSglScrewNeg0, & !< initial screw_neg dislocation density per slip system for each family and instance + rhoDipEdge0, & !< initial edge dipole dislocation density per slip system for each family and instance + rhoDipScrew0, & !< initial screw dipole dislocation density per slip system for each family and instance + lambda0PerSlipFamily, & !< mean free path prefactor for each family and instance + lambda0, & !< mean free path prefactor for each slip system and instance + burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each family and instance + burgers, & !< absolute length of burgers vector [m] for each slip system and instance + interactionSlipSlip !< coefficients for slip-slip interaction for each interaction type and instance + + real(pReal), dimension(:,:,:), allocatable, private :: & + minDipoleHeightPerSlipFamily, & !< minimum stable edge/screw dipole height for each family and instance + minDipoleHeight, & !< minimum stable edge/screw dipole height for each slip system and instance + peierlsStressPerSlipFamily, & !< Peierls stress (edge and screw) + peierlsStress, & !< Peierls stress (edge and screw) + forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance + forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance + interactionMatrixSlipSlip !< interaction matrix of the different slip systems for each instance + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + lattice2slip, & !< orthogonal transformation matrix from lattice coordinate system to slip coordinate system (passive rotation !!!) + rhoDotEdgeJogsOutput, & + sourceProbability + + real(pReal), dimension(:,:,:,:,:), allocatable, private :: & + rhoDotFluxOutput, & + rhoDotMultiplicationOutput, & + rhoDotSingle2DipoleGlideOutput, & + rhoDotAthermalAnnihilationOutput, & + rhoDotThermalAnnihilationOutput, & + nonSchmidProjection !< combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) + + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + compatibility !< slip system compatibility between me and my neighbors + + real(pReal), dimension(:,:), allocatable, private :: & + nonSchmidCoeff + + logical, dimension(:), allocatable, private :: & + shortRangeStressCorrection, & !< flag indicating the use of the short range stress correction by a excess density gradient term + probabilisticMultiplication + + enum, bind(c) + enumerator :: undefined_ID, & + rho_ID, & + delta_ID, & + rho_edge_ID, & + rho_screw_ID, & + rho_sgl_ID, & + delta_sgl_ID, & + rho_sgl_edge_ID, & + rho_sgl_edge_pos_ID, & + rho_sgl_edge_neg_ID, & + rho_sgl_screw_ID, & + rho_sgl_screw_pos_ID, & + rho_sgl_screw_neg_ID, & + rho_sgl_mobile_ID, & + rho_sgl_edge_mobile_ID, & + rho_sgl_edge_pos_mobile_ID, & + rho_sgl_edge_neg_mobile_ID, & + rho_sgl_screw_mobile_ID, & + rho_sgl_screw_pos_mobile_ID, & + rho_sgl_screw_neg_mobile_ID, & + rho_sgl_immobile_ID, & + rho_sgl_edge_immobile_ID, & + rho_sgl_edge_pos_immobile_ID, & + rho_sgl_edge_neg_immobile_ID, & + rho_sgl_screw_immobile_ID, & + rho_sgl_screw_pos_immobile_ID, & + rho_sgl_screw_neg_immobile_ID, & + rho_dip_ID, & + delta_dip_ID, & + rho_dip_edge_ID, & + rho_dip_screw_ID, & + excess_rho_ID, & + excess_rho_edge_ID, & + excess_rho_screw_ID, & + rho_forest_ID, & + shearrate_ID, & + resolvedstress_ID, & + resolvedstress_external_ID, & + resolvedstress_back_ID, & + resistance_ID, & + rho_dot_ID, & + rho_dot_sgl_ID, & + rho_dot_sgl_mobile_ID, & + rho_dot_dip_ID, & + rho_dot_gen_ID, & + rho_dot_gen_edge_ID, & + rho_dot_gen_screw_ID, & + rho_dot_sgl2dip_ID, & + rho_dot_sgl2dip_edge_ID, & + rho_dot_sgl2dip_screw_ID, & + rho_dot_ann_ath_ID, & + rho_dot_ann_the_ID, & + rho_dot_ann_the_edge_ID, & + rho_dot_ann_the_screw_ID, & + rho_dot_edgejogs_ID, & + rho_dot_flux_ID, & + rho_dot_flux_mobile_ID, & + rho_dot_flux_edge_ID, & + rho_dot_flux_screw_ID, & + velocity_edge_pos_ID, & + velocity_edge_neg_ID, & + velocity_screw_pos_ID, & + velocity_screw_neg_ID, & + slipdirectionx_ID, & + slipdirectiony_ID, & + slipdirectionz_ID, & + slipnormalx_ID, & + slipnormaly_ID, & + slipnormalz_ID, & + fluxdensity_edge_posx_ID, & + fluxdensity_edge_posy_ID, & + fluxdensity_edge_posz_ID, & + fluxdensity_edge_negx_ID, & + fluxdensity_edge_negy_ID, & + fluxdensity_edge_negz_ID, & + fluxdensity_screw_posx_ID, & + fluxdensity_screw_posy_ID, & + fluxdensity_screw_posz_ID, & + fluxdensity_screw_negx_ID, & + fluxdensity_screw_negy_ID, & + fluxdensity_screw_negz_ID, & + maximumdipoleheight_edge_ID, & + maximumdipoleheight_screw_ID, & + accumulatedshear_ID, & + dislocationstress_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_nonlocal_outputID !< ID of each post result output + + public :: & + plastic_nonlocal_init, & + plastic_nonlocal_stateInit, & + plastic_nonlocal_aTolState, & + plastic_nonlocal_microstructure, & + plastic_nonlocal_LpAndItsTangent, & + plastic_nonlocal_dotState, & + plastic_nonlocal_deltaState, & + plastic_nonlocal_updateCompatibility, & + plastic_nonlocal_postResults + + private :: & + plastic_nonlocal_kinetics, & + plastic_nonlocal_dislocationstress + + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_init(fileUnit) +use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) +use math, only: math_Mandel3333to66, & + math_Voigt66to3333, & + math_mul3x3, & + math_transpose33 +use IO, only: IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF +use debug, only: debug_level, & + debug_constitutive, & + debug_levelBasic +use mesh, only: mesh_NcpElems, & + mesh_maxNips, & + mesh_maxNipNeighbors +use material, only: phase_plasticity, & + homogenization_maxNgrains, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_NONLOCAL_label, & + PLASTICITY_NONLOCAL_ID, & + plasticState, & + MATERIAL_partPhase ,& + material_phase +use lattice +use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + +implicit none +integer(pInt), intent(in) :: fileUnit + +!*** local variables +integer(pInt), allocatable, dimension(:) :: chunkPos +integer(pInt) :: phase, & + maxNinstances, & + maxTotalNslip, & + f, & ! index of my slip family + instance, & ! index of my instance of this plasticity + l, & + ns, & ! short notation for total number of active slip systems for the current instance + o, & ! index of my output + s, & ! index of my slip system + s1, & ! index of my slip system + s2, & ! index of my slip system + it, & ! index of my interaction type + t, & ! index of dislocation type + c, & ! index of dislocation character + Nchunks_SlipSlip = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, & + Nchunks_nonSchmid = 0_pInt, & + mySize = 0_pInt ! to suppress warnings, safe as init is called only once + character(len=65536) :: & + tag = '', & + line = '' + + integer(pInt) :: sizeState, sizeDotState,sizeDependentState, sizeDeltaState + + + integer(pInt) :: NofMyPhase + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONLOCAL_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) + if (maxNinstances == 0) return ! we don't have to do anything if there's no instance for this constitutive law + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstances + +!*** memory allocation for global variables + +allocate(plastic_nonlocal_sizeDotState(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizeDependentState(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizeState(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizePostResults(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizePostResult(maxval(phase_Noutput), maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_Noutput(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_output(maxval(phase_Noutput), maxNinstances)) + plastic_nonlocal_output = '' +allocate(plastic_nonlocal_outputID(maxval(phase_Noutput), maxNinstances), source=undefined_ID) +allocate(Nslip(lattice_maxNslipFamily,maxNinstances), source=0_pInt) +allocate(slipFamily(lattice_maxNslip,maxNinstances), source=0_pInt) +allocate(slipSystemLattice(lattice_maxNslip,maxNinstances), source=0_pInt) +allocate(totalNslip(maxNinstances), source=0_pInt) +allocate(atomicVolume(maxNinstances), source=0.0_pReal) +allocate(Dsd0(maxNinstances), source=-1.0_pReal) +allocate(selfDiffusionEnergy(maxNinstances), source=0.0_pReal) +allocate(aTolRho(maxNinstances), source=0.0_pReal) +allocate(aTolShear(maxNinstances), source=0.0_pReal) +allocate(significantRho(maxNinstances), source=0.0_pReal) +allocate(significantN(maxNinstances), source=0.0_pReal) +allocate(cutoffRadius(maxNinstances), source=-1.0_pReal) +allocate(doublekinkwidth(maxNinstances), source=0.0_pReal) +allocate(solidSolutionEnergy(maxNinstances), source=0.0_pReal) +allocate(solidSolutionSize(maxNinstances), source=0.0_pReal) +allocate(solidSolutionConcentration(maxNinstances), source=0.0_pReal) +allocate(pParam(maxNinstances), source=1.0_pReal) +allocate(qParam(maxNinstances), source=1.0_pReal) +allocate(viscosity(maxNinstances), source=0.0_pReal) +allocate(fattack(maxNinstances), source=0.0_pReal) +allocate(rhoSglScatter(maxNinstances), source=0.0_pReal) +allocate(rhoSglRandom(maxNinstances), source=0.0_pReal) +allocate(rhoSglRandomBinning(maxNinstances), source=1.0_pReal) +allocate(surfaceTransmissivity(maxNinstances), source=1.0_pReal) +allocate(grainboundaryTransmissivity(maxNinstances), source=-1.0_pReal) +allocate(CFLfactor(maxNinstances), source=2.0_pReal) +allocate(fEdgeMultiplication(maxNinstances), source=0.0_pReal) +allocate(linetensionEffect(maxNinstances), source=0.0_pReal) +allocate(edgeJogFactor(maxNinstances), source=1.0_pReal) +allocate(shortRangeStressCorrection(maxNinstances), source=.false.) +allocate(probabilisticMultiplication(maxNinstances), source=.false.) + +allocate(rhoSglEdgePos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoSglEdgeNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoSglScrewPos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoSglScrewNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoDipEdge0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoDipScrew0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) +allocate(lambda0PerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) +allocate(interactionSlipSlip(lattice_maxNinteraction,maxNinstances), source=0.0_pReal) +allocate(minDipoleHeightPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=-1.0_pReal) +allocate(peierlsStressPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=0.0_pReal) +allocate(nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstances), source=0.0_pReal) + + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through phases of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_SlipSlip = maxval(lattice_InteractionSlipSlip(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + endif + cycle + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then ! one of my phases. do not short-circuit here (.and. with next if statement). It's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('rho') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('delta') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('delta_sgl') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_sgl_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_pos_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_neg_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_pos_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_neg_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_pos_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_neg_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_pos_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_neg_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('delta_dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dip_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dip_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('excess_rho') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('excess_rho_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('excess_rho_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_forest') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_forest_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = shearrate_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_external') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_external_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_back') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_back_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resistance_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_gen') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_gen_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_gen_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl2dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl2dip_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl2dip_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_ath') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_ath_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_the') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_the_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_the_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_edgejogs') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_edgejogs_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_edge_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_edge_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_screw_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_screw_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipdirection.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipdirection.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectiony_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipdirection.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipnormal.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipnormal.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormaly_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipnormal.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_pos.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_pos.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_pos.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_neg.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_neg.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_neg.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_pos.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_pos.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_pos.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_neg.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_neg.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_neg.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('maximumdipoleheight_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('maximumdipoleheight_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear','accumulated_shear') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = accumulatedshear_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('dislocationstress') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = dislocationstress_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + case ('nslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do f = 1_pInt, Nchunks_SlipFamilies + Nslip(f,instance) = IO_intValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosgledgepos0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglEdgePos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosgledgeneg0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglEdgeNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosglscrewpos0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglScrewPos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosglscrewneg0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglScrewNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhodipedge0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoDipEdge0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhodipscrew0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoDipScrew0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('lambda0') + do f = 1_pInt, Nchunks_SlipFamilies + lambda0PerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('burgers') + do f = 1_pInt, Nchunks_SlipFamilies + burgersPerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('cutoffradius','r') + cutoffRadius(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('minimumdipoleheightedge','ddipminedge') + do f = 1_pInt, Nchunks_SlipFamilies + minDipoleHeightPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('minimumdipoleheightscrew','ddipminscrew') + do f = 1_pInt, Nchunks_SlipFamilies + minDipoleHeightPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('atomicvolume') + atomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('selfdiffusionprefactor','dsd0') + Dsd0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('selfdiffusionenergy','qsd') + selfDiffusionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('atol_rho','atol_density','absolutetolerancedensity','absolutetolerance_density') + aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('atol_shear','atol_plasticshear','atol_accumulatedshear','absolutetoleranceshear','absolutetolerance_shear') + aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('significantrho','significant_rho','significantdensity','significant_density') + significantRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('significantn','significant_n','significantdislocations','significant_dislcations') + significantN(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('interaction_slipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') + do it = 1_pInt,Nchunks_SlipSlip + interactionSlipSlip(it,instance) = IO_floatValue(line,chunkPos,1_pInt+it) + enddo + case('linetension','linetensioneffect','linetension_effect') + linetensionEffect(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('edgejog','edgejogs','edgejogeffect','edgejog_effect') + edgeJogFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('peierlsstressedge','peierlsstress_edge') + do f = 1_pInt, Nchunks_SlipFamilies + peierlsStressPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('peierlsstressscrew','peierlsstress_screw') + do f = 1_pInt, Nchunks_SlipFamilies + peierlsStressPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('doublekinkwidth') + doublekinkwidth(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('solidsolutionenergy') + solidSolutionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('solidsolutionsize') + solidSolutionSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('solidsolutionconcentration') + solidSolutionConcentration(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('p') + pParam(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('q') + qParam(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('viscosity','glideviscosity') + viscosity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('attackfrequency','fattack') + fattack(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('rhosglscatter') + rhoSglScatter(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('rhosglrandom') + rhoSglRandom(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('rhosglrandombinning') + rhoSglRandomBinning(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('surfacetransmissivity') + surfaceTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('grainboundarytransmissivity') + grainboundaryTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('cflfactor') + CFLfactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('fedgemultiplication','edgemultiplicationfactor','edgemultiplication') + fEdgeMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('shortrangestresscorrection') + shortRangeStressCorrection(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_label//')') + do f = 1_pInt,Nchunks_nonSchmid + nonSchmidCoeff(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('probabilisticmultiplication','randomsources','randommultiplication','discretesources') + probabilisticMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then + instance = phase_plasticityInstance(phase) + if (sum(Nslip(:,instance)) <= 0_pInt) & + call IO_error(211_pInt,ext_msg='Nslip ('//PLASTICITY_NONLOCAL_label//')') + do o = 1_pInt,maxval(phase_Noutput) + if(len(plastic_nonlocal_output(o,instance)) > 64_pInt) & + call IO_error(666_pInt) + enddo + do f = 1_pInt,lattice_maxNslipFamily + if (Nslip(f,instance) > 0_pInt) then + if (rhoSglEdgePos0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglEdgePos0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglEdgeNeg0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglEdgeNeg0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglScrewPos0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglScrewPos0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglScrewNeg0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglScrewNeg0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoDipEdge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoDipEdge0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoDipScrew0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoDipScrew0 ('//PLASTICITY_NONLOCAL_label//')') + if (burgersPerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='Burgers ('//PLASTICITY_NONLOCAL_label//')') + if (lambda0PerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='lambda0 ('//PLASTICITY_NONLOCAL_label//')') + if (minDipoleHeightPerSlipFamily(f,1,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='minimumDipoleHeightEdge ('//PLASTICITY_NONLOCAL_label//')') + if (minDipoleHeightPerSlipFamily(f,2,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='minimumDipoleHeightScrew ('//PLASTICITY_NONLOCAL_label//')') + if (peierlsStressPerSlipFamily(f,1,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='peierlsStressEdge ('//PLASTICITY_NONLOCAL_label//')') + if (peierlsStressPerSlipFamily(f,2,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='peierlsStressScrew ('//PLASTICITY_NONLOCAL_label//')') + endif + enddo + if (any(interactionSlipSlip(1:maxval(lattice_interactionSlipSlip(:,:,phase)),instance) < 0.0_pReal)) & + call IO_error(211_pInt,ext_msg='interaction_SlipSlip ('//PLASTICITY_NONLOCAL_label//')') + if (linetensionEffect(instance) < 0.0_pReal .or. linetensionEffect(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='linetension ('//PLASTICITY_NONLOCAL_label//')') + if (edgeJogFactor(instance) < 0.0_pReal .or. edgeJogFactor(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='edgejog ('//PLASTICITY_NONLOCAL_label//')') + if (cutoffRadius(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='r ('//PLASTICITY_NONLOCAL_label//')') + if (atomicVolume(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='atomicVolume ('//PLASTICITY_NONLOCAL_label//')') + if (Dsd0(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='selfDiffusionPrefactor ('//PLASTICITY_NONLOCAL_label//')') + if (selfDiffusionEnergy(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='selfDiffusionEnergy ('//PLASTICITY_NONLOCAL_label//')') + if (aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='aTol_rho ('//PLASTICITY_NONLOCAL_label//')') + if (aTolShear(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='aTol_shear ('//PLASTICITY_NONLOCAL_label//')') + if (significantRho(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='significantRho ('//PLASTICITY_NONLOCAL_label//')') + if (significantN(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='significantN ('//PLASTICITY_NONLOCAL_label//')') + if (doublekinkwidth(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='doublekinkwidth ('//PLASTICITY_NONLOCAL_label//')') + if (solidSolutionEnergy(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='solidSolutionEnergy ('//PLASTICITY_NONLOCAL_label//')') + if (solidSolutionSize(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='solidSolutionSize ('//PLASTICITY_NONLOCAL_label//')') + if (solidSolutionConcentration(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='solidSolutionConcentration ('//PLASTICITY_NONLOCAL_label//')') + if (pParam(instance) <= 0.0_pReal .or. pParam(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='p ('//PLASTICITY_NONLOCAL_label//')') + if (qParam(instance) < 1.0_pReal .or. qParam(instance) > 2.0_pReal) & + call IO_error(211_pInt,ext_msg='q ('//PLASTICITY_NONLOCAL_label//')') + if (viscosity(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='viscosity ('//PLASTICITY_NONLOCAL_label//')') + if (fattack(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='attackFrequency ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglScatter(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglScatter ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglRandom(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglRandom ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglRandomBinning(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglRandomBinning ('//PLASTICITY_NONLOCAL_label//')') + if (surfaceTransmissivity(instance) < 0.0_pReal .or. surfaceTransmissivity(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='surfaceTransmissivity ('//PLASTICITY_NONLOCAL_label//')') + if (grainboundaryTransmissivity(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='grainboundaryTransmissivity ('//PLASTICITY_NONLOCAL_label//')') + if (CFLfactor(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='CFLfactor ('//PLASTICITY_NONLOCAL_label//')') + if (fEdgeMultiplication(instance) < 0.0_pReal .or. fEdgeMultiplication(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='edgemultiplicationfactor ('//PLASTICITY_NONLOCAL_label//')') + + + !*** determine total number of active slip systems + Nslip(1:lattice_maxNslipFamily,instance) = min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase), & + Nslip(1:lattice_maxNslipFamily,instance) ) ! we can't use more slip systems per family than specified in lattice + totalNslip(instance) = sum(Nslip(1:lattice_maxNslipFamily,instance)) + endif myPhase +enddo sanityChecks + + +!*** allocation of variables whose size depends on the total number of active slip systems + +maxTotalNslip = maxval(totalNslip) + +allocate(iRhoU(maxTotalNslip,4,maxNinstances), source=0_pInt) +allocate(iRhoB(maxTotalNslip,4,maxNinstances), source=0_pInt) +allocate(iRhoD(maxTotalNslip,2,maxNinstances), source=0_pInt) +allocate(iV(maxTotalNslip,4,maxNinstances), source=0_pInt) +allocate(iD(maxTotalNslip,2,maxNinstances), source=0_pInt) +allocate(iGamma(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(iRhoF(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(iTauF(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(iTauB(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(burgers(maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(lambda0(maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(minDipoleHeight(maxTotalNslip,2,maxNinstances), source=-1.0_pReal) +allocate(forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(lattice2slip(1:3, 1:3, maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(sourceProbability(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=2.0_pReal) + +allocate(rhoDotFluxOutput(maxTotalNslip,8,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotMultiplicationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotSingle2DipoleGlideOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotAthermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotThermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotEdgeJogsOutput(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) + +allocate(compatibility(2,maxTotalNslip,maxTotalNslip,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(peierlsStress(maxTotalNslip,2,maxNinstances), source=0.0_pReal) +allocate(colinearSystem(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + NofMyPhase=count(material_phase==phase) + myPhase2: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID .and. NofMyPhase/=0) then + instance = phase_plasticityInstance(phase) + !*** Inverse lookup of my slip system family and the slip system in lattice + + l = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily + do s = 1_pInt,Nslip(f,instance) + l = l + 1_pInt + slipFamily(l,instance) = f + slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt, phase)) + s + enddo; enddo + + + !*** determine size of state array + + ns = totalNslip(instance) + + sizeDotState = int(size(BASICSTATES),pInt) * ns + sizeDependentState = int(size(DEPENDENTSTATES),pInt) * ns + sizeState = sizeDotState + sizeDependentState & + + int(size(OTHERSTATES),pInt) * ns + sizeDeltaState = sizeDotState + + !*** determine indices to state array + + l = 0_pInt + do t = 1_pInt,4_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iRhoU(s,t,instance) = l + enddo + enddo + do t = 1_pInt,4_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iRhoB(s,t,instance) = l + enddo + enddo + do c = 1_pInt,2_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iRhoD(s,c,instance) = l + enddo + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iGamma(s,instance) = l + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iRhoF(s,instance) = l + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iTauF(s,instance) = l + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iTauB(s,instance) = l + enddo + do t = 1_pInt,4_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iV(s,t,instance) = l + enddo + enddo + do c = 1_pInt,2_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iD(s,c,instance) = l + enddo + enddo + if (iD(ns,2,instance) /= sizeState) & ! check if last index is equal to size of state + call IO_error(0_pInt, ext_msg = 'state indices not properly set ('//PLASTICITY_NONLOCAL_label//')') + + + !*** determine size of postResults array + + outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) + select case(plastic_nonlocal_outputID(o,instance)) + case( rho_ID, & + delta_ID, & + rho_edge_ID, & + rho_screw_ID, & + rho_sgl_ID, & + delta_sgl_ID, & + rho_sgl_edge_ID, & + rho_sgl_edge_pos_ID, & + rho_sgl_edge_neg_ID, & + rho_sgl_screw_ID, & + rho_sgl_screw_pos_ID, & + rho_sgl_screw_neg_ID, & + rho_sgl_mobile_ID, & + rho_sgl_edge_mobile_ID, & + rho_sgl_edge_pos_mobile_ID, & + rho_sgl_edge_neg_mobile_ID, & + rho_sgl_screw_mobile_ID, & + rho_sgl_screw_pos_mobile_ID, & + rho_sgl_screw_neg_mobile_ID, & + rho_sgl_immobile_ID, & + rho_sgl_edge_immobile_ID, & + rho_sgl_edge_pos_immobile_ID, & + rho_sgl_edge_neg_immobile_ID, & + rho_sgl_screw_immobile_ID, & + rho_sgl_screw_pos_immobile_ID, & + rho_sgl_screw_neg_immobile_ID, & + rho_dip_ID, & + delta_dip_ID, & + rho_dip_edge_ID, & + rho_dip_screw_ID, & + excess_rho_ID, & + excess_rho_edge_ID, & + excess_rho_screw_ID, & + rho_forest_ID, & + shearrate_ID, & + resolvedstress_ID, & + resolvedstress_external_ID, & + resolvedstress_back_ID, & + resistance_ID, & + rho_dot_ID, & + rho_dot_sgl_ID, & + rho_dot_sgl_mobile_ID, & + rho_dot_dip_ID, & + rho_dot_gen_ID, & + rho_dot_gen_edge_ID, & + rho_dot_gen_screw_ID, & + rho_dot_sgl2dip_ID, & + rho_dot_sgl2dip_edge_ID, & + rho_dot_sgl2dip_screw_ID, & + rho_dot_ann_ath_ID, & + rho_dot_ann_the_ID, & + rho_dot_ann_the_edge_ID, & + rho_dot_ann_the_screw_ID, & + rho_dot_edgejogs_ID, & + rho_dot_flux_ID, & + rho_dot_flux_mobile_ID, & + rho_dot_flux_edge_ID, & + rho_dot_flux_screw_ID, & + velocity_edge_pos_ID, & + velocity_edge_neg_ID, & + velocity_screw_pos_ID, & + velocity_screw_neg_ID, & + slipdirectionx_ID, & + slipdirectiony_ID, & + slipdirectionz_ID, & + slipnormalx_ID, & + slipnormaly_ID, & + slipnormalz_ID, & + fluxdensity_edge_posx_ID, & + fluxdensity_edge_posy_ID, & + fluxdensity_edge_posz_ID, & + fluxdensity_edge_negx_ID, & + fluxdensity_edge_negy_ID, & + fluxdensity_edge_negz_ID, & + fluxdensity_screw_posx_ID, & + fluxdensity_screw_posy_ID, & + fluxdensity_screw_posz_ID, & + fluxdensity_screw_negx_ID, & + fluxdensity_screw_negy_ID, & + fluxdensity_screw_negz_ID, & + maximumdipoleheight_edge_ID, & + maximumdipoleheight_screw_ID, & + accumulatedshear_ID ) + mySize = totalNslip(instance) + case(dislocationstress_ID) + mySize = 6_pInt + case default + end select + + if (mySize > 0_pInt) then ! any meaningful output found + plastic_nonlocal_sizePostResult(o,instance) = mySize + plastic_nonlocal_sizePostResults(instance) = plastic_nonlocal_sizePostResults(instance) + mySize + endif + enddo outputsLoop + + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_nonlocal_sizePostResults(instance) + plasticState(phase)%nonlocal = .true. + plasticState(phase)%nSlip = totalNslip(instance) + plasticState(phase)%nTwin = 0_pInt + plasticState(phase)%nTrans= 0_pInt + allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) + + do s1 = 1_pInt,ns + f = slipFamily(s1,instance) + + !*** burgers vector, mean free path prefactor and minimum dipole distance for each slip system + + burgers(s1,instance) = burgersPerSlipFamily(f,instance) + lambda0(s1,instance) = lambda0PerSlipFamily(f,instance) + minDipoleHeight(s1,1:2,instance) = minDipoleHeightPerSlipFamily(f,1:2,instance) + peierlsStress(s1,1:2,instance) = peierlsStressPerSlipFamily(f,1:2,instance) + + do s2 = 1_pInt,ns + + !*** calculation of forest projections for edge and screw dislocations. s2 acts as forest for s1 + + forestProjectionEdge(s1,s2,instance) & + = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & + lattice_st(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of edge dislocations is the projection of (t = b x n) onto the slip normal of the respective slip plane + + forestProjectionScrew(s1,s2,instance) & + = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & + lattice_sd(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of screw dislocations is the projection of b onto the slip normal of the respective splip plane + + !*** calculation of interaction matrices + + interactionMatrixSlipSlip(s1,s2,instance) & + = interactionSlipSlip(lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & + slipSystemLattice(s2,instance), & + phase), instance) + + !*** colinear slip system (only makes sense for fcc like it is defined here) + + if (lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & + slipSystemLattice(s2,instance), & + phase) == 3_pInt) then + colinearSystem(s1,instance) = s2 + endif + + enddo + + !*** rotation matrix from lattice configuration to slip system + + lattice2slip(1:3,1:3,s1,instance) & + = math_transpose33( reshape([ lattice_sd(1:3, slipSystemLattice(s1,instance), phase), & + -lattice_st(1:3, slipSystemLattice(s1,instance), phase), & + lattice_sn(1:3, slipSystemLattice(s1,instance), phase)], [3,3])) + enddo + + + !*** combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) + !* four types t: + !* 1) positive screw at positive resolved stress + !* 2) positive screw at negative resolved stress + !* 3) negative screw at positive resolved stress + !* 4) negative screw at negative resolved stress + + do s = 1_pInt,ns + do l = 1_pInt,lattice_NnonSchmid(phase) + nonSchmidProjection(1:3,1:3,1,s,instance) = nonSchmidProjection(1:3,1:3,1,s,instance) & + + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l,slipSystemLattice(s,instance),phase) + nonSchmidProjection(1:3,1:3,2,s,instance) = nonSchmidProjection(1:3,1:3,2,s,instance) & + + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l+1,slipSystemLattice(s,instance),phase) + enddo + nonSchmidProjection(1:3,1:3,3,s,instance) = -nonSchmidProjection(1:3,1:3,2,s,instance) + nonSchmidProjection(1:3,1:3,4,s,instance) = -nonSchmidProjection(1:3,1:3,1,s,instance) + forall (t = 1:4) & + nonSchmidProjection(1:3,1:3,t,s,instance) = nonSchmidProjection(1:3,1:3,t,s,instance) & + + lattice_Sslip(1:3,1:3,1,slipSystemLattice(s,instance),phase) + enddo + + call plastic_nonlocal_aTolState(phase,instance) + endif myPhase2 + + enddo initializeInstances + +end subroutine plastic_nonlocal_init + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- + +subroutine plastic_nonlocal_stateInit() +use IO, only: IO_error +use lattice, only: lattice_maxNslipFamily +use math, only: math_sampleGaussVar +use mesh, only: mesh_ipVolume, & + mesh_NcpElems, & + mesh_element, & + FE_Nips, & + FE_geomtype +use material, only: material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticity ,& + PLASTICITY_NONLOCAL_ID +implicit none + +integer(pInt) :: e, & + i, & + ns, & ! short notation for total number of active slip systems + f, & ! index of lattice family + from, & + upto, & + s, & ! index of slip system + t, & + j, & + instance, & + maxNinstances +real(pReal), dimension(2) :: noise +real(pReal), dimension(4) :: rnd +real(pReal) meanDensity, & + totalVolume, & + densityBinning, & + minimumIpVolume + +maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) + +do instance = 1_pInt,maxNinstances + ns = totalNslip(instance) + + ! randomly distribute dislocation segments on random slip system and of random type in the volume + if (rhoSglRandom(instance) > 0.0_pReal) then + + ! get the total volume of the instance + + minimumIpVolume = huge(1.0_pReal) + totalVolume = 0.0_pReal + do e = 1_pInt,mesh_NcpElems + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & + .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then + totalVolume = totalVolume + mesh_ipVolume(i,e) + minimumIpVolume = min(minimumIpVolume, mesh_ipVolume(i,e)) + endif + enddo + enddo + densityBinning = rhoSglRandomBinning(instance) / minimumIpVolume ** (2.0_pReal / 3.0_pReal) + + ! subsequently fill random ips with dislocation segments until we reach the desired overall density + + meanDensity = 0.0_pReal + do while(meanDensity < rhoSglRandom(instance)) + call random_number(rnd) + e = nint(rnd(1)*real(mesh_NcpElems,pReal)+0.5_pReal,pInt) + i = nint(rnd(2)*real(FE_Nips(FE_geomtype(mesh_element(2,e))),pReal)+0.5_pReal,pInt) + if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & + .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then + s = nint(rnd(3)*real(ns,pReal)+0.5_pReal,pInt) + t = nint(rnd(4)*4.0_pReal+0.5_pReal,pInt) + meanDensity = meanDensity + densityBinning * mesh_ipVolume(i,e) / totalVolume + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) = & + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) & + + densityBinning + endif + enddo + ! homogeneous distribution of density with some noise + else + do e = 1_pInt,mesh_NcpElems + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & + .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then + do f = 1_pInt,lattice_maxNslipFamily + from = 1_pInt + sum(Nslip(1:f-1_pInt,instance)) + upto = sum(Nslip(1:f,instance)) + do s = from,upto + do j = 1_pInt,2_pInt + noise(j) = math_sampleGaussVar(0.0_pReal, rhoSglScatter(instance)) + enddo + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,1,instance),phasememberAt(1,i,e)) = & + rhoSglEdgePos0(f,instance) + noise(1) + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,2,instance),phasememberAt(1,i,e)) = & + rhoSglEdgeNeg0(f,instance) + noise(1) + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,3,instance),phasememberAt(1,i,e)) = & + rhoSglScrewPos0(f,instance) + noise(2) + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,4,instance),phasememberAt(1,i,e)) = & + rhoSglScrewNeg0(f,instance) + noise(2) + enddo + plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,1,instance),phasememberAt(1,i,e)) = & + rhoDipEdge0(f,instance) + plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,2,instance),phasememberAt(1,i,e)) = & + rhoDipScrew0(f,instance) + enddo + endif + enddo + enddo + endif +enddo + +end subroutine plastic_nonlocal_stateInit + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + integer(pInt) :: & + ns, & + t, c + + ns = totalNslip(instance) + forall (t = 1_pInt:4_pInt) + plasticState(ph)%aTolState(iRhoU(1:ns,t,instance)) = aTolRho(instance) + plasticState(ph)%aTolState(iRhoB(1:ns,t,instance)) = aTolRho(instance) + end forall + forall (c = 1_pInt:2_pInt) & + plasticState(ph)%aTolState(iRhoD(1:ns,c,instance)) = aTolRho(instance) + + plasticState(ph)%aTolState(iGamma(1:ns,instance)) = aTolShear(instance) + +end subroutine plastic_nonlocal_aTolState + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates quantities characterizing the microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_microstructure(Fe, Fp, ip, el) +use IO, only: & + IO_error +use math, only: & + pi, & + math_mul33x3, & + math_mul3x3, & + math_inv33, & + math_transpose33 +use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use mesh, only: & + mesh_element, & + mesh_ipNeighborhood, & + mesh_ipCoordinates, & + mesh_ipVolume, & + mesh_ipAreaNormal, & + mesh_ipArea, & + FE_NipNeighbors, & + mesh_maxNipNeighbors, & + FE_geomtype, & + FE_celltype +use material, only: & + material_phase, & + phase_localPlasticity, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance +use lattice, only: & + lattice_sd, & + lattice_st, & + lattice_mu, & + lattice_nu, & + lattice_structure, & + LATTICE_bcc_ID, & + LATTICE_fcc_ID + +implicit none + +integer(pInt), intent(in) :: ip, & ! current integration point + el ! current element +real(pReal), dimension(3,3), intent(in) :: & + Fe, & ! elastic deformation gradient + Fp ! elastic deformation gradient + + integer(pInt) :: & + ph, & !< phase + of, & !< offset + np, & !< neighbor phase + no !< nieghbor offset + +integer(pInt) neighbor_el, & ! element number of neighboring material point + neighbor_ip, & ! integration point of neighboring material point + instance, & ! my instance of this plasticity + neighbor_instance, & ! instance of this plasticity of neighboring material point + neighbor_phase, & + ns, & ! total number of active slip systems at my material point + neighbor_ns, & ! total number of active slip systems at neighboring material point + c, & ! index of dilsocation character (edge, screw) + s, & ! slip system index + t, & ! index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) + dir, & + n, & + nRealNeighbors ! number of really existing neighbors +integer(pInt), dimension(2) :: neighbors +real(pReal) FVsize, & + correction, & + myRhoForest +real(pReal), dimension(2) :: rhoExcessGradient, & + rhoExcessGradient_over_rho, & + rhoTotal +real(pReal), dimension(3) :: rhoExcessDifferences, & + normal_latticeConf +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoForest, & ! forest dislocation density + tauBack, & ! back stress from pileup on same slip system + tauThreshold ! threshold shear stress +real(pReal), dimension(3,3) :: invFe, & ! inverse of elastic deformation gradient + invFp, & ! inverse of plastic deformation gradient + connections, & + invConnections +real(pReal), dimension(3,mesh_maxNipNeighbors) :: & + connection_latticeConf +real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoExcess +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + rhoDip ! dipole dislocation density (edge, screw) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))), & + totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + myInteractionMatrix ! corrected slip interaction matrix +real(pReal), dimension(2,maxval(totalNslip),mesh_maxNipNeighbors) :: & + neighbor_rhoExcess, & ! excess density at neighboring material point + neighbor_rhoTotal ! total density at neighboring material point +real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + m ! direction of dislocation motion + +ph = phaseAt(1,ip,el) +of = phasememberAt(1,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + +!*** get basic states + + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & + rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities + +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal +where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoDip) < significantRho(instance)) & + rhoDip = 0.0_pReal + +!*** calculate the forest dislocation density +!*** (= projection of screw and edge dislocations) + +forall (s = 1_pInt:ns) & + rhoForest(s) = dot_product((sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1)), & + forestProjectionEdge(s,1:ns,instance)) & + + dot_product((sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2)), & + forestProjectionScrew(s,1:ns,instance)) + + +!*** calculate the threshold shear stress for dislocation slip +!*** coefficients are corrected for the line tension effect +!*** (see Kubin,Devincre,Hoc; 2008; Modeling dislocation storage rates and mean free paths in face-centered cubic crystals) + +myInteractionMatrix = 0.0_pReal +myInteractionMatrix(1:ns,1:ns) = interactionMatrixSlipSlip(1:ns,1:ns,instance) +if (lattice_structure(ph) == LATTICE_bcc_ID .or. lattice_structure(ph) == LATTICE_fcc_ID) then ! only fcc and bcc + do s = 1_pInt,ns + myRhoForest = max(rhoForest(s),significantRho(instance)) + correction = ( 1.0_pReal - linetensionEffect(instance) & + + linetensionEffect(instance) & + * log(0.35_pReal * burgers(s,instance) * sqrt(myRhoForest)) & + / log(0.35_pReal * burgers(s,instance) * 1e6_pReal)) ** 2.0_pReal + myInteractionMatrix(s,1:ns) = correction * myInteractionMatrix(s,1:ns) + enddo +endif +forall (s = 1_pInt:ns) & + tauThreshold(s) = lattice_mu(ph) * burgers(s,instance) & + * sqrt(dot_product((sum(abs(rhoSgl),2) + sum(abs(rhoDip),2)), myInteractionMatrix(s,1:ns))) + + +!*** calculate the dislocation stress of the neighboring excess dislocation densities +!*** zero for material points of local plasticity + +tauBack = 0.0_pReal + +if (.not. phase_localPlasticity(ph) .and. shortRangeStressCorrection(instance)) then + invFe = math_inv33(Fe) + invFp = math_inv33(Fp) + rhoExcess(1,1:ns) = rhoSgl(1:ns,1) - rhoSgl(1:ns,2) + rhoExcess(2,1:ns) = rhoSgl(1:ns,3) - rhoSgl(1:ns,4) + FVsize = mesh_ipVolume(ip,el) ** (1.0_pReal/3.0_pReal) + + !* loop through my neighborhood and get the connection vectors (in lattice frame) and the excess densities + + nRealNeighbors = 0_pInt + neighbor_rhoTotal = 0.0_pReal + do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) + neighbor_el = mesh_ipNeighborhood(1,n,ip,el) + neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) + np = phaseAt(1,neighbor_ip,neighbor_el) + no = phasememberAt(1,neighbor_ip,neighbor_el) + if (neighbor_el > 0 .and. neighbor_ip > 0) then + neighbor_phase = material_phase(1,neighbor_ip,neighbor_el) + neighbor_instance = phase_plasticityInstance(neighbor_phase) + neighbor_ns = totalNslip(neighbor_instance) + if (.not. phase_localPlasticity(neighbor_phase) & + .and. neighbor_instance == instance) then ! same instance should be same structure + if (neighbor_ns == ns) then + nRealNeighbors = nRealNeighbors + 1_pInt + forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + + neighbor_rhoExcess(c,s,n) = & + max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles + - max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) ! negative mobiles + neighbor_rhoTotal(c,s,n) = & + max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles + + max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) & ! negative mobiles + + abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads + + abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance), no)) & ! negative deads + + max(plasticState(np)%state(iRhoD(s,c,neighbor_instance), no), 0.0_pReal) ! dipoles + + endforall + connection_latticeConf(1:3,n) = & + math_mul33x3(invFe, mesh_ipCoordinates(1:3,neighbor_ip,neighbor_el) & + - mesh_ipCoordinates(1:3,ip,el)) + normal_latticeConf = math_mul33x3(math_transpose33(invFp), mesh_ipAreaNormal(1:3,n,ip,el)) + if (math_mul3x3(normal_latticeConf,connection_latticeConf(1:3,n)) < 0.0_pReal) then ! neighboring connection points in opposite direction to face normal: must be periodic image + connection_latticeConf(1:3,n) = normal_latticeConf * mesh_ipVolume(ip,el) & + / mesh_ipArea(n,ip,el) ! instead take the surface normal scaled with the diameter of the cell + endif + else + ! different number of active slip systems + call IO_error(-1_pInt,ext_msg='different number of active slip systems in neighboring IPs of same crystal structure') + endif + else + ! local neighbor or different lattice structure or different constitution instance -> use central values instead + connection_latticeConf(1:3,n) = 0.0_pReal + neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess + endif + else + ! free surface -> use central values instead + connection_latticeConf(1:3,n) = 0.0_pReal + neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess + endif + enddo + + + !* loop through the slip systems and calculate the dislocation gradient by + !* 1. interpolation of the excess density in the neighorhood + !* 2. interpolation of the dead dislocation density in the central volume + + m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) + m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) + + do s = 1_pInt,ns + + !* gradient from interpolation of neighboring excess density + + do c = 1_pInt,2_pInt + do dir = 1_pInt,3_pInt + neighbors(1) = 2_pInt * dir - 1_pInt + neighbors(2) = 2_pInt * dir + connections(dir,1:3) = connection_latticeConf(1:3,neighbors(1)) & + - connection_latticeConf(1:3,neighbors(2)) + rhoExcessDifferences(dir) = neighbor_rhoExcess(c,s,neighbors(1)) & + - neighbor_rhoExcess(c,s,neighbors(2)) + enddo + invConnections = math_inv33(connections) + if (all(abs(invConnections) <= tiny(0.0_pReal))) & ! check for failed in version (math_inv33 returns 0) and avoid floating point equality comparison + call IO_error(-1_pInt,ext_msg='back stress calculation: inversion error') + rhoExcessGradient(c) = math_mul3x3(m(1:3,s,c), & + math_mul33x3(invConnections,rhoExcessDifferences)) + enddo + + !* plus gradient from deads + + do t = 1_pInt,4_pInt + c = (t - 1_pInt) / 2_pInt + 1_pInt + rhoExcessGradient(c) = rhoExcessGradient(c) + rhoSgl(s,t+4_pInt) / FVsize + enddo + + !* normalized with the total density + + rhoExcessGradient_over_rho = 0.0_pReal + forall (c = 1_pInt:2_pInt) & + rhoTotal(c) = (sum(abs(rhoSgl(s,[2*c-1,2*c,2*c+3,2*c+4]))) + rhoDip(s,c) & + + sum(neighbor_rhoTotal(c,s,:))) / real(1_pInt + nRealNeighbors,pReal) + forall (c = 1_pInt:2_pInt, rhoTotal(c) > 0.0_pReal) & + rhoExcessGradient_over_rho(c) = rhoExcessGradient(c) / rhoTotal(c) + + !* gives the local stress correction when multiplied with a factor + + tauBack(s) = - lattice_mu(ph) * burgers(s,instance) / (2.0_pReal * pi) & + * (rhoExcessGradient_over_rho(1) / (1.0_pReal - lattice_nu(ph)) & + + rhoExcessGradient_over_rho(2)) + + enddo +endif + + +!*** set dependent states +plasticState(ph)%state(iRhoF(1:ns,instance),of) = rhoForest +plasticState(ph)%state(iTauF(1:ns,instance),of) = tauThreshold +plasticState(ph)%state(iTauB(1:ns,instance),of) = tauBack + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_microstructure at el ip ',el,ip + write(6,'(a,/,12x,12(e10.3,1x))') '<< CONST >> rhoForest', rhoForest + write(6,'(a,/,12x,12(f10.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold/1e6 + write(6,'(a,/,12x,12(f10.5,1x),/)') '<< CONST >> tauBack / MPa', tauBack/1e6 + endif +#endif + +end subroutine plastic_nonlocal_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates kinetics +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_kinetics(v, dv_dtau, dv_dtauNS, tau, tauNS, & + tauThreshold, c, Temperature, ip, el) + +use debug, only: debug_level, & + debug_constitutive, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use material, only: material_phase, & + phase_plasticityInstance + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el, & !< current element number + c !< dislocation character (1:edge, 2:screw) +real(pReal), intent(in) :: Temperature !< temperature +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & + intent(in) :: tau, & !< resolved external shear stress (without non Schmid effects) + tauNS, & !< resolved external shear stress (including non Schmid effects) + tauThreshold !< threshold shear stress + +!*** output variables +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & + intent(out) :: v, & !< velocity + dv_dtau, & !< velocity derivative with respect to resolved shear stress (without non Schmid contributions) + dv_dtauNS !< velocity derivative with respect to resolved shear stress (including non Schmid contributions) + +!*** local variables +integer(pInt) :: instance, & !< current instance of this plasticity + ns, & !< short notation for the total number of active slip systems + s !< index of my current slip system +real(pReal) tauRel_P, & + tauRel_S, & + tauEff, & !< effective shear stress + tPeierls, & !< waiting time in front of a peierls barriers + tSolidSolution, & !< waiting time in front of a solid solution obstacle + vViscous, & !< viscous glide velocity + dtPeierls_dtau, & !< derivative with respect to resolved shear stress + dtSolidSolution_dtau, & !< derivative with respect to resolved shear stress + meanfreepath_S, & !< mean free travel distance for dislocations between two solid solution obstacles + meanfreepath_P, & !< mean free travel distance for dislocations between two Peierls barriers + jumpWidth_P, & !< depth of activated area + jumpWidth_S, & !< depth of activated area + activationLength_P, & !< length of activated dislocation line + activationLength_S, & !< length of activated dislocation line + activationVolume_P, & !< volume that needs to be activated to overcome barrier + activationVolume_S, & !< volume that needs to be activated to overcome barrier + activationEnergy_P, & !< energy that is needed to overcome barrier + activationEnergy_S, & !< energy that is needed to overcome barrier + criticalStress_P, & !< maximum obstacle strength + criticalStress_S, & !< maximum obstacle strength + mobility !< dislocation mobility + + +instance = phase_plasticityInstance(material_phase(1_pInt,ip,el)) +ns = totalNslip(instance) + +v = 0.0_pReal +dv_dtau = 0.0_pReal +dv_dtauNS = 0.0_pReal + + +if (Temperature > 0.0_pReal) then + do s = 1_pInt,ns + if (abs(tau(s)) > tauThreshold(s)) then + + !* Peierls contribution + !* Effective stress includes non Schmid constributions + !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity + + tauEff = max(0.0_pReal, abs(tauNS(s)) - tauThreshold(s)) ! ensure that the effective stress is positive + meanfreepath_P = burgers(s,instance) + jumpWidth_P = burgers(s,instance) + activationLength_P = doublekinkwidth(instance) * burgers(s,instance) + activationVolume_P = activationLength_P * jumpWidth_P * burgers(s,instance) + criticalStress_P = peierlsStress(s,c,instance) + activationEnergy_P = criticalStress_P * activationVolume_P + tauRel_P = min(1.0_pReal, tauEff / criticalStress_P) ! ensure that the activation probability cannot become greater than one + tPeierls = 1.0_pReal / fattack(instance) & + * exp(activationEnergy_P / (KB * Temperature) & + * (1.0_pReal - tauRel_P**pParam(instance))**qParam(instance)) + if (tauEff < criticalStress_P) then + dtPeierls_dtau = tPeierls * pParam(instance) * qParam(instance) * activationVolume_P / (KB * Temperature) & + * (1.0_pReal - tauRel_P**pParam(instance))**(qParam(instance)-1.0_pReal) & + * tauRel_P**(pParam(instance)-1.0_pReal) + else + dtPeierls_dtau = 0.0_pReal + endif + + + !* Contribution from solid solution strengthening + !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity + + tauEff = abs(tau(s)) - tauThreshold(s) + meanfreepath_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) + jumpWidth_S = solidSolutionSize(instance) * burgers(s,instance) + activationLength_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) + activationVolume_S = activationLength_S * jumpWidth_S * burgers(s,instance) + activationEnergy_S = solidSolutionEnergy(instance) + criticalStress_S = activationEnergy_S / activationVolume_S + tauRel_S = min(1.0_pReal, tauEff / criticalStress_S) ! ensure that the activation probability cannot become greater than one + tSolidSolution = 1.0_pReal / fattack(instance) & + * exp(activationEnergy_S / (KB * Temperature) & + * (1.0_pReal - tauRel_S**pParam(instance))**qParam(instance)) + if (tauEff < criticalStress_S) then + dtSolidSolution_dtau = tSolidSolution * pParam(instance) * qParam(instance) & + * activationVolume_S / (KB * Temperature) & + * (1.0_pReal - tauRel_S**pParam(instance))**(qParam(instance)-1.0_pReal) & + * tauRel_S**(pParam(instance)-1.0_pReal) + else + dtSolidSolution_dtau = 0.0_pReal + endif + + + !* viscous glide velocity + + tauEff = abs(tau(s)) - tauThreshold(s) + mobility = burgers(s,instance) / viscosity(instance) + vViscous = mobility * tauEff + + + !* Mean velocity results from waiting time at peierls barriers and solid solution obstacles with respective meanfreepath of + !* free flight at glide velocity in between. + !* adopt sign from resolved stress + + v(s) = sign(1.0_pReal,tau(s)) & + / (tPeierls / meanfreepath_P + tSolidSolution / meanfreepath_S + 1.0_pReal / vViscous) + dv_dtau(s) = v(s) * v(s) * (dtSolidSolution_dtau / meanfreepath_S & + + mobility / (vViscous * vViscous)) + dv_dtauNS(s) = v(s) * v(s) * dtPeierls_dtau / meanfreepath_P + endif + enddo +endif + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_kinetics at el ip',el,ip + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold / 1e6_pReal + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tau / MPa', tau / 1e6_pReal + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauNS / MPa', tauNS / 1e6_pReal + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> v / 1e-3m/s', v * 1e3 + write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtau', dv_dtau + write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtauNS', dv_dtauNS + endif +#endif + +end subroutine plastic_nonlocal_kinetics + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_LpAndItsTangent(Lp, dLp_dTstar99, Tstar_v, Temperature, ip, el) + +use math, only: math_Plain3333to99, & + math_mul6x6, & + math_mul33xx33, & + math_Mandel6to33 +use debug, only: debug_level, & + debug_constitutive, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use material, only: material_phase, & + plasticState, & + phaseAt, phasememberAt,& + phase_plasticityInstance +use lattice, only: lattice_Sslip, & + lattice_Sslip_v, & + lattice_NnonSchmid +use mesh, only: mesh_ipVolume + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el !< current element number +real(pReal), intent(in) :: Temperature !< temperature +real(pReal), dimension(6), intent(in) :: Tstar_v !< 2nd Piola-Kirchhoff stress in Mandel notation + + +!*** output variables +real(pReal), dimension(3,3), intent(out) :: Lp !< plastic velocity gradient +real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 !< derivative of Lp with respect to Tstar (9x9 matrix) + +!*** local variables +integer(pInt) instance, & !< current instance of this plasticity + ns, & !< short notation for the total number of active slip systems + i, & + j, & + k, & + l, & + ph, & !phase number + of, & !offset + t, & !< dislocation type + s, & !< index of my current slip system + sLattice !< index of my current slip system according to lattice order +real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 !< derivative of Lp with respect to Tstar (3x3x3x3 matrix) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl !< single dislocation densities (including blocked) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + v, & !< velocity + tauNS, & !< resolved shear stress including non Schmid and backstress terms + dv_dtau, & !< velocity derivative with respect to the shear stress + dv_dtauNS !< velocity derivative with respect to the shear stress +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + tau, & !< resolved shear stress including backstress terms + gdotTotal, & !< shear rate + tauBack, & !< back stress from dislocation gradients on same slip system + tauThreshold !< threshold shear stress +!*** shortcut for mapping +ph = phaseAt(1_pInt,ip,el) +of = phasememberAt(1_pInt,ip,el) + +!*** initialize local variables + +Lp = 0.0_pReal +dLp_dTstar3333 = 0.0_pReal + +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + + +!*** shortcut to state variables + + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + + rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) +endforall +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal + +tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) +tauThreshold = plasticState(ph)%state(iTauF(1:ns,instance),of) + + +!*** get resolved shear stress +!*** for screws possible non-schmid contributions are also taken into account + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauNS(s,1) = tau(s) + tauNS(s,2) = tau(s) + if (tau(s) > 0.0_pReal) then + tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,1,s,instance)) + tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,3,s,instance)) + else + tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,2,s,instance)) + tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,4,s,instance)) + endif +enddo +forall (t = 1_pInt:4_pInt) & + tauNS(1:ns,t) = tauNS(1:ns,t) + tauBack ! add backstress +tau = tau + tauBack ! add backstress + + +!*** get dislocation velocity and its tangent and store the velocity in the state array + +! edges +call plastic_nonlocal_kinetics(v(1:ns,1), dv_dtau(1:ns,1), dv_dtauNS(1:ns,1), & + tau(1:ns), tauNS(1:ns,1), tauThreshold(1:ns), & + 1_pInt, Temperature, ip, el) +v(1:ns,2) = v(1:ns,1) +dv_dtau(1:ns,2) = dv_dtau(1:ns,1) +dv_dtauNS(1:ns,2) = dv_dtauNS(1:ns,1) + +!screws +if (lattice_NnonSchmid(ph) == 0_pInt) then ! no non-Schmid contributions + forall(t = 3_pInt:4_pInt) + v(1:ns,t) = v(1:ns,1) + dv_dtau(1:ns,t) = dv_dtau(1:ns,1) + dv_dtauNS(1:ns,t) = dv_dtauNS(1:ns,1) + endforall +else ! take non-Schmid contributions into account + do t = 3_pInt,4_pInt + call plastic_nonlocal_kinetics(v(1:ns,t), dv_dtau(1:ns,t), dv_dtauNS(1:ns,t), & + tau(1:ns), tauNS(1:ns,t), tauThreshold(1:ns), & + 2_pInt , Temperature, ip, el) + enddo +endif + + +!*** store velocity in state + +forall (t = 1_pInt:4_pInt) & + plasticState(ph)%state(iV(1:ns,t,instance),of) = v(1:ns,t) +!*** Bauschinger effect + +forall (s = 1_pInt:ns, t = 5_pInt:8_pInt, rhoSgl(s,t) * v(s,t-4_pInt) < 0.0_pReal) & + rhoSgl(s,t-4_pInt) = rhoSgl(s,t-4_pInt) + abs(rhoSgl(s,t)) + + +!*** Calculation of Lp and its tangent + +gdotTotal = sum(rhoSgl(1:ns,1:4) * v, 2) * burgers(1:ns,instance) + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + Lp = Lp + gdotTotal(s) * lattice_Sslip(1:3,1:3,1,sLattice,ph) + + ! Schmid contributions to tangent + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + + lattice_Sslip(i,j,1,sLattice,ph) * lattice_Sslip(k,l,1,sLattice,ph) & + * sum(rhoSgl(s,1:4) * dv_dtau(s,1:4)) * burgers(s,instance) + + ! non Schmid contributions to tangent + if (tau(s) > 0.0_pReal) then + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + + lattice_Sslip(i,j,1,sLattice,ph) & + * ( nonSchmidProjection(k,l,1,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & + + nonSchmidProjection(k,l,3,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & + * burgers(s,instance) + else + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + + lattice_Sslip(i,j,1,sLattice,ph) & + * ( nonSchmidProjection(k,l,2,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & + + nonSchmidProjection(k,l,4,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & + * burgers(s,instance) + endif +enddo +dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_LpandItsTangent at el ip',el,ip + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> gdot total / 1e-3',gdotTotal*1e3_pReal + write(6,'(a,/,3(12x,3(f12.7,1x),/))') '<< CONST >> Lp',transpose(Lp) + endif +#endif + +end subroutine plastic_nonlocal_LpAndItsTangent + + + +!-------------------------------------------------------------------------------------------------- +!> @brief (instantaneous) incremental change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_deltaState(Tstar_v,ip,el) +use debug, only: debug_level, & + debug_constitutive, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use math, only: pi, & + math_mul6x6 +use lattice, only: lattice_Sslip_v ,& + lattice_mu, & + lattice_nu +use mesh, only: mesh_ipVolume +use material, only: material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + +implicit none +integer(pInt), intent(in) :: ip, & ! current grain number + el ! current element number +real(pReal), dimension(6), intent(in) :: Tstar_v ! current 2nd Piola-Kirchhoff stress in Mandel notation + + + integer(pInt) :: & + ph, & !< phase + of !< offset + +integer(pInt) ::instance, & ! current instance of this plasticity + ns, & ! short notation for the total number of active slip systems + c, & ! character of dislocation + t, & ! type of dislocation + s, & ! index of my current slip system + sLattice ! index of my current slip system according to lattice order +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),10) :: & + deltaRho, & ! density increment + deltaRhoRemobilization, & ! density increment by remobilization + deltaRhoDipole2SingleStress ! density increment by dipole dissociation (by stress change) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),8) :: & + rhoSgl ! current single dislocation densities (positive/negative screw and edge without dipoles) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),4) :: & + v ! dislocation glide velocity +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + tau, & ! current resolved shear stress + tauBack ! current back stress from pileups on same slip system +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),2) :: & + rhoDip, & ! current dipole dislocation densities (screw and edge dipoles) + dLower, & ! minimum stable dipole distance for edges and screws + dUpper, & ! current maximum stable dipole distance for edges and screws + dUpperOld, & ! old maximum stable dipole distance for edges and screws + deltaDUpper ! change in maximum stable dipole distance for edges and screws + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_deltaState at el ip ',el,ip +#endif + + ph = phaseAt(1,ip,el) + of = phasememberAt(1,ip,el) + instance = phase_plasticityInstance(ph) + ns = totalNslip(instance) + + +!*** shortcut to state variables + + forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) + v(s,t) = plasticState(ph)%state(iV(s,t,instance),of) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities + dUpperOld(s,c) = plasticState(ph)%state(iD(s,c,instance),of) +endforall + tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) + +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal +where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoDip) < significantRho(instance)) & + rhoDip = 0.0_pReal + + + + +!**************************************************************************** +!*** dislocation remobilization (bauschinger effect) + +deltaRhoRemobilization = 0.0_pReal +do t = 1_pInt,4_pInt + do s = 1_pInt,ns + if (rhoSgl(s,t+4_pInt) * v(s,t) < 0.0_pReal) then + deltaRhoRemobilization(s,t) = abs(rhoSgl(s,t+4_pInt)) + rhoSgl(s,t) = rhoSgl(s,t) + abs(rhoSgl(s,t+4_pInt)) + deltaRhoRemobilization(s,t+4_pInt) = - rhoSgl(s,t+4_pInt) + rhoSgl(s,t+4_pInt) = 0.0_pReal + endif + enddo +enddo + + + +!**************************************************************************** +!*** calculate dipole formation and dissociation by stress change + +!*** calculate limits for stable dipole height + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) + if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal +enddo +dLower = minDipoleHeight(1:ns,1:2,instance) +dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & + / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) +dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) / (4.0_pReal * pi * abs(tau)) + + +forall (c = 1_pInt:2_pInt) + where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& + abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & + dUpper(1:ns,c)) +end forall +dUpper = max(dUpper,dLower) +deltaDUpper = dUpper - dUpperOld + + +!*** dissociation by stress increase +deltaRhoDipole2SingleStress = 0.0_pReal +forall (c=1_pInt:2_pInt, s=1_pInt:ns, deltaDUpper(s,c) < 0.0_pReal .and. & + abs(dUpperOld(s,c) - dLower(s,c)) > tiny(0.0_pReal)) & + deltaRhoDipole2SingleStress(s,8_pInt+c) = rhoDip(s,c) * deltaDUpper(s,c) & + / (dUpperOld(s,c) - dLower(s,c)) + +forall (t=1_pInt:4_pInt) & + deltaRhoDipole2SingleStress(1_pInt:ns,t) = -0.5_pReal & + * deltaRhoDipole2SingleStress(1_pInt:ns,(t-1_pInt)/2_pInt+9_pInt) + + +!*** store new maximum dipole height in state + +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & + plasticState(ph)%state(iD(s,c,instance),of) = dUpper(s,c) + + + +!**************************************************************************** +!*** assign the changes in the dislocation densities to deltaState + +deltaRho = deltaRhoRemobilization & + + deltaRhoDipole2SingleStress +plasticState(ph)%deltaState(:,of) = 0.0_pReal +forall (s = 1:ns, t = 1_pInt:4_pInt) + plasticState(ph)%deltaState(iRhoU(s,t,instance),of)= deltaRho(s,t) + plasticState(ph)%deltaState(iRhoB(s,t,instance),of) = deltaRho(s,t+4_pInt) +endforall +forall (s = 1:ns, c = 1_pInt:2_pInt) & + plasticState(ph)%deltaState(iRhoD(s,c,instance),of) = deltaRho(s,c+8_pInt) + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation remobilization', deltaRhoRemobilization(1:ns,1:8) + write(6,'(a,/,10(12x,12(e12.5,1x),/),/)') '<< CONST >> dipole dissociation by stress increase', deltaRhoDipole2SingleStress + endif +#endif + +end subroutine plastic_nonlocal_deltaState + +!--------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!--------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_dotState(Tstar_v, Fe, Fp, Temperature, & + timestep,subfrac, ip,el) + +use prec, only: DAMASK_NaN +use numerics, only: numerics_integrationMode, & + numerics_timeSyncing +use IO, only: IO_error +use debug, only: debug_level, & + debug_constitutive, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_g, & + debug_i, & + debug_e +use math, only: math_mul6x6, & + math_mul3x3, & + math_mul33x3, & + math_mul33x33, & + math_inv33, & + math_det33, & + math_transpose33, & + pi +use mesh, only: mesh_NcpElems, & + mesh_maxNips, & + mesh_element, & + mesh_ipNeighborhood, & + mesh_ipVolume, & + mesh_ipArea, & + mesh_ipAreaNormal, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype +use material, only: homogenization_maxNgrains, & + material_phase, & + phase_plasticityInstance, & + phase_localPlasticity, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticity ,& + PLASTICITY_NONLOCAL_ID +use lattice, only: lattice_Sslip_v, & + lattice_sd, & + lattice_st ,& + lattice_mu, & + lattice_nu, & + lattice_structure, & + LATTICE_bcc_ID, & + LATTICE_fcc_ID + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el !< current element number +real(pReal), intent(in) :: Temperature, & !< temperature + timestep !< substepped crystallite time increment +real(pReal), dimension(6), intent(in) :: Tstar_v !< current 2nd Piola-Kirchhoff stress in Mandel notation +real(pReal), dimension(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + subfrac !< fraction of timestep at the beginning of the substepped crystallite time increment +real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + Fe, & !< elastic deformation gradient + Fp !< plastic deformation gradient + + +!*** local variables +integer(pInt) :: ph, & + instance, & !< current instance of this plasticity + neighbor_instance, & !< instance of my neighbor's plasticity + ns, & !< short notation for the total number of active slip systems + c, & !< character of dislocation + n, & !< index of my current neighbor + neighbor_el, & !< element number of my neighbor + neighbor_ip, & !< integration point of my neighbor + neighbor_n, & !< neighbor index pointing to me when looking from my neighbor + opposite_neighbor, & !< index of my opposite neighbor + opposite_ip, & !< ip of my opposite neighbor + opposite_el, & !< element index of my opposite neighbor + opposite_n, & !< neighbor index pointing to me when looking from my opposite neighbor + t, & !< type of dislocation + o,& !< offset shortcut + no,& !< neighbour offset shortcut + p,& !< phase shortcut + np,& !< neighbour phase shortcut + topp, & !< type of dislocation with opposite sign to t + s, & !< index of my current slip system + sLattice !< index of my current slip system according to lattice order +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),10) :: & + rhoDot, & !< density evolution + rhoDotMultiplication, & !< density evolution by multiplication + rhoDotFlux, & !< density evolution by flux + rhoDotSingle2DipoleGlide, & !< density evolution by dipole formation (by glide) + rhoDotAthermalAnnihilation, & !< density evolution by athermal annihilation + rhoDotThermalAnnihilation !< density evolution by thermal annihilation +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) + rhoSglOriginal, & + neighbor_rhoSgl, & !< current single dislocation densities of neighboring ip (positive/negative screw and edge without dipoles) + rhoSgl0, & !< single dislocation densities at start of cryst inc (positive/negative screw and edge without dipoles) + my_rhoSgl !< single dislocation densities of central ip (positive/negative screw and edge without dipoles) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + v, & !< current dislocation glide velocity + v0, & !< dislocation glide velocity at start of cryst inc + my_v, & !< dislocation glide velocity of central ip + neighbor_v, & !< dislocation glide velocity of enighboring ip + gdot !< shear rates +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoForest, & !< forest dislocation density + tauThreshold, & !< threshold shear stress + tau, & !< current resolved shear stress + tauBack, & !< current back stress from pileups on same slip system + vClimb, & !< climb velocity of edge dipoles + nSources +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) + rhoDipOriginal, & + dLower, & !< minimum stable dipole distance for edges and screws + dUpper !< current maximum stable dipole distance for edges and screws +real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + m !< direction of dislocation motion +real(pReal), dimension(3,3) :: my_F, & !< my total deformation gradient + neighbor_F, & !< total deformation gradient of my neighbor + my_Fe, & !< my elastic deformation gradient + neighbor_Fe, & !< elastic deformation gradient of my neighbor + Favg !< average total deformation gradient of me and my neighbor +real(pReal), dimension(3) :: normal_neighbor2me, & !< interface normal pointing from my neighbor to me in neighbor's lattice configuration + normal_neighbor2me_defConf, & !< interface normal pointing from my neighbor to me in shared deformed configuration + normal_me2neighbor, & !< interface normal pointing from me to my neighbor in my lattice configuration + normal_me2neighbor_defConf !< interface normal pointing from me to my neighbor in shared deformed configuration +real(pReal) area, & !< area of the current interface + transmissivity, & !< overall transmissivity of dislocation flux to neighboring material point + lineLength, & !< dislocation line length leaving the current interface + selfDiffusion, & !< self diffusion + rnd, & + meshlength +logical considerEnteringFlux, & + considerLeavingFlux + + + p = phaseAt(1,ip,el) + o = phasememberAt(1,ip,el) + + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_dotState at el ip ',el,ip +#endif + +ph = material_phase(1_pInt,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + +tau = 0.0_pReal +gdot = 0.0_pReal + + +!*** shortcut to state variables + + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) + v(s,t) = plasticState(p)%state(iV (s,t,instance),o) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + rhoDip(s,c) = max(plasticState(p)%state(iRhoD(s,c,instance),o), 0.0_pReal) ! ensure positive dipole densities +endforall +rhoForest = plasticState(p)%state(iRhoF(1:ns,instance),o) +tauThreshold = plasticState(p)%state(iTauF(1:ns,instance),o) +tauBack = plasticState(p)%state(iTauB(1:ns,instance),o) + +rhoSglOriginal = rhoSgl +rhoDipOriginal = rhoDip +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal +where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoDip) < significantRho(instance)) & + rhoDip = 0.0_pReal + +if (numerics_timeSyncing) then + forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl0(s,t) = max(plasticState(p)%state0(iRhoU(s,t,instance),o), 0.0_pReal) + rhoSgl0(s,t+4_pInt) = plasticState(p)%state0(iRhoB(s,t,instance),o) + v0(s,t) = plasticState(p)%state0(iV (s,t,instance),o) + endforall + where (abs(rhoSgl0) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl0) < significantRho(instance)) & + rhoSgl0 = 0.0_pReal +endif + + + +!*** sanity check for timestep + +if (timestep <= 0.0_pReal) then ! if illegal timestep... Why here and not on function entry?? + plasticState(p)%dotState = 0.0_pReal ! ...return without doing anything (-> zero dotState) + return +endif + + + +!**************************************************************************** +!*** Calculate shear rate + +forall (t = 1_pInt:4_pInt) & + gdot(1_pInt:ns,t) = rhoSgl(1_pInt:ns,t) * burgers(1:ns,instance) * v(1:ns,t) + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> rho / 1/m^2', rhoSgl, rhoDip + write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> gdot / 1/s',gdot + endif +#endif + + + +!**************************************************************************** +!*** calculate limits for stable dipole height + +do s = 1_pInt,ns ! loop over slip systems + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) + if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal +enddo + +dLower = minDipoleHeight(1:ns,1:2,instance) +dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & + / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) +dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & + / (4.0_pReal * pi * abs(tau)) +forall (c = 1_pInt:2_pInt) + where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& + abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & + dUpper(1:ns,c)) +end forall +dUpper = max(dUpper,dLower) + +!**************************************************************************** +!*** calculate dislocation multiplication + +rhoDotMultiplication = 0.0_pReal +if (lattice_structure(ph) == LATTICE_bcc_ID) then ! BCC + forall (s = 1:ns, sum(abs(v(s,1:4))) > 0.0_pReal) + rhoDotMultiplication(s,1:2) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication + * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path + ! * 2.0_pReal * sum(abs(v(s,3:4))) / sum(abs(v(s,1:4))) ! ratio of screw to overall velocity determines edge generation + rhoDotMultiplication(s,3:4) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication + * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path + ! * 2.0_pReal * sum(abs(v(s,1:2))) / sum(abs(v(s,1:4))) ! ratio of edge to overall velocity determines screw generation + endforall + +else ! ALL OTHER STRUCTURES + if (probabilisticMultiplication(instance)) then + meshlength = mesh_ipVolume(ip,el)**0.333_pReal + where(sum(rhoSgl(1:ns,1:4),2) > 0.0_pReal) + nSources = (sum(rhoSgl(1:ns,1:2),2) * fEdgeMultiplication(instance) + sum(rhoSgl(1:ns,3:4),2)) & + / sum(rhoSgl(1:ns,1:4),2) * meshlength / lambda0(1:ns,instance)*sqrt(rhoForest(1:ns)) + elsewhere + nSources = meshlength / lambda0(1:ns,instance) * sqrt(rhoForest(1:ns)) + endwhere + do s = 1_pInt,ns + if (nSources(s) < 1.0_pReal) then + if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal) then + call random_number(rnd) + sourceProbability(s,1_pInt,ip,el) = rnd + !$OMP FLUSH(sourceProbability) + endif + if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal - nSources(s)) then + rhoDotMultiplication(s,1:4) = sum(rhoSglOriginal(s,1:4) * abs(v(s,1:4))) / meshlength + endif + else + sourceProbability(s,1_pInt,ip,el) = 2.0_pReal + rhoDotMultiplication(s,1:4) = & + (sum(abs(gdot(s,1:2))) * fEdgeMultiplication(instance) + sum(abs(gdot(s,3:4)))) & + / burgers(s,instance) * sqrt(rhoForest(s)) / lambda0(s,instance) + endif + enddo +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) & + write(6,'(a,/,4(12x,12(f12.5,1x),/,/))') '<< CONST >> sources', nSources +#endif + else + rhoDotMultiplication(1:ns,1:4) = spread( & + (sum(abs(gdot(1:ns,1:2)),2) * fEdgeMultiplication(instance) + sum(abs(gdot(1:ns,3:4)),2)) & + * sqrt(rhoForest(1:ns)) / lambda0(1:ns,instance) / burgers(1:ns,instance), 2, 4) + endif +endif + + + +!**************************************************************************** +!*** calculate dislocation fluxes (only for nonlocal plasticity) + +rhoDotFlux = 0.0_pReal +!? why needed here +if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then ! only for nonlocal plasticity + + !*** check CFL (Courant-Friedrichs-Lewy) condition for flux + + if (any( abs(gdot) > 0.0_pReal & ! any active slip system ... + .and. CFLfactor(instance) * abs(v) * timestep & + > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el)))) then ! ...with velocity above critical value (we use the reference volume and area for simplicity here) +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then + write(6,'(a,i5,a,i2)') '<< CONST >> CFL condition not fullfilled at el ',el,' ip ',ip + write(6,'(a,e10.3,a,e10.3)') '<< CONST >> velocity is at ', & + maxval(abs(v), abs(gdot) > 0.0_pReal & + .and. CFLfactor(instance) * abs(v) * timestep & + > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el))), & + ' at a timestep of ',timestep + write(6,'(a)') '<< CONST >> enforcing cutback !!!' + endif +#endif + plasticState(p)%dotState = DAMASK_NaN ! -> return NaN and, hence, enforce cutback + return + endif + + + !*** be aware of the definition of lattice_st = lattice_sd x lattice_sn !!! + !*** opposite sign to our p vector in the (s,p,n) triplet !!! + + m(1:3,1:ns,1) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) + m(1:3,1:ns,2) = -lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) + m(1:3,1:ns,3) = -lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) + m(1:3,1:ns,4) = lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) + + my_Fe = Fe(1:3,1:3,1_pInt,ip,el) + my_F = math_mul33x33(my_Fe, Fp(1:3,1:3,1_pInt,ip,el)) + + do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) ! loop through my neighbors +! write(6,*) 'c' + neighbor_el = mesh_ipNeighborhood(1,n,ip,el) + neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) + neighbor_n = mesh_ipNeighborhood(3,n,ip,el) + np = phaseAt(1,neighbor_ip,neighbor_el) + no = phasememberAt(1,neighbor_ip,neighbor_el) + + opposite_neighbor = n + mod(n,2_pInt) - mod(n+1_pInt,2_pInt) + opposite_el = mesh_ipNeighborhood(1,opposite_neighbor,ip,el) + opposite_ip = mesh_ipNeighborhood(2,opposite_neighbor,ip,el) + opposite_n = mesh_ipNeighborhood(3,opposite_neighbor,ip,el) + + if (neighbor_n > 0_pInt) then ! if neighbor exists, average deformation gradient + neighbor_instance = phase_plasticityInstance(material_phase(1_pInt,neighbor_ip,neighbor_el)) + neighbor_Fe = Fe(1:3,1:3,1_pInt,neighbor_ip,neighbor_el) + neighbor_F = math_mul33x33(neighbor_Fe, Fp(1:3,1:3,1_pInt,neighbor_ip,neighbor_el)) + Favg = 0.5_pReal * (my_F + neighbor_F) + else ! if no neighbor, take my value as average + Favg = my_F + endif + + + !* FLUX FROM MY NEIGHBOR TO ME + !* This is only considered, if I have a neighbor of nonlocal plasticity + !* (also nonlocal constitutive law with local properties) that is at least a little bit + !* compatible. + !* If it's not at all compatible, no flux is arriving, because everything is dammed in front of + !* my neighbor's interface. + !* The entering flux from my neighbor will be distributed on my slip systems according to the + !*compatibility + + considerEnteringFlux = .false. + neighbor_v = 0.0_pReal ! needed for check of sign change in flux density below + neighbor_rhoSgl = 0.0_pReal + if (neighbor_n > 0_pInt) then + if (phase_plasticity(material_phase(1,neighbor_ip,neighbor_el)) == PLASTICITY_NONLOCAL_ID & + .and. any(compatibility(:,:,:,n,ip,el) > 0.0_pReal)) & + considerEnteringFlux = .true. + endif + + if (considerEnteringFlux) then + if(numerics_timeSyncing .and. (subfrac(1_pInt,neighbor_ip,neighbor_el) /= subfrac(1_pInt,ip,el))) & + then ! for timesyncing: in case of a timestep at the interface we have to use "state0" to make sure that fluxes n both sides are equal + forall (s = 1:ns, t = 1_pInt:4_pInt) + + neighbor_v(s,t) = plasticState(np)%state0(iV (s,t,neighbor_instance),no) + neighbor_rhoSgl(s,t) = max(plasticState(np)%state0(iRhoU(s,t,neighbor_instance),no),0.0_pReal) + + endforall + else + forall (s = 1:ns, t = 1_pInt:4_pInt) + neighbor_v(s,t) = plasticState(np)%state(iV (s,t,neighbor_instance),no) + neighbor_rhoSgl(s,t) = max(plasticState(np)%state(iRhoU(s,t,neighbor_instance),no), & + 0.0_pReal) + endforall + endif + + where (neighbor_rhoSgl * mesh_ipVolume(neighbor_ip,neighbor_el) ** 0.667_pReal < significantN(instance) & + .or. neighbor_rhoSgl < significantRho(instance)) & + neighbor_rhoSgl = 0.0_pReal + normal_neighbor2me_defConf = math_det33(Favg) * math_mul33x3(math_inv33(transpose(Favg)), & + mesh_ipAreaNormal(1:3,neighbor_n,neighbor_ip,neighbor_el)) ! calculate the normal of the interface in (average) deformed configuration (now pointing from my neighbor to me!!!) + normal_neighbor2me = math_mul33x3(transpose(neighbor_Fe), normal_neighbor2me_defConf) & + / math_det33(neighbor_Fe) ! interface normal in the lattice configuration of my neighbor + area = mesh_ipArea(neighbor_n,neighbor_ip,neighbor_el) * norm2(normal_neighbor2me) + normal_neighbor2me = normal_neighbor2me / norm2(normal_neighbor2me) ! normalize the surface normal to unit length + do s = 1_pInt,ns + do t = 1_pInt,4_pInt + c = (t + 1_pInt) / 2 + topp = t + mod(t,2_pInt) - mod(t+1_pInt,2_pInt) + if (neighbor_v(s,t) * math_mul3x3(m(1:3,s,t), normal_neighbor2me) > 0.0_pReal & ! flux from my neighbor to me == entering flux for me + .and. v(s,t) * neighbor_v(s,t) >= 0.0_pReal ) then ! ... only if no sign change in flux density + lineLength = neighbor_rhoSgl(s,t) * neighbor_v(s,t) & + * math_mul3x3(m(1:3,s,t), normal_neighbor2me) * area ! positive line length that wants to enter through this interface + where (compatibility(c,1_pInt:ns,s,n,ip,el) > 0.0_pReal) & ! positive compatibility... + rhoDotFlux(1_pInt:ns,t) = rhoDotFlux(1_pInt:ns,t) & + + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to equally signed mobile dislocation type + * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal + where (compatibility(c,1_pInt:ns,s,n,ip,el) < 0.0_pReal) & ! ..negative compatibility... + rhoDotFlux(1_pInt:ns,topp) = rhoDotFlux(1_pInt:ns,topp) & + + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to opposite signed mobile dislocation type + * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal + endif + enddo + enddo + endif + + + !* FLUX FROM ME TO MY NEIGHBOR + !* This is not considered, if my opposite neighbor has a different constitutive law than nonlocal (still considered for nonlocal law with lcal properties). + !* Then, we assume, that the opposite(!) neighbor sends an equal amount of dislocations to me. + !* So the net flux in the direction of my neighbor is equal to zero: + !* leaving flux to neighbor == entering flux from opposite neighbor + !* In case of reduced transmissivity, part of the leaving flux is stored as dead dislocation density. + !* That means for an interface of zero transmissivity the leaving flux is fully converted to dead dislocations. + + considerLeavingFlux = .true. + if (opposite_n > 0_pInt) then + if (phase_plasticity(material_phase(1,opposite_ip,opposite_el)) /= PLASTICITY_NONLOCAL_ID) & + considerLeavingFlux = .false. + endif + + if (considerLeavingFlux) then + + !* timeSyncing mode: If the central ip has zero subfraction, always use "state0". This is needed in case of + !* a synchronization step for the central ip, because then "state" contains the values at the end of the + !* previously converged full time step. Also, if either me or my neighbor has zero subfraction, we have to + !* use "state0" to make sure that fluxes on both sides of the (potential) timestep are equal. + my_rhoSgl = rhoSgl + my_v = v + if(numerics_timeSyncing) then + if (abs(subfrac(1_pInt,ip,el))<= tiny(0.0_pReal)) then + my_rhoSgl = rhoSgl0 + my_v = v0 + elseif (neighbor_n > 0_pInt) then + if (abs(subfrac(1_pInt,neighbor_ip,neighbor_el))<= tiny(0.0_pReal)) then + my_rhoSgl = rhoSgl0 + my_v = v0 + endif + endif + endif + + normal_me2neighbor_defConf = math_det33(Favg) & + * math_mul33x3(math_inv33(math_transpose33(Favg)), & + mesh_ipAreaNormal(1:3,n,ip,el)) ! calculate the normal of the interface in (average) deformed configuration (pointing from me to my neighbor!!!) + normal_me2neighbor = math_mul33x3(math_transpose33(my_Fe), normal_me2neighbor_defConf) & + / math_det33(my_Fe) ! interface normal in my lattice configuration + area = mesh_ipArea(n,ip,el) * norm2(normal_me2neighbor) + normal_me2neighbor = normal_me2neighbor / norm2(normal_me2neighbor) ! normalize the surface normal to unit length + do s = 1_pInt,ns + do t = 1_pInt,4_pInt + c = (t + 1_pInt) / 2_pInt + if (my_v(s,t) * math_mul3x3(m(1:3,s,t), normal_me2neighbor) > 0.0_pReal ) then ! flux from me to my neighbor == leaving flux for me (might also be a pure flux from my mobile density to dead density if interface not at all transmissive) + if (my_v(s,t) * neighbor_v(s,t) >= 0.0_pReal) then ! no sign change in flux density + transmissivity = sum(compatibility(c,1_pInt:ns,s,n,ip,el)**2.0_pReal) ! overall transmissivity from this slip system to my neighbor + else ! sign change in flux density means sign change in stress which does not allow for dislocations to arive at the neighbor + transmissivity = 0.0_pReal + endif + lineLength = my_rhoSgl(s,t) * my_v(s,t) & + * math_mul3x3(m(1:3,s,t), normal_me2neighbor) * area ! positive line length of mobiles that wants to leave through this interface + rhoDotFlux(s,t) = rhoDotFlux(s,t) - lineLength / mesh_ipVolume(ip,el) ! subtract dislocation flux from current type + rhoDotFlux(s,t+4_pInt) = rhoDotFlux(s,t+4_pInt) & + + lineLength / mesh_ipVolume(ip,el) * (1.0_pReal - transmissivity) & + * sign(1.0_pReal, my_v(s,t)) ! dislocation flux that is not able to leave through interface (because of low transmissivity) will remain as immobile single density at the material point + endif + enddo + enddo + endif + + enddo ! neighbor loop +endif + + + +!**************************************************************************** +!*** calculate dipole formation and annihilation + +!*** formation by glide + +do c = 1_pInt,2_pInt + rhoDotSingle2DipoleGlide(1:ns,2*c-1) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile + + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile + + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) ! positive mobile --> negative immobile + + rhoDotSingle2DipoleGlide(1:ns,2*c) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile + + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile + + abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c))) ! negative mobile --> positive immobile + + rhoDotSingle2DipoleGlide(1:ns,2*c+3) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * rhoSgl(1:ns,2*c+3) * abs(gdot(1:ns,2*c)) ! negative mobile --> positive immobile + + rhoDotSingle2DipoleGlide(1:ns,2*c+4) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * rhoSgl(1:ns,2*c+4) * abs(gdot(1:ns,2*c-1)) ! positive mobile --> negative immobile + + rhoDotSingle2DipoleGlide(1:ns,c+8) = - rhoDotSingle2DipoleGlide(1:ns,2*c-1) & + - rhoDotSingle2DipoleGlide(1:ns,2*c) & + + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+3)) & + + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+4)) +enddo + + +!*** athermal annihilation + +rhoDotAthermalAnnihilation = 0.0_pReal + +forall (c=1_pInt:2_pInt) & + rhoDotAthermalAnnihilation(1:ns,c+8_pInt) = -2.0_pReal * dLower(1:ns,c) / burgers(1:ns,instance) & + * ( 2.0_pReal * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1))) & ! was single hitting single + + 2.0_pReal * (abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c)) + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) & ! was single hitting immobile single or was immobile single hit by single + + rhoDip(1:ns,c) * (abs(gdot(1:ns,2*c-1)) + abs(gdot(1:ns,2*c)))) ! single knocks dipole constituent +! annihilated screw dipoles leave edge jogs behind on the colinear system +if (lattice_structure(ph) == LATTICE_fcc_ID) & ! only fcc + forall (s = 1:ns, colinearSystem(s,instance) > 0_pInt) & + rhoDotAthermalAnnihilation(colinearSystem(s,instance),1:2) = - rhoDotAthermalAnnihilation(s,10) & + * 0.25_pReal * sqrt(rhoForest(s)) * (dUpper(s,2) + dLower(s,2)) * edgeJogFactor(instance) + + + +!*** thermally activated annihilation of edge dipoles by climb + +rhoDotThermalAnnihilation = 0.0_pReal +selfDiffusion = Dsd0(instance) * exp(-selfDiffusionEnergy(instance) / (KB * Temperature)) +vClimb = atomicVolume(instance) * selfDiffusion / ( KB * Temperature ) & + * lattice_mu(ph) / ( 2.0_pReal * PI * (1.0_pReal-lattice_nu(ph)) ) & + * 2.0_pReal / ( dUpper(1:ns,1) + dLower(1:ns,1) ) +forall (s = 1_pInt:ns, dUpper(s,1) > dLower(s,1)) & + rhoDotThermalAnnihilation(s,9) = max(- 4.0_pReal * rhoDip(s,1) * vClimb(s) / (dUpper(s,1) - dLower(s,1)), & + - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & + - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have + + + +!**************************************************************************** +!*** assign the rates of dislocation densities to my dotState +!*** if evolution rates lead to negative densities, a cutback is enforced + +rhoDot = 0.0_pReal +rhoDot = rhoDotFlux & + + rhoDotMultiplication & + + rhoDotSingle2DipoleGlide & + + rhoDotAthermalAnnihilation & + + rhoDotThermalAnnihilation + +if (numerics_integrationMode == 1_pInt) then ! save rates for output if in central integration mode + rhoDotFluxOutput(1:ns,1:8,1_pInt,ip,el) = rhoDotFlux(1:ns,1:8) + rhoDotMultiplicationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotMultiplication(1:ns,[1,3]) + rhoDotSingle2DipoleGlideOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotSingle2DipoleGlide(1:ns,9:10) + rhoDotAthermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotAthermalAnnihilation(1:ns,9:10) + rhoDotThermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotThermalAnnihilation(1:ns,9:10) + rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) = 2.0_pReal * rhoDotThermalAnnihilation(1:ns,1) +endif + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip .and. debug_g == 1_pInt)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> dislocation multiplication', & + rhoDotMultiplication(1:ns,1:4) * timestep + write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation flux', & + rhoDotFlux(1:ns,1:8) * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> dipole formation by glide', & + rhoDotSingle2DipoleGlide * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> athermal dipole annihilation', & + rhoDotAthermalAnnihilation * timestep + write(6,'(a,/,2(12x,12(e12.5,1x),/))') '<< CONST >> thermally activated dipole annihilation', & + rhoDotThermalAnnihilation(1:ns,9:10) * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> total density change', & + rhoDot * timestep + write(6,'(a,/,10(12x,12(f12.5,1x),/))') '<< CONST >> relative density change', & + rhoDot(1:ns,1:8) * timestep / (abs(rhoSglOriginal)+1.0e-10), & + rhoDot(1:ns,9:10) * timestep / (rhoDipOriginal+1.0e-10) + write(6,*) + endif +#endif + + +if ( any(rhoSglOriginal(1:ns,1:4) + rhoDot(1:ns,1:4) * timestep < -aTolRho(instance)) & + .or. any(rhoDipOriginal(1:ns,1:2) + rhoDot(1:ns,9:10) * timestep < -aTolRho(instance))) then +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then + write(6,'(a,i5,a,i2)') '<< CONST >> evolution rate leads to negative density at el ',el,' ip ',ip + write(6,'(a)') '<< CONST >> enforcing cutback !!!' + endif +#endif + plasticState(p)%dotState = DAMASK_NaN + return +else + forall (s = 1:ns, t = 1_pInt:4_pInt) + plasticState(p)%dotState(iRhoU(s,t,instance),o) = rhoDot(s,t) + plasticState(p)%dotState(iRhoB(s,t,instance),o) = rhoDot(s,t+4_pInt) + endforall + forall (s = 1:ns, c = 1_pInt:2_pInt) & + plasticState(p)%dotState(iRhoD(s,c,instance),o) = rhoDot(s,c+8_pInt) + forall (s = 1:ns) & + plasticState(p)%dotState(iGamma(s,instance),o) = sum(gdot(s,1:4)) +endif + +end subroutine plastic_nonlocal_dotState + + +!********************************************************************* +!* COMPATIBILITY UPDATE * +!* Compatibility is defined as normalized product of signed cosine * +!* of the angle between the slip plane normals and signed cosine of * +!* the angle between the slip directions. Only the largest values * +!* that sum up to a total of 1 are considered, all others are set to * +!* zero. * +!********************************************************************* +subroutine plastic_nonlocal_updateCompatibility(orientation,i,e) + +use math, only: math_mul3x3, & + math_qRot +use material, only: material_phase, & + material_texture, & + phase_localPlasticity, & + phase_plasticityInstance, & + homogenization_maxNgrains +use mesh, only: mesh_element, & + mesh_ipNeighborhood, & + mesh_maxNips, & + mesh_NcpElems, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype +use lattice, only: lattice_sn, & + lattice_sd, & + lattice_qDisorientation + +implicit none + +!* input variables +integer(pInt), intent(in) :: i, & ! ip index + e ! element index +real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + orientation ! crystal orientation in quaternions + +!* local variables +integer(pInt) Nneighbors, & ! number of neighbors + n, & ! neighbor index + neighbor_e, & ! element index of my neighbor + neighbor_i, & ! integration point index of my neighbor + ph, & + neighbor_phase, & + textureID, & + neighbor_textureID, & + instance, & ! instance of plasticity + ns, & ! number of active slip systems + s1, & ! slip system index (me) + s2 ! slip system index (my neighbor) +real(pReal), dimension(4) :: absoluteMisorientation ! absolute misorientation (without symmetry) between me and my neighbor +real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& + totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& + FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e))))) :: & + my_compatibility ! my_compatibility for current element and ip +real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & + slipNormal, & + slipDirection +real(pReal) my_compatibilitySum, & + thresholdValue, & + nThresholdValues +logical, dimension(totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & + belowThreshold + + +Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) +ph = material_phase(1,i,e) +textureID = material_texture(1,i,e) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) +slipNormal(1:3,1:ns) = lattice_sn(1:3, slipSystemLattice(1:ns,instance), ph) +slipDirection(1:3,1:ns) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) + + +!*** start out fully compatible + +my_compatibility = 0.0_pReal +forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,1:Nneighbors) = 1.0_pReal + + +!*** Loop thrugh neighbors and check whether there is any my_compatibility. + +do n = 1_pInt,Nneighbors + neighbor_e = mesh_ipNeighborhood(1,n,i,e) + neighbor_i = mesh_ipNeighborhood(2,n,i,e) + + + !* FREE SURFACE + !* Set surface transmissivity to the value specified in the material.config + + if (neighbor_e <= 0_pInt .or. neighbor_i <= 0_pInt) then + forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,n) = sqrt(surfaceTransmissivity(instance)) + cycle + endif + + + !* PHASE BOUNDARY + !* If we encounter a different nonlocal "cpfem" phase at the neighbor, + !* we consider this to be a real "physical" phase boundary, so completely incompatible. + !* If one of the two "CPFEM" phases has a local plasticity law, + !* we do not consider this to be a phase boundary, so completely compatible. + + neighbor_phase = material_phase(1,neighbor_i,neighbor_e) + if (neighbor_phase /= ph) then + if (.not. phase_localPlasticity(neighbor_phase) .and. .not. phase_localPlasticity(ph)) then + forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,n) = 0.0_pReal ! = sqrt(0.0) + endif + cycle + endif + + + !* GRAIN BOUNDARY ! + !* fixed transmissivity for adjacent ips with different texture (only if explicitly given in material.config) + + if (grainboundaryTransmissivity(instance) >= 0.0_pReal) then + neighbor_textureID = material_texture(1,neighbor_i,neighbor_e) + if (neighbor_textureID /= textureID) then + if (.not. phase_localPlasticity(neighbor_phase)) then + forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,n) = sqrt(grainboundaryTransmissivity(instance)) + endif + cycle + endif + + + !* GRAIN BOUNDARY ? + !* Compatibility defined by relative orientation of slip systems: + !* The my_compatibility value is defined as the product of the slip normal projection and the slip direction projection. + !* Its sign is always positive for screws, for edges it has the same sign as the slip normal projection. + !* Since the sum for each slip system can easily exceed one (which would result in a transmissivity larger than one), + !* only values above or equal to a certain threshold value are considered. This threshold value is chosen, such that + !* the number of compatible slip systems is minimized with the sum of the original my_compatibility values exceeding one. + !* Finally the smallest my_compatibility value is decreased until the sum is exactly equal to one. + !* All values below the threshold are set to zero. + else + absoluteMisorientation = lattice_qDisorientation(orientation(1:4,1,i,e), & + orientation(1:4,1,neighbor_i,neighbor_e)) ! no symmetry + do s1 = 1_pInt,ns ! my slip systems + do s2 = 1_pInt,ns ! my neighbor's slip systems + my_compatibility(1,s2,s1,n) = math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2))) & + * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) + my_compatibility(2,s2,s1,n) = abs(math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2)))) & + * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) + enddo + + my_compatibilitySum = 0.0_pReal + belowThreshold = .true. + do while (my_compatibilitySum < 1.0_pReal .and. any(belowThreshold(1:ns))) + thresholdValue = maxval(my_compatibility(2,1:ns,s1,n), belowThreshold(1:ns)) ! screws always positive + nThresholdValues = real(count(my_compatibility(2,1:ns,s1,n) == thresholdValue),pReal) + where (my_compatibility(2,1:ns,s1,n) >= thresholdValue) & + belowThreshold(1:ns) = .false. + if (my_compatibilitySum + thresholdValue * nThresholdValues > 1.0_pReal) & + where (abs(my_compatibility(1:2,1:ns,s1,n)) == thresholdValue) & ! MD: rather check below threshold? + my_compatibility(1:2,1:ns,s1,n) = sign((1.0_pReal - my_compatibilitySum) & + / nThresholdValues, my_compatibility(1:2,1:ns,s1,n)) + my_compatibilitySum = my_compatibilitySum + nThresholdValues * thresholdValue + enddo + where (belowThreshold(1:ns)) my_compatibility(1,1:ns,s1,n) = 0.0_pReal + where (belowThreshold(1:ns)) my_compatibility(2,1:ns,s1,n) = 0.0_pReal + enddo ! my slip systems cycle + endif + +enddo ! neighbor cycle + +compatibility(1:2,1:ns,1:ns,1:Nneighbors,i,e) = my_compatibility + +end subroutine plastic_nonlocal_updateCompatibility + +!********************************************************************* +!* calculates quantities characterizing the microstructure * +!********************************************************************* +function plastic_nonlocal_dislocationstress(Fe, ip, el) +use math, only: math_mul33x33, & + math_mul33x3, & + math_inv33, & + math_transpose33, & + pi +use mesh, only: mesh_NcpElems, & + mesh_maxNips, & + mesh_element, & + mesh_node0, & + mesh_cellCenterCoordinates, & + mesh_ipVolume, & + mesh_periodicSurface, & + FE_Nips, & + FE_geomtype +use material, only: homogenization_maxNgrains, & + material_phase, & + plasticState, & + phaseAt, phasememberAt,& + phase_localPlasticity, & + phase_plasticityInstance +use lattice, only: lattice_mu, & + lattice_nu + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el !< current element +real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + Fe !< elastic deformation gradient + +!*** output variables +real(pReal), dimension(3,3) :: plastic_nonlocal_dislocationstress + +!*** local variables +integer(pInt) neighbor_el, & !< element number of neighbor material point + neighbor_ip, & !< integration point of neighbor material point + instance, & !< my instance of this plasticity + neighbor_instance, & !< instance of this plasticity of neighbor material point + ph, & + neighbor_phase, & + ns, & !< total number of active slip systems at my material point + neighbor_ns, & !< total number of active slip systems at neighbor material point + c, & !< index of dilsocation character (edge, screw) + s, & !< slip system index + o,& !< offset shortcut + no,& !< neighbour offset shortcut + p,& !< phase shortcut + np,& !< neighbour phase shortcut + t, & !< index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) + dir, & + deltaX, deltaY, deltaZ, & + side, & + j +integer(pInt), dimension(2,3) :: periodicImages +real(pReal) x, y, z, & !< coordinates of connection vector in neighbor lattice frame + xsquare, ysquare, zsquare, & !< squares of respective coordinates + distance, & !< length of connection vector + segmentLength, & !< segment length of dislocations + lambda, & + R, Rsquare, Rcube, & + denominator, & + flipSign, & + neighbor_ipVolumeSideLength +real(pReal), dimension(3) :: connection, & !< connection vector between me and my neighbor in the deformed configuration + connection_neighborLattice, & !< connection vector between me and my neighbor in the lattice configuration of my neighbor + connection_neighborSlip, & !< connection vector between me and my neighbor in the slip system frame of my neighbor + maxCoord, minCoord, & + meshSize, & + coords, & !< x,y,z coordinates of cell center of ip volume + neighbor_coords !< x,y,z coordinates of cell center of neighbor ip volume +real(pReal), dimension(3,3) :: sigma, & !< dislocation stress for one slip system in neighbor material point's slip system frame + Tdislo_neighborLattice, & !< dislocation stress as 2nd Piola-Kirchhoff stress at neighbor material point + invFe, & !< inverse of my elastic deformation gradient + neighbor_invFe, & + neighborLattice2myLattice !< mapping from neighbor MPs lattice configuration to my lattice configuration +real(pReal), dimension(2,2,maxval(totalNslip)) :: & + neighbor_rhoExcess !< excess density at neighbor material point (edge/screw,mobile/dead,slipsystem) +real(pReal), dimension(2,maxval(totalNslip)) :: & + rhoExcessDead +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) + +ph = material_phase(1_pInt,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) +p = phaseAt(1,ip,el) +o = phasememberAt(1,ip,el) + +!*** get basic states + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) +endforall + + + +!*** calculate the dislocation stress of the neighboring excess dislocation densities +!*** zero for material points of local plasticity + +plastic_nonlocal_dislocationstress = 0.0_pReal + +if (.not. phase_localPlasticity(ph)) then + invFe = math_inv33(Fe(1:3,1:3,1_pInt,ip,el)) + + !* in case of periodic surfaces we have to find out how many periodic images in each direction we need + + do dir = 1_pInt,3_pInt + maxCoord(dir) = maxval(mesh_node0(dir,:)) + minCoord(dir) = minval(mesh_node0(dir,:)) + enddo + meshSize = maxCoord - minCoord + coords = mesh_cellCenterCoordinates(ip,el) + periodicImages = 0_pInt + do dir = 1_pInt,3_pInt + if (mesh_periodicSurface(dir)) then + periodicImages(1,dir) = floor((coords(dir) - cutoffRadius(instance) - minCoord(dir)) / meshSize(dir), pInt) + periodicImages(2,dir) = ceiling((coords(dir) + cutoffRadius(instance) - maxCoord(dir)) / meshSize(dir), pInt) + endif + enddo + + + !* loop through all material points (also through their periodic images if present), + !* but only consider nonlocal neighbors within a certain cutoff radius R + + do neighbor_el = 1_pInt,mesh_NcpElems + ipLoop: do neighbor_ip = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,neighbor_el))) + neighbor_phase = material_phase(1_pInt,neighbor_ip,neighbor_el) + np = phaseAt(1,neighbor_ip,neighbor_el) + no = phasememberAt(1,neighbor_ip,neighbor_el) + + if (phase_localPlasticity(neighbor_phase)) cycle + neighbor_instance = phase_plasticityInstance(neighbor_phase) + neighbor_ns = totalNslip(neighbor_instance) + neighbor_invFe = math_inv33(Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) + neighbor_ipVolumeSideLength = mesh_ipVolume(neighbor_ip,neighbor_el) ** (1.0_pReal/3.0_pReal) ! reference volume used here + + forall (s = 1_pInt:neighbor_ns, c = 1_pInt:2_pInt) + neighbor_rhoExcess(c,1,s) = plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no) & ! positive mobiles + - plasticState(np)%state(iRhoU(s,2*c,neighbor_instance),no) ! negative mobiles + neighbor_rhoExcess(c,2,s) = abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads + - abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance),no)) ! negative deads + + endforall + Tdislo_neighborLattice = 0.0_pReal + do deltaX = periodicImages(1,1),periodicImages(2,1) + do deltaY = periodicImages(1,2),periodicImages(2,2) + do deltaZ = periodicImages(1,3),periodicImages(2,3) + + + !* regular case + + if (neighbor_el /= el .or. neighbor_ip /= ip & + .or. deltaX /= 0_pInt .or. deltaY /= 0_pInt .or. deltaZ /= 0_pInt) then + + neighbor_coords = mesh_cellCenterCoordinates(neighbor_ip,neighbor_el) & + + [real(deltaX,pReal), real(deltaY,pReal), real(deltaZ,pReal)] * meshSize + connection = neighbor_coords - coords + distance = sqrt(sum(connection * connection)) + if (distance > cutoffRadius(instance)) cycle + + + !* the segment length is the minimum of the third root of the control volume and the ip distance + !* this ensures, that the central MP never sits on a neighbor dislocation segment + + connection_neighborLattice = math_mul33x3(neighbor_invFe, connection) + segmentLength = min(neighbor_ipVolumeSideLength, distance) + + + !* loop through all slip systems of the neighbor material point + !* and add up the stress contributions from egde and screw excess on these slip systems (if significant) + + do s = 1_pInt,neighbor_ns + if (all(abs(neighbor_rhoExcess(:,:,s)) < significantRho(instance))) cycle ! not significant + + + !* map the connection vector from the lattice into the slip system frame + + connection_neighborSlip = math_mul33x3(lattice2slip(1:3,1:3,s,neighbor_instance), & + connection_neighborLattice) + + + !* edge contribution to stress + sigma = 0.0_pReal + + x = connection_neighborSlip(1) + y = connection_neighborSlip(2) + z = connection_neighborSlip(3) + xsquare = x * x + ysquare = y * y + zsquare = z * z + + do j = 1_pInt,2_pInt + if (abs(neighbor_rhoExcess(1,j,s)) < significantRho(instance)) then + cycle + elseif (j > 1_pInt) then + x = connection_neighborSlip(1) & + + sign(0.5_pReal * segmentLength, & + plasticState(np)%state(iRhoB(s,1,neighbor_instance),no) & + - plasticState(np)%state(iRhoB(s,2,neighbor_instance),no)) + + xsquare = x * x + endif + + flipSign = sign(1.0_pReal, -y) + do side = 1_pInt,-1_pInt,-2_pInt + lambda = real(side,pReal) * 0.5_pReal * segmentLength - y + R = sqrt(xsquare + zsquare + lambda * lambda) + Rsquare = R * R + Rcube = Rsquare * R + denominator = R * (R + flipSign * lambda) + if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop + + sigma(1,1) = sigma(1,1) - real(side,pReal) & + * flipSign * z / denominator & + * (1.0_pReal + xsquare / Rsquare + xsquare / denominator) & + * neighbor_rhoExcess(1,j,s) + sigma(2,2) = sigma(2,2) - real(side,pReal) & + * (flipSign * 2.0_pReal * lattice_nu(ph) * z / denominator + z * lambda / Rcube) & + * neighbor_rhoExcess(1,j,s) + sigma(3,3) = sigma(3,3) + real(side,pReal) & + * flipSign * z / denominator & + * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & + * neighbor_rhoExcess(1,j,s) + sigma(1,2) = sigma(1,2) + real(side,pReal) & + * x * z / Rcube * neighbor_rhoExcess(1,j,s) + sigma(1,3) = sigma(1,3) + real(side,pReal) & + * flipSign * x / denominator & + * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & + * neighbor_rhoExcess(1,j,s) + sigma(2,3) = sigma(2,3) - real(side,pReal) & + * (lattice_nu(ph) / R - zsquare / Rcube) * neighbor_rhoExcess(1,j,s) + enddo + enddo + + !* screw contribution to stress + + x = connection_neighborSlip(1) ! have to restore this value, because position might have been adapted for edge deads before + do j = 1_pInt,2_pInt + if (abs(neighbor_rhoExcess(2,j,s)) < significantRho(instance)) then + cycle + elseif (j > 1_pInt) then + y = connection_neighborSlip(2) & + + sign(0.5_pReal * segmentLength, & + plasticState(np)%state(iRhoB(s,3,neighbor_instance),no) & + - plasticState(np)%state(iRhoB(s,4,neighbor_instance),no)) + ysquare = y * y + endif + + flipSign = sign(1.0_pReal, x) + do side = 1_pInt,-1_pInt,-2_pInt + lambda = x + real(side,pReal) * 0.5_pReal * segmentLength + R = sqrt(ysquare + zsquare + lambda * lambda) + Rsquare = R * R + Rcube = Rsquare * R + denominator = R * (R + flipSign * lambda) + if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop + + sigma(1,2) = sigma(1,2) - real(side,pReal) * flipSign * z & + * (1.0_pReal - lattice_nu(ph)) / denominator & + * neighbor_rhoExcess(2,j,s) + sigma(1,3) = sigma(1,3) + real(side,pReal) * flipSign * y & + * (1.0_pReal - lattice_nu(ph)) / denominator & + * neighbor_rhoExcess(2,j,s) + enddo + enddo + + if (all(abs(sigma) < 1.0e-10_pReal)) cycle ! SIGMA IS NOT A REAL STRESS, THATS WHY WE NEED A REALLY SMALL VALUE HERE + + !* copy symmetric parts + + sigma(2,1) = sigma(1,2) + sigma(3,1) = sigma(1,3) + sigma(3,2) = sigma(2,3) + + + !* scale stresses and map them into the neighbor material point's lattice configuration + + sigma = sigma * lattice_mu(neighbor_phase) * burgers(s,neighbor_instance) & + / (4.0_pReal * pi * (1.0_pReal - lattice_nu(neighbor_phase))) & + * mesh_ipVolume(neighbor_ip,neighbor_el) / segmentLength ! reference volume is used here (according to the segment length calculation) + Tdislo_neighborLattice = Tdislo_neighborLattice & + + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,neighbor_instance)), & + math_mul33x33(sigma, lattice2slip(1:3,1:3,s,neighbor_instance))) + + enddo ! slip system loop + + + !* special case of central ip volume + !* only consider dead dislocations + !* we assume that they all sit at a distance equal to half the third root of V + !* in direction of the according slip direction + + else + + forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & + + rhoExcessDead(c,s) = plasticState(p)%state(iRhoB(s,2*c-1,instance),o) & ! positive deads (here we use symmetry: if this has negative sign it is + !treated as negative density at positive position instead of positive + !density at negative position) + + plasticState(p)%state(iRhoB(s,2*c,instance),o) ! negative deads (here we use symmetry: if this has negative sign it is + !treated as positive density at positive position instead of negative + !density at negative position) + do s = 1_pInt,ns + if (all(abs(rhoExcessDead(:,s)) < significantRho(instance))) cycle ! not significant + sigma = 0.0_pReal ! all components except for sigma13 are zero + sigma(1,3) = - (rhoExcessDead(1,s) + rhoExcessDead(2,s) * (1.0_pReal - lattice_nu(ph))) & + * neighbor_ipVolumeSideLength * lattice_mu(ph) * burgers(s,instance) & + / (sqrt(2.0_pReal) * pi * (1.0_pReal - lattice_nu(ph))) + sigma(3,1) = sigma(1,3) + + Tdislo_neighborLattice = Tdislo_neighborLattice & + + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,instance)), & + math_mul33x33(sigma, lattice2slip(1:3,1:3,s,instance))) + + enddo ! slip system loop + + endif + + enddo ! deltaZ loop + enddo ! deltaY loop + enddo ! deltaX loop + + + !* map the stress from the neighbor MP's lattice configuration into the deformed configuration + !* and back into my lattice configuration + + neighborLattice2myLattice = math_mul33x33(invFe, Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) + plastic_nonlocal_dislocationstress = plastic_nonlocal_dislocationstress & + + math_mul33x33(neighborLattice2myLattice, & + math_mul33x33(Tdislo_neighborLattice, & + math_transpose33(neighborLattice2myLattice))) + + enddo ipLoop + enddo ! element loop + +endif + +end function plastic_nonlocal_dislocationstress + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_nonlocal_postResults(Tstar_v,Fe,ip,el) + use math, only: & + math_mul6x6, & + math_mul33x3, & + math_mul33x33, & + pi + use mesh, only: & + mesh_NcpElems, & + mesh_maxNips + use material, only: & + homogenization_maxNgrains, & + material_phase, & + phaseAt, phasememberAt, & + plasticState, & + phase_plasticityInstance + use lattice, only: & + lattice_Sslip_v, & + lattice_sd, & + lattice_st, & + lattice_sn, & + lattice_mu, & + lattice_nu + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + Fe !< elastic deformation gradient + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + + real(pReal), dimension(plastic_nonlocal_sizePostResults(& + phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + plastic_nonlocal_postResults + + integer(pInt) :: & + ph, & + instance, & !< current instance of this plasticity + ns, & !< short notation for the total number of active slip systems + c, & !< character of dislocation + cs, & !< constitutive result index + o, & !< index of current output + of,& !< offset shortcut + t, & !< type of dislocation + s, & !< index of my current slip system + sLattice !< index of my current slip system according to lattice order + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) + rhoDotSgl !< evolution rate of single dislocation densities (positive/negative screw and edge without dipoles) + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + gdot, & !< shear rates + v !< velocities + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoForest, & !< forest dislocation density + tauThreshold, & !< threshold shear stress + tau, & !< current resolved shear stress + tauBack !< back stress from pileups on same slip system + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) + rhoDotDip, & !< evolution rate of dipole dislocation densities (screw and edge dipoles) + dLower, & !< minimum stable dipole distance for edges and screws + dUpper !< current maximum stable dipole distance for edges and screws + real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + m, & !< direction of dislocation motion for edge and screw (unit vector) + m_currentconf !< direction of dislocation motion for edge and screw (unit vector) in current configuration + real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + n_currentconf !< slip system normal (unit vector) in current configuration + real(pReal), dimension(3,3) :: & + sigma + +ph = phaseAt(1,ip,el) +of = phasememberAt(1,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + +cs = 0_pInt +plastic_nonlocal_postResults = 0.0_pReal + + +!* short hand notations for state variables + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = plasticState(ph)%State(iRhoU(s,t,instance),of) + rhoSgl(s,t+4_pInt) = plasticState(ph)%State(iRhoB(s,t,instance),of) + v(s,t) = plasticState(ph)%State(iV(s,t,instance),of) + rhoDotSgl(s,t) = plasticState(ph)%dotState(iRhoU(s,t,instance),of) + rhoDotSgl(s,t+4_pInt) = plasticState(ph)%dotState(iRhoB(s,t,instance),of) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + rhoDip(s,c) = plasticState(ph)%State(iRhoD(s,c,instance),of) + rhoDotDip(s,c) = plasticState(ph)%dotState(iRhoD(s,c,instance),of) +endforall +rhoForest = plasticState(ph)%State(iRhoF(1:ns,instance),of) +tauThreshold = plasticState(ph)%State(iTauF(1:ns,instance),of) +tauBack = plasticState(ph)%State(iTauB(1:ns,instance),of) + +!* Calculate shear rate + +forall (t = 1_pInt:4_pInt) & + gdot(1:ns,t) = rhoSgl(1:ns,t) * burgers(1:ns,instance) * v(1:ns,t) + + +!* calculate limits for stable dipole height + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) + if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal +enddo + +dLower = minDipoleHeight(1:ns,1:2,instance) +dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & + / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) +dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & + / (4.0_pReal * pi * abs(tau)) +forall (c = 1_pInt:2_pInt) + where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& + abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & + dUpper(1:ns,c)) +end forall +dUpper = max(dUpper,dLower) + + +!*** dislocation motion + +m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) +m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) +forall (c = 1_pInt:2_pInt, s = 1_pInt:ns) & + m_currentconf(1:3,s,c) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), m(1:3,s,c)) +forall (s = 1_pInt:ns) & + n_currentconf(1:3,s) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), & + lattice_sn(1:3,slipSystemLattice(s,instance),ph)) + + +outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) + select case(plastic_nonlocal_outputID(o,instance)) + case (rho_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) + sum(rhoDip,2) + cs = cs + ns + + case (rho_sgl_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) + cs = cs + ns + + case (rho_sgl_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,1:4)),2) + cs = cs + ns + + case (rho_sgl_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:8),2) + cs = cs + ns + + case (rho_dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDip,2) + cs = cs + ns + + case (rho_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1) + cs = cs + ns + + case (rho_sgl_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + cs = cs + ns + + case (rho_sgl_edge_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,1:2),2) + cs = cs + ns + + case (rho_sgl_edge_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:6),2) + cs = cs + ns + + case (rho_sgl_edge_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5)) + cs = cs + ns + + case (rho_sgl_edge_pos_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) + cs = cs + ns + + case (rho_sgl_edge_pos_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,5) + cs = cs + ns + + case (rho_sgl_edge_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6)) + cs = cs + ns + + case (rho_sgl_edge_neg_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) + cs = cs + ns + + case (rho_sgl_edge_neg_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,6) + cs = cs + ns + + case (rho_dip_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,1) + cs = cs + ns + + case (rho_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2) + cs = cs + ns + + case (rho_sgl_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + cs = cs + ns + + case (rho_sgl_screw_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,3:4),2) + cs = cs + ns + + case (rho_sgl_screw_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,7:8),2) + cs = cs + ns + + case (rho_sgl_screw_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7)) + cs = cs + ns + + case (rho_sgl_screw_pos_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) + cs = cs + ns + + case (rho_sgl_screw_pos_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,7) + cs = cs + ns + + case (rho_sgl_screw_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8)) + cs = cs + ns + + case (rho_sgl_screw_neg_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) + cs = cs + ns + + case (rho_sgl_screw_neg_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,8) + cs = cs + ns + + case (rho_dip_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,2) + cs = cs + ns + + case (excess_rho_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & + - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) & + + (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & + - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) + cs = cs + ns + + case (excess_rho_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & + - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) + cs = cs + ns + + case (excess_rho_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & + - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) + cs = cs + ns + + case (rho_forest_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoForest + cs = cs + ns + + case (delta_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2) + sum(rhoDip,2)) + cs = cs + ns + + case (delta_sgl_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2)) + cs = cs + ns + + case (delta_dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(rhoDip,2)) + cs = cs + ns + + case (shearrate_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(gdot,2) + cs = cs + ns + + case (resolvedstress_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tau + cs = cs + ns + + case (resolvedstress_back_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauBack + cs = cs + ns + + case (resolvedstress_external_ID) + do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + plastic_nonlocal_postResults(cs+s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + enddo + cs = cs + ns + + case (resistance_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauThreshold + cs = cs + ns + + case (rho_dot_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & + + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) & + + sum(rhoDotDip,2) + cs = cs + ns + + case (rho_dot_sgl_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & + + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) + cs = cs + ns + + case (rho_dot_sgl_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) + cs = cs + ns + + case (rho_dot_dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotDip,2) + cs = cs + ns + + case (rho_dot_gen_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_gen_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_gen_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_sgl2dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_sgl2dip_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_sgl2dip_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_ath_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotAthermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotAthermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_the_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_the_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_the_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_edgejogs_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_flux_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) + cs = cs + ns + + case (rho_dot_flux_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) & + + sum(rhoDotFluxOutput(1:ns,5:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) + cs = cs + ns + + case (rho_dot_flux_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:2,1_pInt,ip,el),2) & + + sum(rhoDotFluxOutput(1:ns,5:6,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:6)),2) + cs = cs + ns + + case (rho_dot_flux_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,3:4,1_pInt,ip,el),2) & + + sum(rhoDotFluxOutput(1:ns,7:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,7:8)),2) + cs = cs + ns + + case (velocity_edge_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,1) + cs = cs + ns + + case (velocity_edge_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,2) + cs = cs + ns + + case (velocity_screw_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,3) + cs = cs + ns + + case (velocity_screw_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,4) + cs = cs + ns + + case (slipdirectionx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(1,1:ns,1) + cs = cs + ns + + case (slipdirectiony_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(2,1:ns,1) + cs = cs + ns + + case (slipdirectionz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(3,1:ns,1) + cs = cs + ns + + case (slipnormalx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(1,1:ns) + cs = cs + ns + + case (slipnormaly_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(2,1:ns) + cs = cs + ns + + case (slipnormalz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(3,1:ns) + cs = cs + ns + + case (fluxdensity_edge_posx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(1,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_posy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(2,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_posz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(3,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_negx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(1,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_negy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(2,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_negz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(3,1:ns,1) + cs = cs + ns + + case (fluxdensity_screw_posx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(1,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_posy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(2,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_posz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(3,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_negx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(1,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_negy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(2,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_negz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(3,1:ns,2) + cs = cs + ns + + case (maximumdipoleheight_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,1) + cs = cs + ns + + case (maximumdipoleheight_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,2) + cs = cs + ns + + case(dislocationstress_ID) + sigma = plastic_nonlocal_dislocationstress(Fe, ip, el) + plastic_nonlocal_postResults(cs+1_pInt) = sigma(1,1) + plastic_nonlocal_postResults(cs+2_pInt) = sigma(2,2) + plastic_nonlocal_postResults(cs+3_pInt) = sigma(3,3) + plastic_nonlocal_postResults(cs+4_pInt) = sigma(1,2) + plastic_nonlocal_postResults(cs+5_pInt) = sigma(2,3) + plastic_nonlocal_postResults(cs+6_pInt) = sigma(3,1) + cs = cs + 6_pInt + + case(accumulatedshear_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = plasticState(ph)%state(iGamma(1:ns,instance),of) + cs = cs + ns + + end select +enddo outputsLoop + +end function plastic_nonlocal_postResults + +end module plastic_nonlocal diff --git a/code/plastic/plastic_phenoplus.f90 b/code/plastic/plastic_phenoplus.f90 new file mode 100644 index 000000000..0a40edd84 --- /dev/null +++ b/code/plastic/plastic_phenoplus.f90 @@ -0,0 +1,1419 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Chen Zhang, Michigan State University +!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw +!... fitting +!-------------------------------------------------------------------------------------------------- +module plastic_phenoplus + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenoplus_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_phenoplus_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_phenoplus_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_phenoplus_Noutput !< number of outputs per instance of this constitution + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenoplus_totalNslip, & !< no. of slip system used in simulation + plastic_phenoplus_totalNtwin, & !< no. of twin system used in simulation + plastic_phenoplus_totalNtrans !< no. of trans system used in simulation + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_phenoplus_Nslip, & !< active number of slip systems per family (input parameter, per family) + plastic_phenoplus_Ntwin, & !< active number of twin systems per family (input parameter, per family) + plastic_phenoplus_Ntrans !< active number of trans systems per family (input parameter, per family) + + real(pReal), dimension(:), allocatable, private :: & + plastic_phenoplus_gdot0_slip, & !< reference shear strain rate for slip (input parameter) + plastic_phenoplus_gdot0_twin, & !< reference shear strain rate for twin (input parameter) + plastic_phenoplus_n_slip, & !< stress exponent for slip (input parameter) + plastic_phenoplus_n_twin, & !< stress exponent for twin (input parameter) + plastic_phenoplus_spr, & !< push-up factor for slip saturation due to twinning + plastic_phenoplus_twinB, & + plastic_phenoplus_twinC, & + plastic_phenoplus_twinD, & + plastic_phenoplus_twinE, & + plastic_phenoplus_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) + plastic_phenoplus_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) + plastic_phenoplus_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) + plastic_phenoplus_a_slip, & + plastic_phenoplus_aTolResistance, & + plastic_phenoplus_aTolShear, & + plastic_phenoplus_aTolTwinfrac, & + plastic_phenoplus_aTolTransfrac, & + plastic_phenoplus_Cnuc, & !< coefficient for strain-induced martensite nucleation + plastic_phenoplus_Cdwp, & !< coefficient for double well potential + plastic_phenoplus_Cgro, & !< coefficient for stress-assisted martensite growth + plastic_phenoplus_deltaG, & !< free energy difference between austensite and martensite [MPa] + plastic_phenoplus_kappa_max !< capped kappa for each slip system + + real(pReal), dimension(:,:), allocatable, private :: & + plastic_phenoplus_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) + plastic_phenoplus_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) + plastic_phenoplus_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) + plastic_phenoplus_nonSchmidCoeff, & + + plastic_phenoplus_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) + plastic_phenoplus_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) + plastic_phenoplus_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) + plastic_phenoplus_interaction_TwinTwin !< interaction factors twin - twin (input parameter) + + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_phenoplus_hardeningMatrix_SlipSlip, & + plastic_phenoplus_hardeningMatrix_SlipTwin, & + plastic_phenoplus_hardeningMatrix_TwinSlip, & + plastic_phenoplus_hardeningMatrix_TwinTwin + + enum, bind(c) + enumerator :: undefined_ID, & + resistance_slip_ID, & + accumulatedshear_slip_ID, & + shearrate_slip_ID, & + resolvedstress_slip_ID, & + kappa_slip_ID, & + totalshear_ID, & + resistance_twin_ID, & + accumulatedshear_twin_ID, & + shearrate_twin_ID, & + resolvedstress_twin_ID, & + totalvolfrac_twin_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_phenoplus_outputID !< ID of each post result output + + public :: & + plastic_phenoplus_init, & + plastic_phenoplus_microstructure, & + plastic_phenoplus_LpAndItsTangent, & + plastic_phenoplus_dotState, & + plastic_phenoplus_postResults + private :: & + plastic_phenoplus_aTolState, & + plastic_phenoplus_stateInit + + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_PHENOPLUS_label, & + PLASTICITY_PHENOPLUS_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + maxNinstance, & + instance,phase,j,k, f,o, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & + Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & + NipcMyPhase, & + offset_slip, index_myFamily, index_otherFamily, & + mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPLUS_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPLUS_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_phenoplus_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_sizePostResult(maxval(phase_Noutput),maxNinstance), & + source=0_pInt) + allocate(plastic_phenoplus_output(maxval(phase_Noutput),maxNinstance)) + plastic_phenoplus_output = '' + allocate(plastic_phenoplus_outputID(maxval(phase_Noutput),maxNinstance),source=undefined_ID) + allocate(plastic_phenoplus_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_Ntrans(lattice_maxNtransFamily,maxNinstance),source=0_pInt) + allocate(plastic_phenoplus_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_totalNtrans(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_gdot0_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_n_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_tau0_slip(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_tausat_slip(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_gdot0_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_n_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_tau0_twin(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_spr(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinB(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinC(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinD(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinE(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_h0_SlipSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_h0_TwinSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_h0_TwinTwin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_a_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolShear(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolTwinfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolTransfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_Cnuc(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_Cdwp(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_Cgro(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_deltaG(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_kappa_max(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase + Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('resistance_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_slip','accumulated_shear_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('kappa_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = kappa_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalshear') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalshear_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_twin','accumulated_shear_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalvolfrac_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalvolfrac_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case default + + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) + do j = 1_pInt, Nchunks_SlipFamilies + plastic_phenoplus_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tausat_slip','tau0_slip') + tempPerSlip = 0.0_pReal + do j = 1_pInt, Nchunks_SlipFamilies + if (plastic_phenoplus_Nslip(j,instance) > 0_pInt) & + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('tausat_slip') + plastic_phenoplus_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau0_slip') + plastic_phenoplus_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_phenoplus_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0_twin') + do j = 1_pInt, Nchunks_TwinFamilies + if (plastic_phenoplus_Ntwin(j,instance) > 0_pInt) & + plastic_phenoplus_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of transformation families + case ('ntrans') + if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + Nchunks_TransFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TransFamilies + plastic_phenoplus_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_phenoplus_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_phenoplus_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_phenoplus_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_phenoplus_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt,Nchunks_nonSchmid + plastic_phenoplus_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin systems + case ('gdot0_slip') + plastic_phenoplus_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_slip') + plastic_phenoplus_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('a_slip', 'w0_slip') + plastic_phenoplus_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('gdot0_twin') + plastic_phenoplus_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_twin') + plastic_phenoplus_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('s_pr') + plastic_phenoplus_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_b') + plastic_phenoplus_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_c') + plastic_phenoplus_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_d') + plastic_phenoplus_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_e') + plastic_phenoplus_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_slipslip') + plastic_phenoplus_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twinslip') + plastic_phenoplus_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twintwin') + plastic_phenoplus_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_resistance') + plastic_phenoplus_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_shear') + plastic_phenoplus_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_phenoplus_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_transfrac') + plastic_phenoplus_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('kappa_max') + plastic_phenoplus_kappa_max(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cnuc') + plastic_phenoplus_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cdwp') + plastic_phenoplus_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cgro') + plastic_phenoplus_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('deltag') + plastic_phenoplus_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) + case default + + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then + instance = phase_plasticityInstance(phase) + plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested + plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance)) + plastic_phenoplus_Ntwin(1:lattice_maxNtwinFamily,instance) = & + min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested + plastic_phenoplus_Ntwin(:,instance)) + plastic_phenoplus_totalNslip(instance) = sum(plastic_phenoplus_Nslip(:,instance)) ! how many slip systems altogether + plastic_phenoplus_totalNtwin(instance) = sum(plastic_phenoplus_Ntwin(:,instance)) ! how many twin systems altogether + plastic_phenoplus_totalNtrans(instance) = sum(plastic_phenoplus_Ntrans(:,instance)) ! how many trans systems altogether + + if (any(plastic_phenoplus_tau0_slip(:,instance) < 0.0_pReal .and. & + plastic_phenoplus_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (plastic_phenoplus_gdot0_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (plastic_phenoplus_n_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (any(plastic_phenoplus_tausat_slip(:,instance) <= 0.0_pReal .and. & + plastic_phenoplus_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (any(abs(plastic_phenoplus_a_slip(instance)) <= tiny(0.0_pReal) .and. & + plastic_phenoplus_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (any(plastic_phenoplus_tau0_twin(:,instance) < 0.0_pReal .and. & + plastic_phenoplus_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPLUS_label//')') + if ( plastic_phenoplus_gdot0_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenoplus_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPLUS_label//')') + if ( plastic_phenoplus_n_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenoplus_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPLUS_label//')') + if (plastic_phenoplus_aTolResistance(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa + if (plastic_phenoplus_aTolShear(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenoplus_aTolTwinfrac(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenoplus_aTolTransfrac(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + allocate(plastic_phenoplus_hardeningMatrix_SlipSlip(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from slip activity + maxval(plastic_phenoplus_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_hardeningMatrix_SlipTwin(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from twin activity + maxval(plastic_phenoplus_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_hardeningMatrix_TwinSlip(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_phenoplus_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_hardeningMatrix_TwinTwin(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_phenoplus_totalNtwin),& + maxNinstance), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config + myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then ! only consider my phase + NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase + instance = phase_plasticityInstance(phase) ! which instance of my phase + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) + select case(plastic_phenoplus_outputID(o,instance)) + case(resistance_slip_ID, & + shearrate_slip_ID, & + accumulatedshear_slip_ID, & + resolvedstress_slip_ID, & + kappa_slip_ID & + ) + mySize = plastic_phenoplus_totalNslip(instance) + case(resistance_twin_ID, & + shearrate_twin_ID, & + accumulatedshear_twin_ID, & + resolvedstress_twin_ID & + ) + mySize = plastic_phenoplus_totalNtwin(instance) + case(totalshear_ID, & + totalvolfrac_twin_ID & + ) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_phenoplus_sizePostResult(o,instance) = mySize + plastic_phenoplus_sizePostResults(instance) = plastic_phenoplus_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = plastic_phenoplus_totalNslip(instance) & ! s_slip + + plastic_phenoplus_totalNtwin(instance) & ! s_twin + + 2_pInt & ! sum(gamma) + sum(f) + + plastic_phenoplus_totalNslip(instance) & ! accshear_slip + + plastic_phenoplus_totalNtwin(instance) & ! accshear_twin + + plastic_phenoplus_totalNslip(instance) ! kappa + + !sizeDotState = sizeState ! same as sizeState + !QUICK FIX: the dotState cannot have redundancy, which could cause unknown error + ! explicitly specify the size of the dotState to avoid this potential + ! memory leak issue. + sizeDotState = plastic_phenoplus_totalNslip(instance) & ! s_slip + + plastic_phenoplus_totalNtwin(instance) & ! s_twin + + 2_pInt & ! sum(gamma) + sum(f) + + plastic_phenoplus_totalNslip(instance) & ! accshear_slip + + plastic_phenoplus_totalNtwin(instance) ! accshear_twin + + sizeDeltaState = 0_pInt + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_phenoplus_sizePostResults(instance) + plasticState(phase)%nSlip =plastic_phenoplus_totalNslip(instance) + plasticState(phase)%nTwin =plastic_phenoplus_totalNtwin(instance) + plasticState(phase)%nTrans=plastic_phenoplus_totalNtrans(instance) + allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) + + offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + + do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X + index_myFamily = sum(plastic_phenoplus_Nslip(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenoplus_Nslip(f,instance) ! loop over (active) systems in my family (slip) + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenoplus_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenoplus_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + + do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X + index_myFamily = sum(plastic_phenoplus_Ntwin(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenoplus_Ntwin(f,instance) ! loop over (active) systems in my family (twin) + + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenoplus_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenoplus_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + + call plastic_phenoplus_stateInit(phase,instance) + call plastic_phenoplus_aTolState(phase,instance) + endif myPhase2 + enddo initializeInstances + +end subroutine plastic_phenoplus_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_stateInit(ph,instance) + use lattice, only: & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + integer(pInt) :: & + i + real(pReal), dimension(plasticState(ph)%sizeState) :: & + tempState + + tempState = 0.0_pReal + do i = 1_pInt,lattice_maxNslipFamily + tempState(1+sum(plastic_phenoplus_Nslip(1:i-1,instance)) : & + sum(plastic_phenoplus_Nslip(1:i ,instance))) = & + plastic_phenoplus_tau0_slip(i,instance) + enddo + + do i = 1_pInt,lattice_maxNtwinFamily + tempState(1+sum(plastic_phenoplus_Nslip(:,instance))+& + sum(plastic_phenoplus_Ntwin(1:i-1,instance)) : & + sum(plastic_phenoplus_Nslip(:,instance))+& + sum(plastic_phenoplus_Ntwin(1:i ,instance))) = & + plastic_phenoplus_tau0_twin(i,instance) + enddo + + plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array + 2, & ! along dimension 2 + size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) + +end subroutine plastic_phenoplus_stateInit + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + plasticState(ph)%aTolState(1:plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance)) = & + plastic_phenoplus_aTolResistance(instance) + plasticState(ph)%aTolState(1+plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance)) = & + plastic_phenoplus_aTolShear(instance) + plasticState(ph)%aTolState(2+plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance)) = & + plastic_phenoplus_aTolTwinFrac(instance) + plasticState(ph)%aTolState(3+plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance): & + 2+2*(plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance))) = & + plastic_phenoplus_aTolShear(instance) + +end subroutine plastic_phenoplus_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate push-up factors (kappa) for each voxel based on its neighbors +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el) + use math, only: pi, & + math_mul33x33, & + math_mul3x3, & + math_transpose33, & + math_qDot, & + math_qRot, & + indeg + + use mesh, only: mesh_element, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype, & + mesh_maxNips, & + mesh_NcpElems, & + mesh_ipNeighborhood + + use material, only: material_phase, & + material_texture, & + phase_plasticityInstance, & + phaseAt, phasememberAt, & + homogenization_maxNgrains, & + plasticState + + use lattice, only: lattice_sn, & + lattice_sd, & + lattice_qDisorientation + + !***input variables + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + orientation ! crystal orientation in quaternions + + !***local variables + integer(pInt) instance, & !my instance of this plasticity + ph, & !my phase + of, & !my spatial position in memory (offset) + textureID, & !my texture + Nneighbors, & !number of neighbors (<= 6) + vld_Nneighbors, & !number of my valid neighbors + n, & !neighbor index (for iterating through all neighbors) + ns, & !number of slip system + nt, & !number of twin system + me_slip, & !my slip system index + neighbor_el, & !element number of neighboring material point + neighbor_ip, & !integration point of neighboring material point + neighbor_n, & !I have no idea what is this + neighbor_of, & !spatial position in memory for this neighbor (offset) + neighbor_ph, & !neighbor's phase + neighbor_tex, & !neighbor's texture ID + ne_slip_ac, & !loop to find neighbor shear + ne_slip, & !slip system index for neighbor + index_kappa, & !index of pushup factors in plasticState + offset_acshear_slip, & !offset in PlasticState for the accumulative shear + j !quickly loop through slip families + + real(pReal) kappa_max, & ! + tmp_myshear_slip, & !temp storage for accumulative shear for me + mprime_cut, & !m' cutoff to consider neighboring effect + avg_acshear_ne, & !the average accumulative shear from my neighbor + tmp_mprime, & !temp holder for m' value + tmp_acshear !temp holder for accumulative shear for m' + + + real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + m_primes, & !m' between me_alpha(one) and neighbor beta(all) + me_acshear, & !temp storage for ac_shear of one particular system for me + ne_acshear !temp storage for ac_shear of one particular system for one of my neighbor + + real(pReal), dimension(3,plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + slipNormal, & + slipDirect + + real(pReal), dimension(4) :: my_orientation, & !store my orientation + neighbor_orientation, & !store my neighbor orientation + absMisorientation + + real(pReal), dimension(FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) :: & + ne_mprimes !m' between each neighbor + + !***Get my properties + Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) + ph = phaseAt(ipc,ip,el) !get my phase + of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory + textureID = material_texture(1,ip,el) !get my texture ID + instance = phase_plasticityInstance(ph) !get my instance based on phase ID + ns = plastic_phenoplus_totalNslip(instance) + nt = plastic_phenoplus_totalNtwin(instance) + offset_acshear_slip = ns + nt + 2_pInt + index_kappa = ns + nt + 2_pInt + ns + nt !location of kappa in plasticState + mprime_cut = 0.7_pReal !set by Dr.Bieler + + !***gather my accumulative shear from palsticState + FINDMYSHEAR: do j = 1_pInt,ns + me_acshear(j) = plasticState(ph)%state(offset_acshear_slip+j, of) + enddo FINDMYSHEAR + + !***gather my orientation and slip systems + my_orientation = orientation(1:4, ipc, ip, el) + slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) + slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) + kappa_max = plastic_phenoplus_kappa_max(instance) !maximum pushups allowed (READIN) + + !***calculate kappa between me and all my neighbors + LOOPMYSLIP: DO me_slip=1_pInt,ns + vld_Nneighbors = Nneighbors + tmp_myshear_slip = me_acshear(me_slip) + tmp_mprime = 0.0_pReal !highest m' from all neighbors + tmp_acshear = 0.0_pReal !accumulative shear from highest m' + + !***go through my neighbors to find highest m' + LOOPNEIGHBORS: DO n=1_pInt,Nneighbors + neighbor_el = mesh_ipNeighborhood(1,n,ip,el) + neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) + neighbor_n = 1 !It is ipc + neighbor_of = phasememberAt( neighbor_n, neighbor_ip, neighbor_el) + neighbor_ph = phaseAt( neighbor_n, neighbor_ip, neighbor_el) + neighbor_tex = material_texture(1,neighbor_ip,neighbor_el) + neighbor_orientation = orientation(1:4, neighbor_n, neighbor_ip, neighbor_el) !ipc is always 1. + absMisorientation = lattice_qDisorientation(my_orientation, & + neighbor_orientation, & + 0_pInt) !no need for explicit calculation of symmetry + + !***find the accumulative shear for this neighbor + LOOPFINDNEISHEAR: DO ne_slip_ac=1_pInt, ns + ne_acshear(ne_slip_ac) = plasticState(ph)%state(offset_acshear_slip+ne_slip_ac, & + neighbor_of) + ENDDO LOOPFINDNEISHEAR + + !***calculate the average accumulative shear and use it as cutoff + avg_acshear_ne = SUM(ne_acshear)/ns + + !*** + IF (ph==neighbor_ph) THEN + !***walk through all the + LOOPNEIGHBORSLIP: DO ne_slip=1_pInt,ns + !***only consider slip system that is active (above average accumulative shear) + IF (ne_acshear(ne_slip) > avg_acshear_ne) THEN + m_primes(ne_slip) = abs(math_mul3x3(slipNormal(1:3,me_slip), & + math_qRot(absMisorientation, slipNormal(1:3,ne_slip)))) & + *abs(math_mul3x3(slipDirect(1:3,me_slip), & + math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) + !***find the highest m' and corresponding accumulative shear + IF (m_primes(ne_slip) > tmp_mprime) THEN + tmp_mprime = m_primes(ne_slip) + tmp_acshear = ne_acshear(ne_slip) + ENDIF + ENDIF + ENDDO LOOPNEIGHBORSLIP + + ELSE + ne_mprimes(n) = 0.0_pReal + vld_Nneighbors = vld_Nneighbors - 1_pInt + ENDIF + + ENDDO LOOPNEIGHBORS + + !***check if this element close to rim + IF (vld_Nneighbors < Nneighbors) THEN + !***rim voxel, no modification allowed + plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal + ELSE + !***patch voxel, started to calculate push up factor for gamma_dot + IF ((tmp_mprime > mprime_cut) .AND. (tmp_acshear > tmp_myshear_slip)) THEN + plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal / tmp_mprime + ELSE + !***minimum damping factor is 0.5 + plasticState(ph)%state(index_kappa+me_slip, of) = 0.5_pReal + tmp_mprime * 0.5_pReal + ENDIF + ENDIF + + ENDDO LOOPMYSLIP + +end subroutine plastic_phenoplus_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use math, only: & + math_Plain3333to99, & + math_Mandel6to33 + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + use material, only: & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + + integer(pInt) :: & + instance, & + nSlip, & + nTwin,index_Gamma,index_F,index_myFamily, index_kappa, & + f,i,j,k,l,m,n, & + of, & + ph + real(pReal) :: & + tau_slip_pos,tau_slip_neg, & + gdot_slip_pos,gdot_slip_neg, & + dgdot_dtauslip_pos,dgdot_dtauslip_neg, & + gdot_twin,dgdot_dtautwin,tau_twin + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal), dimension(3,3,2) :: & + nonSchmid_tensor + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + nSlip = plastic_phenoplus_totalNslip(instance) + nTwin = plastic_phenoplus_totalNtwin(instance) + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + index_kappa = nSlip + nTwin + 2_pInt +nSlip + nTwin + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Slip part + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) + enddo + + !***insert non-local effect here by modify gdot with kappa in plastic state + !***this implementation will most likely cause convergence issue + ! gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ! ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of)* & + ! plasticState(ph)%state(j+index_kappa, of))) & !in-place modification of gdot + ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) + + ! gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ! ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of)* & + ! plasticState(ph)%state(j+index_kappa, of))) & !?should we make it direction aware + ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) + + !***original calculation + gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of))) & !in-place modification of gdot + **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) + + gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of))) & !?should we make it direction aware + **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) + + !***MAGIC HERE***! + !***directly modify the amount of shear happens considering neighborhood + gdot_slip_pos = gdot_slip_pos * plasticState(ph)%state(j+index_kappa, of) + gdot_slip_neg = gdot_slip_neg * plasticState(ph)%state(j+index_kappa, of) + + Lp = Lp + (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then + dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenoplus_n_slip(instance)/tau_slip_pos + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,1) + endif + + if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then + dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenoplus_n_slip(instance)/tau_slip_neg + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,2) + endif + enddo slipSystems + enddo slipFamilies + +!-------------------------------------------------------------------------------------------------- +! Twinning part + j = 0_pInt + twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenoplus_gdot0_twin(instance)*& + (abs(tau_twin)/plasticState(ph)%state(nSlip+j,of))**& + plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_twin) > tiny(0.0_pReal)) then + dgdot_dtautwin = gdot_twin*plastic_phenoplus_n_twin(instance)/tau_twin + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & + lattice_Stwin(m,n,index_myFamily+i,ph) + endif + enddo twinSystems + enddo twinFamilies + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + + +end subroutine plastic_phenoplus_LpAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_dotState(Tstar_v,ipc,ip,el) + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_shearTwin, & + lattice_NnonSchmid + use material, only: & + material_phase, & + phaseAt, phasememberAt, & + plasticState, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + integer(pInt) :: & + instance,ph, & + nSlip,nTwin, & + f,i,j,k, & + index_Gamma,index_F,index_myFamily,& + offset_accshear_slip,offset_accshear_twin, offset_kappa, & + of + real(pReal) :: & + c_SlipSlip,c_TwinSlip,c_TwinTwin, & + ssat_offset, & + tau_slip_pos,tau_slip_neg,tau_twin + + real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip + real(pReal), dimension(plastic_phenoplus_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenoplus_totalNslip(instance) + nTwin = plastic_phenoplus_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + offset_accshear_slip = nSlip + nTwin + 2_pInt + offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + offset_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin + plasticState(ph)%dotState(:,of) = 0.0_pReal + + +!-------------------------------------------------------------------------------------------------- +! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices + c_SlipSlip = plastic_phenoplus_h0_SlipSlip(instance)*& + (1.0_pReal + plastic_phenoplus_twinC(instance)*plasticState(ph)%state(index_F,of)**& + plastic_phenoplus_twinB(instance)) + c_TwinSlip = plastic_phenoplus_h0_TwinSlip(instance)*& + plasticState(ph)%state(index_Gamma,of)**plastic_phenoplus_twinE(instance) + c_TwinTwin = plastic_phenoplus_h0_TwinTwin(instance)*& + plasticState(ph)%state(index_F,of)**plastic_phenoplus_twinD(instance) + +!-------------------------------------------------------------------------------------------------- +! calculate left and right vectors and calculate dot gammas + ssat_offset = plastic_phenoplus_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j+1_pInt + left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part + left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part + !***original implementation + right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & + **plastic_phenoplus_a_slip(instance)& + *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) + !***modify a_slip to get nonlocal effect + ! right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & + ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & + ! **(plastic_phenoplus_a_slip(instance)*plasticState(ph)%state(j+offset_kappa, of))& + ! *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & + ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) + right_TwinSlip(j) = 1.0_pReal ! no system-dependent part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot gamma + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + gdot_slip(j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance) & + +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + enddo slipSystems1 + enddo slipFamilies1 + + + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j+1_pInt + left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part + left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part + right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part + right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot vol frac + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenoplus_gdot0_twin(instance)*& + (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& + plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + enddo twinSystems1 + enddo twinFamilies1 + +!-------------------------------------------------------------------------------------------------- +! calculate the overall hardening based on above + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j + c_SlipSlip * left_SlipSlip(j) * & + dot_product(plastic_phenoplus_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & + right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + dot_product(plastic_phenoplus_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & + right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & + abs(gdot_slip(j)) + plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) + enddo slipSystems2 + enddo slipFamilies2 + + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j + c_TwinSlip * left_TwinSlip(j) * & + dot_product(plastic_phenoplus_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & + right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + c_TwinTwin * left_TwinTwin(j) * & + dot_product(plastic_phenoplus_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & + right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 + plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & + gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) + plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) + enddo twinSystems2 + enddo twinFamilies2 + + +end subroutine plastic_phenoplus_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_phenoplus_postResults(Tstar_v,ipc,ip,el) + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + real(pReal), dimension(plastic_phenoplus_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_phenoplus_postResults + + integer(pInt) :: & + instance,ph, of, & + nSlip,nTwin, & + o,f,i,c,j,k, & + index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily,index_kappa + real(pReal) :: & + tau_slip_pos,tau_slip_neg,tau + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenoplus_totalNslip(instance) + nTwin = plastic_phenoplus_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + index_accshear_slip = nSlip + nTwin + 2_pInt + 1_pInt + index_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + 1_pInt + index_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin + 1_pInt + + plastic_phenoplus_postResults = 0.0_pReal + c = 0_pInt + + outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) + select case(plastic_phenoplus_outputID(o,instance)) + case (resistance_slip_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) + c = c + nSlip + + case (accumulatedshear_slip_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& + index_accshear_slip+nSlip-1_pInt,of) + c = c + nSlip + + case (shearrate_slip_ID) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j + 1_pInt + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo + plastic_phenoplus_postResults(c+j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance) & + +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + + enddo slipSystems1 + enddo slipFamilies1 + c = c + nSlip + + case (resolvedstress_slip_ID) + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j + 1_pInt + plastic_phenoplus_postResults(c+j) = & + dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + enddo slipSystems2 + enddo slipFamilies2 + c = c + nSlip + + case (kappa_slip_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = & + plasticState(ph)%state(index_kappa:index_kappa+nSlip-1_pInt,of) + c = c + nSlip + + case (totalshear_ID) + plastic_phenoplus_postResults(c+1_pInt) = & + plasticState(ph)%state(index_Gamma,of) + c = c + 1_pInt + + case (resistance_twin_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) + c = c + nTwin + + case (accumulatedshear_twin_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) + c = c + nTwin + + case (shearrate_twin_ID) + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j + 1_pInt + tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + plastic_phenoplus_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenoplus_gdot0_twin(instance)*& + (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& + plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) + enddo twinSystems1 + enddo twinFamilies1 + c = c + nTwin + + case (resolvedstress_twin_ID) + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j + 1_pInt + plastic_phenoplus_postResults(c+j) = & + dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + enddo twinSystems2 + enddo twinFamilies2 + c = c + nTwin + + case (totalvolfrac_twin_ID) + plastic_phenoplus_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) + c = c + 1_pInt + + end select + enddo outputsLoop + +end function plastic_phenoplus_postResults + +end module plastic_phenoplus diff --git a/code/plastic/plastic_phenopowerlaw.f90 b/code/plastic/plastic_phenopowerlaw.f90 new file mode 100644 index 000000000..1f8e16250 --- /dev/null +++ b/code/plastic/plastic_phenopowerlaw.f90 @@ -0,0 +1,1226 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw +!! fitting +!-------------------------------------------------------------------------------------------------- +module plastic_phenopowerlaw + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenopowerlaw_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_phenopowerlaw_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_phenopowerlaw_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_phenopowerlaw_Noutput !< number of outputs per instance of this constitution + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenopowerlaw_totalNslip, & !< no. of slip system used in simulation + plastic_phenopowerlaw_totalNtwin, & !< no. of twin system used in simulation + plastic_phenopowerlaw_totalNtrans !< no. of trans system used in simulation + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_phenopowerlaw_Nslip, & !< active number of slip systems per family (input parameter, per family) + plastic_phenopowerlaw_Ntwin, & !< active number of twin systems per family (input parameter, per family) + plastic_phenopowerlaw_Ntrans !< active number of trans systems per family (input parameter, per family) + + real(pReal), dimension(:), allocatable, private :: & + plastic_phenopowerlaw_gdot0_slip, & !< reference shear strain rate for slip (input parameter) + plastic_phenopowerlaw_gdot0_twin, & !< reference shear strain rate for twin (input parameter) + plastic_phenopowerlaw_n_slip, & !< stress exponent for slip (input parameter) + plastic_phenopowerlaw_n_twin, & !< stress exponent for twin (input parameter) + plastic_phenopowerlaw_spr, & !< push-up factor for slip saturation due to twinning + plastic_phenopowerlaw_twinB, & + plastic_phenopowerlaw_twinC, & + plastic_phenopowerlaw_twinD, & + plastic_phenopowerlaw_twinE, & + plastic_phenopowerlaw_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) + plastic_phenopowerlaw_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) + plastic_phenopowerlaw_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) + plastic_phenopowerlaw_a_slip, & + plastic_phenopowerlaw_aTolResistance, & + plastic_phenopowerlaw_aTolShear, & + plastic_phenopowerlaw_aTolTwinfrac, & + plastic_phenopowerlaw_aTolTransfrac, & + plastic_phenopowerlaw_Cnuc, & !< coefficient for strain-induced martensite nucleation + plastic_phenopowerlaw_Cdwp, & !< coefficient for double well potential + plastic_phenopowerlaw_Cgro, & !< coefficient for stress-assisted martensite growth + plastic_phenopowerlaw_deltaG !< free energy difference between austensite and martensite [MPa] + + real(pReal), dimension(:,:), allocatable, private :: & + plastic_phenopowerlaw_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) + plastic_phenopowerlaw_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) + plastic_phenopowerlaw_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) + plastic_phenopowerlaw_nonSchmidCoeff, & + + plastic_phenopowerlaw_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) + plastic_phenopowerlaw_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) + plastic_phenopowerlaw_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) + plastic_phenopowerlaw_interaction_TwinTwin !< interaction factors twin - twin (input parameter) + + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_phenopowerlaw_hardeningMatrix_SlipSlip, & + plastic_phenopowerlaw_hardeningMatrix_SlipTwin, & + plastic_phenopowerlaw_hardeningMatrix_TwinSlip, & + plastic_phenopowerlaw_hardeningMatrix_TwinTwin + + enum, bind(c) + enumerator :: undefined_ID, & + resistance_slip_ID, & + accumulatedshear_slip_ID, & + shearrate_slip_ID, & + resolvedstress_slip_ID, & + totalshear_ID, & + resistance_twin_ID, & + accumulatedshear_twin_ID, & + shearrate_twin_ID, & + resolvedstress_twin_ID, & + totalvolfrac_twin_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_phenopowerlaw_outputID !< ID of each post result output + + type, private :: tPhenopowerlawState + real(pReal), pointer, dimension(:,:) :: & + s_slip, & + s_twin, & + accshear_slip, & + accshear_twin + real(pReal), pointer, dimension(:) :: & + sumGamma, & + sumF + end type + + type(tPhenopowerlawState), allocatable, dimension(:), private :: & + dotState, & + state, & + state0 + + public :: & + plastic_phenopowerlaw_init, & + plastic_phenopowerlaw_LpAndItsTangent, & + plastic_phenopowerlaw_dotState, & + plastic_phenopowerlaw_postResults + private :: & + plastic_phenopowerlaw_aTolState, & + plastic_phenopowerlaw_stateInit + + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_PHENOPOWERLAW_label, & + PLASTICITY_PHENOPOWERLAW_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + maxNinstance, & + instance,phase,j,k, f,o, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & + Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & + NipcMyPhase, & + offset_slip, index_myFamily, index_otherFamily, & + mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState, & + startIndex, endIndex + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPOWERLAW_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPOWERLAW_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + + allocate(plastic_phenopowerlaw_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_sizePostResult(maxval(phase_Noutput),maxNinstance), & + source=0_pInt) + allocate(plastic_phenopowerlaw_output(maxval(phase_Noutput),maxNinstance)) + plastic_phenopowerlaw_output = '' + allocate(plastic_phenopowerlaw_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_phenopowerlaw_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_totalNtrans(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_gdot0_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_n_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_tau0_slip(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_tausat_slip(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_phenopowerlaw_gdot0_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_n_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_tau0_twin(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_spr(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinB(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinC(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinD(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinE(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_h0_SlipSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_h0_TwinSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_h0_TwinTwin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_a_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolShear(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolTwinfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolTransfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_Cnuc(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_Cdwp(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_Cgro(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_deltaG(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase + Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('resistance_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_slip','accumulated_shear_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalshear') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalshear_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_twin','accumulated_shear_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalvolfrac_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalvolfrac_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case default + + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) + do j = 1_pInt, Nchunks_SlipFamilies + plastic_phenopowerlaw_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tausat_slip','tau0_slip') + tempPerSlip = 0.0_pReal + do j = 1_pInt, Nchunks_SlipFamilies + if (plastic_phenopowerlaw_Nslip(j,instance) > 0_pInt) & + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('tausat_slip') + plastic_phenopowerlaw_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau0_slip') + plastic_phenopowerlaw_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_phenopowerlaw_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0_twin') + do j = 1_pInt, Nchunks_TwinFamilies + if (plastic_phenopowerlaw_Ntwin(j,instance) > 0_pInt) & + plastic_phenopowerlaw_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of transformation families + case ('ntrans') + if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + Nchunks_TransFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TransFamilies + plastic_phenopowerlaw_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_phenopowerlaw_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_phenopowerlaw_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_phenopowerlaw_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_phenopowerlaw_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt,Nchunks_nonSchmid + plastic_phenopowerlaw_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin systems + case ('gdot0_slip') + plastic_phenopowerlaw_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_slip') + plastic_phenopowerlaw_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('a_slip', 'w0_slip') + plastic_phenopowerlaw_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('gdot0_twin') + plastic_phenopowerlaw_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_twin') + plastic_phenopowerlaw_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('s_pr') + plastic_phenopowerlaw_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_b') + plastic_phenopowerlaw_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_c') + plastic_phenopowerlaw_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_d') + plastic_phenopowerlaw_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_e') + plastic_phenopowerlaw_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_slipslip') + plastic_phenopowerlaw_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twinslip') + plastic_phenopowerlaw_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twintwin') + plastic_phenopowerlaw_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_resistance') + plastic_phenopowerlaw_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_shear') + plastic_phenopowerlaw_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_phenopowerlaw_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_transfrac') + plastic_phenopowerlaw_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cnuc') + plastic_phenopowerlaw_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cdwp') + plastic_phenopowerlaw_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cgro') + plastic_phenopowerlaw_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('deltag') + plastic_phenopowerlaw_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) + case default + + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then + instance = phase_plasticityInstance(phase) + plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested + plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance)) + plastic_phenopowerlaw_Ntwin(1:lattice_maxNtwinFamily,instance) = & + min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested + plastic_phenopowerlaw_Ntwin(:,instance)) + plastic_phenopowerlaw_totalNslip(instance) = sum(plastic_phenopowerlaw_Nslip(:,instance)) ! how many slip systems altogether + plastic_phenopowerlaw_totalNtwin(instance) = sum(plastic_phenopowerlaw_Ntwin(:,instance)) ! how many twin systems altogether + plastic_phenopowerlaw_totalNtrans(instance) = sum(plastic_phenopowerlaw_Ntrans(:,instance)) ! how many trans systems altogether + + if (any(plastic_phenopowerlaw_tau0_slip(:,instance) < 0.0_pReal .and. & + plastic_phenopowerlaw_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (plastic_phenopowerlaw_gdot0_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (plastic_phenopowerlaw_n_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (any(plastic_phenopowerlaw_tausat_slip(:,instance) <= 0.0_pReal .and. & + plastic_phenopowerlaw_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (any(abs(plastic_phenopowerlaw_a_slip(instance)) <= tiny(0.0_pReal) .and. & + plastic_phenopowerlaw_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (any(plastic_phenopowerlaw_tau0_twin(:,instance) < 0.0_pReal .and. & + plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') + if ( plastic_phenopowerlaw_gdot0_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') + if ( plastic_phenopowerlaw_n_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (plastic_phenopowerlaw_aTolResistance(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa + if (plastic_phenopowerlaw_aTolShear(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenopowerlaw_aTolTwinfrac(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenopowerlaw_aTolTransfrac(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + allocate(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from slip activity + maxval(plastic_phenopowerlaw_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from twin activity + maxval(plastic_phenopowerlaw_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_phenopowerlaw_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_phenopowerlaw_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(state(maxNinstance)) + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config + myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then ! only consider my phase + NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase + instance = phase_plasticityInstance(phase) ! which instance of my phase + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) + select case(plastic_phenopowerlaw_outputID(o,instance)) + case(resistance_slip_ID, & + shearrate_slip_ID, & + accumulatedshear_slip_ID, & + resolvedstress_slip_ID & + ) + mySize = plastic_phenopowerlaw_totalNslip(instance) + case(resistance_twin_ID, & + shearrate_twin_ID, & + accumulatedshear_twin_ID, & + resolvedstress_twin_ID & + ) + mySize = plastic_phenopowerlaw_totalNtwin(instance) + case(totalshear_ID, & + totalvolfrac_twin_ID & + ) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_phenopowerlaw_sizePostResult(o,instance) = mySize + plastic_phenopowerlaw_sizePostResults(instance) = plastic_phenopowerlaw_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = plastic_phenopowerlaw_totalNslip(instance) & ! s_slip + + plastic_phenopowerlaw_totalNtwin(instance) & ! s_twin + + 2_pInt & ! sum(gamma) + sum(f) + + plastic_phenopowerlaw_totalNslip(instance) & ! accshear_slip + + plastic_phenopowerlaw_totalNtwin(instance) ! accshear_twin + + sizeDotState = sizeState + sizeDeltaState = 0_pInt + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_phenopowerlaw_sizePostResults(instance) + plasticState(phase)%nSlip =plastic_phenopowerlaw_totalNslip(instance) + plasticState(phase)%nTwin =plastic_phenopowerlaw_totalNtwin(instance) + plasticState(phase)%nTrans=plastic_phenopowerlaw_totalNtrans(instance) + allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) + + offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + + do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X + index_myFamily = sum(plastic_phenopowerlaw_Nslip(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) ! loop over (active) systems in my family (slip) + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenopowerlaw_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenopowerlaw_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + + do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X + index_myFamily = sum(plastic_phenopowerlaw_Ntwin(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) ! loop over (active) systems in my family (twin) + + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenopowerlaw_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenopowerlaw_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + startIndex = 1_pInt + endIndex = plastic_phenopowerlaw_totalNslip(instance) + state (instance)%s_slip=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%s_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%s_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex + plastic_phenopowerlaw_totalNtwin(instance) + state (instance)%s_twin=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%s_twin=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%s_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex + 1_pInt + state (instance)%sumGamma=>plasticState(phase)%state (startIndex,:) + state0 (instance)%sumGamma=>plasticState(phase)%state0 (startIndex,:) + dotState(instance)%sumGamma=>plasticState(phase)%dotState(startIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex + 1_pInt + state (instance)%sumF=>plasticState(phase)%state (startIndex,:) + state0 (instance)%sumF=>plasticState(phase)%state0 (startIndex,:) + dotState(instance)%sumF=>plasticState(phase)%dotState(startIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex +plastic_phenopowerlaw_totalNslip(instance) + state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex +plastic_phenopowerlaw_totalNtwin(instance) + state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + + call plastic_phenopowerlaw_stateInit(phase,instance) + call plastic_phenopowerlaw_aTolState(phase,instance) + endif myPhase2 + enddo initializeInstances + +end subroutine plastic_phenopowerlaw_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_stateInit(ph,instance) + use lattice, only: & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + integer(pInt) :: & + i + real(pReal), dimension(plasticState(ph)%sizeState) :: & + tempState + + tempState = 0.0_pReal + do i = 1_pInt,lattice_maxNslipFamily + tempState(1+sum(plastic_phenopowerlaw_Nslip(1:i-1,instance)) : & + sum(plastic_phenopowerlaw_Nslip(1:i ,instance))) = & + plastic_phenopowerlaw_tau0_slip(i,instance) + enddo + + do i = 1_pInt,lattice_maxNtwinFamily + tempState(1+sum(plastic_phenopowerlaw_Nslip(:,instance))+& + sum(plastic_phenopowerlaw_Ntwin(1:i-1,instance)) : & + sum(plastic_phenopowerlaw_Nslip(:,instance))+& + sum(plastic_phenopowerlaw_Ntwin(1:i ,instance))) = & + plastic_phenopowerlaw_tau0_twin(i,instance) + enddo + + plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array + 2, & ! along dimension 2 + size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) + +end subroutine plastic_phenopowerlaw_stateInit + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + plasticState(ph)%aTolState(1:plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance)) = & + plastic_phenopowerlaw_aTolResistance(instance) + plasticState(ph)%aTolState(1+plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance)) = & + plastic_phenopowerlaw_aTolShear(instance) + plasticState(ph)%aTolState(2+plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance)) = & + plastic_phenopowerlaw_aTolTwinFrac(instance) + plasticState(ph)%aTolState(3+plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance): & + 2+2*(plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance))) = & + plastic_phenopowerlaw_aTolShear(instance) + +end subroutine plastic_phenopowerlaw_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use math, only: & + math_Plain3333to99, & + math_Mandel6to33 + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + use material, only: & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + + integer(pInt) :: & + instance, & + index_myFamily, & + f,i,j,k,l,m,n, & + of, & + ph + real(pReal) :: & + tau_slip_pos,tau_slip_neg, & + gdot_slip_pos,gdot_slip_neg, & + dgdot_dtauslip_pos,dgdot_dtauslip_neg, & + gdot_twin,dgdot_dtautwin,tau_twin + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal), dimension(3,3,2) :: & + nonSchmid_tensor + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Slip part + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) + enddo + gdot_slip_pos = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & + ((abs(tau_slip_pos)/(state(instance)%s_slip(j,of))) & + **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) + + gdot_slip_neg = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & + ((abs(tau_slip_neg)/(state(instance)%s_slip(j,of))) & + **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) + + Lp = Lp + (1.0_pReal-state(instance)%sumF(of))*& ! 1-F + (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then + dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenopowerlaw_n_slip(instance)/tau_slip_pos + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,1) + endif + + if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then + dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenopowerlaw_n_slip(instance)/tau_slip_neg + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,2) + endif + enddo slipSystems + enddo slipFamilies + +!-------------------------------------------------------------------------------------------------- +! Twinning part + j = 0_pInt + twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin = (1.0_pReal-state(instance)%sumF(of))*& ! 1-F + plastic_phenopowerlaw_gdot0_twin(instance)*& + (abs(tau_twin)/state(instance)%s_twin(j,of))**& + plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_twin) > tiny(0.0_pReal)) then + dgdot_dtautwin = gdot_twin*plastic_phenopowerlaw_n_twin(instance)/tau_twin + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & + lattice_Stwin(m,n,index_myFamily+i,ph) + endif + enddo twinSystems + enddo twinFamilies + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + + +end subroutine plastic_phenopowerlaw_LpAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_dotState(Tstar_v,ipc,ip,el) + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_shearTwin, & + lattice_NnonSchmid + use material, only: & + material_phase, & + phaseAt, phasememberAt, & + plasticState, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + integer(pInt) :: & + instance,ph, & + nSlip,nTwin, & + f,i,j,k, & + index_Gamma,index_F,index_myFamily, & + offset_accshear_slip,offset_accshear_twin, & + of + real(pReal) :: & + c_SlipSlip,c_TwinSlip,c_TwinTwin, & + ssat_offset, & + tau_slip_pos,tau_slip_neg,tau_twin + + real(pReal), dimension(plastic_phenopowerlaw_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip + real(pReal), dimension(plastic_phenopowerlaw_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenopowerlaw_totalNslip(instance) + nTwin = plastic_phenopowerlaw_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + offset_accshear_slip = nSlip + nTwin + 2_pInt + offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + plasticState(ph)%dotState(:,of) = 0.0_pReal + + +!-------------------------------------------------------------------------------------------------- +! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices + c_SlipSlip = plastic_phenopowerlaw_h0_SlipSlip(instance)*& + (1.0_pReal + plastic_phenopowerlaw_twinC(instance)*plasticState(ph)%state(index_F,of)**& + plastic_phenopowerlaw_twinB(instance)) + c_TwinSlip = plastic_phenopowerlaw_h0_TwinSlip(instance)*& + plasticState(ph)%state(index_Gamma,of)**plastic_phenopowerlaw_twinE(instance) + c_TwinTwin = plastic_phenopowerlaw_h0_TwinTwin(instance)*& + plasticState(ph)%state(index_F,of)**plastic_phenopowerlaw_twinD(instance) + +!-------------------------------------------------------------------------------------------------- +! calculate left and right vectors and calculate dot gammas + ssat_offset = plastic_phenopowerlaw_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j+1_pInt + left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part + left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part + right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) & + **plastic_phenopowerlaw_a_slip(instance)& + *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) + right_TwinSlip(j) = 1.0_pReal ! no system-dependent part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot gamma + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + gdot_slip(j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance) & + +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + enddo slipSystems1 + enddo slipFamilies1 + + + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j+1_pInt + left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part + left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part + right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part + right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot vol frac + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenopowerlaw_gdot0_twin(instance)*& + (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& + plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + enddo twinSystems1 + enddo twinFamilies1 + +!-------------------------------------------------------------------------------------------------- +! calculate the overall hardening based on above + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j + c_SlipSlip * left_SlipSlip(j) * & + dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & + right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & + right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & + abs(gdot_slip(j)) + plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) + enddo slipSystems2 + enddo slipFamilies2 + + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j + c_TwinSlip * left_TwinSlip(j) * & + dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & + right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + c_TwinTwin * left_TwinTwin(j) * & + dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & + right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 + plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & + gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) + plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) + enddo twinSystems2 + enddo twinFamilies2 + + +end subroutine plastic_phenopowerlaw_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_phenopowerlaw_postResults(Tstar_v,ipc,ip,el) + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + real(pReal), dimension(plastic_phenopowerlaw_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_phenopowerlaw_postResults + + integer(pInt) :: & + instance,ph, of, & + nSlip,nTwin, & + o,f,i,c,j,k, & + index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily + real(pReal) :: & + tau_slip_pos,tau_slip_neg,tau + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenopowerlaw_totalNslip(instance) + nTwin = plastic_phenopowerlaw_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + index_accshear_slip = nSlip + nTwin + 3_pInt + index_accshear_twin = nSlip + nTwin + 3_pInt + nSlip + + plastic_phenopowerlaw_postResults = 0.0_pReal + c = 0_pInt + + outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) + select case(plastic_phenopowerlaw_outputID(o,instance)) + case (resistance_slip_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) + c = c + nSlip + + case (accumulatedshear_slip_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& + index_accshear_slip+nSlip-1_pInt,of) + c = c + nSlip + + case (shearrate_slip_ID) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j + 1_pInt + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo + plastic_phenopowerlaw_postResults(c+j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance) & + +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + + enddo slipSystems1 + enddo slipFamilies1 + c = c + nSlip + + case (resolvedstress_slip_ID) + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j + 1_pInt + plastic_phenopowerlaw_postResults(c+j) = & + dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + enddo slipSystems2 + enddo slipFamilies2 + c = c + nSlip + + case (totalshear_ID) + plastic_phenopowerlaw_postResults(c+1_pInt) = & + plasticState(ph)%state(index_Gamma,of) + c = c + 1_pInt + + case (resistance_twin_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) + c = c + nTwin + + case (accumulatedshear_twin_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) + c = c + nTwin + case (shearrate_twin_ID) + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j + 1_pInt + tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + plastic_phenopowerlaw_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenopowerlaw_gdot0_twin(instance)*& + (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& + plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) + enddo twinSystems1 + enddo twinFamilies1 + c = c + nTwin + + case (resolvedstress_twin_ID) + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j + 1_pInt + plastic_phenopowerlaw_postResults(c+j) = & + dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + enddo twinSystems2 + enddo twinFamilies2 + c = c + nTwin + + case (totalvolfrac_twin_ID) + plastic_phenopowerlaw_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) + c = c + 1_pInt + + end select + enddo outputsLoop + +end function plastic_phenopowerlaw_postResults + +end module plastic_phenopowerlaw diff --git a/code/plastic/plastic_titanmod.f90 b/code/plastic/plastic_titanmod.f90 new file mode 100644 index 000000000..abc6d661b --- /dev/null +++ b/code/plastic/plastic_titanmod.f90 @@ -0,0 +1,1913 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Alankar Alankar, 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 +!> @brief material subroutine for titanium +!-------------------------------------------------------------------------------------------------- +module plastic_titanmod + use prec, only: & + pReal, & + pInt + + implicit none + private + character(len=18), dimension(3), parameter, private :: & + plastic_titanmod_listBasicSlipStates = & + ['rho_edge ', 'rho_screw ', 'shear_system'] + character(len=18), dimension(1), parameter, private :: & + plastic_titanmod_listBasicTwinStates = ['gdot_twin'] + character(len=19), dimension(11), parameter, private :: & + plastic_titanmod_listDependentSlipStates = & + ['segment_edge ', 'segment_screw ', & + 'resistance_edge ', 'resistance_screw ', & + 'tau_slip ', & + 'velocity_edge ', 'velocity_screw ', & + 'gdot_slip_edge ', 'gdot_slip_screw ', & + 'stressratio_edge_p ', 'stressratio_screw_p' ] + character(len=18), dimension(2), parameter, private :: & + plastic_titanmod_listDependentTwinStates = & + ['twin_fraction', 'tau_twin '] + real(pReal), parameter, private :: & + kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin + + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_titanmod_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_titanmod_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_titanmod_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_titanmod_Noutput !< number of outputs per instance of this plasticity !< ID of the lattice structure + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_titanmod_totalNslip, & !< total number of active slip systems for each instance + plastic_titanmod_totalNtwin !< total number of active twin systems for each instance + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_titanmod_Nslip, & !< number of active slip systems for each family and instance + plastic_titanmod_Ntwin, & !< number of active twin systems for each family and instance + plastic_titanmod_slipFamily, & !< lookup table relating active slip system to slip family for each instance + plastic_titanmod_twinFamily, & !< lookup table relating active twin system to twin family for each instance + plastic_titanmod_slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance + plastic_titanmod_twinSystemLattice !< lookup table relating active twin system index to lattice twin system index for each instance + + real(pReal), dimension(:), allocatable, private :: & + plastic_titanmod_debyefrequency, & !< Debye frequency + plastic_titanmod_kinkf0, & !< + plastic_titanmod_CAtomicVolume, & !< atomic volume in Bugers vector unit + plastic_titanmod_dc, & !< prefactor for self-diffusion coefficient + plastic_titanmod_twinhpconstant, & !< activation energy for dislocation climb + plastic_titanmod_GrainSize, & !< grain size - Not being used + plastic_titanmod_MaxTwinFraction, & !< maximum allowed total twin volume fraction + plastic_titanmod_r, & !< r-exponent in twin nucleation rate + plastic_titanmod_CEdgeDipMinDistance, & !< Not being used + plastic_titanmod_Cmfptwin, & !< Not being used + plastic_titanmod_Cthresholdtwin, & !< Not being used + plastic_titanmod_aTolRho !< absolute tolerance for integration of dislocation density + + real(pReal), dimension(:,:), allocatable, private :: & + plastic_titanmod_rho_edge0, & !< initial edge dislocation density per slip system for each family and instance + plastic_titanmod_rho_screw0, & !< initial screw dislocation density per slip system for each family and instance + plastic_titanmod_shear_system0, & !< accumulated shear on each system + plastic_titanmod_burgersPerSlipFam, & !< absolute length of burgers vector [m] for each slip family and instance + plastic_titanmod_burgersPerSlipSys, & !< absolute length of burgers vector [m] for each slip system and instance + plastic_titanmod_burgersPerTwinFam, & !< absolute length of burgers vector [m] for each twin family and instance + plastic_titanmod_burgersPerTwinSys, & !< absolute length of burgers vector [m] for each twin system and instance + plastic_titanmod_f0_PerSlipFam, & !< activation energy for glide [J] for each slip family and instance + plastic_titanmod_f0_PerSlipSys, & !< activation energy for glide [J] for each slip system and instance + plastic_titanmod_twinf0_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance + plastic_titanmod_twinf0_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance + plastic_titanmod_twinshearconstant_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance + plastic_titanmod_twinshearconstant_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance + plastic_titanmod_tau0e_PerSlipFam, & !< Initial yield stress for edge dislocations per slip family + plastic_titanmod_tau0e_PerSlipSys, & !< Initial yield stress for edge dislocations per slip system + plastic_titanmod_tau0s_PerSlipFam, & !< Initial yield stress for screw dislocations per slip family + plastic_titanmod_tau0s_PerSlipSys, & !< Initial yield stress for screw dislocations per slip system + plastic_titanmod_twintau0_PerTwinFam, & !< Initial yield stress for edge dislocations per twin family + plastic_titanmod_twintau0_PerTwinSys, & !< Initial yield stress for edge dislocations per twin system + plastic_titanmod_capre_PerSlipFam, & !< Capture radii for edge dislocations per slip family + plastic_titanmod_capre_PerSlipSys, & !< Capture radii for edge dislocations per slip system + plastic_titanmod_caprs_PerSlipFam, & !< Capture radii for screw dislocations per slip family + plastic_titanmod_caprs_PerSlipSys, & !< Capture radii for screw dislocations per slip system + plastic_titanmod_pe_PerSlipFam, & !< p-exponent in glide velocity + plastic_titanmod_ps_PerSlipFam, & !< p-exponent in glide velocity + plastic_titanmod_qe_PerSlipFam, & !< q-exponent in glide velocity + plastic_titanmod_qs_PerSlipFam, & !< q-exponent in glide velocity + plastic_titanmod_pe_PerSlipSys, & !< p-exponent in glide velocity + plastic_titanmod_ps_PerSlipSys, & !< p-exponent in glide velocity + plastic_titanmod_qe_PerSlipSys, & !< q-exponent in glide velocity + plastic_titanmod_qs_PerSlipSys, & !< q-exponent in glide velocity + plastic_titanmod_twinp_PerTwinFam, & !< p-exponent in glide velocity + plastic_titanmod_twinq_PerTwinFam, & !< q-exponent in glide velocity + plastic_titanmod_twinp_PerTwinSys, & !< p-exponent in glide velocity + plastic_titanmod_twinq_PerTwinSys, & !< p-exponent in glide velocity + plastic_titanmod_v0e_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance + plastic_titanmod_v0e_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance + plastic_titanmod_v0s_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance + plastic_titanmod_v0s_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance + plastic_titanmod_twingamma0_PerTwinFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance + plastic_titanmod_twingamma0_PerTwinSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance + plastic_titanmod_kinkcriticallength_PerSlipFam, & !< screw dislocation mobility prefactor for kink-pairs per slip family + plastic_titanmod_kinkcriticallength_PerSlipSys, & !< screw dislocation mobility prefactor for kink-pairs per slip system + plastic_titanmod_twinsizePerTwinFam, & !< twin thickness [m] for each twin family and instance + plastic_titanmod_twinsizePerTwinSys, & !< twin thickness [m] for each twin system and instance + plastic_titanmod_CeLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_titanmod_CeLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_titanmod_CsLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_titanmod_CsLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_titanmod_twinLambdaSlipPerTwinFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_titanmod_twinLambdaSlipPerTwinSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_titanmod_interactionSlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance + plastic_titanmod_interaction_ee, & !< coefficients for e-e interaction for each interaction type and instance + plastic_titanmod_interaction_ss, & !< coefficients for s-s interaction for each interaction type and instance + plastic_titanmod_interaction_es, & !< coefficients for e-s-twin interaction for each interaction type and instance + plastic_titanmod_interactionSlipTwin, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_titanmod_interactionTwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_titanmod_interactionTwinTwin !< coefficients for twin-twin interaction for each interaction type and instance + + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_titanmod_interactionMatrixSlipSlip, & !< interaction matrix of the different slip systems for each instance + plastic_titanmod_interactionMatrix_ee, & !< interaction matrix of e-e for each instance + plastic_titanmod_interactionMatrix_ss, & !< interaction matrix of s-s for each instance + plastic_titanmod_interactionMatrix_es, & !< interaction matrix of e-s for each instance + plastic_titanmod_interactionMatrixSlipTwin, & !< interaction matrix of slip systems with twin systems for each instance + plastic_titanmod_interactionMatrixTwinSlip, & !< interaction matrix of twin systems with slip systems for each instance + plastic_titanmod_interactionMatrixTwinTwin, & !< interaction matrix of the different twin systems for each instance + plastic_titanmod_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance + plastic_titanmod_forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance + plastic_titanmod_TwinforestProjectionEdge, & !< matrix of forest projections of edge dislocations in twin system for each instance + plastic_titanmod_TwinforestProjectionScrew !< matrix of forest projections of screw dislocations in twin system for each instance + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_titanmod_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance + + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_titanmod_Ctwin3333 !< twin elasticity matrix for each instance + + enum, bind(c) + enumerator :: undefined_ID, & + rhoedge_ID, rhoscrew_ID, & + segment_edge_ID, segment_screw_ID, & + resistance_edge_ID, resistance_screw_ID, & + velocity_edge_ID, velocity_screw_ID, & + tau_slip_ID, & + gdot_slip_edge_ID, gdot_slip_screw_ID, & + gdot_slip_ID, & + stressratio_edge_p_ID, stressratio_screw_p_ID, & + shear_system_ID, & + twin_fraction_ID, & + shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & + rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & + rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & + shear_total_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_titanmod_outputID !< ID of each post result output + + public :: & + plastic_titanmod_microstructure, & + plastic_titanmod_stateInit, & + plastic_titanmod_init, & + plastic_titanmod_LpAndItsTangent, & + plastic_titanmod_dotState, & + plastic_titanmod_postResults, & + plastic_titanmod_homogenizedC + + contains + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66,& + math_Voigt66to3333,& + math_mul3x3 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_TITANMOD_label, & + PLASTICITY_TITANMOD_ID, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + phase, & + instance, j, k, l, m, n, p, q, r, & + f, o, & + s, s1, s2, & + t, t1, t2, & + ns, nt, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & + offset_slip, mySize, & + maxTotalNslip,maxTotalNtwin, maxNinstance + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase = 0_pInt + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_TITANMOD_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_TITANMOD_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_titanmod_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_titanmod_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) + allocate(plastic_titanmod_output(maxval(phase_Noutput),maxNinstance)) + plastic_titanmod_output = '' + allocate(plastic_titanmod_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_titanmod_Noutput(maxNinstance), source=0_pInt) + + allocate(plastic_titanmod_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_slipFamily(lattice_maxNslip,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_twinFamily(lattice_maxNtwin,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_slipSystemLattice(lattice_maxNslip,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_twinSystemLattice(lattice_maxNtwin,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_titanmod_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_titanmod_debyefrequency(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_kinkf0(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CAtomicVolume(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_dc(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinhpconstant(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_GrainSize(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_MaxTwinFraction(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_r(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Cmfptwin(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Cthresholdtwin(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_aTolRho(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_rho_edge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_rho_screw0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_shear_system0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_burgersPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_burgersPerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_f0_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_capre_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_caprs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_pe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_ps_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_kinkcriticallength_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinsizePerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CeLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CsLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_twinf0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinshearconstant_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twintau0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinp_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinq_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twingamma0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinLambdaSlipPerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_interactionSlipSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interaction_ee(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interaction_ss(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interaction_es(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionSlipTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionTwinSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionTwinTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + phase = phase + 1_pInt ! advance section counter + if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then ! one of my sections. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('rhoedge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('segment_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('segment_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('tau_slip') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = tau_slip_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('gdot_slip_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('gdot_slip_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('gdot_slip') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stressratio_edge_p') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_edge_p_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stressratio_screw_p') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_screw_p_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_system') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_system_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('twin_fraction') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = twin_fraction_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_basal') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_basal_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_prism') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_prism_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_pyra') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyra_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_pyrca') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyrca_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_basal') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_basal_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_prism') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_prism_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_pyra') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyra_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_pyrca') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyrca_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_basal') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_basal_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_prism') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_prism_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_pyra') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyra_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_pyrca') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyrca_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_total') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_total_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + case ('debyefrequency') + plastic_titanmod_debyefrequency(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('kinkf0') + plastic_titanmod_kinkf0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('nslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ntwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinFamilies) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('rho_edge0') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_rho_edge0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('rho_screw0') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_rho_screw0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('slipburgers') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_burgersPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinburgers') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_burgersPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('f0') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_f0_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinf0') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinf0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0e') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_tau0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twintau0') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twintau0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0s') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_tau0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('capre') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_capre_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('caprs') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_caprs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('v0e') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_v0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twingamma0') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twingamma0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('v0s') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_v0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('kinkcriticallength') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_kinkcriticallength_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinsize') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinsizePerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('celambdaslip') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_CeLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinlambdaslip') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinlambdaslipPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('cslambdaslip') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_CsLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('grainsize') + plastic_titanmod_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('maxtwinfraction') + plastic_titanmod_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('pe') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_pe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinp') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinp_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('ps') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_ps_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('qe') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_qe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinq') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinq_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('qs') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_qs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinshearconstant') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinshearconstant_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('dc') + plastic_titanmod_dc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twinhpconstant') + plastic_titanmod_twinhpconstant(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_rho') + plastic_titanmod_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('interactionee') + do j = 1_pInt, lattice_maxNinteraction + plastic_titanmod_interaction_ee(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interactionss') + do j = 1_pInt, lattice_maxNinteraction + plastic_titanmod_interaction_ss(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interactiones') + do j = 1_pInt, lattice_maxNinteraction + plastic_titanmod_interaction_es(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_slipslip','interactionslipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_titanmod_interactionSlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin','interactionsliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_titanmod_interactionSlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip','interactiontwinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_titanmod_interactionTwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin','interactiontwintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_titanmod_interactionTwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then + instance = phase_plasticityInstance(phase) + if (sum(plastic_titanmod_Nslip(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='nslip ('//PLASTICITY_TITANMOD_label//')') + if (sum(plastic_titanmod_Ntwin(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='ntwin ('//PLASTICITY_TITANMOD_label//')') + do f = 1_pInt,lattice_maxNslipFamily + if (plastic_titanmod_Nslip(f,instance) > 0_pInt) then + if (plastic_titanmod_rho_edge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rho_edge0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_rho_screw0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rho_screw0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_burgersPerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='slipburgers ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_f0_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='f0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_tau0e_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau0e ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_tau0s_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau0s ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_capre_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='capre ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_caprs_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='caprs ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_v0e_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0e ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_v0s_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0s ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='kinkCriticalLength ('//PLASTICITY_TITANMOD_label//')') + endif + enddo + do f = 1_pInt,lattice_maxNtwinFamily + if (plastic_titanmod_Ntwin(f,instance) > 0_pInt) then + if (plastic_titanmod_burgersPerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twinf0_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinf0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinshearconstant ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twintau0_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twintau0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twingamma0_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twingamma0 ('//PLASTICITY_TITANMOD_label//')') + endif + enddo + if (plastic_titanmod_dc(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='dc ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twinhpconstant(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinhpconstant ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTol_rho ('//PLASTICITY_TITANMOD_label//')') + +!-------------------------------------------------------------------------------------------------- +! determine total number of active slip or twin systems + plastic_titanmod_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_titanmod_Nslip(:,instance)) + plastic_titanmod_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_titanmod_Ntwin(:,instance)) + plastic_titanmod_totalNslip(instance) = sum(plastic_titanmod_Nslip(:,instance)) + plastic_titanmod_totalNtwin(instance) = sum(plastic_titanmod_Ntwin(:,instance)) + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + maxTotalNslip = maxval(plastic_titanmod_totalNslip) + maxTotalNtwin = maxval(plastic_titanmod_totalNtwin) + + allocate(plastic_titanmod_burgersPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_f0_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_capre_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_caprs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_pe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_ps_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_kinkcriticallength_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CeLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CsLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_burgersPerTwinSys(maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinf0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinshearconstant_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twintau0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinp_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinq_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twingamma0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinsizePerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinLambdaSlipPerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Ctwin66 (6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Ctwin3333 (3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrix_ee(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrix_ss(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrix_es(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrixSlipTwin(maxTotalNslip,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrixTwinSlip(maxTotalNtwin,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrixTwinTwin(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_TwinforestProjectionEdge(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_TwinforestProjectionScrew(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then + instance = phase_plasticityInstance(phase) + +!-------------------------------------------------------------------------------------------------- +! inverse lookup of slip system family + l = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily + do s = 1_pInt,plastic_titanmod_Nslip(f,instance) + l = l + 1_pInt + plastic_titanmod_slipFamily(l,instance) = f + plastic_titanmod_slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt,phase)) + s + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! inverse lookup of twin system family + l = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily + do t = 1_pInt,plastic_titanmod_Ntwin(f,instance) + l = l + 1_pInt + plastic_titanmod_twinFamily(l,instance) = f + plastic_titanmod_twinSystemLattice(l,instance) = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) + t + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! determine size of state array + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + sizeDotState = & + size(plastic_titanmod_listBasicSlipStates)*ns + & + size(plastic_titanmod_listBasicTwinStates)*nt + sizeState = sizeDotState+ & + size(plastic_titanmod_listDependentSlipStates)*ns + & + size(plastic_titanmod_listDependentTwinStates)*nt + sizeDeltaState = 0_pInt + +!-------------------------------------------------------------------------------------------------- +! determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_titanmod_Noutput(instance) + mySize = 0_pInt + select case(plastic_titanmod_outputID(o,instance)) + case(rhoedge_ID, rhoscrew_ID, & + segment_edge_ID, segment_screw_ID, & + resistance_edge_ID, resistance_screw_ID, & + velocity_edge_ID, velocity_screw_ID, & + tau_slip_ID, & + gdot_slip_edge_ID, gdot_slip_screw_ID, & + gdot_slip_ID, & + stressratio_edge_p_ID, stressratio_screw_p_ID, & + shear_system_ID) + mySize = plastic_titanmod_totalNslip(instance) + case(twin_fraction_ID) + mySize = plastic_titanmod_totalNtwin(instance) + case(shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & ! use only if all 4 slip families in hex are considered + rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & + rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & + shear_total_ID) + mySize = 1_pInt + case default + call IO_error(105_pInt,ext_msg=plastic_titanmod_output(o,instance)// & + ' ('//PLASTICITY_TITANMOD_label//')') + end select + + outputFound: if (mySize > 0_pInt) then + plastic_titanmod_sizePostResult(o,instance) = mySize + plastic_titanmod_sizePostResults(instance) = plastic_titanmod_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop +! Determine size of state array + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_titanmod_sizePostResults(instance) + plasticState(phase)%nSlip =plastic_titanmod_totalNslip(instance) + plasticState(phase)%nTwin = 0_pInt + plasticState(phase)%nTrans= 0_pInt + allocate(plasticState(phase)%aTolState (sizeState), source=plastic_titanmod_aTolRho(instance)) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + offset_slip = 2_pInt*plasticState(phase)%nSlip+1 + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) +!-------------------------------------------------------------------------------------------------- +! construction of the twin elasticity matrices + do j=1_pInt,lattice_maxNtwinFamily + do k=1_pInt,plastic_titanmod_Ntwin(j,instance) + do l=1_pInt,3_pInt ; do m=1_pInt,3_pInt ; do n=1_pInt,3_pInt ; do o=1_pInt,3_pInt + do p=1_pInt,3_pInt ; do q=1_pInt,3_pInt ; do r=1_pInt,3_pInt ; do s=1_pInt,3_pInt + plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) = & + plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) + & + lattice_C3333(p,q,r,s,phase)*& + lattice_Qtwin(l,p,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & + lattice_Qtwin(m,q,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & + lattice_Qtwin(n,r,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & + lattice_Qtwin(o,s,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo ; enddo + plastic_titanmod_Ctwin66(1:6,1:6,k,instance) = & + math_Mandel3333to66(plastic_titanmod_Ctwin3333(1:3,1:3,1:3,1:3,k,instance)) + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! Burgers vector, dislocation velocity prefactor for each slip system + do s = 1_pInt,plastic_titanmod_totalNslip(instance) + f = plastic_titanmod_slipFamily(s,instance) + + plastic_titanmod_burgersPerSlipSys(s,instance) = & + plastic_titanmod_burgersPerSlipFam(f,instance) + + plastic_titanmod_f0_PerSlipSys(s,instance) = & + plastic_titanmod_f0_PerSlipFam(f,instance) + + plastic_titanmod_tau0e_PerSlipSys(s,instance) = & + plastic_titanmod_tau0e_PerSlipFam(f,instance) + + plastic_titanmod_tau0s_PerSlipSys(s,instance) = & + plastic_titanmod_tau0s_PerSlipFam(f,instance) + + plastic_titanmod_capre_PerSlipSys(s,instance) = & + plastic_titanmod_capre_PerSlipFam(f,instance) + + plastic_titanmod_caprs_PerSlipSys(s,instance) = & + plastic_titanmod_caprs_PerSlipFam(f,instance) + + plastic_titanmod_v0e_PerSlipSys(s,instance) = & + plastic_titanmod_v0e_PerSlipFam(f,instance) + + plastic_titanmod_v0s_PerSlipSys(s,instance) = & + plastic_titanmod_v0s_PerSlipFam(f,instance) + + plastic_titanmod_kinkcriticallength_PerSlipSys(s,instance) = & + plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) + + plastic_titanmod_pe_PerSlipSys(s,instance) = & + plastic_titanmod_pe_PerSlipFam(f,instance) + + plastic_titanmod_ps_PerSlipSys(s,instance) = & + plastic_titanmod_ps_PerSlipFam(f,instance) + + plastic_titanmod_qe_PerSlipSys(s,instance) = & + plastic_titanmod_qe_PerSlipFam(f,instance) + + plastic_titanmod_qs_PerSlipSys(s,instance) = & + plastic_titanmod_qs_PerSlipFam(f,instance) + + plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance) = & + plastic_titanmod_CeLambdaSlipPerSlipFam(f,instance) + + plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance) = & + plastic_titanmod_CsLambdaSlipPerSlipFam(f,instance) + enddo + +!-------------------------------------------------------------------------------------------------- +! Burgers vector, nucleation rate prefactor and twin size for each twin system + do t = 1_pInt,plastic_titanmod_totalNtwin(instance) + f = plastic_titanmod_twinFamily(t,instance) + + plastic_titanmod_burgersPerTwinSys(t,instance) = & + plastic_titanmod_burgersPerTwinFam(f,instance) + + plastic_titanmod_twinsizePerTwinSys(t,instance) = & + plastic_titanmod_twinsizePerTwinFam(f,instance) + + plastic_titanmod_twinf0_PerTwinSys(t,instance) = & + plastic_titanmod_twinf0_PerTwinFam(f,instance) + + plastic_titanmod_twinshearconstant_PerTwinSys(t,instance) = & + plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) + + plastic_titanmod_twintau0_PerTwinSys(t,instance) = & + plastic_titanmod_twintau0_PerTwinFam(f,instance) + + plastic_titanmod_twingamma0_PerTwinSys(t,instance) = & + plastic_titanmod_twingamma0_PerTwinFam(f,instance) + + plastic_titanmod_twinp_PerTwinSys(t,instance) = & + plastic_titanmod_twinp_PerTwinFam(f,instance) + + plastic_titanmod_twinq_PerTwinSys(t,instance) = & + plastic_titanmod_twinq_PerTwinFam(f,instance) + + plastic_titanmod_twinLambdaSlipPerTwinSys(t,instance) = & + plastic_titanmod_twinLambdaSlipPerTwinFam(f,instance) + enddo + +!-------------------------------------------------------------------------------------------------- +! Construction of interaction matrices + do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) + do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) + plastic_titanmod_interactionMatrixSlipSlip(s1,s2,instance) = & + plastic_titanmod_interactionSlipSlip(lattice_interactionSlipSlip( & + plastic_titanmod_slipSystemLattice(s1,instance),& + plastic_titanmod_slipSystemLattice(s2,instance),phase),instance) + + plastic_titanmod_interactionMatrix_ee(s1,s2,instance) = & + plastic_titanmod_interaction_ee(lattice_interactionSlipSlip ( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + + plastic_titanmod_interactionMatrix_ss(s1,s2,instance) = & + plastic_titanmod_interaction_ss(lattice_interactionSlipSlip( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + + plastic_titanmod_interactionMatrix_es(s1,s2,instance) = & + plastic_titanmod_interaction_es(lattice_interactionSlipSlip( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + enddo; enddo + + do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) + do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) + plastic_titanmod_interactionMatrixSlipTwin(s1,t2,instance) = & + plastic_titanmod_interactionSlipTwin(lattice_interactionSlipTwin( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) + enddo; enddo + + do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) + do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) + plastic_titanmod_interactionMatrixTwinSlip(t1,s2,instance) = & + plastic_titanmod_interactionTwinSlip(lattice_interactionTwinSlip( & + plastic_titanmod_twinSystemLattice(t1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + enddo; enddo + + do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) + do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) + plastic_titanmod_interactionMatrixTwinTwin(t1,t2,instance) = & + plastic_titanmod_interactionTwinTwin(lattice_interactionTwinTwin( & + plastic_titanmod_twinSystemLattice(t1,instance), & + plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) + enddo; enddo + + do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) + do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for edge dislocations + plastic_titanmod_forestProjectionEdge(s1,s2,instance) = & + abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & + lattice_st(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) + +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for screw dislocations + plastic_titanmod_forestProjectionScrew(s1,s2,instance) = & + abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & + lattice_sd(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for edge dislocations in twin system + do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) + do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) + plastic_titanmod_TwinforestProjectionEdge(t1,t2,instance) = & + abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & + lattice_tt(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) + +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for screw dislocations in twin system + plastic_titanmod_TwinforestProjectionScrew(t1,t2,instance) = & + abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & + lattice_td(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) + enddo; enddo + call plastic_titanmod_stateInit(phase,instance) + endif + enddo initializeInstances + +end subroutine plastic_titanmod_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_stateInit(ph,instance) + use lattice, only: & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_mu + + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: instance !< number specifying the instance of the plasticity + integer(pInt), intent(in) :: ph !< number specifying the phase of the plasticity + + + integer(pInt) :: & + s,s0,s1, & + t,t0,t1, & + ns,nt,f + real(pReal), dimension(plastic_titanmod_totalNslip(instance)) :: & + rho_edge0, & + rho_screw0, & + shear_system0, & + segment_edge0, & + segment_screw0, & + resistance_edge0, & + resistance_screw0 + real(pReal), dimension(plastic_titanmod_totalNtwin(instance)) :: & + twingamma_dot0, & + resistance_twin0 + real(pReal), dimension(plasticState(ph)%sizeState) :: tempState !!!!!!!!!????????? check + + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + tempState = 0.0_pReal +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables for slip + s1 = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily + s0 = s1 + 1_pInt + s1 = s0 + plastic_titanmod_Nslip(f,instance) - 1_pInt + do s = s0,s1 + rho_edge0(s) = plastic_titanmod_rho_edge0(f,instance) + rho_screw0(s) = plastic_titanmod_rho_screw0(f,instance) + shear_system0(s) = 0.0_pReal + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables for twin + t1 = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily + t0 = t1 + 1_pInt + t1 = t0 + plastic_titanmod_Ntwin(f,instance) - 1_pInt + do t = t0,t1 + twingamma_dot0(t)=0.0_pReal + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! initialize dependent slip microstructural variables + forall (s = 1_pInt:ns) + segment_edge0(s) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) + segment_screw0(s) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) + resistance_edge0(s) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & + sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & + dot_product((rho_screw0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) + resistance_screw0(s) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & + sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & + dot_product((rho_screw0), plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) + end forall + + forall (t = 1_pInt:nt) & + resistance_twin0(t) = 0.0_pReal + +tempState = 0.0_pReal +tempState (1:ns) = rho_edge0 +tempState (1_pInt*ns+1_pInt:2_pInt*ns) = rho_screw0 +tempState (2_pInt*ns+1_pInt:3_pInt*ns) = shear_system0 +tempState (3_pInt*ns+1_pInt:3_pInt*ns+nt) = twingamma_dot0 +tempState (3_pInt*ns+nt+1_pInt:4_pInt*ns+nt) = segment_edge0 +tempState (4_pInt*ns+nt+1_pInt:5_pInt*ns+nt) = segment_screw0 +tempState (5_pInt*ns+nt+1_pInt:6_pInt*ns+nt) = resistance_edge0 +tempState (6_pInt*ns+nt+1_pInt:7_pInt*ns+nt) = resistance_screw0 +tempState (7_pInt*ns+nt+1_pInt:7_pInt*ns+2_pInt*nt)=resistance_twin0 + +plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) +end subroutine plastic_titanmod_stateInit + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenized elasticity matrix +!-------------------------------------------------------------------------------------------------- +function plastic_titanmod_homogenizedC(ipc,ip,el) + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_C66 + +implicit none + real(pReal), dimension(6,6) :: & + plastic_titanmod_homogenizedC + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element +real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + volumefraction_PerTwinSys + integer(pInt) :: & + ph, & + of, & + instance, & + ns, nt, & + i + real(pReal) :: & + sumf + +!-------------------------------------------------------------------------------------------------- +! shortened notation +! ph = material_phase(ipc,ip,el) + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! total twin volume fraction + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + enddo + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + +!-------------------------------------------------------------------------------------------------- +! homogenized elasticity matrix + plastic_titanmod_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) + do i=1_pInt,nt + plastic_titanmod_homogenizedC = plastic_titanmod_homogenizedC & + + volumefraction_PerTwinSys(i)*& + plastic_titanmod_Ctwin66(1:6,1:6,i,instance) + enddo + +end function plastic_titanmod_homogenizedC + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_microstructure(temperature,ipc,ip,el) + + use material, only: & + material_phase,& + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_mu + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + temperature !< temperature at IP + integer(pInt) :: & + instance, & + ns, nt, s, t, & + i, & + ph, & + of + real(pReal) :: & + sumf, & + sfe ! stacking fault energy + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + volumefraction_PerTwinSys + +!-------------------------------------------------------------------------------------------------- + +!Shortened notation + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! total twin volume fraction + forall (i = 1_pInt:nt) & + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + + sfe = 0.0002_pReal*Temperature-0.0396_pReal + +!-------------------------------------------------------------------------------------------------- +! average segment length for edge dislocations in matrix + forall (s = 1_pInt:ns) & + plasticState(ph)%state(3_pInt*ns+nt+s, of) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product(plasticState(ph)%state(1:ns, of), & + plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & + plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! average segment length for screw dislocations in matrix + forall (s = 1_pInt:ns) & + plasticState(ph)%state(4_pInt*ns+nt+s, of) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product(plasticState(ph)%state(1:ns, of), & + plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & + plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! threshold stress or slip resistance for edge dislocation motion + forall (s = 1_pInt:ns) & + plasticState(ph)%state(5_pInt*ns+nt+s, of) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& + sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& + plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & + dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& + plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! threshold stress or slip resistance for screw dislocation motion + forall (s = 1_pInt:ns) & + plasticState(ph)%state(6_pInt*ns+nt+s, of) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& + sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& + plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & + dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& + plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! threshold stress or slip resistance for dislocation motion in twin + forall (t = 1_pInt:nt) & + plasticState(ph)%state(7_pInt*ns+nt+t, of) = & + lattice_mu(ph)*plastic_titanmod_burgersPerTwinSys(t,instance)*& + (dot_product((abs(plasticState(ph)%state(2_pInt*ns+1_pInt:2_pInt*ns+nt, of))),& + plastic_titanmod_interactionMatrixTwinTwin(1:nt,t,instance))) + +! state=tempState + +end subroutine plastic_titanmod_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,temperature,ipc,ip,el) + use math, only: & + math_Plain3333to99, & + math_Mandel6to33 + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_structure, & + LATTICE_hex_ID + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at IP + integer(pInt) :: & + index_myFamily, instance, & + ns,nt, & + f,i,j,k,l,m,n, & + ph, & + of + real(pReal) :: sumf, & + StressRatio_edge_p, minusStressRatio_edge_p, StressRatio_edge_pminus1, BoltzmannRatioedge, & + StressRatio_screw_p, minusStressRatio_screw_p, StressRatio_screw_pminus1, BoltzmannRatioscrew, & + twinStressRatio_p, twinminusStressRatio_p, twinStressRatio_pminus1, BoltzmannRatiotwin, & + twinDotGamma0, bottomstress_edge, bottomstress_screw, screwvelocity_prefactor + real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 + real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,dgdot_dtauslip,tau_slip, & + edge_velocity, screw_velocity, & + gdot_slip_edge, gdot_slip_screw + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,dgdot_dtautwin,tau_twin, volumefraction_PerTwinSys + +! tempState=state + + + +!-------------------------------------------------------------------------------------------------- +! shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + + enddo + + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + + !* Dislocation glide part + gdot_slip = 0.0_pReal + gdot_slip_edge = 0.0_pReal + gdot_slip_screw = 0.0_pReal + dgdot_dtauslip = 0.0_pReal + j = 0_pInt + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on slip system + tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + if(lattice_structure(ph)==LATTICE_hex_ID) then ! only for prismatic and pyr systems in hex + screwvelocity_prefactor=plastic_titanmod_debyefrequency(instance)* & + plasticState(ph)%state(4_pInt*ns+nt+j, of)*(plastic_titanmod_burgersPerSlipSys(j,instance)/ & + plastic_titanmod_kinkcriticallength_PerSlipSys(j,instance))**2 + + !* Stress ratio for screw ! No slip resistance for screw dislocations, only Peierls stress + bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) + StressRatio_screw_p = ((abs(tau_slip(j)))/ & + ( bottomstress_screw) & + )**plastic_titanmod_ps_PerSlipSys(j,instance) + + if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then + minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p + else + minusStressRatio_screw_p=0.001_pReal + endif + + bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) + StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/ & + ( bottomstress_screw) & + )**(plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio for screw + BoltzmannRatioscrew = plastic_titanmod_kinkf0(instance)/(kB*Temperature) + + else ! if the structure is not hex or the slip family is basal + screwvelocity_prefactor=plastic_titanmod_v0s_PerSlipSys(j,instance) + bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance)+ & + plasticState(ph)%state(6*ns+nt+j, of) + StressRatio_screw_p = ((abs(tau_slip(j)))/( bottomstress_screw ))**plastic_titanmod_ps_PerSlipSys(j,instance) + + if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then + minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p + else + minusStressRatio_screw_p=0.001_pReal + endif + + StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/( bottomstress_screw))** & + (plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio for screw + BoltzmannRatioscrew = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) + + endif + + !* Stress ratio for edge + bottomstress_edge=plastic_titanmod_tau0e_PerSlipSys(j,instance)+ & + plasticState(ph)%state(5*ns+nt+j, of) + StressRatio_edge_p = ((abs(tau_slip(j)))/ & + ( bottomstress_edge) & + )**plastic_titanmod_pe_PerSlipSys(j,instance) + + if((1.0_pReal-StressRatio_edge_p)>0.001_pReal) then + minusStressRatio_edge_p=1.0_pReal-StressRatio_edge_p + else + minusStressRatio_edge_p=0.001_pReal + endif + + StressRatio_edge_pminus1 = ((abs(tau_slip(j)))/( bottomstress_edge))** & + (plastic_titanmod_pe_PerSlipSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio for edge. For screws it is defined above + BoltzmannRatioedge = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) + + screw_velocity(j) =screwvelocity_prefactor * & ! there is no v0 for screw now because it is included in the prefactor + exp(-BoltzmannRatioscrew*(minusStressRatio_screw_p)** & + plastic_titanmod_qs_PerSlipSys(j,instance)) + + edge_velocity(j) =plastic_titanmod_v0e_PerSlipSys(j,instance)*exp(-BoltzmannRatioedge* & + (minusStressRatio_edge_p)** & + plastic_titanmod_qe_PerSlipSys(j,instance)) + + !* Shear rates due to edge slip + gdot_slip_edge(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(j, of)* & + edge_velocity(j))* sign(1.0_pReal,tau_slip(j)) + !* Shear rates due to screw slip + gdot_slip_screw(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(ns+j, of) * & + screw_velocity(j))* sign(1.0_pReal,tau_slip(j)) + !Total shear rate + + gdot_slip(j) = gdot_slip_edge(j) + gdot_slip_screw(j) + + plasticState(ph)%state( 7*ns+2*nt+j, of)= edge_velocity(j) + plasticState(ph)%state( 8*ns+2*nt+j, of)= screw_velocity(j) + plasticState(ph)%state( 9*ns+2*nt+j, of)= tau_slip(j) + plasticState(ph)%state(10*ns+2*nt+j, of)= gdot_slip_edge(j) + plasticState(ph)%state(11*ns+2*nt+j, of)= gdot_slip_screw(j) + plasticState(ph)%state(12*ns+2*nt+j, of)= StressRatio_edge_p + plasticState(ph)%state(13*ns+2*nt+j, of)= StressRatio_screw_p + + !* Derivatives of shear rates + dgdot_dtauslip(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(( & + ( & + ( & + ( & + (edge_velocity(j)*plasticState(ph)%state(j, of))) * & + BoltzmannRatioedge*& + plastic_titanmod_pe_PerSlipSys(j,instance)* & + plastic_titanmod_qe_PerSlipSys(j,instance) & + )/ & + bottomstress_edge & + )*& + StressRatio_edge_pminus1*(minusStressRatio_edge_p)** & + (plastic_titanmod_qe_PerSlipSys(j,instance)-1.0_pReal) & + ) + & + ( & + ( & + ( & + (plasticState(ph)%state(ns+j, of) * screw_velocity(j)) * & + BoltzmannRatioscrew* & + plastic_titanmod_ps_PerSlipSys(j,instance)* & + plastic_titanmod_qs_PerSlipSys(j,instance) & + )/ & + bottomstress_screw & + )*& + StressRatio_screw_pminus1*(minusStressRatio_screw_p)**(plastic_titanmod_qs_PerSlipSys(j,instance)-1.0_pReal) & + ) & + ) !* sign(1.0_pReal,tau_slip(j)) + + + +!************************************************* +!sumf=0.0_pReal + !* Plastic velocity gradient for dislocation glide + Lp = Lp + (1.0_pReal - sumf)*gdot_slip(j)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& + lattice_Sslip(k,l,1,index_myFamily+i,ph)*& + lattice_Sslip(m,n,1,index_myFamily+i,ph) + enddo + enddo slipFamiliesLoop + +!* Mechanical twinning part + gdot_twin = 0.0_pReal + dgdot_dtautwin = 0.0_pReal + j = 0_pInt + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on twin system + tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + +!************************************************************************************** + !* Stress ratios +! StressRatio_r = (plasticState(ph)%state6*ns+3*nt+j, of)/tau_twin(j))**plastic_titanmod_r(instance) + + !* Shear rates and their derivatives due to twin +! if ( tau_twin(j) > 0.0_pReal ) !then +! gdot_twin(j) = 0.0_pReal!& +! (plastic_titanmod_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& +! plasticState(ph)%state(6*ns+4*nt+j, of)*plastic_titanmod_Ndot0PerTwinSys(f,instance)*exp(-StressRatio_r) +! dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_titanmod_r(instance))/tau_twin(j))*StressRatio_r +! endif +!************************************************************************************** + + !* Stress ratio for edge + twinStressRatio_p = ((abs(tau_twin(j)))/ & + ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & + )**plastic_titanmod_twinp_PerTwinSys(j,instance) + + if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then + twinminusStressRatio_p=1.0_pReal-twinStressRatio_p + else + twinminusStressRatio_p=0.001_pReal + endif + + twinStressRatio_pminus1 = ((abs(tau_twin(j)))/ & + ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & + )**(plastic_titanmod_twinp_PerTwinSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio + BoltzmannRatiotwin = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) + + !* Initial twin shear rates + TwinDotGamma0 = & + plastic_titanmod_twingamma0_PerTwinSys(j,instance) + + !* Shear rates due to twin + gdot_twin(j) =sign(1.0_pReal,tau_twin(j))*plastic_titanmod_twingamma0_PerTwinSys(j,instance)* & + exp(-BoltzmannRatiotwin*(twinminusStressRatio_p)**plastic_titanmod_twinq_PerTwinSys(j,instance)) + + + !* Derivatives of shear rates in twin + dgdot_dtautwin(j) = ( & + ( & + ( & + (abs(gdot_twin(j))) * & + BoltzmannRatiotwin*& + plastic_titanmod_twinp_PerTwinSys(j,instance)* & + plastic_titanmod_twinq_PerTwinSys(j,instance) & + )/ & + plastic_titanmod_twintau0_PerTwinSys(j,instance) & + )*& + twinStressRatio_pminus1*(twinminusStressRatio_p)** & + (plastic_titanmod_twinq_PerTwinSys(j,instance)-1.0_pReal) & + ) !* sign(1.0_pReal,tau_slip(j)) + + !* Plastic velocity gradient for mechanical twinning +! Lp = Lp + sumf*gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) + Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& + lattice_Stwin(k,l,index_myFamily+i,ph)*& + lattice_Stwin(m,n,index_myFamily+i,ph) + enddo + enddo twinFamiliesLoop + +dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) +! tempState=state + + +end subroutine plastic_titanmod_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_dotState(Tstar_v,temperature,ipc,ip,el) + use lattice, only: & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + +implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: & + index_myFamily, instance, & + ns,nt,& + f,i,j, & + ph, & + of + real(pReal) :: & + sumf,BoltzmannRatio, & + twinStressRatio_p,twinminusStressRatio_p + real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + DotRhoEdgeGeneration, & + DotRhoEdgeAnnihilation, & + DotRhoScrewGeneration, & + DotRhoScrewAnnihilation + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin, & + tau_twin, & + volumefraction_PerTwinSys + +!-------------------------------------------------------------------------------------------------- +! shortened notation + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + + enddo + + sumf = sum(abs(volumefraction_PerTwinSys(1_pInt:nt))) ! safe for nt == 0 + + plasticState(ph)%dotState(:,of) = 0.0_pReal + j = 0_pInt + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + DotRhoEdgeGeneration(j) = & ! multiplication of edge dislocations + plasticState(ph)%state(ns+j, of)*plasticState(ph)%state(8*ns+2*nt+j, of)/plasticState(ph)%state(4*ns+nt+j, of) + DotRhoScrewGeneration(j) = & ! multiplication of screw dislocations + plasticState(ph)%state(j, of)*plasticState(ph)%state(7*ns+2*nt+j, of)/plasticState(ph)%state(3*ns+nt+j, of) + DotRhoEdgeAnnihilation(j) = -((plasticState(ph)%state(j, of))**2)* & ! annihilation of edge dislocations + plastic_titanmod_capre_PerSlipSys(j,instance)*plasticState(ph)%state(7*ns+2*nt+j, of)*0.5_pReal + DotRhoScrewAnnihilation(j) = -((plasticState(ph)%state(ns+j, of))**2)* & ! annihilation of screw dislocations + plastic_titanmod_caprs_PerSlipSys(j,instance)*plasticState(ph)%state(8*ns+2*nt+j, of)*0.5_pReal + plasticState(ph)%dotState(j, of) = & ! edge dislocation density rate of change + DotRhoEdgeGeneration(j)+DotRhoEdgeAnnihilation(j) + + plasticState(ph)%dotState(ns+j, of) = & ! screw dislocation density rate of change + DotRhoScrewGeneration(j)+DotRhoScrewAnnihilation(j) + + plasticState(ph)%dotState(2*ns+j, of) = & ! sum of shear due to edge and screw + plasticState(ph)%state(10*ns+2*nt+j, of)+plasticState(ph)%state(11*ns+2*nt+j, of) + enddo + enddo slipFamiliesLoop + +!* Twin fraction evolution + j = 0_pInt + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) twin system in family + j = j+1_pInt + + !* Resolved shear stress on twin system + tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + !* Stress ratio for edge + twinStressRatio_p = ((abs(tau_twin(j)))/ & + ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & + )**(plastic_titanmod_twinp_PerTwinSys(j,instance)) + + + if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then + twinminusStressRatio_p=1.0_pReal-twinStressRatio_p + else + twinminusStressRatio_p=0.001_pReal + endif + + BoltzmannRatio = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) + + gdot_twin(j) =plastic_titanmod_twingamma0_PerTwinSys(j,instance)*exp(-BoltzmannRatio* & + (twinminusStressRatio_p)** & + plastic_titanmod_twinq_PerTwinSys(j,instance))*sign(1.0_pReal,tau_twin(j)) + + plasticState(ph)%dotState(3*ns+j, of)=gdot_twin(j) + + enddo + enddo twinFamiliesLoop + +end subroutine plastic_titanmod_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_titanmod_postResults(ipc,ip,el) + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(plastic_titanmod_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_titanmod_postResults + + integer(pInt) :: & + instance, & + ns,nt,& + o,i,c, & + ph, & + of + real(pReal) :: sumf + + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + volumefraction_PerTwinSys + +!-------------------------------------------------------------------------------------------------- +! shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + enddo + + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + + +!-------------------------------------------------------------------------------------------------- +! required output + c = 0_pInt + plastic_titanmod_postResults = 0.0_pReal + + do o = 1_pInt,plastic_titanmod_Noutput(instance) + select case(plastic_titanmod_outputID(o,instance)) + case (rhoedge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(1_pInt:ns, of) + c = c + ns + case (rhoscrew_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of) + c = c + ns + case (segment_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(3_pInt*ns+nt+1_pInt:4_pInt*ns+nt, of) + c = c + ns + case (segment_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(4_pInt*ns+nt+1_pInt:5_pInt*ns+nt, of) + c = c + ns + case (resistance_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(5_pInt*ns+nt+1_pInt:6_pInt*ns+nt, of) + c = c + ns + case (resistance_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(6_pInt*ns+nt+1_pInt:7_pInt*ns+nt, of) + c = c + ns + case (velocity_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(7*ns+2*nt+1:8*ns+2*nt, of) + c = c + ns + case (velocity_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(8*ns+2*nt+1:9*ns+2*nt, of) + c = c + ns + case (tau_slip_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(9*ns+2*nt+1:10*ns+2*nt, of)) + c = c + ns + case (gdot_slip_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) + c = c + ns + case (gdot_slip_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) + c = c + ns + case (gdot_slip_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) + & + abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) + c = c + ns + case (stressratio_edge_p_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(12*ns+2*nt+1:13*ns+2*nt, of)) + c = c + ns + case (stressratio_screw_p_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(13*ns+2*nt+1:14*ns+2*nt, of)) + c = c + ns + case (shear_system_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(2*ns+1:3*ns, of)) + c = c + ns + case (shear_basal_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:2*ns+3, of))) + c = c + 1_pInt + case (shear_prism_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+4:2*ns+6, of))) + c = c + 1_pInt + case (shear_pyra_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+7:2*ns+12, of))) + c = c + 1_pInt + case (shear_pyrca_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+13:2*ns+24, of))) + c = c + 1_pInt + + case (rhoedge_basal_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(1:3, of)) + c = c + 1_pInt + case (rhoedge_prism_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(4:6, of)) + c = c + 1_pInt + case (rhoedge_pyra_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(7:12,of)) + c = c + 1_pInt + case (rhoedge_pyrca_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(13:24, of)) + c = c + 1_pInt + + case (rhoscrew_basal_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+1:ns+3, of)) + c = c + 1_pInt + case (rhoscrew_prism_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+4:ns+6, of)) + c = c + 1_pInt + case (rhoscrew_pyra_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+7:ns+12, of)) + c = c + 1_pInt + case (rhoscrew_pyrca_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+13:ns+24, of)) + c = c + 1_pInt + case (shear_total_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:3*ns, of))) + c = c + 1_pInt + case (twin_fraction_ID) + plastic_titanmod_postResults(c+1_pInt:c+nt) = abs(volumefraction_PerTwinSys(1:nt)) + c = c + nt + end select + enddo + +end function plastic_titanmod_postResults + +end module plastic_titanmod diff --git a/code/porosity/CMakeLists.txt b/code/porosity/CMakeLists.txt new file mode 100644 index 000000000..0695a1bf5 --- /dev/null +++ b/code/porosity/CMakeLists.txt @@ -0,0 +1,9 @@ +# group sources +set (POROSITY "porosity_none" + "porosity_phasefield" + ) + +# compile porosity modules +foreach (p ${POROSITY}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) diff --git a/code/porosity/porosity_none.f90 b/code/porosity/porosity_none.f90 new file mode 100644 index 000000000..69f10a5c6 --- /dev/null +++ b/code/porosity/porosity_none.f90 @@ -0,0 +1,61 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for constant porosity +!-------------------------------------------------------------------------------------------------- +module porosity_none + + implicit none + private + + public :: & + porosity_none_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine porosity_none_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- porosity_'//POROSITY_none_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (porosity_type(homog) == POROSITY_none_ID) then + NofMyHomog = count(material_homog == homog) + porosityState(homog)%sizeState = 0_pInt + porosityState(homog)%sizePostResults = 0_pInt + allocate(porosityState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) + allocate(porosityState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) + allocate(porosityState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) + + deallocate(porosity(homog)%p) + allocate (porosity(homog)%p(1), source=porosity_initialPhi(homog)) + + endif myhomog + enddo initializeInstances + + +end subroutine porosity_none_init + +end module porosity_none diff --git a/code/porosity/porosity_phasefield.f90 b/code/porosity/porosity_phasefield.f90 new file mode 100644 index 000000000..dc8b82b76 --- /dev/null +++ b/code/porosity/porosity_phasefield.f90 @@ -0,0 +1,450 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for phase field modelling of pore nucleation and growth +!> @details phase field model for pore nucleation and growth based on vacancy clustering +!-------------------------------------------------------------------------------------------------- +module porosity_phasefield + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + porosity_phasefield_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + porosity_phasefield_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + porosity_phasefield_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + porosity_phasefield_Noutput !< number of outputs per instance of this porosity + + enum, bind(c) + enumerator :: undefined_ID, & + porosity_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + porosity_phasefield_outputID !< ID of each post result output + + + public :: & + porosity_phasefield_init, & + porosity_phasefield_getFormationEnergy, & + porosity_phasefield_getSurfaceEnergy, & + porosity_phasefield_getSourceAndItsTangent, & + porosity_phasefield_getDiffusion33, & + porosity_phasefield_getMobility, & + porosity_phasefield_putPorosity, & + porosity_phasefield_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine porosity_phasefield_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + porosity_type, & + porosity_typeInstance, & + homogenization_Noutput, & + POROSITY_phasefield_label, & + POROSITY_phasefield_ID, & + material_homog, & + mappingHomogenization, & + porosityState, & + porosityMapping, & + porosity, & + porosity_initialPhi, & + material_partHomogenization, & + material_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- porosity_'//POROSITY_phasefield_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(porosity_type == POROSITY_phasefield_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(porosity_phasefield_sizePostResults(maxNinstance), source=0_pInt) + allocate(porosity_phasefield_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(porosity_phasefield_output (maxval(homogenization_Noutput),maxNinstance)) + porosity_phasefield_output = '' + allocate(porosity_phasefield_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(porosity_phasefield_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (porosity_type(section) == POROSITY_phasefield_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = porosity_typeInstance(section) ! which instance of my porosity is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('porosity') + porosity_phasefield_Noutput(instance) = porosity_phasefield_Noutput(instance) + 1_pInt + porosity_phasefield_outputID(porosity_phasefield_Noutput(instance),instance) = porosity_ID + porosity_phasefield_output(porosity_phasefield_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingHomog + + initializeInstances: do section = 1_pInt, size(porosity_type) + if (porosity_type(section) == POROSITY_phasefield_ID) then + NofMyHomog=count(material_homog==section) + instance = porosity_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,porosity_phasefield_Noutput(instance) + select case(porosity_phasefield_outputID(o,instance)) + case(porosity_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + porosity_phasefield_sizePostResult(o,instance) = mySize + porosity_phasefield_sizePostResults(instance) = porosity_phasefield_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 0_pInt + porosityState(section)%sizeState = sizeState + porosityState(section)%sizePostResults = porosity_phasefield_sizePostResults(instance) + allocate(porosityState(section)%state0 (sizeState,NofMyHomog)) + allocate(porosityState(section)%subState0(sizeState,NofMyHomog)) + allocate(porosityState(section)%state (sizeState,NofMyHomog)) + + nullify(porosityMapping(section)%p) + porosityMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(porosity(section)%p) + allocate(porosity(section)%p(NofMyHomog), source=porosity_initialPhi(section)) + + endif + + enddo initializeInstances +end subroutine porosity_phasefield_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized vacancy formation energy +!-------------------------------------------------------------------------------------------------- +function porosity_phasefield_getFormationEnergy(ip,el) + use lattice, only: & + lattice_vacancyFormationEnergy, & + lattice_vacancyVol + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + porosity_phasefield_getFormationEnergy + integer(pInt) :: & + grain + + porosity_phasefield_getFormationEnergy = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + porosity_phasefield_getFormationEnergy = porosity_phasefield_getFormationEnergy + & + lattice_vacancyFormationEnergy(material_phase(grain,ip,el))/ & + lattice_vacancyVol(material_phase(grain,ip,el)) + enddo + + porosity_phasefield_getFormationEnergy = & + porosity_phasefield_getFormationEnergy/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function porosity_phasefield_getFormationEnergy + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized pore surface energy (normalized by characteristic length) +!-------------------------------------------------------------------------------------------------- +function porosity_phasefield_getSurfaceEnergy(ip,el) + use lattice, only: & + lattice_vacancySurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + porosity_phasefield_getSurfaceEnergy + integer(pInt) :: & + grain + + porosity_phasefield_getSurfaceEnergy = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + porosity_phasefield_getSurfaceEnergy = porosity_phasefield_getSurfaceEnergy + & + lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) + enddo + + porosity_phasefield_getSurfaceEnergy = & + porosity_phasefield_getSurfaceEnergy/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function porosity_phasefield_getSurfaceEnergy + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates homogenized local driving force for pore nucleation and growth +!-------------------------------------------------------------------------------------------------- +subroutine porosity_phasefield_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) + use math, only : & + math_mul33x33, & + math_mul66x6, & + math_Mandel33to6, & + math_transpose33, & + math_I3 + use material, only: & + homogenization_Ngrains, & + material_homog, & + material_phase, & + phase_NstiffnessDegradations, & + phase_stiffnessDegradation, & + vacancyConc, & + vacancyfluxMapping, & + damage, & + damageMapping, & + STIFFNESS_DEGRADATION_damage_ID + use crystallite, only: & + crystallite_Fe + use constitutive, only: & + constitutive_homogenizedC + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + phi + integer(pInt) :: & + phase, & + grain, & + homog, & + mech + real(pReal) :: & + phiDot, dPhiDot_dPhi, Cv, W_e, strain(6), C(6,6) + + homog = material_homog(ip,el) + Cv = vacancyConc(homog)%p(vacancyfluxMapping(homog)%p(ip,el)) + + W_e = 0.0_pReal + do grain = 1, homogenization_Ngrains(homog) + phase = material_phase(grain,ip,el) + strain = math_Mandel33to6(math_mul33x33(math_transpose33(crystallite_Fe(1:3,1:3,grain,ip,el)), & + crystallite_Fe(1:3,1:3,grain,ip,el)) - math_I3)/2.0_pReal + C = constitutive_homogenizedC(grain,ip,el) + do mech = 1_pInt, phase_NstiffnessDegradations(phase) + select case(phase_stiffnessDegradation(mech,phase)) + case (STIFFNESS_DEGRADATION_damage_ID) + C = damage(homog)%p(damageMapping(homog)%p(ip,el))* & + damage(homog)%p(damageMapping(homog)%p(ip,el))* & + C + + end select + enddo + W_e = W_e + sum(abs(strain*math_mul66x6(C,strain))) + enddo + W_e = W_e/homogenization_Ngrains(homog) + + phiDot = 2.0_pReal*(1.0_pReal - phi)*(1.0_pReal - Cv)*(1.0_pReal - Cv) - & + 2.0_pReal*phi*(W_e + Cv*porosity_phasefield_getFormationEnergy(ip,el))/ & + porosity_phasefield_getSurfaceEnergy (ip,el) + dPhiDot_dPhi = - 2.0_pReal*(1.0_pReal - Cv)*(1.0_pReal - Cv) & + - 2.0_pReal*(W_e + Cv*porosity_phasefield_getFormationEnergy(ip,el))/ & + porosity_phasefield_getSurfaceEnergy (ip,el) + +end subroutine porosity_phasefield_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized nonlocal diffusion tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function porosity_phasefield_getDiffusion33(ip,el) + use lattice, only: & + lattice_PorosityDiffusion33 + use material, only: & + homogenization_Ngrains, & + material_phase, & + mappingHomogenization + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + porosity_phasefield_getDiffusion33 + integer(pInt) :: & + homog, & + grain + + homog = mappingHomogenization(2,ip,el) + porosity_phasefield_getDiffusion33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(homog) + porosity_phasefield_getDiffusion33 = porosity_phasefield_getDiffusion33 + & + crystallite_push33ToRef(grain,ip,el,lattice_PorosityDiffusion33(1:3,1:3,material_phase(grain,ip,el))) + enddo + + porosity_phasefield_getDiffusion33 = & + porosity_phasefield_getDiffusion33/ & + homogenization_Ngrains(homog) + +end function porosity_phasefield_getDiffusion33 + +!-------------------------------------------------------------------------------------------------- +!> @brief Returns homogenized phase field mobility +!-------------------------------------------------------------------------------------------------- +real(pReal) function porosity_phasefield_getMobility(ip,el) + use mesh, only: & + mesh_element + use lattice, only: & + lattice_PorosityMobility + use material, only: & + material_phase, & + homogenization_Ngrains + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + integer(pInt) :: & + ipc + + porosity_phasefield_getMobility = 0.0_pReal + + do ipc = 1, homogenization_Ngrains(mesh_element(3,el)) + porosity_phasefield_getMobility = porosity_phasefield_getMobility + lattice_PorosityMobility(material_phase(ipc,ip,el)) + enddo + + porosity_phasefield_getMobility = porosity_phasefield_getMobility/homogenization_Ngrains(mesh_element(3,el)) + +end function porosity_phasefield_getMobility + +!-------------------------------------------------------------------------------------------------- +!> @brief updates porosity with solution from phasefield PDE +!-------------------------------------------------------------------------------------------------- +subroutine porosity_phasefield_putPorosity(phi,ip,el) + use material, only: & + material_homog, & + porosityMapping, & + porosity + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + phi + integer(pInt) :: & + homog, & + offset + + homog = material_homog(ip,el) + offset = porosityMapping(homog)%p(ip,el) + porosity(homog)%p(offset) = phi + +end subroutine porosity_phasefield_putPorosity + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of porosity results +!-------------------------------------------------------------------------------------------------- +function porosity_phasefield_postResults(ip,el) + use material, only: & + mappingHomogenization, & + porosity_typeInstance, & + porosity + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(porosity_phasefield_sizePostResults(porosity_typeInstance(mappingHomogenization(2,ip,el)))) :: & + porosity_phasefield_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + instance = porosity_typeInstance(homog) + + c = 0_pInt + porosity_phasefield_postResults = 0.0_pReal + + do o = 1_pInt,porosity_phasefield_Noutput(instance) + select case(porosity_phasefield_outputID(o,instance)) + + case (porosity_ID) + porosity_phasefield_postResults(c+1_pInt) = porosity(homog)%p(offset) + c = c + 1 + end select + enddo +end function porosity_phasefield_postResults + +end module porosity_phasefield diff --git a/code/source/CMakeLists.txt b/code/source/CMakeLists.txt new file mode 100644 index 000000000..fa54f332a --- /dev/null +++ b/code/source/CMakeLists.txt @@ -0,0 +1,16 @@ +# group source +set (SOURCE "source_thermal_dissipation" + "source_thermal_externalheat" + "source_damage_isoBrittle" + "source_damage_isoDuctile" + "source_damage_anisoBrittle" + "source_damage_anisoDuctile" + "source_vacancy_phenoplasticity" + "source_vacancy_irradiation" + "source_vacancy_thermalfluc" + ) + +# compile modules for source +foreach (p ${SOURCE}) + add_library (${p} MODULE "${p}.f90") +endforeach (p) diff --git a/code/source/source_damage_anisoBrittle.f90 b/code/source/source_damage_anisoBrittle.f90 new file mode 100644 index 000000000..a751eefdc --- /dev/null +++ b/code/source/source_damage_anisoBrittle.f90 @@ -0,0 +1,425 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @brief material subroutine incorporating anisotropic brittle damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_anisoBrittle + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_anisoBrittle_sizePostResults, & !< cumulative size of post results + source_damage_anisoBrittle_offset, & !< which source is my current source mechanism? + source_damage_anisoBrittle_instance !< instance of source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_anisoBrittle_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_anisoBrittle_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_anisoBrittle_Noutput !< number of outputs per instance of this source + + integer(pInt), dimension(:), allocatable, private :: & + source_damage_anisoBrittle_totalNcleavage !< total number of cleavage systems + + integer(pInt), dimension(:,:), allocatable, private :: & + source_damage_anisoBrittle_Ncleavage !< number of cleavage systems per family + + real(pReal), dimension(:), allocatable, private :: & + source_damage_anisoBrittle_aTol, & + source_damage_anisoBrittle_sdot_0, & + source_damage_anisoBrittle_N + + real(pReal), dimension(:,:), allocatable, private :: & + source_damage_anisoBrittle_critDisp, & + source_damage_anisoBrittle_critLoad + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_anisoBrittle_outputID !< ID of each post result output + + + public :: & + source_damage_anisoBrittle_init, & + source_damage_anisoBrittle_dotState, & + source_damage_anisobrittle_getRateAndItsTangent, & + source_damage_anisoBrittle_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoBrittle_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_anisoBrittle_label, & + SOURCE_damage_anisoBrittle_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + use lattice, only: & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoBrittle_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_anisoBrittle_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_anisoBrittle_offset(material_Nphase), source=0_pInt) + allocate(source_damage_anisoBrittle_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_anisoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoBrittle_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_anisoBrittle_ID) & + source_damage_anisoBrittle_offset(phase) = source + enddo + enddo + + allocate(source_damage_anisoBrittle_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_output(maxval(phase_Noutput),maxNinstance)) + source_damage_anisoBrittle_output = '' + allocate(source_damage_anisoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_anisoBrittle_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_totalNcleavage(maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_aTol(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_sdot_0(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_N(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_anisoBrittle_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('anisobrittle_drivingforce') + source_damage_anisoBrittle_Noutput(instance) = source_damage_anisoBrittle_Noutput(instance) + 1_pInt + source_damage_anisoBrittle_outputID(source_damage_anisoBrittle_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_anisoBrittle_output(source_damage_anisoBrittle_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('anisobrittle_atol') + source_damage_anisoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisobrittle_sdot0') + source_damage_anisoBrittle_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisobrittle_ratesensitivity') + source_damage_anisoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('ncleavage') ! + Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_CleavageFamilies + source_damage_anisoBrittle_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticaldisplacement') + do j = 1_pInt, Nchunks_CleavageFamilies + source_damage_anisoBrittle_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticalload') + do j = 1_pInt, Nchunks_CleavageFamilies + source_damage_anisoBrittle_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then + instance = source_damage_anisoBrittle_instance(phase) + source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & + min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested + source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance)) + source_damage_anisoBrittle_totalNcleavage(instance) = sum(source_damage_anisoBrittle_Ncleavage(:,instance)) ! how many cleavage systems altogether + if (source_damage_anisoBrittle_aTol(instance) < 0.0_pReal) & + source_damage_anisoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_anisoBrittle_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoBrittle_LABEL//')') + if (any(source_damage_anisoBrittle_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//SOURCE_damage_anisoBrittle_LABEL//')') + if (any(source_damage_anisoBrittle_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//SOURCE_damage_anisoBrittle_LABEL//')') + if (source_damage_anisoBrittle_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoBrittle_LABEL//')') + endif myPhase + enddo sanityChecks + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_anisoBrittle_instance(phase) + sourceOffset = source_damage_anisoBrittle_offset(phase) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) + select case(source_damage_anisoBrittle_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_anisoBrittle_sizePostResult(o,instance) = mySize + source_damage_anisoBrittle_sizePostResults(instance) = source_damage_anisoBrittle_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoBrittle_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_anisoBrittle_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_anisoBrittle_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoBrittle_dotState(Tstar_v, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState, & + material_homog, & + damage, & + damageMapping + use lattice, only: & + lattice_Scleavage_v, & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) + integer(pInt) :: & + phase, & + constituent, & + instance, & + sourceOffset, & + damageOffset, & + homog, & + f, i, index_myFamily + real(pReal) :: & + traction_d, traction_t, traction_n, traction_crit + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoBrittle_instance(phase) + sourceOffset = source_damage_anisoBrittle_offset(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal + do f = 1_pInt,lattice_maxNcleavageFamily + index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family + do i = 1_pInt,source_damage_anisoBrittle_Ncleavage(f,instance) ! process each (active) cleavage system in family + traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) + traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) + traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) + + traction_crit = source_damage_anisoBrittle_critLoad(f,instance)* & + damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & + source_damage_anisoBrittle_sdot_0(instance)* & + ((max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & + (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & + (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance))/ & + source_damage_anisoBrittle_critDisp(f,instance) + + enddo + enddo + +end subroutine source_damage_anisoBrittle_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_damage_anisoBrittle_offset(phase) + + localphiDot = 1.0_pReal - & + sourceState(phase)%p(sourceOffset)%state(1,constituent)*phi + + dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_anisobrittle_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_anisoBrittle_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_anisoBrittle_sizePostResults( & + source_damage_anisoBrittle_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_anisoBrittle_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoBrittle_instance(phase) + sourceOffset = source_damage_anisoBrittle_offset(phase) + + c = 0_pInt + source_damage_anisoBrittle_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) + select case(source_damage_anisoBrittle_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_anisoBrittle_postResults(c+1_pInt) = & + sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1_pInt + + end select + enddo +end function source_damage_anisoBrittle_postResults + +end module source_damage_anisoBrittle diff --git a/code/source/source_damage_anisoDuctile.f90 b/code/source/source_damage_anisoDuctile.f90 new file mode 100644 index 000000000..028fd479a --- /dev/null +++ b/code/source/source_damage_anisoDuctile.f90 @@ -0,0 +1,415 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating anisotropic ductile damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_anisoDuctile + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_anisoDuctile_sizePostResults, & !< cumulative size of post results + source_damage_anisoDuctile_offset, & !< which source is my current damage mechanism? + source_damage_anisoDuctile_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_anisoDuctile_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_anisoDuctile_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_anisoDuctile_Noutput !< number of outputs per instance of this damage + + integer(pInt), dimension(:), allocatable, private :: & + source_damage_anisoDuctile_totalNslip !< total number of slip systems + + integer(pInt), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_Nslip !< number of slip systems per family + + real(pReal), dimension(:), allocatable, private :: & + source_damage_anisoDuctile_aTol + + real(pReal), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_critPlasticStrain + + real(pReal), dimension(:), allocatable, private :: & + source_damage_anisoDuctile_sdot_0, & + source_damage_anisoDuctile_N + + real(pReal), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_critLoad + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_outputID !< ID of each post result output + + + public :: & + source_damage_anisoDuctile_init, & + source_damage_anisoDuctile_dotState, & + source_damage_anisoDuctile_getRateAndItsTangent, & + source_damage_anisoDuctile_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoDuctile_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_anisoDuctile_label, & + SOURCE_damage_anisoDuctile_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + use lattice, only: & + lattice_maxNslipFamily, & + lattice_NslipSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoDuctile_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_anisoDuctile_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_anisoDuctile_offset(material_Nphase), source=0_pInt) + allocate(source_damage_anisoDuctile_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_anisoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoDuctile_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_anisoDuctile_ID) & + source_damage_anisoDuctile_offset(phase) = source + enddo + enddo + + allocate(source_damage_anisoDuctile_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_damage_anisoDuctile_output(maxval(phase_Noutput),maxNinstance)) + source_damage_anisoDuctile_output = '' + allocate(source_damage_anisoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_anisoDuctile_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoDuctile_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(source_damage_anisoDuctile_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_totalNslip(maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_N(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoDuctile_sdot_0(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoDuctile_aTol(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_anisoDuctile_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('anisoductile_drivingforce') + source_damage_anisoDuctile_Noutput(instance) = source_damage_anisoDuctile_Noutput(instance) + 1_pInt + source_damage_anisoDuctile_outputID(source_damage_anisoDuctile_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_anisoDuctile_output(source_damage_anisoDuctile_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('anisoductile_atol') + source_damage_anisoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('nslip') ! + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + source_damage_anisoDuctile_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_sdot0') + source_damage_anisoDuctile_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalplasticstrain') + do j = 1_pInt, Nchunks_SlipFamilies + source_damage_anisoDuctile_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_ratesensitivity') + source_damage_anisoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalload') + do j = 1_pInt, Nchunks_SlipFamilies + source_damage_anisoDuctile_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, size(phase_source) + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then + instance = source_damage_anisoDuctile_instance(phase) + source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested + source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance)) + source_damage_anisoDuctile_totalNslip(instance) = sum(source_damage_anisoDuctile_Nslip(:,instance)) + if (source_damage_anisoDuctile_aTol(instance) < 0.0_pReal) & + source_damage_anisoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_anisoDuctile_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoDuctile_LABEL//')') + if (any(source_damage_anisoDuctile_critPlasticStrain(:,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//SOURCE_damage_anisoDuctile_LABEL//')') + if (source_damage_anisoDuctile_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoDuctile_LABEL//')') + endif myPhase + enddo sanityChecks + + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_anisoDuctile_instance(phase) + sourceOffset = source_damage_anisoDuctile_offset(phase) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) + select case(source_damage_anisoDuctile_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_anisoDuctile_sizePostResult(o,instance) = mySize + source_damage_anisoDuctile_sizePostResults(instance) = source_damage_anisoDuctile_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoDuctile_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_anisoDuctile_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_anisoDuctile_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoDuctile_dotState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + sourceState, & + material_homog, & + damage, & + damageMapping + use lattice, only: & + lattice_maxNslipFamily + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, & + constituent, & + sourceOffset, & + homog, damageOffset, & + instance, & + index, f, i + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoDuctile_instance(phase) + sourceOffset = source_damage_anisoDuctile_offset(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + index = 1_pInt + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal + do f = 1_pInt,lattice_maxNslipFamily + do i = 1_pInt,source_damage_anisoDuctile_Nslip(f,instance) ! process each (active) slip system in family + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & + plasticState(phase)%slipRate(index,constituent)/ & + ((damage(homog)%p(damageOffset))**source_damage_anisoDuctile_N(instance))/ & + source_damage_anisoDuctile_critPlasticStrain(f,instance) + + index = index + 1_pInt + enddo + enddo + +end subroutine source_damage_anisoDuctile_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_damage_anisoDuctile_offset(phase) + + localphiDot = 1.0_pReal - & + sourceState(phase)%p(sourceOffset)%state(1,constituent)* & + phi + + dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_anisoDuctile_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_anisoDuctile_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_anisoDuctile_sizePostResults( & + source_damage_anisoDuctile_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_anisoDuctile_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoDuctile_instance(phase) + sourceOffset = source_damage_anisoDuctile_offset(phase) + + c = 0_pInt + source_damage_anisoDuctile_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) + select case(source_damage_anisoDuctile_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_anisoDuctile_postResults(c+1_pInt) = & + sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1_pInt + + end select + enddo +end function source_damage_anisoDuctile_postResults + +end module source_damage_anisoDuctile diff --git a/code/source/source_damage_isoBrittle.f90 b/code/source/source_damage_isoBrittle.f90 new file mode 100644 index 000000000..c063ae86f --- /dev/null +++ b/code/source/source_damage_isoBrittle.f90 @@ -0,0 +1,383 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incoprorating isotropic brittle damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_isoBrittle + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_isoBrittle_sizePostResults, & !< cumulative size of post results + source_damage_isoBrittle_offset, & !< which source is my current damage mechanism? + source_damage_isoBrittle_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_isoBrittle_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_isoBrittle_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_isoBrittle_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_damage_isoBrittle_aTol, & + source_damage_isoBrittle_N, & + source_damage_isoBrittle_critStrainEnergy + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_isoBrittle_outputID !< ID of each post result output + + + public :: & + source_damage_isoBrittle_init, & + source_damage_isoBrittle_deltaState, & + source_damage_isoBrittle_getRateAndItsTangent, & + source_damage_isoBrittle_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoBrittle_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_isoBrittle_label, & + SOURCE_damage_isoBrittle_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoBrittle_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_isoBrittle_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_isoBrittle_offset(material_Nphase), source=0_pInt) + allocate(source_damage_isoBrittle_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_isoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoBrittle_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_isoBrittle_ID) & + source_damage_isoBrittle_offset(phase) = source + enddo + enddo + + allocate(source_damage_isoBrittle_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_isoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_damage_isoBrittle_output(maxval(phase_Noutput),maxNinstance)) + source_damage_isoBrittle_output = '' + allocate(source_damage_isoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_isoBrittle_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_isoBrittle_critStrainEnergy(maxNinstance), source=0.0_pReal) + allocate(source_damage_isoBrittle_N(maxNinstance), source=1.0_pReal) + allocate(source_damage_isoBrittle_aTol(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_isoBrittle_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('isobrittle_drivingforce') + source_damage_isoBrittle_Noutput(instance) = source_damage_isoBrittle_Noutput(instance) + 1_pInt + source_damage_isoBrittle_outputID(source_damage_isoBrittle_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_isoBrittle_output(source_damage_isoBrittle_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('isobrittle_criticalstrainenergy') + source_damage_isoBrittle_critStrainEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isobrittle_n') + source_damage_isoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isobrittle_atol') + source_damage_isoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then + instance = source_damage_isoBrittle_instance(phase) + if (source_damage_isoBrittle_aTol(instance) < 0.0_pReal) & + source_damage_isoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_isoBrittle_critStrainEnergy(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='criticalStrainEnergy ('//SOURCE_damage_isoBrittle_LABEL//')') + endif myPhase + enddo sanityChecks + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_isoBrittle_instance(phase) + sourceOffset = source_damage_isoBrittle_offset(phase) +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) + select case(source_damage_isoBrittle_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_isoBrittle_sizePostResult(o,instance) = mySize + source_damage_isoBrittle_sizePostResults(instance) = source_damage_isoBrittle_sizePostResults(instance) + mySize + endif + enddo outputsLoop +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 1_pInt + sizeState = 1_pInt + + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoBrittle_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_isoBrittle_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_isoBrittle_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoBrittle_deltaState(C, Fe, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState, & + material_homog, & + phase_NstiffnessDegradations, & + phase_stiffnessDegradation, & + porosity, & + porosityMapping, & + STIFFNESS_DEGRADATION_porosity_ID + use math, only : & + math_mul33x33, & + math_mul66x6, & + math_Mandel33to6, & + math_transpose33, & + math_I3 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(3,3) :: & + Fe + real(pReal), intent(in), dimension(6,6) :: & + C + integer(pInt) :: & + phase, constituent, instance, sourceOffset, mech + real(pReal) :: & + strain(6), & + stiffness(6,6), & + strainenergy + + phase = phaseAt(ipc,ip,el) !< phase ID at ipc,ip,el + constituent = phasememberAt(ipc,ip,el) !< state array offset for phase ID at ipc,ip,el + ! ToDo: capability for multiple instances of SAME source within given phase. Needs Ninstance loop from here on! + instance = source_damage_isoBrittle_instance(phase) !< instance of damage_isoBrittle source + sourceOffset = source_damage_isoBrittle_offset(phase) + + stiffness = C + do mech = 1_pInt, phase_NstiffnessDegradations(phase) + select case(phase_stiffnessDegradation(mech,phase)) + case (STIFFNESS_DEGRADATION_porosity_ID) + stiffness = porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & + porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & + stiffness + end select + enddo + strain = 0.5_pReal*math_Mandel33to6(math_mul33x33(math_transpose33(Fe),Fe)-math_I3) + + strainenergy = 2.0_pReal*sum(strain*math_mul66x6(stiffness,strain))/ & + source_damage_isoBrittle_critStrainEnergy(instance) + if (strainenergy > sourceState(phase)%p(sourceOffset)%subState0(1,constituent)) then + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + strainenergy - sourceState(phase)%p(sourceOffset)%state(1,constituent) + else + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + sourceState(phase)%p(sourceOffset)%subState0(1,constituent) - & + sourceState(phase)%p(sourceOffset)%state(1,constituent) + endif + +end subroutine source_damage_isoBrittle_deltaState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoBrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, instance, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoBrittle_instance(phase) + sourceOffset = source_damage_isoBrittle_offset(phase) + + localphiDot = (1.0_pReal - phi)**(source_damage_isoBrittle_N(instance) - 1.0_pReal) - & + phi*sourceState(phase)%p(sourceOffset)%state(1,constituent) + dLocalphiDot_dPhi = - (source_damage_isoBrittle_N(instance) - 1.0_pReal)* & + (1.0_pReal - phi)**max(0.0_pReal,source_damage_isoBrittle_N(instance) - 2.0_pReal) & + - sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_isoBrittle_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_isoBrittle_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_isoBrittle_sizePostResults( & + source_damage_isoBrittle_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_isoBrittle_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoBrittle_instance(phase) + sourceOffset = source_damage_isoBrittle_offset(phase) + + c = 0_pInt + source_damage_isoBrittle_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) + select case(source_damage_isoBrittle_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_isoBrittle_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1 + + end select + enddo +end function source_damage_isoBrittle_postResults + +end module source_damage_isoBrittle diff --git a/code/source/source_damage_isoDuctile.f90 b/code/source/source_damage_isoDuctile.f90 new file mode 100644 index 000000000..b0290264c --- /dev/null +++ b/code/source/source_damage_isoDuctile.f90 @@ -0,0 +1,350 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @brief material subroutine incoprorating isotropic ductile damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_isoDuctile + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_isoDuctile_sizePostResults, & !< cumulative size of post results + source_damage_isoDuctile_offset, & !< which source is my current damage mechanism? + source_damage_isoDuctile_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_isoDuctile_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_isoDuctile_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_isoDuctile_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_damage_isoDuctile_aTol, & + source_damage_isoDuctile_critPlasticStrain, & + source_damage_isoDuctile_N + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_isoDuctile_outputID !< ID of each post result output + + + public :: & + source_damage_isoDuctile_init, & + source_damage_isoDuctile_dotState, & + source_damage_isoDuctile_getRateAndItsTangent, & + source_damage_isoDuctile_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoDuctile_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_isoDuctile_label, & + SOURCE_damage_isoDuctile_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoDuctile_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_isoDuctile_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_isoDuctile_offset(material_Nphase), source=0_pInt) + allocate(source_damage_isoDuctile_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_isoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoDuctile_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_isoDuctile_ID) & + source_damage_isoDuctile_offset(phase) = source + enddo + enddo + + allocate(source_damage_isoDuctile_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_isoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_damage_isoDuctile_output(maxval(phase_Noutput),maxNinstance)) + source_damage_isoDuctile_output = '' + allocate(source_damage_isoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_isoDuctile_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_isoDuctile_critPlasticStrain(maxNinstance), source=0.0_pReal) + allocate(source_damage_isoDuctile_N(maxNinstance), source=0.0_pReal) + allocate(source_damage_isoDuctile_aTol(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_isoDuctile_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('isoductile_drivingforce') + source_damage_isoDuctile_Noutput(instance) = source_damage_isoDuctile_Noutput(instance) + 1_pInt + source_damage_isoDuctile_outputID(source_damage_isoDuctile_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_isoDuctile_output(source_damage_isoDuctile_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('isoductile_criticalplasticstrain') + source_damage_isoDuctile_critPlasticStrain(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isoductile_ratesensitivity') + source_damage_isoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isoductile_atol') + source_damage_isoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then + instance = source_damage_isoDuctile_instance(phase) + if (source_damage_isoDuctile_aTol(instance) < 0.0_pReal) & + source_damage_isoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_isoDuctile_critPlasticStrain(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='critical plastic strain ('//SOURCE_damage_isoDuctile_LABEL//')') + endif myPhase + enddo sanityChecks + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_isoDuctile_instance(phase) + sourceOffset = source_damage_isoDuctile_offset(phase) +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) + select case(source_damage_isoDuctile_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_isoDuctile_sizePostResult(o,instance) = mySize + source_damage_isoDuctile_sizePostResults(instance) = source_damage_isoDuctile_sizePostResults(instance) + mySize + endif + enddo outputsLoop +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoDuctile_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_isoDuctile_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_isoDuctile_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoDuctile_dotState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + sourceState, & + material_homog, & + damage, & + damageMapping + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, constituent, instance, homog, sourceOffset, damageOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoDuctile_instance(phase) + sourceOffset = source_damage_isoDuctile_offset(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & + sum(plasticState(phase)%slipRate(:,constituent))/ & + ((damage(homog)%p(damageOffset))**source_damage_isoDuctile_N(instance))/ & + source_damage_isoDuctile_critPlasticStrain(instance) + +end subroutine source_damage_isoDuctile_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_damage_isoDuctile_offset(phase) + + localphiDot = 1.0_pReal - & + sourceState(phase)%p(sourceOffset)%state(1,constituent)* & + phi + + dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_isoDuctile_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_isoDuctile_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_isoDuctile_sizePostResults( & + source_damage_isoDuctile_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_isoDuctile_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoDuctile_instance(phase) + sourceOffset = source_damage_isoDuctile_offset(phase) + + c = 0_pInt + source_damage_isoDuctile_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) + select case(source_damage_isoDuctile_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_isoDuctile_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1 + + end select + enddo +end function source_damage_isoDuctile_postResults + +end module source_damage_isoDuctile diff --git a/code/source/source_thermal_dissipation.f90 b/code/source/source_thermal_dissipation.f90 new file mode 100644 index 000000000..83ad85167 --- /dev/null +++ b/code/source/source_thermal_dissipation.f90 @@ -0,0 +1,220 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for thermal source due to plastic dissipation +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_thermal_dissipation + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_thermal_dissipation_sizePostResults, & !< cumulative size of post results + source_thermal_dissipation_offset, & !< which source is my current thermal dissipation mechanism? + source_thermal_dissipation_instance !< instance of thermal dissipation source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_thermal_dissipation_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_thermal_dissipation_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_thermal_dissipation_Noutput !< number of outputs per instance of this source + + real(pReal), dimension(:), allocatable, private :: & + source_thermal_dissipation_coldworkCoeff + + public :: & + source_thermal_dissipation_init, & + source_thermal_dissipation_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_dissipation_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_thermal_dissipation_label, & + SOURCE_thermal_dissipation_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_dissipation_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_thermal_dissipation_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_thermal_dissipation_offset(material_Nphase), source=0_pInt) + allocate(source_thermal_dissipation_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_thermal_dissipation_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_dissipation_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == SOURCE_thermal_dissipation_ID) & + source_thermal_dissipation_offset(phase) = source + enddo + enddo + + allocate(source_thermal_dissipation_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_thermal_dissipation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_thermal_dissipation_output (maxval(phase_Noutput),maxNinstance)) + source_thermal_dissipation_output = '' + allocate(source_thermal_dissipation_Noutput(maxNinstance), source=0_pInt) + allocate(source_thermal_dissipation_coldworkCoeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_thermal_dissipation_instance(phase) ! which instance of my source is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('dissipation_coldworkcoeff') + source_thermal_dissipation_coldworkCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_thermal_dissipation_instance(phase) + sourceOffset = source_thermal_dissipation_offset(phase) + + sizeDotState = 0_pInt + sizeDeltaState = 0_pInt + sizeState = 0_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_dissipation_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_thermal_dissipation_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_dissipation_getRateAndItsTangent(TDot, dTDOT_dT, Tstar_v, Lp, ipc, ip, el) + use math, only: & + math_Mandel6to33 + use material, only: & + phaseAt, phasememberAt + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) + real(pReal), intent(in), dimension(3,3) :: & + Lp + real(pReal), intent(out) :: & + TDot, & + dTDOT_dT + integer(pInt) :: & + instance, phase, constituent + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_thermal_dissipation_instance(phase) + + TDot = source_thermal_dissipation_coldworkCoeff(instance)* & + sum(abs(math_Mandel6to33(Tstar_v)*Lp)) + dTDOT_dT = 0.0_pReal + +end subroutine source_thermal_dissipation_getRateAndItsTangent + +end module source_thermal_dissipation diff --git a/code/source/source_thermal_externalheat.f90 b/code/source/source_thermal_externalheat.f90 new file mode 100644 index 000000000..257012c06 --- /dev/null +++ b/code/source/source_thermal_externalheat.f90 @@ -0,0 +1,277 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for thermal source due to plastic dissipation +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_thermal_externalheat + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_thermal_externalheat_sizePostResults, & !< cumulative size of post results + source_thermal_externalheat_offset, & !< which source is my current thermal dissipation mechanism? + source_thermal_externalheat_instance !< instance of thermal dissipation source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_thermal_externalheat_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_thermal_externalheat_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_thermal_externalheat_Noutput !< number of outputs per instance of this source + + integer(pInt), dimension(:), allocatable, private :: & + source_thermal_externalheat_nIntervals + + real(pReal), dimension(:,:), allocatable, private :: & + source_thermal_externalheat_time, & + source_thermal_externalheat_rate + + public :: & + source_thermal_externalheat_init, & + source_thermal_externalheat_dotState, & + source_thermal_externalheat_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_externalheat_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_thermal_externalheat_label, & + SOURCE_thermal_externalheat_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase,interval + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), allocatable, dimension(:,:) :: temp_time, temp_rate + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_externalheat_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_thermal_externalheat_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_thermal_externalheat_offset(material_Nphase), source=0_pInt) + allocate(source_thermal_externalheat_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_thermal_externalheat_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_externalheat_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == SOURCE_thermal_externalheat_ID) & + source_thermal_externalheat_offset(phase) = source + enddo + enddo + + allocate(source_thermal_externalheat_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_thermal_externalheat_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_thermal_externalheat_output (maxval(phase_Noutput),maxNinstance)) + source_thermal_externalheat_output = '' + allocate(source_thermal_externalheat_Noutput(maxNinstance), source=0_pInt) + allocate(source_thermal_externalheat_nIntervals(maxNinstance), source=0_pInt) + + allocate(temp_time(maxNinstance,1000), source=0.0_pReal) + allocate(temp_rate(maxNinstance,1000), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_thermal_externalheat_instance(phase) ! which instance of my source is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('externalheat_time') + if (chunkPos(1) <= 2_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//SOURCE_thermal_externalheat_label//')') + source_thermal_externalheat_nIntervals(instance) = chunkPos(1) - 2_pInt + do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt + temp_time(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) + enddo + + case ('externalheat_rate') + do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt + temp_rate(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) + enddo + + end select + endif; endif + enddo parsingFile + + allocate(source_thermal_externalheat_time(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) + allocate(source_thermal_externalheat_rate(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_thermal_externalheat_instance(phase) + sourceOffset = source_thermal_externalheat_offset(phase) + source_thermal_externalheat_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & + temp_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) + source_thermal_externalheat_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & + temp_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) + + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_externalheat_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.00001_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_thermal_externalheat_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_externalheat_dotState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, & + constituent, & + sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_thermal_externalheat_offset(phase) + + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 1.0_pReal + +end subroutine source_thermal_externalheat_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_externalheat_getRateAndItsTangent(TDot, dTDot_dT, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + TDot, & + dTDot_dT + integer(pInt) :: & + instance, phase, constituent, sourceOffset, interval + real(pReal) :: & + norm_time + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_thermal_externalheat_instance(phase) + sourceOffset = source_thermal_externalheat_offset(phase) + + do interval = 1, source_thermal_externalheat_nIntervals(instance) + norm_time = (sourceState(phase)%p(sourceOffset)%state(1,constituent) - & + source_thermal_externalheat_time(instance,interval)) / & + (source_thermal_externalheat_time(instance,interval+1) - & + source_thermal_externalheat_time(instance,interval)) + if (norm_time >= 0.0_pReal .and. norm_time < 1.0_pReal) & + TDot = source_thermal_externalheat_rate(instance,interval ) * (1.0_pReal - norm_time) + & + source_thermal_externalheat_rate(instance,interval+1) * norm_time + enddo + dTDot_dT = 0.0 + +end subroutine source_thermal_externalheat_getRateAndItsTangent + +end module source_thermal_externalheat diff --git a/code/source/source_vacancy_irradiation.f90 b/code/source/source_vacancy_irradiation.f90 new file mode 100644 index 000000000..c4bcfba04 --- /dev/null +++ b/code/source/source_vacancy_irradiation.f90 @@ -0,0 +1,253 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for vacancy generation due to irradiation +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_vacancy_irradiation + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_vacancy_irradiation_sizePostResults, & !< cumulative size of post results + source_vacancy_irradiation_offset, & !< which source is my current damage mechanism? + source_vacancy_irradiation_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_vacancy_irradiation_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_vacancy_irradiation_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_vacancy_irradiation_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_vacancy_irradiation_cascadeProb, & + source_vacancy_irradiation_cascadeVolume + + public :: & + source_vacancy_irradiation_init, & + source_vacancy_irradiation_deltaState, & + source_vacancy_irradiation_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_irradiation_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_vacancy_irradiation_label, & + SOURCE_vacancy_irradiation_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_irradiation_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_vacancy_irradiation_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_vacancy_irradiation_offset(material_Nphase), source=0_pInt) + allocate(source_vacancy_irradiation_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_vacancy_irradiation_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_irradiation_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_vacancy_irradiation_ID) & + source_vacancy_irradiation_offset(phase) = source + enddo + enddo + + allocate(source_vacancy_irradiation_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_vacancy_irradiation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_vacancy_irradiation_output(maxval(phase_Noutput),maxNinstance)) + source_vacancy_irradiation_output = '' + allocate(source_vacancy_irradiation_Noutput(maxNinstance), source=0_pInt) + allocate(source_vacancy_irradiation_cascadeProb(maxNinstance), source=0.0_pReal) + allocate(source_vacancy_irradiation_cascadeVolume(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_vacancy_irradiation_instance(phase) ! which instance of my vacancy is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('irradiation_cascadeprobability') + source_vacancy_irradiation_cascadeProb(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('irradiation_cascadevolume') + source_vacancy_irradiation_cascadeVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_vacancy_irradiation_instance(phase) + sourceOffset = source_vacancy_irradiation_offset(phase) + + sizeDotState = 2_pInt + sizeDeltaState = 2_pInt + sizeState = 2_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_irradiation_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_vacancy_irradiation_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_irradiation_deltaState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, constituent, sourceOffset + real(pReal) :: & + randNo + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_vacancy_irradiation_offset(phase) + + call random_number(randNo) + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + randNo - sourceState(phase)%p(sourceOffset)%state(1,constituent) + call random_number(randNo) + sourceState(phase)%p(sourceOffset)%deltaState(2,constituent) = & + randNo - sourceState(phase)%p(sourceOffset)%state(2,constituent) + +end subroutine source_vacancy_irradiation_deltaState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_irradiation_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + CvDot, dCvDot_dCv + integer(pInt) :: & + instance, phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_vacancy_irradiation_instance(phase) + sourceOffset = source_vacancy_irradiation_offset(phase) + + CvDot = 0.0_pReal + dCvDot_dCv = 0.0_pReal + if (sourceState(phase)%p(sourceOffset)%state0(1,constituent) < source_vacancy_irradiation_cascadeProb(instance)) & + CvDot = sourceState(phase)%p(sourceOffset)%state0(2,constituent)*source_vacancy_irradiation_cascadeVolume(instance) + +end subroutine source_vacancy_irradiation_getRateAndItsTangent + +end module source_vacancy_irradiation diff --git a/code/source/source_vacancy_phenoplasticity.f90 b/code/source/source_vacancy_phenoplasticity.f90 new file mode 100644 index 000000000..f9e766b2c --- /dev/null +++ b/code/source/source_vacancy_phenoplasticity.f90 @@ -0,0 +1,215 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for vacancy generation due to plasticity +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_vacancy_phenoplasticity + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_vacancy_phenoplasticity_sizePostResults, & !< cumulative size of post results + source_vacancy_phenoplasticity_offset, & !< which source is my current damage mechanism? + source_vacancy_phenoplasticity_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_vacancy_phenoplasticity_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_vacancy_phenoplasticity_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_vacancy_phenoplasticity_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_vacancy_phenoplasticity_rateCoeff + + public :: & + source_vacancy_phenoplasticity_init, & + source_vacancy_phenoplasticity_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_phenoplasticity_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_vacancy_phenoplasticity_label, & + SOURCE_vacancy_phenoplasticity_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_phenoplasticity_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_vacancy_phenoplasticity_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_vacancy_phenoplasticity_offset(material_Nphase), source=0_pInt) + allocate(source_vacancy_phenoplasticity_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_vacancy_phenoplasticity_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_phenoplasticity_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_vacancy_phenoplasticity_ID) & + source_vacancy_phenoplasticity_offset(phase) = source + enddo + enddo + + allocate(source_vacancy_phenoplasticity_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_vacancy_phenoplasticity_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_vacancy_phenoplasticity_output(maxval(phase_Noutput),maxNinstance)) + source_vacancy_phenoplasticity_output = '' + allocate(source_vacancy_phenoplasticity_Noutput(maxNinstance), source=0_pInt) + allocate(source_vacancy_phenoplasticity_rateCoeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_vacancy_phenoplasticity_instance(phase) ! which instance of my vacancy is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('phenoplasticity_ratecoeff') + source_vacancy_phenoplasticity_rateCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_vacancy_phenoplasticity_instance(phase) + sourceOffset = source_vacancy_phenoplasticity_offset(phase) + + sizeDotState = 0_pInt + sizeDeltaState = 0_pInt + sizeState = 0_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_phenoplasticity_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_vacancy_phenoplasticity_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_phenoplasticity_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + plasticState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + CvDot, dCvDot_dCv + integer(pInt) :: & + instance, phase, constituent + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_vacancy_phenoplasticity_instance(phase) + + CvDot = & + source_vacancy_phenoplasticity_rateCoeff(instance)* & + sum(plasticState(phase)%slipRate(:,constituent)) + dCvDot_dCv = 0.0_pReal + +end subroutine source_vacancy_phenoplasticity_getRateAndItsTangent + +end module source_vacancy_phenoplasticity diff --git a/code/source/source_vacancy_thermalfluc.f90 b/code/source/source_vacancy_thermalfluc.f90 new file mode 100644 index 000000000..c86406430 --- /dev/null +++ b/code/source/source_vacancy_thermalfluc.f90 @@ -0,0 +1,255 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for vacancy generation due to thermal fluctuations +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_vacancy_thermalfluc + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_vacancy_thermalfluc_sizePostResults, & !< cumulative size of post results + source_vacancy_thermalfluc_offset, & !< which source is my current damage mechanism? + source_vacancy_thermalfluc_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_vacancy_thermalfluc_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_vacancy_thermalfluc_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_vacancy_thermalfluc_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_vacancy_thermalfluc_amplitude, & + source_vacancy_thermalfluc_normVacancyEnergy + + public :: & + source_vacancy_thermalfluc_init, & + source_vacancy_thermalfluc_deltaState, & + source_vacancy_thermalfluc_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_thermalfluc_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use lattice, only: & + lattice_vacancyFormationEnergy + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_vacancy_thermalfluc_label, & + SOURCE_vacancy_thermalfluc_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_thermalfluc_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_vacancy_thermalfluc_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_vacancy_thermalfluc_offset(material_Nphase), source=0_pInt) + allocate(source_vacancy_thermalfluc_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_vacancy_thermalfluc_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_thermalfluc_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_vacancy_thermalfluc_ID) & + source_vacancy_thermalfluc_offset(phase) = source + enddo + enddo + + allocate(source_vacancy_thermalfluc_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_vacancy_thermalfluc_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_vacancy_thermalfluc_output(maxval(phase_Noutput),maxNinstance)) + source_vacancy_thermalfluc_output = '' + allocate(source_vacancy_thermalfluc_Noutput(maxNinstance), source=0_pInt) + allocate(source_vacancy_thermalfluc_amplitude(maxNinstance), source=0.0_pReal) + allocate(source_vacancy_thermalfluc_normVacancyEnergy(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_vacancy_thermalfluc_instance(phase) ! which instance of my vacancy is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('thermalfluctuation_amplitude') + source_vacancy_thermalfluc_amplitude(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_vacancy_thermalfluc_instance(phase) + source_vacancy_thermalfluc_normVacancyEnergy(instance) = & + lattice_vacancyFormationEnergy(phase)/1.3806488e-23_pReal + sourceOffset = source_vacancy_thermalfluc_offset(phase) + + sizeDotState = 1_pInt + sizeDeltaState = 1_pInt + sizeState = 1_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_thermalfluc_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_vacancy_thermalfluc_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_thermalfluc_deltaState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, constituent, sourceOffset + real(pReal) :: & + randNo + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_vacancy_thermalfluc_offset(phase) + + call random_number(randNo) + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + randNo - 0.5_pReal - sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_vacancy_thermalfluc_deltaState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_thermalfluc_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + material_homog, & + temperature, & + thermalMapping, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + CvDot, dCvDot_dCv + integer(pInt) :: & + instance, phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_vacancy_thermalfluc_instance(phase) + sourceOffset = source_vacancy_thermalfluc_offset(phase) + + CvDot = source_vacancy_thermalfluc_amplitude(instance)* & + sourceState(phase)%p(sourceOffset)%state0(2,constituent)* & + exp(-source_vacancy_thermalfluc_normVacancyEnergy(instance)/ & + temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))) + dCvDot_dCv = 0.0_pReal + +end subroutine source_vacancy_thermalfluc_getRateAndItsTangent + +end module source_vacancy_thermalfluc diff --git a/lib/damask/core.so b/lib/damask/core.so deleted file mode 100755 index 7f744dafa08ce566942c429233d709e85fbcf11b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2117501 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 z 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%0D*Ti17!eSW|(;6 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 >0c>OoqEI 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

0em~kYd-wU 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
*QxiQ}XqIc;G9102 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

=mW!IC#?9NETN@Tv_Pq7 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 R!AmMCFb9ppiT2~e{{eB6CcXdw From eae0c3c2a4e49a8156e69c591310562a76262cae Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 24 Feb 2016 16:25:57 -0500 Subject: [PATCH 006/183] use subdirectory to streamline CMake build system. --- CMakeLists.txt | 18 +- code/CMakeLists.txt | 8 +- code/damage/CMakeLists.txt | 5 + code/damage_local.f90 | 327 -- code/damage_none.f90 | 60 - code/damage_nonlocal.f90 | 380 --- code/homogenization.f90 | 1396 -------- code/homogenization/CMakeLists.txt | 5 + code/homogenization_RGC.f90 | 1558 --------- code/homogenization_isostrain.f90 | 317 -- code/homogenization_none.f90 | 60 - code/hydrogenflux/CMakeLists.txt | 5 + code/hydrogenflux_cahnhilliard.f90 | 513 --- code/hydrogenflux_isoconc.f90 | 63 - code/kinematics/CMakeLists.txt | 5 + code/kinematics_cleavage_opening.f90 | 303 -- code/kinematics_hydrogen_strain.f90 | 264 -- code/kinematics_slipplane_opening.f90 | 323 -- code/kinematics_thermal_expansion.f90 | 228 -- code/kinematics_vacancy_strain.f90 | 265 -- code/plastic/CMakeLists.txt | 7 +- code/plastic_disloUCLA.f90 | 2116 ------------ code/plastic_dislotwin.f90 | 2542 -------------- code/plastic_isotropic.f90 | 678 ---- code/plastic_j2.f90 | 579 ---- code/plastic_none.f90 | 109 - code/plastic_nonlocal.f90 | 4031 ----------------------- code/plastic_phenoplus.f90 | 1419 -------- code/plastic_phenopowerlaw.f90 | 1226 ------- code/plastic_titanmod.f90 | 1913 ----------- code/porosity/CMakeLists.txt | 5 + code/porosity_none.f90 | 61 - code/porosity_phasefield.f90 | 450 --- code/source/CMakeLists.txt | 7 +- code/source_damage_anisoBrittle.f90 | 425 --- code/source_damage_anisoDuctile.f90 | 415 --- code/source_damage_isoBrittle.f90 | 383 --- code/source_damage_isoDuctile.f90 | 350 -- code/source_thermal_dissipation.f90 | 220 -- code/source_thermal_externalheat.f90 | 277 -- code/source_vacancy_irradiation.f90 | 253 -- code/source_vacancy_phenoplasticity.f90 | 215 -- code/source_vacancy_thermalfluc.f90 | 255 -- code/spectral/CMakeLists.txt | 7 +- code/spectral_damage.f90 | 414 --- code/spectral_interface.f90 | 568 ---- code/spectral_mech_AL.f90 | 715 ---- code/spectral_mech_Basic.f90 | 569 ---- code/spectral_mech_Polarisation.f90 | 712 ---- code/spectral_thermal.f90 | 419 --- code/spectral_utilities.f90 | 1262 ------- code/thermal/CMakeLists.txt | 5 + code/thermal_adiabatic.f90 | 422 --- code/thermal_conduction.f90 | 444 --- code/thermal_isothermal.f90 | 65 - code/vacancyflux/CMakeLists.txt | 5 + code/vacancyflux_cahnhilliard.f90 | 606 ---- code/vacancyflux_isochempot.f90 | 329 -- code/vacancyflux_isoconc.f90 | 63 - 59 files changed, 74 insertions(+), 30570 deletions(-) delete mode 100644 code/damage_local.f90 delete mode 100644 code/damage_none.f90 delete mode 100644 code/damage_nonlocal.f90 delete mode 100644 code/homogenization.f90 delete mode 100644 code/homogenization_RGC.f90 delete mode 100644 code/homogenization_isostrain.f90 delete mode 100644 code/homogenization_none.f90 delete mode 100644 code/hydrogenflux_cahnhilliard.f90 delete mode 100644 code/hydrogenflux_isoconc.f90 delete mode 100644 code/kinematics_cleavage_opening.f90 delete mode 100644 code/kinematics_hydrogen_strain.f90 delete mode 100644 code/kinematics_slipplane_opening.f90 delete mode 100644 code/kinematics_thermal_expansion.f90 delete mode 100644 code/kinematics_vacancy_strain.f90 delete mode 100644 code/plastic_disloUCLA.f90 delete mode 100644 code/plastic_dislotwin.f90 delete mode 100644 code/plastic_isotropic.f90 delete mode 100644 code/plastic_j2.f90 delete mode 100644 code/plastic_none.f90 delete mode 100644 code/plastic_nonlocal.f90 delete mode 100644 code/plastic_phenoplus.f90 delete mode 100644 code/plastic_phenopowerlaw.f90 delete mode 100644 code/plastic_titanmod.f90 delete mode 100644 code/porosity_none.f90 delete mode 100644 code/porosity_phasefield.f90 delete mode 100644 code/source_damage_anisoBrittle.f90 delete mode 100644 code/source_damage_anisoDuctile.f90 delete mode 100644 code/source_damage_isoBrittle.f90 delete mode 100644 code/source_damage_isoDuctile.f90 delete mode 100644 code/source_thermal_dissipation.f90 delete mode 100644 code/source_thermal_externalheat.f90 delete mode 100644 code/source_vacancy_irradiation.f90 delete mode 100644 code/source_vacancy_phenoplasticity.f90 delete mode 100644 code/source_vacancy_thermalfluc.f90 delete mode 100644 code/spectral_damage.f90 delete mode 100644 code/spectral_interface.f90 delete mode 100644 code/spectral_mech_AL.f90 delete mode 100644 code/spectral_mech_Basic.f90 delete mode 100644 code/spectral_mech_Polarisation.f90 delete mode 100644 code/spectral_thermal.f90 delete mode 100644 code/spectral_utilities.f90 delete mode 100644 code/thermal_adiabatic.f90 delete mode 100644 code/thermal_conduction.f90 delete mode 100644 code/thermal_isothermal.f90 delete mode 100644 code/vacancyflux_cahnhilliard.f90 delete mode 100644 code/vacancyflux_isochempot.f90 delete mode 100644 code/vacancyflux_isoconc.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a2af196d..2b9eba77b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -# Initial attempt of using CMake to build the spectral solver -# --> CMake should be able to take care of the dependence by itself. +# INITIAL ATTEMPT OF USING CMAKE TO BUILD THE SPECTRAL SOLVER +# CMAKE SHOULD BE ABLE TO TAKE CARE OF THE DEPENDENCE BY ITSELF. # cmake_minimum_required (VERSION 3.1.0) project (DAMASKSpectral Fortran) @@ -52,5 +52,15 @@ else (Fortran_COMPILER_NAME MATCHES "gfortran.*") endif (Fortran_COMPILER_NAME MATCHES "gfortran.*") -# add code(source) directory -add_subdirectory(code) \ No newline at end of file +# ADD CODE(SOURCE) DIRECTORY +add_subdirectory(code) + + +# ADD TESTING CASES +add_test (SmokeTestRun + DAMASK_spectral.exe -g test/test1.geom -l test/test.load) + + +# Enable Dashboard scripting +# include (CTest) +# set (CTEST_PROJECT_NAME "DAMASK") diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 742d7e146..9c9688490 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -25,6 +25,11 @@ foreach (p ${SRC}) add_library (${p} MODULE "${p}.f90") endforeach (p) +# set libraries/modules for linking +foreach (p ${SRC}) + set (AUX_LIB ${AUX_LIB} ${p}) +endforeach (p) + # compile each sub moudel add_subdirectory(damage) add_subdirectory(homogenization) @@ -37,5 +42,6 @@ add_subdirectory(spectral) add_subdirectory(thermal) add_subdirectory(vacancyflux) -# compile spectral solver +# compile spectral solver add_executable(DAMASKSpectral.exe DAMASK_spectral.f90) +target_link_libraries (DAMASKSpectral.exe ${AUX_LIB}) \ No newline at end of file diff --git a/code/damage/CMakeLists.txt b/code/damage/CMakeLists.txt index 483baba57..ef6c768bd 100644 --- a/code/damage/CMakeLists.txt +++ b/code/damage/CMakeLists.txt @@ -8,3 +8,8 @@ set (DAMAGE "damage_none" foreach (p ${DAMAGE}) add_library (${p} MODULE "${p}.f90") endforeach (p) + +# set libraries for linking +foreach (p ${DAMAGE}) + set (AUX_LIB ${AUX_LIB} ${P}) +endforeach (p) \ No newline at end of file diff --git a/code/damage_local.f90 b/code/damage_local.f90 deleted file mode 100644 index 196382c13..000000000 --- a/code/damage_local.f90 +++ /dev/null @@ -1,327 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for locally evolving damage field -!-------------------------------------------------------------------------------------------------- -module damage_local - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - damage_local_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - damage_local_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - damage_local_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - damage_local_Noutput !< number of outputs per instance of this damage - - enum, bind(c) - enumerator :: undefined_ID, & - damage_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - damage_local_outputID !< ID of each post result output - - public :: & - damage_local_init, & - damage_local_updateState, & - damage_local_postResults - private :: & - damage_local_getSourceAndItsTangent - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine damage_local_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - damage_type, & - damage_typeInstance, & - homogenization_Noutput, & - DAMAGE_local_label, & - DAMAGE_local_ID, & - material_homog, & - mappingHomogenization, & - damageState, & - damageMapping, & - damage, & - damage_initialPhi, & - material_partHomogenization - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,homog,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_local_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(damage_type == DAMAGE_local_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(damage_local_sizePostResults(maxNinstance), source=0_pInt) - allocate(damage_local_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(damage_local_output (maxval(homogenization_Noutput),maxNinstance)) - damage_local_output = '' - allocate(damage_local_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(damage_local_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - homog = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - homog = homog + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (homog > 0_pInt ) then; if (damage_type(homog) == DAMAGE_local_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = damage_typeInstance(homog) ! which instance of my damage is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('damage') - damage_local_Noutput(instance) = damage_local_Noutput(instance) + 1_pInt - damage_local_outputID(damage_local_Noutput(instance),instance) = damage_ID - damage_local_output(damage_local_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingFile - - initializeInstances: do homog = 1_pInt, size(damage_type) - - myhomog: if (damage_type(homog) == DAMAGE_local_ID) then - NofMyHomog = count(material_homog == homog) - instance = damage_typeInstance(homog) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,damage_local_Noutput(instance) - select case(damage_local_outputID(o,instance)) - case(damage_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - damage_local_sizePostResult(o,instance) = mySize - damage_local_sizePostResults(instance) = damage_local_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 1_pInt - damageState(homog)%sizeState = sizeState - damageState(homog)%sizePostResults = damage_local_sizePostResults(instance) - allocate(damageState(homog)%state0 (sizeState,NofMyHomog), source=damage_initialPhi(homog)) - allocate(damageState(homog)%subState0(sizeState,NofMyHomog), source=damage_initialPhi(homog)) - allocate(damageState(homog)%state (sizeState,NofMyHomog), source=damage_initialPhi(homog)) - - nullify(damageMapping(homog)%p) - damageMapping(homog)%p => mappingHomogenization(1,:,:) - deallocate(damage(homog)%p) - damage(homog)%p => damageState(homog)%state(1,:) - - endif myhomog - enddo initializeInstances - - -end subroutine damage_local_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates local change in damage field -!-------------------------------------------------------------------------------------------------- -function damage_local_updateState(subdt, ip, el) - use numerics, only: & - residualStiffness, & - err_damage_tolAbs, & - err_damage_tolRel - use material, only: & - mappingHomogenization, & - damageState - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - subdt - logical, dimension(2) :: & - damage_local_updateState - integer(pInt) :: & - homog, & - offset - real(pReal) :: & - phi, phiDot, dPhiDot_dPhi - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - phi = damageState(homog)%subState0(1,offset) - call damage_local_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) - phi = max(residualStiffness,min(1.0_pReal,phi + subdt*phiDot)) - - damage_local_updateState = [ abs(phi - damageState(homog)%state(1,offset)) & - <= err_damage_tolAbs & - .or. abs(phi - damageState(homog)%state(1,offset)) & - <= err_damage_tolRel*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) - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - phase_source, & - phase_Nsources, & - SOURCE_damage_isoBrittle_ID, & - SOURCE_damage_isoDuctile_ID, & - SOURCE_damage_anisoBrittle_ID, & - SOURCE_damage_anisoDuctile_ID - use source_damage_isoBrittle, only: & - source_damage_isobrittle_getRateAndItsTangent - use source_damage_isoDuctile, only: & - source_damage_isoductile_getRateAndItsTangent - use source_damage_anisoBrittle, only: & - source_damage_anisobrittle_getRateAndItsTangent - use source_damage_anisoDuctile, only: & - source_damage_anisoductile_getRateAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - integer(pInt) :: & - phase, & - grain, & - source - real(pReal) :: & - phiDot, dPhiDot_dPhi, localphiDot, dLocalphiDot_dPhi - - phiDot = 0.0_pReal - dPhiDot_dPhi = 0.0_pReal - do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) - phase = phaseAt(grain,ip,el) - do source = 1, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_damage_isoBrittle_ID) - call source_damage_isobrittle_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_isoDuctile_ID) - call source_damage_isoductile_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_anisoBrittle_ID) - call source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_anisoDuctile_ID) - call source_damage_anisoductile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case default - localphiDot = 0.0_pReal - dLocalphiDot_dPhi = 0.0_pReal - - end select - phiDot = phiDot + localphiDot - dPhiDot_dPhi = dPhiDot_dPhi + dLocalphiDot_dPhi - enddo - enddo - - phiDot = phiDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - dPhiDot_dPhi = dPhiDot_dPhi/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - -end subroutine damage_local_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of damage results -!-------------------------------------------------------------------------------------------------- -function damage_local_postResults(ip,el) - use material, only: & - mappingHomogenization, & - damage_typeInstance, & - damageMapping, & - damage - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(damage_local_sizePostResults(damage_typeInstance(mappingHomogenization(2,ip,el)))) :: & - damage_local_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = damageMapping(homog)%p(ip,el) - instance = damage_typeInstance(homog) - - c = 0_pInt - damage_local_postResults = 0.0_pReal - - do o = 1_pInt,damage_local_Noutput(instance) - select case(damage_local_outputID(o,instance)) - - case (damage_ID) - damage_local_postResults(c+1_pInt) = damage(homog)%p(offset) - c = c + 1 - end select - enddo -end function damage_local_postResults - -end module damage_local diff --git a/code/damage_none.f90 b/code/damage_none.f90 deleted file mode 100644 index 956ba5cc8..000000000 --- a/code/damage_none.f90 +++ /dev/null @@ -1,60 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for constant damage field -!-------------------------------------------------------------------------------------------------- -module damage_none - - implicit none - private - - public :: & - damage_none_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine damage_none_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_none_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (damage_type(homog) == DAMAGE_none_ID) then - NofMyHomog = count(material_homog == homog) - damageState(homog)%sizeState = 0_pInt - damageState(homog)%sizePostResults = 0_pInt - allocate(damageState(homog)%state0 (0_pInt,NofMyHomog)) - allocate(damageState(homog)%subState0(0_pInt,NofMyHomog)) - allocate(damageState(homog)%state (0_pInt,NofMyHomog)) - - deallocate(damage(homog)%p) - allocate (damage(homog)%p(1), source=damage_initialPhi(homog)) - - endif myhomog - enddo initializeInstances - - -end subroutine damage_none_init - -end module damage_none diff --git a/code/damage_nonlocal.f90 b/code/damage_nonlocal.f90 deleted file mode 100644 index 311570781..000000000 --- a/code/damage_nonlocal.f90 +++ /dev/null @@ -1,380 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for non-locally evolving damage field -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module damage_nonlocal - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - damage_nonlocal_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - damage_nonlocal_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - damage_nonlocal_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - damage_nonlocal_Noutput !< number of outputs per instance of this damage - - enum, bind(c) - enumerator :: undefined_ID, & - damage_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - damage_nonlocal_outputID !< ID of each post result output - - - public :: & - damage_nonlocal_init, & - damage_nonlocal_getSourceAndItsTangent, & - damage_nonlocal_getDiffusion33, & - damage_nonlocal_getMobility, & - damage_nonlocal_putNonLocalDamage, & - damage_nonlocal_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine damage_nonlocal_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - damage_type, & - damage_typeInstance, & - homogenization_Noutput, & - DAMAGE_nonlocal_label, & - DAMAGE_nonlocal_ID, & - material_homog, & - mappingHomogenization, & - damageState, & - damageMapping, & - damage, & - damage_initialPhi, & - material_partHomogenization - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_nonlocal_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(damage_type == DAMAGE_nonlocal_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(damage_nonlocal_sizePostResults(maxNinstance), source=0_pInt) - allocate(damage_nonlocal_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(damage_nonlocal_output (maxval(homogenization_Noutput),maxNinstance)) - damage_nonlocal_output = '' - allocate(damage_nonlocal_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(damage_nonlocal_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (damage_type(section) == DAMAGE_nonlocal_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = damage_typeInstance(section) ! which instance of my damage is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('damage') - damage_nonlocal_Noutput(instance) = damage_nonlocal_Noutput(instance) + 1_pInt - damage_nonlocal_outputID(damage_nonlocal_Noutput(instance),instance) = damage_ID - damage_nonlocal_output(damage_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingFile - - initializeInstances: do section = 1_pInt, size(damage_type) - if (damage_type(section) == DAMAGE_nonlocal_ID) then - NofMyHomog=count(material_homog==section) - instance = damage_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,damage_nonlocal_Noutput(instance) - select case(damage_nonlocal_outputID(o,instance)) - case(damage_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - damage_nonlocal_sizePostResult(o,instance) = mySize - damage_nonlocal_sizePostResults(instance) = damage_nonlocal_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 0_pInt - damageState(section)%sizeState = sizeState - damageState(section)%sizePostResults = damage_nonlocal_sizePostResults(instance) - allocate(damageState(section)%state0 (sizeState,NofMyHomog)) - allocate(damageState(section)%subState0(sizeState,NofMyHomog)) - allocate(damageState(section)%state (sizeState,NofMyHomog)) - - nullify(damageMapping(section)%p) - damageMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(damage(section)%p) - allocate(damage(section)%p(NofMyHomog), source=damage_initialPhi(section)) - - endif - - enddo initializeInstances -end subroutine damage_nonlocal_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates homogenized damage driving forces -!-------------------------------------------------------------------------------------------------- -subroutine damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - phase_source, & - phase_Nsources, & - SOURCE_damage_isoBrittle_ID, & - SOURCE_damage_isoDuctile_ID, & - SOURCE_damage_anisoBrittle_ID, & - SOURCE_damage_anisoDuctile_ID - use source_damage_isoBrittle, only: & - source_damage_isobrittle_getRateAndItsTangent - use source_damage_isoDuctile, only: & - source_damage_isoductile_getRateAndItsTangent - use source_damage_anisoBrittle, only: & - source_damage_anisobrittle_getRateAndItsTangent - use source_damage_anisoDuctile, only: & - source_damage_anisoductile_getRateAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - integer(pInt) :: & - phase, & - grain, & - source - real(pReal) :: & - phiDot, dPhiDot_dPhi, localphiDot, dLocalphiDot_dPhi - - phiDot = 0.0_pReal - dPhiDot_dPhi = 0.0_pReal - do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) - phase = phaseAt(grain,ip,el) - do source = 1_pInt, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_damage_isoBrittle_ID) - call source_damage_isobrittle_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_isoDuctile_ID) - call source_damage_isoductile_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_anisoBrittle_ID) - call source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_anisoDuctile_ID) - call source_damage_anisoductile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case default - localphiDot = 0.0_pReal - dLocalphiDot_dPhi = 0.0_pReal - - end select - phiDot = phiDot + localphiDot - dPhiDot_dPhi = dPhiDot_dPhi + dLocalphiDot_dPhi - enddo - enddo - - phiDot = phiDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - dPhiDot_dPhi = dPhiDot_dPhi/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - -end subroutine damage_nonlocal_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized non local damage diffusion tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function damage_nonlocal_getDiffusion33(ip,el) - use numerics, only: & - charLength - use lattice, only: & - lattice_DamageDiffusion33 - use material, only: & - homogenization_Ngrains, & - material_phase, & - mappingHomogenization - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - damage_nonlocal_getDiffusion33 - integer(pInt) :: & - homog, & - grain - - homog = mappingHomogenization(2,ip,el) - damage_nonlocal_getDiffusion33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(homog) - damage_nonlocal_getDiffusion33 = damage_nonlocal_getDiffusion33 + & - crystallite_push33ToRef(grain,ip,el,lattice_DamageDiffusion33(1:3,1:3,material_phase(grain,ip,el))) - enddo - - damage_nonlocal_getDiffusion33 = & - charLength*charLength* & - damage_nonlocal_getDiffusion33/ & - homogenization_Ngrains(homog) - -end function damage_nonlocal_getDiffusion33 - -!-------------------------------------------------------------------------------------------------- -!> @brief Returns homogenized nonlocal damage mobility -!-------------------------------------------------------------------------------------------------- -real(pReal) function damage_nonlocal_getMobility(ip,el) - use mesh, only: & - mesh_element - use lattice, only: & - lattice_damageMobility - use material, only: & - material_phase, & - homogenization_Ngrains - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - integer(pInt) :: & - ipc - - damage_nonlocal_getMobility = 0.0_pReal - - do ipc = 1, homogenization_Ngrains(mesh_element(3,el)) - damage_nonlocal_getMobility = damage_nonlocal_getMobility + lattice_DamageMobility(material_phase(ipc,ip,el)) - enddo - - damage_nonlocal_getMobility = damage_nonlocal_getMobility /homogenization_Ngrains(mesh_element(3,el)) - -end function damage_nonlocal_getMobility - -!-------------------------------------------------------------------------------------------------- -!> @brief updated nonlocal damage field with solution from damage phase field PDE -!-------------------------------------------------------------------------------------------------- -subroutine damage_nonlocal_putNonLocalDamage(phi,ip,el) - use material, only: & - material_homog, & - damageMapping, & - damage - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - integer(pInt) :: & - homog, & - offset - - homog = material_homog(ip,el) - offset = damageMapping(homog)%p(ip,el) - damage(homog)%p(offset) = phi - -end subroutine damage_nonlocal_putNonLocalDamage - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of damage results -!-------------------------------------------------------------------------------------------------- -function damage_nonlocal_postResults(ip,el) - use material, only: & - mappingHomogenization, & - damage_typeInstance, & - damage - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(damage_nonlocal_sizePostResults(damage_typeInstance(mappingHomogenization(2,ip,el)))) :: & - damage_nonlocal_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - instance = damage_typeInstance(homog) - - c = 0_pInt - damage_nonlocal_postResults = 0.0_pReal - - do o = 1_pInt,damage_nonlocal_Noutput(instance) - select case(damage_nonlocal_outputID(o,instance)) - - case (damage_ID) - damage_nonlocal_postResults(c+1_pInt) = damage(homog)%p(offset) - c = c + 1 - end select - enddo -end function damage_nonlocal_postResults - -end module damage_nonlocal diff --git a/code/homogenization.f90 b/code/homogenization.f90 deleted file mode 100644 index 00186ff06..000000000 --- a/code/homogenization.f90 +++ /dev/null @@ -1,1396 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Denny Tjahjanto, Max-Planck-Institut für Eisenforschung GmbH -!> @brief homogenization manager, organizing deformation partitioning and stress homogenization -!-------------------------------------------------------------------------------------------------- -module homogenization - use prec, only: & -#ifdef FEM - tOutputData, & -#endif - pInt, & - pReal - -!-------------------------------------------------------------------------------------------------- -! General variables for the homogenization at a material point - implicit none - private - real(pReal), dimension(:,:,:,:), allocatable, public :: & - materialpoint_F0, & !< def grad of IP at start of FE increment - materialpoint_F, & !< def grad of IP to be reached at end of FE increment - materialpoint_P !< first P--K stress of IP - real(pReal), dimension(:,:,:,:,:,:), allocatable, public :: & - materialpoint_dPdF !< tangent of first P--K stress at IP -#ifdef FEM - type(tOutputData), dimension(:), allocatable, public :: & - homogOutput - type(tOutputData), dimension(:,:), allocatable, public :: & - crystalliteOutput, & - phaseOutput -#else - real(pReal), dimension(:,:,:), allocatable, public :: & - materialpoint_results !< results array of material point -#endif - integer(pInt), public, protected :: & - materialpoint_sizeResults, & - homogenization_maxSizePostResults, & - thermal_maxSizePostResults, & - damage_maxSizePostResults, & - vacancyflux_maxSizePostResults, & - porosity_maxSizePostResults, & - hydrogenflux_maxSizePostResults - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - materialpoint_subF0, & !< def grad of IP at beginning of homogenization increment - materialpoint_subF !< def grad of IP to be reached at end of homog inc - real(pReal), dimension(:,:), allocatable, private :: & - materialpoint_subFrac, & - materialpoint_subStep, & - materialpoint_subdt - logical, dimension(:,:), allocatable, private :: & - materialpoint_requested, & - materialpoint_converged - logical, dimension(:,:,:), allocatable, private :: & - materialpoint_doneAndHappy - - public :: & - homogenization_init, & - materialpoint_stressAndItsTangent, & - materialpoint_postResults - private :: & - homogenization_partitionDeformation, & - homogenization_updateState, & - homogenization_averageStressAndItsTangent, & - homogenization_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_init -#ifdef HDF - use hdf5, only: & - HID_T - use IO, only : & - HDF5_mappingHomogenization -#endif - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use math, only: & - math_I3 - use debug, only: & - debug_level, & - debug_homogenization, & - debug_levelBasic, & - debug_e, & - debug_g - use mesh, only: & - mesh_maxNips, & - mesh_NcpElems, & - mesh_element, & - FE_Nips, & - FE_geomtype -#ifdef FEM - use crystallite, only: & - crystallite_sizePostResults -#else - use constitutive, only: & - constitutive_plasticity_maxSizePostResults, & - constitutive_source_maxSizePostResults - use crystallite, only: & - crystallite_maxSizePostResults -#endif - use material - use homogenization_none - use homogenization_isostrain - use homogenization_RGC - use thermal_isothermal - use thermal_adiabatic - use thermal_conduction - use damage_none - use damage_local - use damage_nonlocal - use vacancyflux_isoconc - use vacancyflux_isochempot - use vacancyflux_cahnhilliard - use porosity_none - use porosity_phasefield - use hydrogenflux_isoconc - use hydrogenflux_cahnhilliard - use IO - use numerics, only: & - worldrank - - implicit none - integer(pInt), parameter :: FILEUNIT = 200_pInt - integer(pInt) :: e,i,p - integer(pInt), dimension(:,:), pointer :: thisSize - integer(pInt), dimension(:) , pointer :: thisNoutput - character(len=64), dimension(:,:), pointer :: thisOutput - character(len=32) :: outputName !< name of output, intermediate fix until HDF5 output is ready - logical :: knownHomogenization, knownThermal, knownDamage, knownVacancyflux, knownPorosity, knownHydrogenflux -#ifdef HDF - integer(pInt), dimension(:,:), allocatable :: mapping - integer(pInt), dimension(:), allocatable :: InstancePosition - allocate(mapping(mesh_ncpelems,4),source=0_pInt) - allocate(InstancePosition(material_Nhomogenization),source=0_pInt) -#endif - - -!-------------------------------------------------------------------------------------------------- -! open material.config - if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... - call IO_open_file(FILEUNIT,material_configFile) ! ... open material.config file - -!-------------------------------------------------------------------------------------------------- -! parse homogenization from config file - if (any(homogenization_type == HOMOGENIZATION_NONE_ID)) & - call homogenization_none_init() - if (any(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID)) & - call homogenization_isostrain_init(FILEUNIT) - if (any(homogenization_type == HOMOGENIZATION_RGC_ID)) & - call homogenization_RGC_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse thermal from config file - call IO_checkAndRewind(FILEUNIT) - if (any(thermal_type == THERMAL_isothermal_ID)) & - call thermal_isothermal_init() - if (any(thermal_type == THERMAL_adiabatic_ID)) & - call thermal_adiabatic_init(FILEUNIT) - if (any(thermal_type == THERMAL_conduction_ID)) & - call thermal_conduction_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse damage from config file - call IO_checkAndRewind(FILEUNIT) - if (any(damage_type == DAMAGE_none_ID)) & - call damage_none_init() - if (any(damage_type == DAMAGE_local_ID)) & - call damage_local_init(FILEUNIT) - if (any(damage_type == DAMAGE_nonlocal_ID)) & - call damage_nonlocal_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse vacancy transport from config file - call IO_checkAndRewind(FILEUNIT) - if (any(vacancyflux_type == VACANCYFLUX_isoconc_ID)) & - call vacancyflux_isoconc_init() - if (any(vacancyflux_type == VACANCYFLUX_isochempot_ID)) & - call vacancyflux_isochempot_init(FILEUNIT) - if (any(vacancyflux_type == VACANCYFLUX_cahnhilliard_ID)) & - call vacancyflux_cahnhilliard_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse porosity from config file - call IO_checkAndRewind(FILEUNIT) - if (any(porosity_type == POROSITY_none_ID)) & - call porosity_none_init() - if (any(porosity_type == POROSITY_phasefield_ID)) & - call porosity_phasefield_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse hydrogen transport from config file - call IO_checkAndRewind(FILEUNIT) - if (any(hydrogenflux_type == HYDROGENFLUX_isoconc_ID)) & - call hydrogenflux_isoconc_init() - if (any(hydrogenflux_type == HYDROGENFLUX_cahnhilliard_ID)) & - call hydrogenflux_cahnhilliard_init(FILEUNIT) - close(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! write description file for homogenization output - mainProcess2: if (worldrank == 0) then - call IO_write_jobFile(FILEUNIT,'outputHomogenization') - do p = 1,material_Nhomogenization - if (any(material_homog == p)) then - i = homogenization_typeInstance(p) ! which instance of this homogenization type - knownHomogenization = .true. ! assume valid - select case(homogenization_type(p)) ! split per homogenization type - case (HOMOGENIZATION_NONE_ID) - outputName = HOMOGENIZATION_NONE_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (HOMOGENIZATION_ISOSTRAIN_ID) - outputName = HOMOGENIZATION_ISOSTRAIN_label - thisNoutput => homogenization_isostrain_Noutput - thisOutput => homogenization_isostrain_output - thisSize => homogenization_isostrain_sizePostResult - case (HOMOGENIZATION_RGC_ID) - outputName = HOMOGENIZATION_RGC_label - thisNoutput => homogenization_RGC_Noutput - thisOutput => homogenization_RGC_output - thisSize => homogenization_RGC_sizePostResult - case default - knownHomogenization = .false. - end select - write(FILEUNIT,'(/,a,/)') '['//trim(homogenization_name(p))//']' - if (knownHomogenization) then - write(FILEUNIT,'(a)') '(type)'//char(9)//trim(outputName) - write(FILEUNIT,'(a,i4)') '(ngrains)'//char(9),homogenization_Ngrains(p) - if (homogenization_type(p) /= HOMOGENIZATION_NONE_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - i = thermal_typeInstance(p) ! which instance of this thermal type - knownThermal = .true. ! assume valid - select case(thermal_type(p)) ! split per thermal type - case (THERMAL_isothermal_ID) - outputName = THERMAL_isothermal_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (THERMAL_adiabatic_ID) - outputName = THERMAL_adiabatic_label - thisNoutput => thermal_adiabatic_Noutput - thisOutput => thermal_adiabatic_output - thisSize => thermal_adiabatic_sizePostResult - case (THERMAL_conduction_ID) - outputName = THERMAL_conduction_label - thisNoutput => thermal_conduction_Noutput - thisOutput => thermal_conduction_output - thisSize => thermal_conduction_sizePostResult - case default - knownThermal = .false. - end select - if (knownThermal) then - write(FILEUNIT,'(a)') '(thermal)'//char(9)//trim(outputName) - if (thermal_type(p) /= THERMAL_isothermal_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - i = damage_typeInstance(p) ! which instance of this damage type - knownDamage = .true. ! assume valid - select case(damage_type(p)) ! split per damage type - case (DAMAGE_none_ID) - outputName = DAMAGE_none_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (DAMAGE_local_ID) - outputName = DAMAGE_local_label - thisNoutput => damage_local_Noutput - thisOutput => damage_local_output - thisSize => damage_local_sizePostResult - case (DAMAGE_nonlocal_ID) - outputName = DAMAGE_nonlocal_label - thisNoutput => damage_nonlocal_Noutput - thisOutput => damage_nonlocal_output - thisSize => damage_nonlocal_sizePostResult - case default - knownDamage = .false. - end select - if (knownDamage) then - write(FILEUNIT,'(a)') '(damage)'//char(9)//trim(outputName) - if (damage_type(p) /= DAMAGE_none_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - i = vacancyflux_typeInstance(p) ! which instance of this vacancy flux type - knownVacancyflux = .true. ! assume valid - select case(vacancyflux_type(p)) ! split per vacancy flux type - case (VACANCYFLUX_isoconc_ID) - outputName = VACANCYFLUX_isoconc_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (VACANCYFLUX_isochempot_ID) - outputName = VACANCYFLUX_isochempot_label - thisNoutput => vacancyflux_isochempot_Noutput - thisOutput => vacancyflux_isochempot_output - thisSize => vacancyflux_isochempot_sizePostResult - case (VACANCYFLUX_cahnhilliard_ID) - outputName = VACANCYFLUX_cahnhilliard_label - thisNoutput => vacancyflux_cahnhilliard_Noutput - thisOutput => vacancyflux_cahnhilliard_output - thisSize => vacancyflux_cahnhilliard_sizePostResult - case default - knownVacancyflux = .false. - end select - if (knownVacancyflux) then - write(FILEUNIT,'(a)') '(vacancyflux)'//char(9)//trim(outputName) - if (vacancyflux_type(p) /= VACANCYFLUX_isoconc_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - i = porosity_typeInstance(p) ! which instance of this porosity type - knownPorosity = .true. ! assume valid - select case(porosity_type(p)) ! split per porosity type - case (POROSITY_none_ID) - outputName = POROSITY_none_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (POROSITY_phasefield_ID) - outputName = POROSITY_phasefield_label - thisNoutput => porosity_phasefield_Noutput - thisOutput => porosity_phasefield_output - thisSize => porosity_phasefield_sizePostResult - case default - knownPorosity = .false. - end select - if (knownPorosity) then - write(FILEUNIT,'(a)') '(porosity)'//char(9)//trim(outputName) - if (porosity_type(p) /= POROSITY_none_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - i = hydrogenflux_typeInstance(p) ! which instance of this hydrogen flux type - knownHydrogenflux = .true. ! assume valid - select case(hydrogenflux_type(p)) ! split per hydrogen flux type - case (HYDROGENFLUX_isoconc_ID) - outputName = HYDROGENFLUX_isoconc_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (HYDROGENFLUX_cahnhilliard_ID) - outputName = HYDROGENFLUX_cahnhilliard_label - thisNoutput => hydrogenflux_cahnhilliard_Noutput - thisOutput => hydrogenflux_cahnhilliard_output - thisSize => hydrogenflux_cahnhilliard_sizePostResult - case default - knownHydrogenflux = .false. - end select - if (knownHydrogenflux) then - write(FILEUNIT,'(a)') '(hydrogenflux)'//char(9)//trim(outputName) - if (hydrogenflux_type(p) /= HYDROGENFLUX_isoconc_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - endif - enddo - close(FILEUNIT) - endif mainProcess2 - -!-------------------------------------------------------------------------------------------------- -! allocate and initialize global variables - allocate(materialpoint_dPdF(3,3,3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_F0(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - materialpoint_F0 = spread(spread(math_I3,3,mesh_maxNips),4,mesh_NcpElems) ! initialize to identity - allocate(materialpoint_F(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - materialpoint_F = materialpoint_F0 ! initialize to identity - allocate(materialpoint_subF0(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_subF(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_P(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_subFrac(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_subStep(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_subdt(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_requested(mesh_maxNips,mesh_NcpElems), source=.false.) - allocate(materialpoint_converged(mesh_maxNips,mesh_NcpElems), source=.true.) - allocate(materialpoint_doneAndHappy(2,mesh_maxNips,mesh_NcpElems), source=.true.) - -!-------------------------------------------------------------------------------------------------- -! allocate and initialize global state and postresutls variables -#ifdef HDF - elementLooping: do e = 1,mesh_NcpElems - myInstance = homogenization_typeInstance(mesh_element(3,e)) - IpLooping: do i = 1,FE_Nips(FE_geomtype(mesh_element(2,e))) - InstancePosition(myInstance) = InstancePosition(myInstance)+1_pInt - mapping(e,1:4) = [instancePosition(myinstance),myinstance,e,i] - enddo IpLooping - enddo elementLooping - call HDF5_mappingHomogenization(mapping) -#endif - - homogenization_maxSizePostResults = 0_pInt - thermal_maxSizePostResults = 0_pInt - damage_maxSizePostResults = 0_pInt - vacancyflux_maxSizePostResults = 0_pInt - porosity_maxSizePostResults = 0_pInt - hydrogenflux_maxSizePostResults = 0_pInt - do p = 1,material_Nhomogenization - homogenization_maxSizePostResults = max(homogenization_maxSizePostResults,homogState (p)%sizePostResults) - thermal_maxSizePostResults = max(thermal_maxSizePostResults, thermalState (p)%sizePostResults) - damage_maxSizePostResults = max(damage_maxSizePostResults ,damageState (p)%sizePostResults) - vacancyflux_maxSizePostResults = max(vacancyflux_maxSizePostResults ,vacancyfluxState (p)%sizePostResults) - porosity_maxSizePostResults = max(porosity_maxSizePostResults ,porosityState (p)%sizePostResults) - hydrogenflux_maxSizePostResults = max(hydrogenflux_maxSizePostResults ,hydrogenfluxState(p)%sizePostResults) - enddo - -#ifdef FEM - allocate(homogOutput (material_Nhomogenization )) - allocate(crystalliteOutput(material_Ncrystallite, homogenization_maxNgrains)) - allocate(phaseOutput (material_Nphase, homogenization_maxNgrains)) - do p = 1, material_Nhomogenization - homogOutput(p)%sizeResults = homogState (p)%sizePostResults + & - thermalState (p)%sizePostResults + & - damageState (p)%sizePostResults + & - vacancyfluxState (p)%sizePostResults + & - porosityState (p)%sizePostResults + & - hydrogenfluxState(p)%sizePostResults - homogOutput(p)%sizeIpCells = count(material_homog==p) - allocate(homogOutput(p)%output(homogOutput(p)%sizeResults,homogOutput(p)%sizeIpCells)) - enddo - do p = 1, material_Ncrystallite; do e = 1, homogenization_maxNgrains - crystalliteOutput(p,e)%sizeResults = crystallite_sizePostResults(p) - crystalliteOutput(p,e)%sizeIpCells = count(microstructure_crystallite(mesh_element(4,:)) == p .and. & - homogenization_Ngrains (mesh_element(3,:)) >= e)*mesh_maxNips - allocate(crystalliteOutput(p,e)%output(crystalliteOutput(p,e)%sizeResults,crystalliteOutput(p,e)%sizeIpCells)) - enddo; enddo - do p = 1, material_Nphase; do e = 1, homogenization_maxNgrains - phaseOutput(p,e)%sizeResults = plasticState (p)%sizePostResults + & - sum(sourceState (p)%p(:)%sizePostResults) - phaseOutput(p,e)%sizeIpCells = count(material_phase(e,:,:) == p) - allocate(phaseOutput(p,e)%output(phaseOutput(p,e)%sizeResults,phaseOutput(p,e)%sizeIpCells)) - enddo; enddo -#else - materialpoint_sizeResults = 1 & ! grain count - + 1 + homogenization_maxSizePostResults & ! homogSize & homogResult - + thermal_maxSizePostResults & - + damage_maxSizePostResults & - + vacancyflux_maxSizePostResults & - + porosity_maxSizePostResults & - + hydrogenflux_maxSizePostResults & - + homogenization_maxNgrains * (1 + crystallite_maxSizePostResults & ! crystallite size & crystallite results - + 1 + constitutive_plasticity_maxSizePostResults & ! constitutive size & constitutive results - + constitutive_source_maxSizePostResults) - allocate(materialpoint_results(materialpoint_sizeResults,mesh_maxNips,mesh_NcpElems)) -#endif - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- homogenization init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then -#ifdef TODO - write(6,'(a32,1x,7(i8,1x))') 'homogenization_state0: ', shape(homogenization_state0) - write(6,'(a32,1x,7(i8,1x))') 'homogenization_subState0: ', shape(homogenization_subState0) - write(6,'(a32,1x,7(i8,1x))') 'homogenization_state: ', shape(homogenization_state) -#endif - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_dPdF: ', shape(materialpoint_dPdF) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_F0: ', shape(materialpoint_F0) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_F: ', shape(materialpoint_F) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subF0: ', shape(materialpoint_subF0) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subF: ', shape(materialpoint_subF) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_P: ', shape(materialpoint_P) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subFrac: ', shape(materialpoint_subFrac) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subStep: ', shape(materialpoint_subStep) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subdt: ', shape(materialpoint_subdt) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_requested: ', shape(materialpoint_requested) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_converged: ', shape(materialpoint_converged) - write(6,'(a32,1x,7(i8,1x),/)') 'materialpoint_doneAndHappy: ', shape(materialpoint_doneAndHappy) -#ifndef FEM - write(6,'(a32,1x,7(i8,1x),/)') 'materialpoint_results: ', shape(materialpoint_results) -#endif - write(6,'(a32,1x,7(i8,1x))') 'maxSizePostResults: ', homogenization_maxSizePostResults - endif - flush(6) - - if (debug_g < 1 .or. debug_g > homogenization_Ngrains(mesh_element(3,debug_e))) & - call IO_error(602_pInt,ext_msg='component (grain)') - -end subroutine homogenization_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief parallelized calculation of stress and corresponding tangent at material points -!-------------------------------------------------------------------------------------------------- -subroutine materialpoint_stressAndItsTangent(updateJaco,dt) - use numerics, only: & - subStepMinHomog, & - subStepSizeHomog, & - stepIncreaseHomog, & - nHomog, & - nMPstate - use math, only: & - math_transpose33 - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP, & - terminallyIll - use mesh, only: & - mesh_element - use material, only: & - plasticState, & - sourceState, & - homogState, & - thermalState, & - damageState, & - vacancyfluxState, & - porosityState, & - hydrogenfluxState, & - phase_Nsources, & - mappingHomogenization, & - phaseAt, phasememberAt, & - homogenization_Ngrains - use crystallite, only: & - crystallite_F0, & - crystallite_Fp0, & - crystallite_Fp, & - crystallite_Fi0, & - crystallite_Fi, & - crystallite_Lp0, & - crystallite_Lp, & - crystallite_Li0, & - crystallite_Li, & - crystallite_dPdF, & - crystallite_dPdF0, & - crystallite_Tstar0_v, & - crystallite_Tstar_v, & - crystallite_partionedF0, & - crystallite_partionedF, & - crystallite_partionedFp0, & - crystallite_partionedLp0, & - crystallite_partionedFi0, & - crystallite_partionedLi0, & - crystallite_partioneddPdF0, & - crystallite_partionedTstar0_v, & - crystallite_dt, & - crystallite_requested, & - crystallite_converged, & - crystallite_stressAndItsTangent, & - crystallite_orientations - use debug, only: & - debug_level, & - debug_homogenization, & - debug_levelBasic, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_MaterialpointLoopDistribution, & - debug_MaterialpointStateLoopDistribution - - implicit none - real(pReal), intent(in) :: dt !< time increment - logical, intent(in) :: updateJaco !< initiating Jacobian update - integer(pInt) :: & - NiterationHomog, & - NiterationMPstate, & - g, & !< grain number - i, & !< integration point number - e, & !< element number - mySource, & - myNgrains - -!-------------------------------------------------------------------------------------------------- -! initialize to starting condition - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(/a,i5,1x,i2)') '<< HOMOG >> Material Point start at el ip ', debug_e, debug_i - - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< HOMOG >> F0', & - math_transpose33(materialpoint_F0(1:3,1:3,debug_i,debug_e)) - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< HOMOG >> F', & - math_transpose33(materialpoint_F(1:3,1:3,debug_i,debug_e)) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! initialize restoration points of ... - do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do g = 1,myNgrains - - plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) = & - plasticState (phaseAt(g,i,e))%state0( :,phasememberAt(g,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) - sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) = & - sourceState(phaseAt(g,i,e))%p(mySource)%state0( :,phasememberAt(g,i,e)) - enddo - - crystallite_partionedFp0(1:3,1:3,g,i,e) = crystallite_Fp0(1:3,1:3,g,i,e) ! ...plastic def grads - crystallite_partionedLp0(1:3,1:3,g,i,e) = crystallite_Lp0(1:3,1:3,g,i,e) ! ...plastic velocity grads - crystallite_partionedFi0(1:3,1:3,g,i,e) = crystallite_Fi0(1:3,1:3,g,i,e) ! ...intermediate def grads - crystallite_partionedLi0(1:3,1:3,g,i,e) = crystallite_Li0(1:3,1:3,g,i,e) ! ...intermediate velocity grads - crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,g,i,e) = crystallite_dPdF0(1:3,1:3,1:3,1:3,g,i,e) ! ...stiffness - crystallite_partionedF0(1:3,1:3,g,i,e) = crystallite_F0(1:3,1:3,g,i,e) ! ...def grads - crystallite_partionedTstar0_v(1:6,g,i,e) = crystallite_Tstar0_v(1:6,g,i,e) ! ...2nd PK stress - - enddo; enddo - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e)) - materialpoint_subF0(1:3,1:3,i,e) = materialpoint_F0(1:3,1:3,i,e) ! ...def grad - materialpoint_subFrac(i,e) = 0.0_pReal - materialpoint_subStep(i,e) = 1.0_pReal/subStepSizeHomog ! <> - materialpoint_converged(i,e) = .false. ! pretend failed step of twice the required size - materialpoint_requested(i,e) = .true. ! everybody requires calculation - endforall - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - homogState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal homogenization state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - thermalState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal thermal state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - damageState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal damage state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - vacancyfluxState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal vacancy transport state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - porosityState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal porosity state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - hydrogenfluxState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal hydrogen transport state - enddo - NiterationHomog = 0_pInt - - cutBackLooping: do while (.not. terminallyIll .and. & - any(materialpoint_subStep(:,FEsolving_execELem(1):FEsolving_execElem(2)) > subStepMinHomog)) - - !$OMP PARALLEL DO PRIVATE(myNgrains) - elementLooping1: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Ngrains(mesh_element(3,e)) - IpLooping1: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - - converged: if ( materialpoint_converged(i,e) ) then -#ifndef _OPENMP - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i) & - .or. .not. iand(debug_level(debug_homogenization),debug_levelSelective) /= 0_pInt)) then - write(6,'(a,1x,f12.8,1x,a,1x,f12.8,1x,a,i8,1x,i2/)') '<< HOMOG >> winding forward from', & - materialpoint_subFrac(i,e), 'to current materialpoint_subFrac', & - materialpoint_subFrac(i,e)+materialpoint_subStep(i,e),'in materialpoint_stressAndItsTangent at el ip',e,i - endif -#endif - -!--------------------------------------------------------------------------------------------------- -! calculate new subStep and new subFrac - materialpoint_subFrac(i,e) = materialpoint_subFrac(i,e) + materialpoint_subStep(i,e) - !$OMP FLUSH(materialpoint_subFrac) - materialpoint_subStep(i,e) = min(1.0_pReal-materialpoint_subFrac(i,e), & - stepIncreaseHomog*materialpoint_subStep(i,e)) ! introduce flexibility for step increase/acceleration - !$OMP FLUSH(materialpoint_subStep) - - steppingNeeded: if (materialpoint_subStep(i,e) > subStepMinHomog) then - - ! wind forward grain starting point of... - crystallite_partionedF0(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedF(1:3,1:3,1:myNgrains,i,e) ! ...def grads - - crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) = & - crystallite_Fp(1:3,1:3,1:myNgrains,i,e) ! ...plastic def grads - - crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) = & - crystallite_Lp(1:3,1:3,1:myNgrains,i,e) ! ...plastic velocity grads - - crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) = & - crystallite_Fi(1:3,1:3,1:myNgrains,i,e) ! ...intermediate def grads - - crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) = & - crystallite_Li(1:3,1:3,1:myNgrains,i,e) ! ...intermediate velocity grads - - crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,1:myNgrains,i,e) = & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:myNgrains,i,e) ! ...stiffness - - crystallite_partionedTstar0_v(1:6,1:myNgrains,i,e) = & - crystallite_Tstar_v(1:6,1:myNgrains,i,e) ! ...2nd PK stress - - do g = 1,myNgrains - plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) = & - plasticState (phaseAt(g,i,e))%state( :,phasememberAt(g,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) - sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) = & - sourceState(phaseAt(g,i,e))%p(mySource)%state( :,phasememberAt(g,i,e)) - enddo - enddo - - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - homogState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal homogenization state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - thermalState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal thermal state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - damageState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal damage state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - vacancyfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal vacancy transport state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - porosityState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal porosity state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - hydrogenfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal hydrogen transport state - materialpoint_subF0(1:3,1:3,i,e) = materialpoint_subF(1:3,1:3,i,e) ! ...def grad - !$OMP FLUSH(materialpoint_subF0) - elseif (materialpoint_requested(i,e)) then steppingNeeded ! already at final time (??) - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionHomog) - debug_MaterialpointLoopDistribution(min(nHomog+1,NiterationHomog)) = & - debug_MaterialpointLoopDistribution(min(nHomog+1,NiterationHomog)) + 1 - !$OMP END CRITICAL (distributionHomog) - endif - endif steppingNeeded - - else converged - if ( (myNgrains == 1_pInt .and. materialpoint_subStep(i,e) <= 1.0 ) .or. & ! single grain already tried internal subStepping in crystallite - subStepSizeHomog * materialpoint_subStep(i,e) <= subStepMinHomog ) then ! would require too small subStep - ! cutback makes no sense - !$OMP FLUSH(terminallyIll) - if (.not. terminallyIll) then ! so first signals terminally ill... - !$OMP CRITICAL (write2out) - write(6,*) 'Integration point ', i,' at element ', e, ' terminally ill' - !$OMP END CRITICAL (write2out) - endif - !$OMP CRITICAL (setTerminallyIll) - terminallyIll = .true. ! ...and kills all others - !$OMP END CRITICAL (setTerminallyIll) - else ! cutback makes sense - materialpoint_subStep(i,e) = subStepSizeHomog * materialpoint_subStep(i,e) ! crystallite had severe trouble, so do a significant cutback - !$OMP FLUSH(materialpoint_subStep) - -#ifndef _OPENMP - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i) & - .or. .not. iand(debug_level(debug_homogenization), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,1x,f12.8,a,i8,1x,i2/)') & - '<< HOMOG >> cutback step in materialpoint_stressAndItsTangent with new materialpoint_subStep:',& - materialpoint_subStep(i,e),' at el ip',e,i - endif -#endif - -!-------------------------------------------------------------------------------------------------- -! restore... - crystallite_Fp(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) ! ...plastic def grads - crystallite_Lp(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) ! ...plastic velocity grads - crystallite_Fi(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) ! ...intermediate def grads - crystallite_Li(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) ! ...intermediate velocity grads - crystallite_dPdF(1:3,1:3,1:3,1:3,1:myNgrains,i,e) = & - crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,1:myNgrains,i,e) ! ...stiffness - crystallite_Tstar_v(1:6,1:myNgrains,i,e) = & - crystallite_partionedTstar0_v(1:6,1:myNgrains,i,e) ! ...2nd PK stress - do g = 1, myNgrains - plasticState (phaseAt(g,i,e))%state( :,phasememberAt(g,i,e)) = & - plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) - sourceState(phaseAt(g,i,e))%p(mySource)%state( :,phasememberAt(g,i,e)) = & - sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) - enddo - enddo - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - homogState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal homogenization state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - thermalState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal thermal state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - damageState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal damage state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - vacancyfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal vacancy transport state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - porosityState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal porosity state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - hydrogenfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal hydrogen transport state - endif - endif converged - - if (materialpoint_subStep(i,e) > subStepMinHomog) then - materialpoint_requested(i,e) = .true. - materialpoint_subF(1:3,1:3,i,e) = materialpoint_subF0(1:3,1:3,i,e) + & - materialpoint_subStep(i,e) * (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) - materialpoint_subdt(i,e) = materialpoint_subStep(i,e) * dt - materialpoint_doneAndHappy(1:2,i,e) = [.false.,.true.] - endif - enddo IpLooping1 - enddo elementLooping1 - !$OMP END PARALLEL DO - - NiterationMPstate = 0_pInt - - convergenceLooping: do while (.not. terminallyIll .and. & - any( materialpoint_requested(:,FEsolving_execELem(1):FEsolving_execElem(2)) & - .and. .not. materialpoint_doneAndHappy(1,:,FEsolving_execELem(1):FEsolving_execElem(2)) & - ) .and. & - NiterationMPstate < nMPstate) - NiterationMPstate = NiterationMPstate + 1 - -!-------------------------------------------------------------------------------------------------- -! deformation partitioning -! based on materialpoint_subF0,.._subF,crystallite_partionedF0, and homogenization_state, -! results in crystallite_partionedF - !$OMP PARALLEL DO PRIVATE(myNgrains) - elementLooping2: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Ngrains(mesh_element(3,e)) - IpLooping2: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if ( materialpoint_requested(i,e) .and. & ! process requested but... - .not. materialpoint_doneAndHappy(1,i,e)) then ! ...not yet done material points - call homogenization_partitionDeformation(i,e) ! partition deformation onto constituents - crystallite_dt(1:myNgrains,i,e) = materialpoint_subdt(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 -! based on crystallite_partionedF0,.._partionedF -! incrementing by crystallite_dt - call crystallite_stressAndItsTangent(updateJaco) ! request stress and tangent calculation for constituent grains - -!-------------------------------------------------------------------------------------------------- -! state update - !$OMP PARALLEL DO - elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) - IpLooping3: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if ( materialpoint_requested(i,e) .and. & - .not. materialpoint_doneAndHappy(1,i,e)) then - if (.not. all(crystallite_converged(:,i,e))) then - materialpoint_doneAndHappy(1:2,i,e) = [.true.,.false.] - materialpoint_converged(i,e) = .false. - else - materialpoint_doneAndHappy(1:2,i,e) = homogenization_updateState(i,e) - materialpoint_converged(i,e) = all(materialpoint_doneAndHappy(1:2,i,e)) ! converged if done and happy - endif - !$OMP FLUSH(materialpoint_converged) - if (materialpoint_converged(i,e)) then - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionMPState) - debug_MaterialpointStateLoopdistribution(NiterationMPstate) = & - debug_MaterialpointStateLoopdistribution(NiterationMPstate) + 1_pInt - !$OMP END CRITICAL (distributionMPState) - endif - endif - endif - enddo IpLooping3 - enddo elementLooping3 - !$OMP END PARALLEL DO - - enddo convergenceLooping - - NiterationHomog = NiterationHomog + 1_pInt - - enddo cutBackLooping - - 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,e),FEsolving_execIP(2,e) - call homogenization_averageStressAndItsTangent(i,e) - enddo IpLooping4 - enddo elementLooping4 - !$OMP END PARALLEL DO - else - !$OMP CRITICAL (write2out) - write(6,'(/,a,/)') '<< HOMOG >> Material Point terminally ill' - !$OMP END CRITICAL (write2out) - endif - -end subroutine materialpoint_stressAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief parallelized calculation of result array at material points -!-------------------------------------------------------------------------------------------------- -subroutine materialpoint_postResults - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP - use mesh, only: & - mesh_element - use material, only: & - mappingHomogenization, & -#ifdef FEM - phaseAt, phasememberAt, & - homogenization_maxNgrains, & - material_Ncrystallite, & - material_Nphase, & -#else - homogState, & - thermalState, & - damageState, & - vacancyfluxState, & - porosityState, & - hydrogenfluxState, & -#endif - plasticState, & - sourceState, & - material_phase, & - homogenization_Ngrains, & - microstructure_crystallite - use constitutive, only: & -#ifdef FEM - constitutive_plasticity_maxSizePostResults, & - constitutive_source_maxSizePostResults, & -#endif - constitutive_postResults - use crystallite, only: & -#ifdef FEM - crystallite_maxSizePostResults, & -#endif - crystallite_sizePostResults, & - crystallite_postResults - - implicit none - integer(pInt) :: & - thePos, & - theSize, & - myNgrains, & - myCrystallite, & - g, & !< grain number - i, & !< integration point number - e !< element number -#ifdef FEM - integer(pInt) :: & - myHomog, & - myPhase, & - crystalliteCtr(material_Ncrystallite, homogenization_maxNgrains), & - phaseCtr (material_Nphase, homogenization_maxNgrains) - real(pReal), dimension(1+crystallite_maxSizePostResults + & - 1+constitutive_plasticity_maxSizePostResults + & - constitutive_source_maxSizePostResults) :: & - crystalliteResults - - - - crystalliteCtr = 0_pInt; phaseCtr = 0_pInt - elementLooping: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Ngrains(mesh_element(3,e)) - myCrystallite = microstructure_crystallite(mesh_element(4,e)) - IpLooping: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - myHomog = mappingHomogenization(2,i,e) - thePos = mappingHomogenization(1,i,e) - homogOutput(myHomog)%output(1: & - homogOutput(myHomog)%sizeResults, & - thePos) = homogenization_postResults(i,e) - - grainLooping :do g = 1,myNgrains - myPhase = phaseAt(g,i,e) - crystalliteResults(1:1+crystallite_sizePostResults(myCrystallite) + & - 1+plasticState(myPhase)%sizePostResults + & - sum(sourceState(myPhase)%p(:)%sizePostResults)) = crystallite_postResults(g,i,e) - if (microstructure_crystallite(mesh_element(4,e)) == myCrystallite .and. & - homogenization_Ngrains (mesh_element(3,e)) >= g) then - crystalliteCtr(myCrystallite,g) = crystalliteCtr(myCrystallite,g) + 1_pInt - crystalliteOutput(myCrystallite,g)% & - output(1:crystalliteOutput(myCrystallite,g)%sizeResults,crystalliteCtr(myCrystallite,g)) = & - crystalliteResults(2:1+crystalliteOutput(myCrystallite,g)%sizeResults) - endif - if (material_phase(g,i,e) == myPhase) then - phaseCtr(myPhase,g) = phaseCtr(myPhase,g) + 1_pInt - phaseOutput(myPhase,g)% & - output(1:phaseOutput(myPhase,g)%sizeResults,phaseCtr(myPhase,g)) = & - crystalliteResults(3 + crystalliteOutput(myCrystallite,g)%sizeResults: & - 1 + crystalliteOutput(myCrystallite,g)%sizeResults + & - 1 + plasticState (myphase)%sizePostResults + & - sum(sourceState(myphase)%p(:)%sizePostResults)) - endif - enddo grainLooping - enddo IpLooping - enddo elementLooping -#else - - !$OMP PARALLEL DO PRIVATE(myNgrains,myCrystallite,thePos,theSize) - elementLooping: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Ngrains(mesh_element(3,e)) - myCrystallite = microstructure_crystallite(mesh_element(4,e)) - IpLooping: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - thePos = 0_pInt - - theSize = homogState (mappingHomogenization(2,i,e))%sizePostResults & - + thermalState (mappingHomogenization(2,i,e))%sizePostResults & - + damageState (mappingHomogenization(2,i,e))%sizePostResults & - + vacancyfluxState (mappingHomogenization(2,i,e))%sizePostResults & - + porosityState (mappingHomogenization(2,i,e))%sizePostResults & - + hydrogenfluxState(mappingHomogenization(2,i,e))%sizePostResults - materialpoint_results(thePos+1,i,e) = real(theSize,pReal) ! tell size of homogenization results - thePos = thePos + 1_pInt - - if (theSize > 0_pInt) then ! any homogenization results to mention? - materialpoint_results(thePos+1:thePos+theSize,i,e) = homogenization_postResults(i,e) ! tell homogenization results - thePos = thePos + theSize - endif - - materialpoint_results(thePos+1,i,e) = real(myNgrains,pReal) ! tell number of grains at materialpoint - thePos = thePos + 1_pInt - - grainLooping :do g = 1,myNgrains - theSize = 1 + crystallite_sizePostResults(myCrystallite) + & - 1 + plasticState (material_phase(g,i,e))%sizePostResults + & !ToDo - sum(sourceState(material_phase(g,i,e))%p(:)%sizePostResults) - materialpoint_results(thePos+1:thePos+theSize,i,e) = crystallite_postResults(g,i,e) ! tell crystallite results - thePos = thePos + theSize - enddo grainLooping - enddo IpLooping - enddo elementLooping - !$OMP END PARALLEL DO -#endif - -end subroutine materialpoint_postResults - - -!-------------------------------------------------------------------------------------------------- -!> @brief partition material point def grad onto constituents -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_partitionDeformation(ip,el) - use mesh, only: & - mesh_element - use material, only: & - homogenization_type, & - homogenization_maxNgrains, & - HOMOGENIZATION_NONE_ID, & - HOMOGENIZATION_ISOSTRAIN_ID, & - HOMOGENIZATION_RGC_ID - use crystallite, only: & - crystallite_partionedF - use homogenization_isostrain, only: & - homogenization_isostrain_partitionDeformation - use homogenization_RGC, only: & - homogenization_RGC_partitionDeformation - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element number - - chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) - - case (HOMOGENIZATION_NONE_ID) chosenHomogenization - crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el) = 0.0_pReal - crystallite_partionedF(1:3,1:3,1:1,ip,el) = & - spread(materialpoint_subF(1:3,1:3,ip,el),3,1) - - case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization - call homogenization_isostrain_partitionDeformation(& - crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - materialpoint_subF(1:3,1:3,ip,el),& - el) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - call homogenization_RGC_partitionDeformation(& - crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - materialpoint_subF(1:3,1:3,ip,el),& - ip, & - el) - end select chosenHomogenization - -end subroutine homogenization_partitionDeformation - - -!-------------------------------------------------------------------------------------------------- -!> @brief update the internal state of the homogenization scheme and tell whether "done" and -!> "happy" with result -!-------------------------------------------------------------------------------------------------- -function homogenization_updateState(ip,el) - use mesh, only: & - mesh_element - use material, only: & - homogenization_type, & - thermal_type, & - damage_type, & - vacancyflux_type, & - homogenization_maxNgrains, & - HOMOGENIZATION_RGC_ID, & - THERMAL_adiabatic_ID, & - DAMAGE_local_ID, & - VACANCYFLUX_isochempot_ID - use crystallite, only: & - crystallite_P, & - crystallite_dPdF, & - crystallite_partionedF,& - crystallite_partionedF0 - use homogenization_RGC, only: & - homogenization_RGC_updateState - use thermal_adiabatic, only: & - thermal_adiabatic_updateState - use damage_local, only: & - damage_local_updateState - use vacancyflux_isochempot, only: & - vacancyflux_isochempot_updateState - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element number - logical, dimension(2) :: homogenization_updateState - - homogenization_updateState = .true. - chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - homogenization_updateState = & - homogenization_updateState .and. & - homogenization_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - crystallite_partionedF0(1:3,1:3,1:homogenization_maxNgrains,ip,el),& - materialpoint_subF(1:3,1:3,ip,el),& - materialpoint_subdt(ip,el), & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & - ip, & - el) - end select chosenHomogenization - - chosenThermal: select case (thermal_type(mesh_element(3,el))) - case (THERMAL_adiabatic_ID) chosenThermal - homogenization_updateState = & - homogenization_updateState .and. & - thermal_adiabatic_updateState(materialpoint_subdt(ip,el), & - ip, & - el) - end select chosenThermal - - chosenDamage: select case (damage_type(mesh_element(3,el))) - case (DAMAGE_local_ID) chosenDamage - homogenization_updateState = & - homogenization_updateState .and. & - damage_local_updateState(materialpoint_subdt(ip,el), & - ip, & - el) - end select chosenDamage - - chosenVacancyflux: select case (vacancyflux_type(mesh_element(3,el))) - case (VACANCYFLUX_isochempot_ID) chosenVacancyflux - homogenization_updateState = & - homogenization_updateState .and. & - vacancyflux_isochempot_updateState(materialpoint_subdt(ip,el), & - ip, & - el) - end select chosenVacancyflux - -end function homogenization_updateState - - -!-------------------------------------------------------------------------------------------------- -!> @brief derive average stress and stiffness from constituent quantities -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_averageStressAndItsTangent(ip,el) - use mesh, only: & - mesh_element - use material, only: & - homogenization_type, & - homogenization_maxNgrains, & - HOMOGENIZATION_NONE_ID, & - HOMOGENIZATION_ISOSTRAIN_ID, & - HOMOGENIZATION_RGC_ID - use crystallite, only: & - crystallite_P,crystallite_dPdF - use homogenization_isostrain, only: & - homogenization_isostrain_averageStressAndItsTangent - use homogenization_RGC, only: & - homogenization_RGC_averageStressAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element number - - chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) - case (HOMOGENIZATION_NONE_ID) chosenHomogenization - materialpoint_P(1:3,1:3,ip,el) = sum(crystallite_P(1:3,1:3,1:1,ip,el),3) - materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el) & - = sum(crystallite_dPdF(1:3,1:3,1:3,1:3,1:1,ip,el),5) - - case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization - call homogenization_isostrain_averageStressAndItsTangent(& - materialpoint_P(1:3,1:3,ip,el), & - materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& - crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & - el) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - call homogenization_RGC_averageStressAndItsTangent(& - materialpoint_P(1:3,1:3,ip,el), & - materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& - crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & - el) - end select chosenHomogenization - -end subroutine homogenization_averageStressAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of homogenization results for post file inclusion. call only, -!> if homogenization_sizePostResults(i,e) > 0 !! -!-------------------------------------------------------------------------------------------------- -function homogenization_postResults(ip,el) - use mesh, only: & - mesh_element - use material, only: & - mappingHomogenization, & - homogState, & - thermalState, & - damageState, & - vacancyfluxState, & - porosityState, & - hydrogenfluxState, & - homogenization_type, & - thermal_type, & - damage_type, & - vacancyflux_type, & - porosity_type, & - hydrogenflux_type, & - HOMOGENIZATION_NONE_ID, & - HOMOGENIZATION_ISOSTRAIN_ID, & - HOMOGENIZATION_RGC_ID, & - THERMAL_isothermal_ID, & - THERMAL_adiabatic_ID, & - THERMAL_conduction_ID, & - DAMAGE_none_ID, & - DAMAGE_local_ID, & - DAMAGE_nonlocal_ID, & - VACANCYFLUX_isoconc_ID, & - VACANCYFLUX_isochempot_ID, & - VACANCYFLUX_cahnhilliard_ID, & - POROSITY_none_ID, & - POROSITY_phasefield_ID, & - HYDROGENFLUX_isoconc_ID, & - HYDROGENFLUX_cahnhilliard_ID - use homogenization_isostrain, only: & - homogenization_isostrain_postResults - use homogenization_RGC, only: & - homogenization_RGC_postResults - use thermal_adiabatic, only: & - thermal_adiabatic_postResults - use thermal_conduction, only: & - thermal_conduction_postResults - use damage_local, only: & - damage_local_postResults - use damage_nonlocal, only: & - damage_nonlocal_postResults - use vacancyflux_isochempot, only: & - vacancyflux_isochempot_postResults - use vacancyflux_cahnhilliard, only: & - vacancyflux_cahnhilliard_postResults - use porosity_phasefield, only: & - porosity_phasefield_postResults - use hydrogenflux_cahnhilliard, only: & - hydrogenflux_cahnhilliard_postResults - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element number - real(pReal), dimension( homogState (mappingHomogenization(2,ip,el))%sizePostResults & - + thermalState (mappingHomogenization(2,ip,el))%sizePostResults & - + damageState (mappingHomogenization(2,ip,el))%sizePostResults & - + vacancyfluxState (mappingHomogenization(2,ip,el))%sizePostResults & - + porosityState (mappingHomogenization(2,ip,el))%sizePostResults & - + hydrogenfluxState(mappingHomogenization(2,ip,el))%sizePostResults) :: & - homogenization_postResults - integer(pInt) :: & - startPos, endPos - - homogenization_postResults = 0.0_pReal - - startPos = 1_pInt - endPos = homogState(mappingHomogenization(2,ip,el))%sizePostResults - chosenHomogenization: select case (homogenization_type(mesh_element(3,el))) - case (HOMOGENIZATION_NONE_ID) chosenHomogenization - - case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization - homogenization_postResults(startPos:endPos) = & - homogenization_isostrain_postResults(& - ip, & - el, & - materialpoint_P(1:3,1:3,ip,el), & - materialpoint_F(1:3,1:3,ip,el)) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - homogenization_postResults(startPos:endPos) = & - homogenization_RGC_postResults(& - ip, & - el, & - materialpoint_P(1:3,1:3,ip,el), & - materialpoint_F(1:3,1:3,ip,el)) - end select chosenHomogenization - - startPos = endPos + 1_pInt - endPos = endPos + thermalState(mappingHomogenization(2,ip,el))%sizePostResults - chosenThermal: select case (thermal_type(mesh_element(3,el))) - case (THERMAL_isothermal_ID) chosenThermal - - case (THERMAL_adiabatic_ID) chosenThermal - homogenization_postResults(startPos:endPos) = & - thermal_adiabatic_postResults(ip, el) - case (THERMAL_conduction_ID) chosenThermal - homogenization_postResults(startPos:endPos) = & - thermal_conduction_postResults(ip, el) - end select chosenThermal - - startPos = endPos + 1_pInt - endPos = endPos + damageState(mappingHomogenization(2,ip,el))%sizePostResults - chosenDamage: select case (damage_type(mesh_element(3,el))) - case (DAMAGE_none_ID) chosenDamage - - case (DAMAGE_local_ID) chosenDamage - homogenization_postResults(startPos:endPos) = & - damage_local_postResults(ip, el) - - case (DAMAGE_nonlocal_ID) chosenDamage - homogenization_postResults(startPos:endPos) = & - damage_nonlocal_postResults(ip, el) - end select chosenDamage - - startPos = endPos + 1_pInt - endPos = endPos + vacancyfluxState(mappingHomogenization(2,ip,el))%sizePostResults - chosenVacancyflux: select case (vacancyflux_type(mesh_element(3,el))) - case (VACANCYFLUX_isoconc_ID) chosenVacancyflux - - case (VACANCYFLUX_isochempot_ID) chosenVacancyflux - homogenization_postResults(startPos:endPos) = & - vacancyflux_isochempot_postResults(ip, el) - case (VACANCYFLUX_cahnhilliard_ID) chosenVacancyflux - homogenization_postResults(startPos:endPos) = & - vacancyflux_cahnhilliard_postResults(ip, el) - end select chosenVacancyflux - - startPos = endPos + 1_pInt - endPos = endPos + porosityState(mappingHomogenization(2,ip,el))%sizePostResults - chosenPorosity: select case (porosity_type(mesh_element(3,el))) - case (POROSITY_none_ID) chosenPorosity - - case (POROSITY_phasefield_ID) chosenPorosity - homogenization_postResults(startPos:endPos) = & - porosity_phasefield_postResults(ip, el) - end select chosenPorosity - - startPos = endPos + 1_pInt - endPos = endPos + hydrogenfluxState(mappingHomogenization(2,ip,el))%sizePostResults - chosenHydrogenflux: select case (hydrogenflux_type(mesh_element(3,el))) - case (HYDROGENFLUX_isoconc_ID) chosenHydrogenflux - - case (HYDROGENFLUX_cahnhilliard_ID) chosenHydrogenflux - homogenization_postResults(startPos:endPos) = & - hydrogenflux_cahnhilliard_postResults(ip, el) - end select chosenHydrogenflux - -end function homogenization_postResults - -end module homogenization diff --git a/code/homogenization/CMakeLists.txt b/code/homogenization/CMakeLists.txt index 84555e333..584f1f89a 100644 --- a/code/homogenization/CMakeLists.txt +++ b/code/homogenization/CMakeLists.txt @@ -9,3 +9,8 @@ set (HOMOGENIZATION "homogenization" foreach (p ${HOMOGENIZATION}) add_library (${p} MODULE "${p}.f90") endforeach (p) + +# set libraries/modules for linking +foreach (p ${HOMOGENIZATION}) + set (AUX_LIB ${AUX_LIB} ${p}) +endforeach (p) \ No newline at end of file diff --git a/code/homogenization_RGC.f90 b/code/homogenization_RGC.f90 deleted file mode 100644 index 323ca2934..000000000 --- a/code/homogenization_RGC.f90 +++ /dev/null @@ -1,1558 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Denny Tjahjanto, 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 -!> @brief Relaxed grain cluster (RGC) homogenization scheme -!> Ngrains is defined as p x q x r (cluster) -!-------------------------------------------------------------------------------------------------- -module homogenization_RGC - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public :: & - homogenization_RGC_sizeState, & - homogenization_RGC_sizePostResults - integer(pInt), dimension(:,:), allocatable,target, public :: & - homogenization_RGC_sizePostResult - character(len=64), dimension(:,:), allocatable,target, public :: & - homogenization_RGC_output ! name of each post result output - integer(pInt), dimension(:), allocatable,target, public :: & - homogenization_RGC_Noutput !< number of outputs per homog instance - integer(pInt), dimension(:,:), allocatable, private :: & - homogenization_RGC_Ngrains - real(pReal), dimension(:,:), allocatable, private :: & - homogenization_RGC_dAlpha, & - homogenization_RGC_angles - real(pReal), dimension(:,:,:,:), allocatable, private :: & - homogenization_RGC_orientation - real(pReal), dimension(:), allocatable, private :: & - homogenization_RGC_xiAlpha, & - homogenization_RGC_ciAlpha - enum, bind(c) - enumerator :: undefined_ID, & - constitutivework_ID, & - penaltyenergy_ID, & - volumediscrepancy_ID, & - averagerelaxrate_ID,& - maximumrelaxrate_ID,& - ipcoords_ID,& - magnitudemismatch_ID,& - avgdefgrad_ID,& - avgfirstpiola_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - homogenization_RGC_outputID !< ID of each post result output - - public :: & - homogenization_RGC_init, & - homogenization_RGC_partitionDeformation, & - homogenization_RGC_averageStressAndItsTangent, & - homogenization_RGC_updateState, & - homogenization_RGC_postResults - private :: & - homogenization_RGC_stressPenalty, & - homogenization_RGC_volumePenalty, & - homogenization_RGC_grainDeformation, & - homogenization_RGC_surfaceCorrection, & - homogenization_RGC_equivalentModuli, & - homogenization_RGC_relaxationVector, & - homogenization_RGC_interfaceNormal, & - homogenization_RGC_getInterface, & - homogenization_RGC_grain1to3, & - homogenization_RGC_grain3to1, & - homogenization_RGC_interface4to1, & - homogenization_RGC_interface1to4 - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use debug, only: & - debug_level, & - debug_homogenization, & - debug_levelBasic, & - debug_levelExtensive - use math, only: & - math_Mandel3333to66,& - math_Voigt66to3333, & - math_I3, & - math_sampleRandomOri,& - math_EulerToR,& - INRAD - use mesh, only: & - mesh_maxNips, & - mesh_NcpElems,& - mesh_element, & - FE_Nips, & - FE_geomtype - use IO - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit !< file pointer to material configuration - integer(pInt), allocatable, dimension(:) :: chunkPos - integer :: & - homog, & - NofMyHomog, & - o, & - instance, & - sizeHState - integer(pInt) :: section=0_pInt, maxNinstance, i,j,e, mySize, myInstance - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_RGC_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(homogenization_type == HOMOGENIZATION_RGC_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_HOMOGENIZATION),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - allocate(homogenization_RGC_sizeState(maxNinstance), source=0_pInt) - allocate(homogenization_RGC_sizePostResults(maxNinstance), source=0_pInt) - allocate(homogenization_RGC_Noutput(maxNinstance), source=0_pInt) - allocate(homogenization_RGC_Ngrains(3,maxNinstance), source=0_pInt) - allocate(homogenization_RGC_ciAlpha(maxNinstance), source=0.0_pReal) - allocate(homogenization_RGC_xiAlpha(maxNinstance), source=0.0_pReal) - allocate(homogenization_RGC_dAlpha(3,maxNinstance), source=0.0_pReal) - allocate(homogenization_RGC_angles(3,maxNinstance), source=400.0_pReal) - allocate(homogenization_RGC_output(maxval(homogenization_Noutput),maxNinstance)) - homogenization_RGC_output='' - allocate(homogenization_RGC_outputID(maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(homogenization_RGC_sizePostResult(maxval(homogenization_Noutput),maxNinstance),& - source=0_pInt) - allocate(homogenization_RGC_orientation(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - homogenization_RGC_orientation = spread(spread(math_I3,3,mesh_maxNips),4,mesh_NcpElems) ! initialize to identity - - rewind(fileUnit) - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>'))/=material_partHomogenization) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homogenization part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - cycle - endif - if (section > 0_pInt ) then ! do not short-circuit here (.and. with next if-statement). It's not safe in Fortran - if (homogenization_type(section) == HOMOGENIZATION_RGC_ID) then ! one of my sections - i = homogenization_typeInstance(section) ! which instance of my type is present homogenization - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case('constitutivework') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = constitutivework_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('penaltyenergy') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = penaltyenergy_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('volumediscrepancy') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = volumediscrepancy_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('averagerelaxrate') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = averagerelaxrate_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('maximumrelaxrate') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = maximumrelaxrate_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('magnitudemismatch') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = magnitudemismatch_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('ipcoords') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = ipcoords_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('avgdefgrad','avgf') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = avgdefgrad_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('avgp','avgfirstpiola','avg1stpiola') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = avgfirstpiola_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - - end select - case ('clustersize') - homogenization_RGC_Ngrains(1,i) = IO_intValue(line,chunkPos,2_pInt) - homogenization_RGC_Ngrains(2,i) = IO_intValue(line,chunkPos,3_pInt) - homogenization_RGC_Ngrains(3,i) = IO_intValue(line,chunkPos,4_pInt) - if (homogenization_Ngrains(section) /= product(homogenization_RGC_Ngrains(1:3,i))) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//HOMOGENIZATION_RGC_label//')') - case ('scalingparameter') - homogenization_RGC_xiAlpha(i) = IO_floatValue(line,chunkPos,2_pInt) - case ('overproportionality') - homogenization_RGC_ciAlpha(i) = IO_floatValue(line,chunkPos,2_pInt) - case ('grainsize') - homogenization_RGC_dAlpha(1,i) = IO_floatValue(line,chunkPos,2_pInt) - homogenization_RGC_dAlpha(2,i) = IO_floatValue(line,chunkPos,3_pInt) - homogenization_RGC_dAlpha(3,i) = IO_floatValue(line,chunkPos,4_pInt) - case ('clusterorientation') - homogenization_RGC_angles(1,i) = IO_floatValue(line,chunkPos,2_pInt) - homogenization_RGC_angles(2,i) = IO_floatValue(line,chunkPos,3_pInt) - homogenization_RGC_angles(3,i) = IO_floatValue(line,chunkPos,4_pInt) - - end select - endif - endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! * assigning cluster orientations - elementLooping: do e = 1_pInt,mesh_NcpElems - if (homogenization_type(mesh_element(3,e)) == HOMOGENIZATION_RGC_ID) then - myInstance = homogenization_typeInstance(mesh_element(3,e)) - if (all (homogenization_RGC_angles(1:3,myInstance) >= 399.9_pReal)) then - homogenization_RGC_orientation(1:3,1:3,1,e) = math_EulerToR(math_sampleRandomOri()) - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - if (microstructure_elemhomo(mesh_element(4,e))) then - homogenization_RGC_orientation(1:3,1:3,i,e) = homogenization_RGC_orientation(1:3,1:3,1,e) - else - homogenization_RGC_orientation(1:3,1:3,i,e) = math_EulerToR(math_sampleRandomOri()) - endif - enddo - else - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - homogenization_RGC_orientation(1:3,1:3,i,e) = & - math_EulerToR(homogenization_RGC_angles(1:3,myInstance)*inRad) - enddo - endif - endif - enddo elementLooping - - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - do i = 1_pInt,maxNinstance - write(6,'(a15,1x,i4,/)') 'instance: ', i - write(6,'(a25,3(1x,i8))') 'cluster size: ',(homogenization_RGC_Ngrains(j,i),j=1_pInt,3_pInt) - write(6,'(a25,1x,e10.3)') 'scaling parameter: ', homogenization_RGC_xiAlpha(i) - write(6,'(a25,1x,e10.3)') 'over-proportionality: ', homogenization_RGC_ciAlpha(i) - write(6,'(a25,3(1x,e10.3))') 'grain size: ',(homogenization_RGC_dAlpha(j,i),j=1_pInt,3_pInt) - write(6,'(a25,3(1x,e10.3))') 'cluster orientation: ',(homogenization_RGC_angles(j,i),j=1_pInt,3_pInt) - enddo - endif -!-------------------------------------------------------------------------------------------------- - initializeInstances: do homog = 1_pInt, material_Nhomogenization - myHomog: if (homogenization_type(homog) == HOMOGENIZATION_RGC_ID) then - NofMyHomog = count(material_homog == homog) - instance = homogenization_typeInstance(homog) - -! * Determine size of postResults array - outputsLoop: do o = 1_pInt, homogenization_RGC_Noutput(instance) - select case(homogenization_RGC_outputID(o,instance)) - case(constitutivework_ID,penaltyenergy_ID,volumediscrepancy_ID, & - averagerelaxrate_ID,maximumrelaxrate_ID) - mySize = 1_pInt - case(ipcoords_ID,magnitudemismatch_ID) - mySize = 3_pInt - case(avgdefgrad_ID,avgfirstpiola_ID) - mySize = 9_pInt - case default - mySize = 0_pInt - end select - - outputFound: if (mySize > 0_pInt) then - homogenization_RGC_sizePostResult(o,instance) = mySize - homogenization_RGC_sizePostResults(instance) = & - homogenization_RGC_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop - - sizeHState = & - 3_pInt*(homogenization_RGC_Ngrains(1,instance)-1_pInt)* & - homogenization_RGC_Ngrains(2,instance)*homogenization_RGC_Ngrains(3,instance) & - + 3_pInt*homogenization_RGC_Ngrains(1,instance)*(homogenization_RGC_Ngrains(2,instance)-1_pInt)* & - homogenization_RGC_Ngrains(3,instance) & - + 3_pInt*homogenization_RGC_Ngrains(1,instance)*homogenization_RGC_Ngrains(2,instance)* & - (homogenization_RGC_Ngrains(3,instance)-1_pInt) & - + 8_pInt ! (1) Average constitutive work, (2-4) Overall mismatch, (5) Average penalty energy, - ! (6) Volume discrepancy, (7) Avg relaxation rate component, (8) Max relaxation rate component - -! allocate state arrays - homogState(homog)%sizeState = sizeHState - homogState(homog)%sizePostResults = homogenization_RGC_sizePostResults(instance) - allocate(homogState(homog)%state0 (sizeHState,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%subState0(sizeHState,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%state (sizeHState,NofMyHomog), source=0.0_pReal) - - endif myHomog - enddo initializeInstances - - - -end subroutine homogenization_RGC_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief partitions the deformation gradient onto the constituents -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_partitionDeformation(F,avgF,ip,el) - use debug, only: & - debug_level, & - debug_homogenization, & - debug_levelExtensive - use mesh, only: & - mesh_element - use material, only: & - homogenization_maxNgrains, & - homogenization_Ngrains,& - homogenization_typeInstance - - implicit none - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned F per grain - real(pReal), dimension (3,3), intent(in) :: avgF !< averaged F - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension (3) :: aVect,nVect - integer(pInt), dimension (4) :: intFace - integer(pInt), dimension (3) :: iGrain3 - integer(pInt) :: homID, iGrain,iFace,i,j - integer(pInt), parameter :: nFace = 6_pInt - -!-------------------------------------------------------------------------------------------------- -! compute the deformation gradient of individual grains due to relaxations - homID = homogenization_typeInstance(mesh_element(3,el)) - F = 0.0_pReal - do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) - iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) - do iFace = 1_pInt,nFace - intFace = homogenization_RGC_getInterface(iFace,iGrain3) ! identifying 6 interfaces of each grain - - aVect = homogenization_RGC_relaxationVector(intFace,homID, ip, el) ! get the relaxation vectors for each interface from global relaxation vector array - - nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the normal of each interface - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) & - 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 - -!-------------------------------------------------------------------------------------------------- -! debugging the grain deformation gradients - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a32,1x,i3)')'Deformation gradient of grain: ',iGrain - do i = 1_pInt,3_pInt - write(6,'(1x,3(e15.8,1x))')(F(i,j,iGrain), j = 1_pInt,3_pInt) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - - enddo - -end subroutine homogenization_RGC_partitionDeformation - - -!-------------------------------------------------------------------------------------------------- -!> @brief update the internal state of the homogenization scheme and tell whether "done" and -! "happy" with result -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) - use debug, only: & - debug_level, & - debug_homogenization,& - debug_levelExtensive, & - debug_e, & - debug_i - use math, only: & - math_invert - use mesh, only: & - mesh_element - use material, only: & - homogenization_maxNgrains, & - homogenization_typeInstance, & - homogState, & - mappingHomogenization, & - homogenization_Ngrains - use numerics, only: & - absTol_RGC, & - relTol_RGC, & - absMax_RGC, & - relMax_RGC, & - pPert_RGC, & - maxdRelax_RGC, & - viscPower_RGC, & - viscModus_RGC, & - refRelaxRate_RGC - - implicit none - - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: & - P,& !< array of P - F,& !< array of F - F0 !< array of initial F - real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffness - real(pReal), dimension (3,3), intent(in) :: avgF !< average F - real(pReal), intent(in) :: dt !< time increment - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - logical, dimension(2) :: homogenization_RGC_updateState - integer(pInt), dimension (4) :: intFaceN,intFaceP,faceID - integer(pInt), dimension (3) :: nGDim,iGr3N,iGr3P,stresLoc - integer(pInt), dimension (2) :: residLoc - integer(pInt) homID,iNum,i,j,nIntFaceTot,iGrN,iGrP,iMun,iFace,k,l,ipert,iGrain,nGrain - real(pReal), dimension (3,3,homogenization_maxNgrains) :: R,pF,pR,D,pD - real(pReal), dimension (3,homogenization_maxNgrains) :: NN,pNN - real(pReal), dimension (3) :: normP,normN,mornP,mornN - real(pReal) :: residMax,stresMax,constitutiveWork,penaltyEnergy,volDiscrep - logical error - - integer(pInt), parameter :: nFace = 6_pInt - - real(pReal), dimension(:,:), allocatable :: tract,jmatrix,jnverse,smatrix,pmatrix,rmatrix - real(pReal), dimension(:), allocatable :: resid,relax,p_relax,p_resid,drelax - - if(abs(dt) < tiny(0.0_pReal)) then ! zero time step - homogenization_RGC_updateState = .true. ! pretend everything is fine and return - return - endif - -!-------------------------------------------------------------------------------------------------- -! get the dimension of the cluster (grains and interfaces) - homID = homogenization_typeInstance(mesh_element(3,el)) - nGDim = homogenization_RGC_Ngrains(1:3,homID) - nGrain = homogenization_Ngrains(mesh_element(3,el)) - nIntFaceTot = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) + nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) & - + nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) - -!-------------------------------------------------------------------------------------------------- -! allocate the size of the global relaxation arrays/jacobian matrices depending on the size of the cluster - allocate(resid(3_pInt*nIntFaceTot), source=0.0_pReal) - allocate(tract(nIntFaceTot,3), source=0.0_pReal) - allocate(relax(3_pInt*nIntFaceTot)); relax= homogState(mappingHomogenization(2,ip,el))% & - state(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) - allocate(drelax(3_pInt*nIntFaceTot)); drelax= homogState(mappingHomogenization(2,ip,el))% & - state(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) - & - homogState(mappingHomogenization(2,ip,el))% & - state0(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) -!-------------------------------------------------------------------------------------------------- -! debugging the obtained state - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Obtained state: ' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,2(e15.8,1x))')homogState(mappingHomogenization(2,ip,el))%state(i,mappingHomogenization(1,ip,el)) - enddo - write(6,*)' ' - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! computing interface mismatch and stress penalty tensor for all interfaces of all grains - call homogenization_RGC_stressPenalty(R,NN,avgF,F,ip,el,homID) - -!-------------------------------------------------------------------------------------------------- -! calculating volume discrepancy and stress penalty related to overall volume discrepancy - call homogenization_RGC_volumePenalty(D,volDiscrep,F,avgF,ip,el) - -!-------------------------------------------------------------------------------------------------- -! debugging the mismatch, stress and penalties of grains - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - do iGrain = 1_pInt,nGrain - write(6,'(1x,a30,1x,i3,1x,a4,3(1x,e15.8))')'Mismatch magnitude of grain(',iGrain,') :',& - NN(1,iGrain),NN(2,iGrain),NN(3,iGrain) - write(6,'(/,1x,a30,1x,i3)')'Stress and penalties of grain: ',iGrain - do i = 1_pInt,3_pInt - write(6,'(1x,3(e15.8,1x),1x,3(e15.8,1x),1x,3(e15.8,1x))')(P(i,j,iGrain), j = 1_pInt,3_pInt), & - (R(i,j,iGrain), j = 1_pInt,3_pInt), & - (D(i,j,iGrain), j = 1_pInt,3_pInt) - enddo - write(6,*)' ' - enddo - !$OMP END CRITICAL (write2out) - endif - -!------------------------------------------------------------------------------------------------ -! computing the residual stress from the balance of traction at all (interior) interfaces - do iNum = 1_pInt,nIntFaceTot - faceID = homogenization_RGC_interface1to4(iNum,homID) ! identifying the interface ID in local coordinate system (4-dimensional index) - -!-------------------------------------------------------------------------------------------------- -! identify the left/bottom/back grain (-|N) - iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate system (3-dimensional index) - iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) - intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) - normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the interface normal - -!-------------------------------------------------------------------------------------------------- -! identify the right/up/front grain (+|P) - iGr3P = iGr3N - iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate system (3-dimensional index) - iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) - intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) - normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the interface normal - -!-------------------------------------------------------------------------------------------------- -! compute the residual of traction at the interface (in local system, 4-dimensional index) - do i = 1_pInt,3_pInt - tract(iNum,i) = sign(viscModus_RGC*(abs(drelax(i+3*(iNum-1_pInt)))/(refRelaxRate_RGC*dt))**viscPower_RGC, & - drelax(i+3*(iNum-1_pInt))) ! contribution from the relaxation viscosity - do j = 1_pInt,3_pInt - tract(iNum,i) = tract(iNum,i) + (P(i,j,iGrP) + R(i,j,iGrP) + D(i,j,iGrP))*normP(j) & ! contribution from material stress P, mismatch penalty R, and volume penalty D projected into the interface - + (P(i,j,iGrN) + R(i,j,iGrN) + D(i,j,iGrN))*normN(j) - resid(i+3_pInt*(iNum-1_pInt)) = tract(iNum,i) ! translate the local residual into global 1-dimensional residual array - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! debugging the residual stress - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30,1x,i3)')'Traction at interface: ',iNum - write(6,'(1x,3(e15.8,1x))')(tract(iNum,j), j = 1_pInt,3_pInt) - write(6,*)' ' - !$OMP END CRITICAL (write2out) - endif - enddo - -!-------------------------------------------------------------------------------------------------- -! convergence check for stress residual - stresMax = maxval(abs(P)) ! get the maximum of first Piola-Kirchhoff (material) stress - stresLoc = int(maxloc(abs(P)),pInt) ! get the location of the maximum stress - residMax = maxval(abs(tract)) ! get the maximum of the residual - residLoc = int(maxloc(abs(tract)),pInt) ! get the position of the maximum residual - -!-------------------------------------------------------------------------------------------------- -! Debugging the convergent criteria - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a)')' ' - write(6,'(1x,a,1x,i2,1x,i4)')'RGC residual check ...',ip,el - write(6,'(1x,a15,1x,e15.8,1x,a7,i3,1x,a12,i2,i2)')'Max stress: ',stresMax, & - '@ grain',stresLoc(3),'in component',stresLoc(1),stresLoc(2) - write(6,'(1x,a15,1x,e15.8,1x,a7,i3,1x,a12,i2)')'Max residual: ',residMax, & - '@ iface',residLoc(1),'in direction',residLoc(2) - flush(6) - !$OMP END CRITICAL (write2out) - endif - - homogenization_RGC_updateState = .false. - -!-------------------------------------------------------------------------------------------------- -! If convergence reached => done and happy - if (residMax < relTol_RGC*stresMax .or. residMax < absTol_RGC) then - homogenization_RGC_updateState = .true. - - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a55,/)')'... done and happy' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! compute/update the state for postResult, i.e., all energy densities computed by time-integration - constitutiveWork = homogState(mappingHomogenization(2,ip,el))%state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) - penaltyEnergy = homogState(mappingHomogenization(2,ip,el))%state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) - do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) ! time-integration loop for the calculating the work and energy - do i = 1_pInt,3_pInt - do j = 1_pInt,3_pInt - constitutiveWork = constitutiveWork + P(i,j,iGrain)*(F(i,j,iGrain) - F0(i,j,iGrain))/real(nGrain,pReal) - penaltyEnergy = penaltyEnergy + R(i,j,iGrain)*(F(i,j,iGrain) - F0(i,j,iGrain))/real(nGrain,pReal) - enddo - enddo - enddo - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) = constitutiveWork ! the bulk mechanical/constitutive work - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+2,mappingHomogenization(1,ip,el)) = sum(NN(1,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e1-direction - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+3,mappingHomogenization(1,ip,el)) = sum(NN(2,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e2-direction - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+4,mappingHomogenization(1,ip,el)) = sum(NN(3,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e3-direction - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) = penaltyEnergy ! the overall penalty energy - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+6,mappingHomogenization(1,ip,el)) = volDiscrep ! the overall volume discrepancy - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+7,mappingHomogenization(1,ip,el)) = & - sum(abs(drelax))/dt/real(3_pInt*nIntFaceTot,pReal) ! the average rate of relaxation vectors - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+8,mappingHomogenization(1,ip,el)) = maxval(abs(drelax))/dt ! the maximum rate of relaxation vectors - - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30,1x,e15.8)') 'Constitutive work: ',constitutiveWork - write(6,'(1x,a30,3(1x,e15.8))')'Magnitude mismatch: ',sum(NN(1,:))/real(nGrain,pReal), & - sum(NN(2,:))/real(nGrain,pReal), & - sum(NN(3,:))/real(nGrain,pReal) - write(6,'(1x,a30,1x,e15.8)') 'Penalty energy: ',penaltyEnergy - write(6,'(1x,a30,1x,e15.8,/)') 'Volume discrepancy: ',volDiscrep - write(6,'(1x,a30,1x,e15.8)') 'Maximum relaxation rate: ',maxval(abs(drelax))/dt - write(6,'(1x,a30,1x,e15.8,/)') 'Average relaxation rate: ',sum(abs(drelax))/dt/real(3_pInt*nIntFaceTot,pReal) - flush(6) - !$OMP END CRITICAL (write2out) - endif - - deallocate(tract,resid,relax,drelax) - return - -!-------------------------------------------------------------------------------------------------- -! if residual blows-up => done but unhappy - elseif (residMax > relMax_RGC*stresMax .or. residMax > absMax_RGC) then ! try to restart when residual blows up exceeding maximum bound - homogenization_RGC_updateState = [.true.,.false.] ! with direct cut-back - - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a55,/)')'... broken' - flush(6) - !$OMP END CRITICAL (write2out) - endif - - deallocate(tract,resid,relax,drelax) - return - else ! proceed with computing the Jacobian and state update - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a55,/)')'... not yet done' - flush(6) - !$OMP END CRITICAL (write2out) - endif - - endif - -!--------------------------------------------------------------------------------------------------- -! construct the global Jacobian matrix for updating the global relaxation vector array when -! convergence is not yet reached ... - -!-------------------------------------------------------------------------------------------------- -! ... of the constitutive stress tangent, assembled from dPdF or material constitutive model "smatrix" - allocate(smatrix(3*nIntFaceTot,3*nIntFaceTot), source=0.0_pReal) - do iNum = 1_pInt,nIntFaceTot - faceID = homogenization_RGC_interface1to4(iNum,homID) ! assembling of local dPdF into global Jacobian matrix - -!-------------------------------------------------------------------------------------------------- -! identify the left/bottom/back grain (-|N) - iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate sytem - iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate into global grain ID - intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) ! identifying the connecting interface in local coordinate system - normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the interface normal - do iFace = 1_pInt,nFace - intFaceN = homogenization_RGC_getInterface(iFace,iGr3N) ! identifying all interfaces that influence relaxation of the above interface - mornN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get normal of the interfaces - iMun = homogenization_RGC_interface4to1(intFaceN,homID) ! translate the interfaces ID into local 4-dimensional index - if (iMun > 0) then ! get the corresponding tangent - do i=1_pInt,3_pInt; do j=1_pInt,3_pInt; do k=1_pInt,3_pInt; do l=1_pInt,3_pInt - smatrix(3*(iNum-1)+i,3*(iMun-1)+j) = smatrix(3*(iNum-1)+i,3*(iMun-1)+j) + dPdF(i,k,j,l,iGrN)*normN(k)*mornN(l) - enddo;enddo;enddo;enddo -! projecting the material tangent dPdF into the interface -! to obtain the Jacobian matrix contribution of dPdF - endif - enddo - -!-------------------------------------------------------------------------------------------------- -! identify the right/up/front grain (+|P) - iGr3P = iGr3N - iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate sytem - iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate into global grain ID - intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) ! identifying the connecting interface in local coordinate system - normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the interface normal - do iFace = 1_pInt,nFace - intFaceP = homogenization_RGC_getInterface(iFace,iGr3P) ! identifying all interfaces that influence relaxation of the above interface - mornP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get normal of the interfaces - iMun = homogenization_RGC_interface4to1(intFaceP,homID) ! translate the interfaces ID into local 4-dimensional index - if (iMun > 0_pInt) then ! get the corresponding tangent - do i=1_pInt,3_pInt; do j=1_pInt,3_pInt; do k=1_pInt,3_pInt; do l=1_pInt,3_pInt - smatrix(3*(iNum-1)+i,3*(iMun-1)+j) = smatrix(3*(iNum-1)+i,3*(iMun-1)+j) + dPdF(i,k,j,l,iGrP)*normP(k)*mornP(l) - enddo;enddo;enddo;enddo - endif - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! debugging the global Jacobian matrix of stress tangent - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Jacobian matrix of stress' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,100(e11.4,1x))')(smatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! ... of the stress penalty tangent (mismatch penalty and volume penalty, computed using numerical -! perturbation method) "pmatrix" - allocate(pmatrix(3*nIntFaceTot,3*nIntFaceTot), source=0.0_pReal) - allocate(p_relax(3*nIntFaceTot), source=0.0_pReal) - allocate(p_resid(3*nIntFaceTot), source=0.0_pReal) - do ipert = 1_pInt,3_pInt*nIntFaceTot - p_relax = relax - p_relax(ipert) = relax(ipert) + pPert_RGC ! perturb the relaxation vector - homogState(mappingHomogenization(2,ip,el))%state(1:3*nIntFaceTot,mappingHomogenization(1,ip,el)) = p_relax - call homogenization_RGC_grainDeformation(pF,avgF,ip,el) ! compute the grains deformation from perturbed state - call homogenization_RGC_stressPenalty(pR,pNN,avgF,pF,ip,el,homID) ! compute stress penalty due to interface mismatch from perturbed state - call homogenization_RGC_volumePenalty(pD,volDiscrep,pF,avgF,ip,el) ! compute stress penalty due to volume discrepancy from perturbed state - -!-------------------------------------------------------------------------------------------------- -! computing the global stress residual array from the perturbed state - p_resid = 0.0_pReal - do iNum = 1_pInt,nIntFaceTot - faceID = homogenization_RGC_interface1to4(iNum,homID) ! identifying the interface ID in local coordinate system (4-dimensional index) - -!-------------------------------------------------------------------------------------------------- -! identify the left/bottom/back grain (-|N) - iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate system (3-dimensional index) - iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) - intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) ! identifying the interface ID of the grain - normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the corresponding interface normal - -!-------------------------------------------------------------------------------------------------- -! identify the right/up/front grain (+|P) - iGr3P = iGr3N - iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate system (3-dimensional index) - iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) - intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) ! identifying the interface ID of the grain - normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the corresponding normal - -!-------------------------------------------------------------------------------------------------- -! compute the residual stress (contribution of mismatch and volume penalties) from perturbed state -! at all interfaces - do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt - p_resid(i+3*(iNum-1)) = p_resid(i+3*(iNum-1)) + (pR(i,j,iGrP) - R(i,j,iGrP))*normP(j) & - + (pR(i,j,iGrN) - R(i,j,iGrN))*normN(j) & - + (pD(i,j,iGrP) - D(i,j,iGrP))*normP(j) & - + (pD(i,j,iGrN) - D(i,j,iGrN))*normN(j) - enddo; enddo - enddo - pmatrix(:,ipert) = p_resid/pPert_RGC - enddo - -!-------------------------------------------------------------------------------------------------- -! debugging the global Jacobian matrix of penalty tangent - if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Jacobian matrix of penalty' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,100(e11.4,1x))')(pmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! ... of the numerical viscosity traction "rmatrix" - allocate(rmatrix(3*nIntFaceTot,3*nIntFaceTot),source=0.0_pReal) - forall (i=1_pInt:3_pInt*nIntFaceTot) & - rmatrix(i,i) = viscModus_RGC*viscPower_RGC/(refRelaxRate_RGC*dt)* & ! tangent due to numerical viscosity traction appears - (abs(drelax(i))/(refRelaxRate_RGC*dt))**(viscPower_RGC - 1.0_pReal) ! only in the main diagonal term - - - -!-------------------------------------------------------------------------------------------------- -! debugging the global Jacobian matrix of numerical viscosity tangent - if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Jacobian matrix of penalty' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,100(e11.4,1x))')(rmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! The overall Jacobian matrix summarizing contributions of smatrix, pmatrix, rmatrix - allocate(jmatrix(3*nIntFaceTot,3*nIntFaceTot)); jmatrix = smatrix + pmatrix + rmatrix - - if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Jacobian matrix (total)' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,100(e11.4,1x))')(jmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! computing the update of the state variable (relaxation vectors) using the Jacobian matrix - allocate(jnverse(3_pInt*nIntFaceTot,3_pInt*nIntFaceTot),source=0.0_pReal) - call math_invert(size(jmatrix,1),jmatrix,jnverse,error) ! Compute the inverse of the overall Jacobian matrix - -!-------------------------------------------------------------------------------------------------- -! debugging the inverse Jacobian matrix - if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Jacobian inverse' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,100(e11.4,1x))')(jnverse(i,j), j = 1_pInt,3_pInt*nIntFaceTot) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! calculate the state update (global relaxation vectors) for the next Newton-Raphson iteration - drelax = 0.0_pReal - do i = 1_pInt,3_pInt*nIntFaceTot - do j = 1_pInt,3_pInt*nIntFaceTot - drelax(i) = drelax(i) - jnverse(i,j)*resid(j) ! Calculate the correction for the state variable - enddo - enddo - relax = relax + drelax ! Updateing the state variable for the next iteration - homogState(mappingHomogenization(2,ip,el))%state(1:3*nIntFaceTot,mappingHomogenization(1,ip,el)) = relax - if (any(abs(drelax) > maxdRelax_RGC)) then ! Forcing cutback when the incremental change of relaxation vector becomes too large - homogenization_RGC_updateState = [.true.,.false.] - !$OMP CRITICAL (write2out) - write(6,'(1x,a,1x,i3,1x,a,1x,i3,1x,a)')'RGC_updateState: ip',ip,'| el',el,'enforces cutback' - write(6,'(1x,a,1x,e15.8)')'due to large relaxation change =',maxval(abs(drelax)) - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! debugging the return state - if (iand(debug_homogenization, debug_levelExtensive) > 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Returned state: ' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,2(e15.8,1x))')homogState(mappingHomogenization(2,ip,el))%state(i,mappingHomogenization(1,ip,el)) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - - deallocate(tract,resid,jmatrix,jnverse,relax,drelax,pmatrix,smatrix,p_relax,p_resid) - -end function homogenization_RGC_updateState - - -!-------------------------------------------------------------------------------------------------- -!> @brief derive average stress and stiffness from constituent quantities -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,el) - use debug, only: & - debug_level, & - debug_homogenization,& - debug_levelExtensive - use mesh, only: mesh_element - use material, only: & - homogenization_maxNgrains, & - homogenization_Ngrains, & - homogenization_typeInstance - use math, only: math_Plain3333to99 - - implicit none - 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 (3,3,homogenization_maxNgrains), intent(in) :: P !< array of current grain stresses - real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffnesses - integer(pInt), intent(in) :: el !< element number - real(pReal), dimension (9,9) :: dPdF99 - - integer(pInt) :: homID, i, j, Ngrains, iGrain - - homID = homogenization_typeInstance(mesh_element(3,el)) - Ngrains = homogenization_Ngrains(mesh_element(3,el)) - -!-------------------------------------------------------------------------------------------------- -! debugging the grain tangent - if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - do iGrain = 1_pInt,Ngrains - dPdF99 = math_Plain3333to99(dPdF(1:3,1:3,1:3,1:3,iGrain)) - write(6,'(1x,a30,1x,i3)')'Stress tangent of grain: ',iGrain - do i = 1_pInt,9_pInt - write(6,'(1x,(e15.8,1x))') (dPdF99(i,j), j = 1_pInt,9_pInt) - enddo - write(6,*)' ' - enddo - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! computing the average first Piola-Kirchhoff stress P and the average tangent dPdF - avgP = sum(P,3)/real(Ngrains,pReal) - dAvgPdAvgF = sum(dPdF,5)/real(Ngrains,pReal) - -end subroutine homogenization_RGC_averageStressAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of homogenization results for post file inclusion -!-------------------------------------------------------------------------------------------------- -pure function homogenization_RGC_postResults(ip,el,avgP,avgF) - use mesh, only: & - mesh_element, & - mesh_ipCoordinates - use material, only: & - homogenization_typeInstance,& - homogState, & - mappingHomogenization, & - homogenization_Noutput - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3), intent(in) :: & - avgP, & !< average stress at material point - avgF !< average deformation gradient at material point - - integer(pInt) homID,o,c,nIntFaceTot - real(pReal), dimension(homogenization_RGC_sizePostResults(homogenization_typeInstance(mesh_element(3,el)))) :: & - homogenization_RGC_postResults - - homID = homogenization_typeInstance(mesh_element(3,el)) - nIntFaceTot=(homogenization_RGC_Ngrains(1,homID)-1_pInt)*homogenization_RGC_Ngrains(2,homID)*homogenization_RGC_Ngrains(3,homID)& - + homogenization_RGC_Ngrains(1,homID)*(homogenization_RGC_Ngrains(2,homID)-1_pInt)*homogenization_RGC_Ngrains(3,homID)& - + homogenization_RGC_Ngrains(1,homID)*homogenization_RGC_Ngrains(2,homID)*(homogenization_RGC_Ngrains(3,homID)-1_pInt) - - c = 0_pInt - homogenization_RGC_postResults = 0.0_pReal - do o = 1_pInt,homogenization_Noutput(mesh_element(3,el)) - select case(homogenization_RGC_outputID(o,homID)) - case (avgdefgrad_ID) - homogenization_RGC_postResults(c+1_pInt:c+9_pInt) = reshape(avgF,[9]) - c = c + 9_pInt - case (avgfirstpiola_ID) - homogenization_RGC_postResults(c+1_pInt:c+9_pInt) = reshape(avgP,[9]) - c = c + 9_pInt - case (ipcoords_ID) - homogenization_RGC_postResults(c+1_pInt:c+3_pInt) = mesh_ipCoordinates(1:3,ip,el) ! current ip coordinates - c = c + 3_pInt - case (constitutivework_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) - c = c + 1_pInt - case (magnitudemismatch_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+2,mappingHomogenization(1,ip,el)) - homogenization_RGC_postResults(c+2) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+3,mappingHomogenization(1,ip,el)) - homogenization_RGC_postResults(c+3) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+4,mappingHomogenization(1,ip,el)) - c = c + 3_pInt - case (penaltyenergy_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) - c = c + 1_pInt - case (volumediscrepancy_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+6,mappingHomogenization(1,ip,el)) - c = c + 1_pInt - case (averagerelaxrate_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+7,mappingHomogenization(1,ip,el)) - c = c + 1_pInt - case (maximumrelaxrate_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+8,mappingHomogenization(1,ip,el)) - c = c + 1_pInt - end select - enddo - -end function homogenization_RGC_postResults - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate stress-like penalty due to deformation mismatch -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_stressPenalty(rPen,nMis,avgF,fDef,ip,el,homID) - use debug, only: & - debug_level, & - debug_homogenization,& - debug_levelExtensive, & - debug_e, & - debug_i - use mesh, only: & - mesh_element - use constitutive, only: & - constitutive_homogenizedC - use math, only: & - math_civita - use material, only: & - homogenization_maxNgrains,& - homogenization_Ngrains - use numerics, only: & - xSmoo_RGC - - implicit none - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: rPen !< stress-like penalty - real(pReal), dimension (3,homogenization_maxNgrains), intent(out) :: nMis !< total amount of mismatch - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: fDef !< deformation gradients - real(pReal), dimension (3,3), intent(in) :: avgF !< initial effective stretch tensor - integer(pInt), intent(in) :: ip,el - integer(pInt), dimension (4) :: intFace - integer(pInt), dimension (3) :: iGrain3,iGNghb3,nGDim - real(pReal), dimension (3,3) :: gDef,nDef - real(pReal), dimension (3) :: nVect,surfCorr - real(pReal), dimension (2) :: Gmoduli - integer(pInt) :: homID,iGrain,iGNghb,iFace,i,j,k,l - real(pReal) :: muGrain,muGNghb,nDefNorm,bgGrain,bgGNghb - - integer(pInt), parameter :: nFace = 6_pInt - real(pReal), parameter :: nDefToler = 1.0e-10_pReal - - nGDim = homogenization_RGC_Ngrains(1:3,homID) - rPen = 0.0_pReal - nMis = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! get the correction factor the modulus of penalty stress representing the evolution of area of -! the interfaces due to deformations - surfCorr = homogenization_RGC_surfaceCorrection(avgF,ip,el) - -!-------------------------------------------------------------------------------------------------- -! debugging the surface correction factor - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a20,2(1x,i3))')'Correction factor: ',ip,el - write(6,'(1x,3(e11.4,1x))')(surfCorr(i), i = 1,3) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! computing the mismatch and penalty stress tensor of all grains - do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) - Gmoduli = homogenization_RGC_equivalentModuli(iGrain,ip,el) - muGrain = Gmoduli(1) ! collecting the equivalent shear modulus of grain - bgGrain = Gmoduli(2) ! and the lengthh of Burgers vector - iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) ! get the grain ID in local 3-dimensional index (x,y,z)-position - -!* Looping over all six interfaces of each grain - do iFace = 1_pInt,nFace - intFace = homogenization_RGC_getInterface(iFace,iGrain3) ! get the 4-dimensional index of the interface in local numbering system of the grain - nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the interface normal - iGNghb3 = iGrain3 ! identify the neighboring grain across the interface - iGNghb3(abs(intFace(1))) = iGNghb3(abs(intFace(1))) + int(real(intFace(1),pReal)/real(abs(intFace(1)),pReal),pInt) - if (iGNghb3(1) < 1) iGNghb3(1) = nGDim(1) ! with periodicity along e1 direction - if (iGNghb3(1) > nGDim(1)) iGNghb3(1) = 1_pInt - if (iGNghb3(2) < 1) iGNghb3(2) = nGDim(2) ! with periodicity along e2 direction - if (iGNghb3(2) > nGDim(2)) iGNghb3(2) = 1_pInt - if (iGNghb3(3) < 1) iGNghb3(3) = nGDim(3) ! with periodicity along e3 direction - if (iGNghb3(3) > nGDim(3)) iGNghb3(3) = 1_pInt - iGNghb = homogenization_RGC_grain3to1(iGNghb3,homID) ! get the ID of the neighboring grain - Gmoduli = homogenization_RGC_equivalentModuli(iGNghb,ip,el) ! collecting the shear modulus and Burgers vector of the neighbor - muGNghb = Gmoduli(1) - bgGNghb = Gmoduli(2) - gDef = 0.5_pReal*(fDef(1:3,1:3,iGNghb) - fDef(1:3,1:3,iGrain)) ! compute the difference/jump in deformation gradeint across the neighbor - -!-------------------------------------------------------------------------------------------------- -! compute the mismatch tensor of all interfaces - nDefNorm = 0.0_pReal - nDef = 0.0_pReal - do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt - do k = 1_pInt,3_pInt; do l = 1_pInt,3_pInt - nDef(i,j) = nDef(i,j) - nVect(k)*gDef(i,l)*math_civita(j,k,l) ! compute the interface mismatch tensor from the jump of deformation gradient - enddo; enddo - nDefNorm = nDefNorm + nDef(i,j)*nDef(i,j) ! compute the norm of the mismatch tensor - 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) - -!-------------------------------------------------------------------------------------------------- -! debuggin the mismatch tensor - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a20,i2,1x,a20,1x,i3)')'Mismatch to face: ',intFace(1),'neighbor grain: ',iGNghb - do i = 1,3 - write(6,'(1x,3(e11.4,1x))')(nDef(i,j), j = 1,3) - enddo - write(6,'(1x,a20,e11.4)')'with magnitude: ',nDefNorm - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! compute the stress penalty of all interfaces - do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt - do k = 1_pInt,3_pInt; do l = 1_pInt,3_pInt - rPen(i,j,iGrain) = rPen(i,j,iGrain) + 0.5_pReal*(muGrain*bgGrain + muGNghb*bgGNghb)*homogenization_RGC_xiAlpha(homID) & - *surfCorr(abs(intFace(1)))/homogenization_RGC_dAlpha(abs(intFace(1)),homID) & - *cosh(homogenization_RGC_ciAlpha(homID)*nDefNorm) & - *0.5_pReal*nVect(l)*nDef(i,k)/nDefNorm*math_civita(k,l,j) & - *tanh(nDefNorm/xSmoo_RGC) - enddo; enddo - enddo; enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! debugging the stress-like penalty - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a20,i2)')'Penalty of grain: ',iGrain - do i = 1,3 - write(6,'(1x,3(e11.4,1x))')(rPen(i,j,iGrain), j = 1,3) - enddo - !$OMP END CRITICAL (write2out) - endif - - enddo - -end subroutine homogenization_RGC_stressPenalty - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate stress-like penalty due to volume discrepancy -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_volumePenalty(vPen,vDiscrep,fDef,fAvg,ip,el) - use debug, only: & - debug_level, & - debug_homogenization,& - debug_levelExtensive, & - debug_e, & - debug_i - use mesh, only: & - mesh_element - use math, only: & - math_det33, & - math_inv33 - use material, only: & - homogenization_maxNgrains,& - homogenization_Ngrains - use numerics, only: & - maxVolDiscr_RGC,& - volDiscrMod_RGC,& - volDiscrPow_RGC - - implicit none - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: vPen ! stress-like penalty due to volume - real(pReal), intent(out) :: vDiscrep ! total volume discrepancy - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: fDef ! deformation gradients - real(pReal), dimension (3,3), intent(in) :: fAvg ! overall deformation gradient - integer(pInt), intent(in) :: ip,& ! integration point - el - real(pReal), dimension (homogenization_maxNgrains) :: gVol - integer(pInt) :: iGrain,nGrain,i,j - - nGrain = homogenization_Ngrains(mesh_element(3,el)) - -!-------------------------------------------------------------------------------------------------- -! compute the volumes of grains and of cluster - vDiscrep = math_det33(fAvg) ! compute the volume of the cluster - do iGrain = 1_pInt,nGrain - gVol(iGrain) = math_det33(fDef(1:3,1:3,iGrain)) ! compute the volume of individual grains - vDiscrep = vDiscrep - gVol(iGrain)/real(nGrain,pReal) ! calculate the difference/dicrepancy between - ! the volume of the cluster and the the total volume of grains - enddo - -!-------------------------------------------------------------------------------------------------- -! calculate the stress and penalty due to volume discrepancy - vPen = 0.0_pReal - do iGrain = 1_pInt,nGrain - vPen(:,:,iGrain) = -1.0_pReal/real(nGrain,pReal)*volDiscrMod_RGC*volDiscrPow_RGC/maxVolDiscr_RGC* & - sign((abs(vDiscrep)/maxVolDiscr_RGC)**(volDiscrPow_RGC - 1.0),vDiscrep)* & - gVol(iGrain)*transpose(math_inv33(fDef(:,:,iGrain))) - -!-------------------------------------------------------------------------------------------------- -! debugging the stress-like penalty - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30,i2)')'Volume penalty of grain: ',iGrain - do i = 1,3 - write(6,'(1x,3(e11.4,1x))')(vPen(i,j,iGrain), j = 1,3) - enddo - !$OMP END CRITICAL (write2out) - endif - enddo - -end subroutine homogenization_RGC_volumePenalty - - -!-------------------------------------------------------------------------------------------------- -!> @brief compute the correction factor accouted for surface evolution (area change) due to -! deformation -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_surfaceCorrection(avgF,ip,el) - use math, only: & - math_invert33, & - math_mul33x33 - - implicit none - real(pReal), dimension(3) :: homogenization_RGC_surfaceCorrection - real(pReal), dimension(3,3), intent(in) :: avgF !< average F - integer(pInt), intent(in) :: ip,& !< integration point number - el !< element number - real(pReal), dimension(3,3) :: invC,avgC - real(pReal), dimension(3) :: nVect - real(pReal) :: detF - integer(pInt), dimension(4) :: intFace - integer(pInt) :: i,j,iBase - logical :: error - - avgC = math_mul33x33(transpose(avgF),avgF) - call math_invert33(avgC,invC,detF,error) - homogenization_RGC_surfaceCorrection = 0.0_pReal - do iBase = 1_pInt,3_pInt - intFace = [iBase,1_pInt,1_pInt,1_pInt] - nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the normal of the interface - do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt - homogenization_RGC_surfaceCorrection(iBase) = & ! compute the component of (the inverse of) the stretch in the direction of the normal - homogenization_RGC_surfaceCorrection(iBase) + invC(i,j)*nVect(i)*nVect(j) - enddo; enddo - homogenization_RGC_surfaceCorrection(iBase) = & ! get the surface correction factor (area contraction/enlargement) - sqrt(homogenization_RGC_surfaceCorrection(iBase))*detF - enddo - -end function homogenization_RGC_surfaceCorrection - - -!-------------------------------------------------------------------------------------------------- -!> @brief compute the equivalent shear and bulk moduli from the elasticity tensor -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_equivalentModuli(grainID,ip,el) - use constitutive, only: & - constitutive_homogenizedC - - implicit none - integer(pInt), intent(in) :: & - grainID,& - ip, & !< integration point number - el !< element number - real(pReal), dimension (6,6) :: elasTens - real(pReal), dimension(2) :: homogenization_RGC_equivalentModuli - 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 - homogenization_RGC_equivalentModuli(1) = 0.2_pReal*(cEquiv_11 - cEquiv_12) + 0.6_pReal*cEquiv_44 - -!-------------------------------------------------------------------------------------------------- -! obtain the length of Burgers vector (could be model dependend) - homogenization_RGC_equivalentModuli(2) = 2.5e-10_pReal - -end function homogenization_RGC_equivalentModuli - - -!-------------------------------------------------------------------------------------------------- -!> @brief collect relaxation vectors of an interface -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_relaxationVector(intFace,homID, ip, el) - use material, only: & - homogState, & - mappingHomogenization - - implicit none - integer(pInt), intent(in) :: ip, el - real(pReal), dimension (3) :: homogenization_RGC_relaxationVector - integer(pInt), dimension (4), intent(in) :: intFace !< set of interface ID in 4D array (normal and position) - integer(pInt), dimension (3) :: nGDim - integer(pInt) :: & - iNum, & - homID !< homogenization ID - -!-------------------------------------------------------------------------------------------------- -! collect the interface relaxation vector from the global state array - homogenization_RGC_relaxationVector = 0.0_pReal - nGDim = homogenization_RGC_Ngrains(1:3,homID) - iNum = homogenization_RGC_interface4to1(intFace,homID) ! identify the position of the interface in global state array - if (iNum > 0_pInt) homogenization_RGC_relaxationVector = homogState(mappingHomogenization(2,ip,el))% & - state((3*iNum-2):(3*iNum),mappingHomogenization(1,ip,el)) ! get the corresponding entries - -end function homogenization_RGC_relaxationVector - - -!-------------------------------------------------------------------------------------------------- -!> @brief identify the normal of an interface -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_interfaceNormal(intFace,ip,el) - use debug, only: & - debug_homogenization,& - debug_levelExtensive - use math, only: & - math_mul33x3 - - implicit none - real(pReal), dimension (3) :: homogenization_RGC_interfaceNormal - integer(pInt), dimension (4), intent(in) :: intFace !< interface ID in 4D array (normal and position) - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - integer(pInt) :: nPos - -!-------------------------------------------------------------------------------------------------- -! get the normal of the interface, identified from the value of intFace(1) - homogenization_RGC_interfaceNormal = 0.0_pReal - nPos = abs(intFace(1)) ! identify the position of the interface in global state array - homogenization_RGC_interfaceNormal(nPos) = real(intFace(1)/abs(intFace(1)),pReal) ! get the normal vector w.r.t. cluster axis - - homogenization_RGC_interfaceNormal = & - math_mul33x3(homogenization_RGC_orientation(1:3,1:3,ip,el),homogenization_RGC_interfaceNormal) - ! map the normal vector into sample coordinate system (basis) - -end function homogenization_RGC_interfaceNormal - - -!-------------------------------------------------------------------------------------------------- -!> @brief collect six faces of a grain in 4D (normal and position) -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_getInterface(iFace,iGrain3) - - implicit none - integer(pInt), dimension (4) :: homogenization_RGC_getInterface - integer(pInt), dimension (3), intent(in) :: iGrain3 !< grain ID in 3D array - integer(pInt), intent(in) :: iFace !< face index (1..6) mapped like (-e1,-e2,-e3,+e1,+e2,+e3) or iDir = (-1,-2,-3,1,2,3) - integer(pInt) :: iDir - -!* Direction of interface normal - iDir = (int(real(iFace-1_pInt,pReal)/2.0_pReal,pInt)+1_pInt)*(-1_pInt)**iFace - homogenization_RGC_getInterface(1) = iDir - -!-------------------------------------------------------------------------------------------------- -! identify the interface position by the direction of its normal - homogenization_RGC_getInterface(2:4) = iGrain3 - if (iDir < 0_pInt) & ! to have a correlation with coordinate/position in real space - homogenization_RGC_getInterface(1_pInt-iDir) = homogenization_RGC_getInterface(1_pInt-iDir)-1_pInt - -end function homogenization_RGC_getInterface - -!-------------------------------------------------------------------------------------------------- -!> @brief map grain ID from in 1D (global array) to in 3D (local position) -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_grain1to3(grain1,homID) - - implicit none - integer(pInt), dimension (3) :: homogenization_RGC_grain1to3 - integer(pInt), intent(in) :: & - grain1,& !< grain ID in 1D array - homID !< homogenization ID - integer(pInt), dimension (3) :: nGDim - -!-------------------------------------------------------------------------------------------------- -! get the grain position - nGDim = homogenization_RGC_Ngrains(1:3,homID) - homogenization_RGC_grain1to3(3) = 1_pInt+(grain1-1_pInt)/(nGDim(1)*nGDim(2)) - homogenization_RGC_grain1to3(2) = 1_pInt+mod((grain1-1_pInt)/nGDim(1),nGDim(2)) - homogenization_RGC_grain1to3(1) = 1_pInt+mod((grain1-1_pInt),nGDim(1)) - -end function homogenization_RGC_grain1to3 - - -!-------------------------------------------------------------------------------------------------- -!> @brief map grain ID from in 3D (local position) to in 1D (global array) -!-------------------------------------------------------------------------------------------------- -pure function homogenization_RGC_grain3to1(grain3,homID) - - implicit none - integer(pInt), dimension (3), intent(in) :: grain3 !< grain ID in 3D array (pos.x,pos.y,pos.z) - integer(pInt) :: homogenization_RGC_grain3to1 - integer(pInt), dimension (3) :: nGDim - integer(pInt), intent(in) :: homID ! homogenization ID - -!-------------------------------------------------------------------------------------------------- -! get the grain ID - nGDim = homogenization_RGC_Ngrains(1:3,homID) - homogenization_RGC_grain3to1 = grain3(1) + nGDim(1)*(grain3(2)-1_pInt) + nGDim(1)*nGDim(2)*(grain3(3)-1_pInt) - -end function homogenization_RGC_grain3to1 - - -!-------------------------------------------------------------------------------------------------- -!> @brief maps interface ID from 4D (normal and local position) into 1D (global array) -!-------------------------------------------------------------------------------------------------- -integer(pInt) pure function homogenization_RGC_interface4to1(iFace4D, homID) - - implicit none - integer(pInt), dimension (4), intent(in) :: iFace4D !< interface ID in 4D array (n.dir,pos.x,pos.y,pos.z) - integer(pInt), dimension (3) :: nGDim,nIntFace - integer(pInt), intent(in) :: homID !< homogenization ID - - nGDim = homogenization_RGC_Ngrains(1:3,homID) - -!-------------------------------------------------------------------------------------------------- -! compute the total number of interfaces, which ... - nIntFace(1) = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) ! ... normal //e1 - nIntFace(2) = nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) ! ... normal //e2 - nIntFace(3) = nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) ! ... normal //e3 - - homogenization_RGC_interface4to1 = -1_pInt - -!-------------------------------------------------------------------------------------------------- -! get the corresponding interface ID in 1D global array - if (abs(iFace4D(1)) == 1_pInt) then ! interface with normal //e1 - homogenization_RGC_interface4to1 = iFace4D(3) + nGDim(2)*(iFace4D(4)-1_pInt) & - + nGDim(2)*nGDim(3)*(iFace4D(2)-1_pInt) - if ((iFace4D(2) == 0_pInt) .or. (iFace4D(2) == nGDim(1))) homogenization_RGC_interface4to1 = 0_pInt - elseif (abs(iFace4D(1)) == 2_pInt) then ! interface with normal //e2 - homogenization_RGC_interface4to1 = iFace4D(4) + nGDim(3)*(iFace4D(2)-1_pInt) & - + nGDim(3)*nGDim(1)*(iFace4D(3)-1_pInt) + nIntFace(1) - if ((iFace4D(3) == 0_pInt) .or. (iFace4D(3) == nGDim(2))) homogenization_RGC_interface4to1 = 0_pInt - elseif (abs(iFace4D(1)) == 3_pInt) then ! interface with normal //e3 - homogenization_RGC_interface4to1 = iFace4D(2) + nGDim(1)*(iFace4D(3)-1_pInt) & - + nGDim(1)*nGDim(2)*(iFace4D(4)-1_pInt) + nIntFace(1) + nIntFace(2) - if ((iFace4D(4) == 0_pInt) .or. (iFace4D(4) == nGDim(3))) homogenization_RGC_interface4to1 = 0_pInt - endif - -end function homogenization_RGC_interface4to1 - - -!-------------------------------------------------------------------------------------------------- -!> @brief maps interface ID from 1D (global array) into 4D (normal and local position) -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_interface1to4(iFace1D, homID) - - implicit none - integer(pInt), dimension (4) :: homogenization_RGC_interface1to4 - integer(pInt), intent(in) :: iFace1D !< interface ID in 1D array - integer(pInt), dimension (3) :: nGDim,nIntFace - integer(pInt), intent(in) :: homID !< homogenization ID - - nGDim = homogenization_RGC_Ngrains(:,homID) - -!-------------------------------------------------------------------------------------------------- -! compute the total number of interfaces, which ... - nIntFace(1) = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) ! ... normal //e1 - nIntFace(2) = nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) ! ... normal //e2 - nIntFace(3) = nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) ! ... normal //e3 - -!-------------------------------------------------------------------------------------------------- -! get the corresponding interface ID in 4D (normal and local position) - if (iFace1D > 0 .and. iFace1D <= nIntFace(1)) then ! interface with normal //e1 - homogenization_RGC_interface1to4(1) = 1_pInt - homogenization_RGC_interface1to4(3) = mod((iFace1D-1_pInt),nGDim(2))+1_pInt - homogenization_RGC_interface1to4(4) = mod(& - int(& - real(iFace1D-1_pInt,pReal)/& - real(nGDim(2),pReal)& - ,pInt)& - ,nGDim(3))+1_pInt - homogenization_RGC_interface1to4(2) = int(& - real(iFace1D-1_pInt,pReal)/& - real(nGDim(2),pReal)/& - real(nGDim(3),pReal)& - ,pInt)+1_pInt - elseif (iFace1D > nIntFace(1) .and. iFace1D <= (nIntFace(2) + nIntFace(1))) then ! interface with normal //e2 - homogenization_RGC_interface1to4(1) = 2_pInt - homogenization_RGC_interface1to4(4) = mod((iFace1D-nIntFace(1)-1_pInt),nGDim(3))+1_pInt - homogenization_RGC_interface1to4(2) = mod(& - int(& - real(iFace1D-nIntFace(1)-1_pInt,pReal)/& - real(nGDim(3),pReal)& - ,pInt)& - ,nGDim(1))+1_pInt - homogenization_RGC_interface1to4(3) = int(& - real(iFace1D-nIntFace(1)-1_pInt,pReal)/& - real(nGDim(3),pReal)/& - real(nGDim(1),pReal)& - ,pInt)+1_pInt - elseif (iFace1D > nIntFace(2) + nIntFace(1) .and. iFace1D <= (nIntFace(3) + nIntFace(2) + nIntFace(1))) then ! interface with normal //e3 - homogenization_RGC_interface1to4(1) = 3_pInt - homogenization_RGC_interface1to4(2) = mod((iFace1D-nIntFace(2)-nIntFace(1)-1_pInt),nGDim(1))+1_pInt - homogenization_RGC_interface1to4(3) = mod(& - int(& - real(iFace1D-nIntFace(2)-nIntFace(1)-1_pInt,pReal)/& - real(nGDim(1),pReal)& - ,pInt)& - ,nGDim(2))+1_pInt - homogenization_RGC_interface1to4(4) = int(& - real(iFace1D-nIntFace(2)-nIntFace(1)-1_pInt,pReal)/& - real(nGDim(1),pReal)/& - real(nGDim(2),pReal)& - ,pInt)+1_pInt - endif - -end function homogenization_RGC_interface1to4 - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculating the grain deformation gradient (the same with -! homogenization_RGC_partionDeformation, but used only for perturbation scheme) -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_grainDeformation(F, avgF, ip, el) - use mesh, only: & - mesh_element - use material, only: & - homogenization_maxNgrains,& - homogenization_Ngrains, & - homogenization_typeInstance - - implicit none - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned F per grain - real(pReal), dimension (3,3), intent(in) :: avgF !< - integer(pInt), intent(in) :: & - el, & !< element number - ip !< integration point number - real(pReal), dimension (3) :: aVect,nVect - integer(pInt), dimension (4) :: intFace - integer(pInt), dimension (3) :: iGrain3 - integer(pInt) :: homID, iGrain,iFace,i,j - integer(pInt), parameter :: nFace = 6_pInt - -!-------------------------------------------------------------------------------------------------- -! compute the deformation gradient of individual grains due to relaxations - homID = homogenization_typeInstance(mesh_element(3,el)) - F = 0.0_pReal - do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) - iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) - do iFace = 1_pInt,nFace - intFace = homogenization_RGC_getInterface(iFace,iGrain3) - aVect = homogenization_RGC_relaxationVector(intFace,homID, ip, el) - nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) & - F(i,j,iGrain) = F(i,j,iGrain) + aVect(i)*nVect(j) ! effective relaxations - enddo - F(1:3,1:3,iGrain) = F(1:3,1:3,iGrain) + avgF ! relaxed deformation gradient - enddo - -end subroutine homogenization_RGC_grainDeformation - -end module homogenization_RGC diff --git a/code/homogenization_isostrain.f90 b/code/homogenization_isostrain.f90 deleted file mode 100644 index 083107d9f..000000000 --- a/code/homogenization_isostrain.f90 +++ /dev/null @@ -1,317 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Isostrain (full constraint Taylor assuption) homogenization scheme -!-------------------------------------------------------------------------------------------------- -module homogenization_isostrain - use prec, only: & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - homogenization_isostrain_sizePostResults - integer(pInt), dimension(:,:), allocatable, target, public :: & - homogenization_isostrain_sizePostResult - - character(len=64), dimension(:,:), allocatable, target, public :: & - homogenization_isostrain_output !< name of each post result output - integer(pInt), dimension(:), allocatable, target, public :: & - homogenization_isostrain_Noutput !< number of outputs per homog instance - integer(pInt), dimension(:), allocatable, private :: & - homogenization_isostrain_Ngrains - enum, bind(c) - enumerator :: undefined_ID, & - nconstituents_ID, & - ipcoords_ID, & - avgdefgrad_ID, & - avgfirstpiola_ID - end enum - enum, bind(c) - enumerator :: parallel_ID, & - average_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - homogenization_isostrain_outputID !< ID of each post result output - integer(kind(average_ID)), dimension(:), allocatable, private :: & - homogenization_isostrain_mapping !< mapping type - - - public :: & - homogenization_isostrain_init, & - homogenization_isostrain_partitionDeformation, & - homogenization_isostrain_averageStressAndItsTangent, & - homogenization_isostrain_postResults - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_isostrain_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal - use debug, only: & - debug_HOMOGENIZATION, & - debug_level, & - debug_levelBasic - use IO - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - section = 0_pInt, i, mySize, o - integer :: & - maxNinstance, & - homog, & - instance - integer :: & - NofMyHomog ! no pInt (stores a system dependen value from 'count' - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_ISOSTRAIN_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = count(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID) - if (maxNinstance == 0) return - - if (iand(debug_level(debug_HOMOGENIZATION),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - allocate(homogenization_isostrain_sizePostResults(maxNinstance), source=0_pInt) - allocate(homogenization_isostrain_sizePostResult(maxval(homogenization_Noutput),maxNinstance), & - source=0_pInt) - allocate(homogenization_isostrain_Noutput(maxNinstance), source=0_pInt) - allocate(homogenization_isostrain_Ngrains(maxNinstance), source=0_pInt) - allocate(homogenization_isostrain_mapping(maxNinstance), source=average_ID) - allocate(homogenization_isostrain_output(maxval(homogenization_Noutput),maxNinstance)) - homogenization_isostrain_output = '' - allocate(homogenization_isostrain_outputID(maxval(homogenization_Noutput),maxNinstance), & - source=undefined_ID) - - rewind(fileUnit) - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homogenization part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - cycle - endif - if (section > 0_pInt ) then ! do not short-circuit here (.and. with next if-statement). It's not safe in Fortran - if (homogenization_type(section) == HOMOGENIZATION_ISOSTRAIN_ID) then ! one of my sections - i = homogenization_typeInstance(section) ! which instance of my type is present homogenization - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case('nconstituents','ngrains') - homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt - homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = nconstituents_ID - homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('ipcoords') - homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt - homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = ipcoords_ID - homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('avgdefgrad','avgf') - homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt - homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = avgdefgrad_ID - homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('avgp','avgfirstpiola','avg1stpiola') - homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt - homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = avgfirstpiola_ID - homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - - end select - case ('nconstituents','ngrains') - homogenization_isostrain_Ngrains(i) = IO_intValue(line,chunkPos,2_pInt) - case ('mapping') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('parallel','sum') - homogenization_isostrain_mapping(i) = parallel_ID - case ('average','mean','avg') - homogenization_isostrain_mapping(i) = average_ID - case default - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//HOMOGENIZATION_isostrain_label//')') - end select - - end select - endif - endif - enddo parsingFile - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - myHomog: if (homogenization_type(homog) == HOMOGENIZATION_ISOSTRAIN_ID) then - NofMyHomog = count(material_homog == homog) - instance = homogenization_typeInstance(homog) - -! * Determine size of postResults array - outputsLoop: do o = 1_pInt, homogenization_isostrain_Noutput(instance) - select case(homogenization_isostrain_outputID(o,instance)) - case(nconstituents_ID) - mySize = 1_pInt - case(ipcoords_ID) - mySize = 3_pInt - case(avgdefgrad_ID, avgfirstpiola_ID) - mySize = 9_pInt - case default - mySize = 0_pInt - end select - - outputFound: if (mySize > 0_pInt) then - homogenization_isostrain_sizePostResult(o,instance) = mySize - homogenization_isostrain_sizePostResults(instance) = & - homogenization_isostrain_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop - -! allocate state arrays - homogState(homog)%sizeState = 0_pInt - homogState(homog)%sizePostResults = homogenization_isostrain_sizePostResults(instance) - allocate(homogState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) - - endif myHomog - enddo initializeInstances - -end subroutine homogenization_isostrain_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief partitions the deformation gradient onto the constituents -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_isostrain_partitionDeformation(F,avgF,el) - use prec, only: & - pReal - use mesh, only: & - mesh_element - use material, only: & - homogenization_maxNgrains, & - homogenization_Ngrains - - implicit none - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned def grad per grain - real(pReal), dimension (3,3), intent(in) :: avgF !< my average def grad - integer(pInt), intent(in) :: & - el !< element number - F=0.0_pReal - F(1:3,1:3,1:homogenization_Ngrains(mesh_element(3,el)))= & - spread(avgF,3,homogenization_Ngrains(mesh_element(3,el))) - -end subroutine homogenization_isostrain_partitionDeformation - - -!-------------------------------------------------------------------------------------------------- -!> @brief derive average stress and stiffness from constituent quantities -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_isostrain_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,el) - use prec, only: & - pReal - use mesh, only: & - mesh_element - use material, only: & - homogenization_maxNgrains, & - homogenization_Ngrains, & - homogenization_typeInstance - - implicit none - 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 (3,3,homogenization_maxNgrains), intent(in) :: P !< array of current grain stresses - real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffnesses - integer(pInt), intent(in) :: el !< element number - integer(pInt) :: & - homID, & - Ngrains - - homID = homogenization_typeInstance(mesh_element(3,el)) - Ngrains = homogenization_Ngrains(mesh_element(3,el)) - - select case (homogenization_isostrain_mapping(homID)) - case (parallel_ID) - avgP = sum(P,3) - dAvgPdAvgF = sum(dPdF,5) - case (average_ID) - avgP = sum(P,3) /real(Ngrains,pReal) - dAvgPdAvgF = sum(dPdF,5)/real(Ngrains,pReal) - end select - -end subroutine homogenization_isostrain_averageStressAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of homogenization results for post file inclusion -!-------------------------------------------------------------------------------------------------- -pure function homogenization_isostrain_postResults(ip,el,avgP,avgF) - use prec, only: & - pReal - use mesh, only: & - mesh_element, & - mesh_ipCoordinates - use material, only: & - homogenization_typeInstance, & - homogenization_Noutput - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3), intent(in) :: & - avgP, & !< average stress at material point - avgF !< average deformation gradient at material point - real(pReal), dimension(homogenization_isostrain_sizePostResults & - (homogenization_typeInstance(mesh_element(3,el)))) :: & - homogenization_isostrain_postResults - - integer(pInt) :: & - homID, & - o, c - - c = 0_pInt - homID = homogenization_typeInstance(mesh_element(3,el)) - homogenization_isostrain_postResults = 0.0_pReal - - do o = 1_pInt,homogenization_Noutput(mesh_element(3,el)) - select case(homogenization_isostrain_outputID(o,homID)) - case (nconstituents_ID) - homogenization_isostrain_postResults(c+1_pInt) = real(homogenization_isostrain_Ngrains(homID),pReal) - c = c + 1_pInt - case (avgdefgrad_ID) - homogenization_isostrain_postResults(c+1_pInt:c+9_pInt) = reshape(avgF,[9]) - c = c + 9_pInt - case (avgfirstpiola_ID) - homogenization_isostrain_postResults(c+1_pInt:c+9_pInt) = reshape(avgP,[9]) - c = c + 9_pInt - case (ipcoords_ID) - homogenization_isostrain_postResults(c+1_pInt:c+3_pInt) = mesh_ipCoordinates(1:3,ip,el) ! current ip coordinates - c = c + 3_pInt - end select - enddo - -end function homogenization_isostrain_postResults - -end module homogenization_isostrain diff --git a/code/homogenization_none.f90 b/code/homogenization_none.f90 deleted file mode 100644 index 59e483c27..000000000 --- a/code/homogenization_none.f90 +++ /dev/null @@ -1,60 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief dummy homogenization homogenization scheme -!-------------------------------------------------------------------------------------------------- -module homogenization_none - - implicit none - private - - public :: & - homogenization_none_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_none_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_NONE_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (homogenization_type(homog) == HOMOGENIZATION_none_ID) then - NofMyHomog = count(material_homog == homog) - homogState(homog)%sizeState = 0_pInt - homogState(homog)%sizePostResults = 0_pInt - allocate(homogState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) - - endif myhomog - enddo initializeInstances - - -end subroutine homogenization_none_init - -end module homogenization_none diff --git a/code/hydrogenflux/CMakeLists.txt b/code/hydrogenflux/CMakeLists.txt index ef296400b..4f133e0f6 100644 --- a/code/hydrogenflux/CMakeLists.txt +++ b/code/hydrogenflux/CMakeLists.txt @@ -7,3 +7,8 @@ set (HYDROGENFLUX "hydrogenflux_isoconc" foreach (p ${HYDROGENFLUX}) add_library (${p} MODULE "${p}.f90") endforeach (p) + +# set libraries/modules for linking +foreach (p ${HYDROGENFLUX}) + set (AUX_LIB ${AUX_LIB} ${p}) +endforeach (p) \ No newline at end of file diff --git a/code/hydrogenflux_cahnhilliard.f90 b/code/hydrogenflux_cahnhilliard.f90 deleted file mode 100644 index d8cb71edc..000000000 --- a/code/hydrogenflux_cahnhilliard.f90 +++ /dev/null @@ -1,513 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for conservative transport of solute hydrogen -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module hydrogenflux_cahnhilliard - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - hydrogenflux_cahnhilliard_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - hydrogenflux_cahnhilliard_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - hydrogenflux_cahnhilliard_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - hydrogenflux_cahnhilliard_Noutput !< number of outputs per instance of this damage - - real(pReal), parameter, private :: & - kB = 1.3806488e-23_pReal !< Boltzmann constant in J/Kelvin - - enum, bind(c) - enumerator :: undefined_ID, & - hydrogenConc_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - hydrogenflux_cahnhilliard_outputID !< ID of each post result output - - - public :: & - hydrogenflux_cahnhilliard_init, & - hydrogenflux_cahnhilliard_getMobility33, & - hydrogenflux_cahnhilliard_getDiffusion33, & - hydrogenflux_cahnhilliard_getFormationEnergy, & - hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent, & - hydrogenflux_cahnhilliard_getChemPotAndItsTangent, & - hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate, & - hydrogenflux_cahnhilliard_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine hydrogenflux_cahnhilliard_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - hydrogenflux_type, & - hydrogenflux_typeInstance, & - homogenization_Noutput, & - HYDROGENFLUX_cahnhilliard_label, & - HYDROGENFLUX_cahnhilliard_ID, & - material_homog, & - mappingHomogenization, & - hydrogenfluxState, & - hydrogenfluxMapping, & - hydrogenConc, & - hydrogenConcRate, & - hydrogenflux_initialCh, & - material_partHomogenization, & - material_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- hydrogenflux_'//HYDROGENFLUX_cahnhilliard_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(hydrogenflux_type == HYDROGENFLUX_cahnhilliard_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(hydrogenflux_cahnhilliard_sizePostResults(maxNinstance), source=0_pInt) - allocate(hydrogenflux_cahnhilliard_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(hydrogenflux_cahnhilliard_output (maxval(homogenization_Noutput),maxNinstance)) - hydrogenflux_cahnhilliard_output = '' - allocate(hydrogenflux_cahnhilliard_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(hydrogenflux_cahnhilliard_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (hydrogenflux_type(section) == HYDROGENFLUX_cahnhilliard_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = hydrogenflux_typeInstance(section) ! which instance of my hydrogenflux is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('hydrogenconc') - hydrogenflux_cahnhilliard_Noutput(instance) = hydrogenflux_cahnhilliard_Noutput(instance) + 1_pInt - hydrogenflux_cahnhilliard_outputID(hydrogenflux_cahnhilliard_Noutput(instance),instance) = hydrogenConc_ID - hydrogenflux_cahnhilliard_output(hydrogenflux_cahnhilliard_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingHomog - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - initializeInstances: do section = 1_pInt, size(hydrogenflux_type) - if (hydrogenflux_type(section) == HYDROGENFLUX_cahnhilliard_ID) then - NofMyHomog=count(material_homog==section) - instance = hydrogenflux_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,hydrogenflux_cahnhilliard_Noutput(instance) - select case(hydrogenflux_cahnhilliard_outputID(o,instance)) - case(hydrogenConc_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - hydrogenflux_cahnhilliard_sizePostResult(o,instance) = mySize - hydrogenflux_cahnhilliard_sizePostResults(instance) = hydrogenflux_cahnhilliard_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 0_pInt - hydrogenfluxState(section)%sizeState = sizeState - hydrogenfluxState(section)%sizePostResults = hydrogenflux_cahnhilliard_sizePostResults(instance) - allocate(hydrogenfluxState(section)%state0 (sizeState,NofMyHomog)) - allocate(hydrogenfluxState(section)%subState0(sizeState,NofMyHomog)) - allocate(hydrogenfluxState(section)%state (sizeState,NofMyHomog)) - - nullify(hydrogenfluxMapping(section)%p) - hydrogenfluxMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(hydrogenConc (section)%p) - deallocate(hydrogenConcRate(section)%p) - allocate (hydrogenConc (section)%p(NofMyHomog), source=hydrogenflux_initialCh(section)) - allocate (hydrogenConcRate(section)%p(NofMyHomog), source=0.0_pReal) - - endif - - enddo initializeInstances - -end subroutine hydrogenflux_cahnhilliard_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized solute mobility tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function hydrogenflux_cahnhilliard_getMobility33(ip,el) - use lattice, only: & - lattice_hydrogenfluxMobility33 - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - hydrogenflux_cahnhilliard_getMobility33 - integer(pInt) :: & - grain - - hydrogenflux_cahnhilliard_getMobility33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - hydrogenflux_cahnhilliard_getMobility33 = hydrogenflux_cahnhilliard_getMobility33 + & - crystallite_push33ToRef(grain,ip,el,lattice_hydrogenfluxMobility33(:,:,material_phase(grain,ip,el))) - enddo - - hydrogenflux_cahnhilliard_getMobility33 = & - hydrogenflux_cahnhilliard_getMobility33/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function hydrogenflux_cahnhilliard_getMobility33 - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized solute nonlocal diffusion tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function hydrogenflux_cahnhilliard_getDiffusion33(ip,el) - use lattice, only: & - lattice_hydrogenfluxDiffusion33 - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - hydrogenflux_cahnhilliard_getDiffusion33 - integer(pInt) :: & - grain - - hydrogenflux_cahnhilliard_getDiffusion33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - hydrogenflux_cahnhilliard_getDiffusion33 = hydrogenflux_cahnhilliard_getDiffusion33 + & - crystallite_push33ToRef(grain,ip,el,lattice_hydrogenfluxDiffusion33(:,:,material_phase(grain,ip,el))) - enddo - - hydrogenflux_cahnhilliard_getDiffusion33 = & - hydrogenflux_cahnhilliard_getDiffusion33/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function hydrogenflux_cahnhilliard_getDiffusion33 - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized solution energy -!-------------------------------------------------------------------------------------------------- -function hydrogenflux_cahnhilliard_getFormationEnergy(ip,el) - use lattice, only: & - lattice_hydrogenFormationEnergy, & - lattice_hydrogenVol, & - lattice_hydrogenSurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - hydrogenflux_cahnhilliard_getFormationEnergy - integer(pInt) :: & - grain - - hydrogenflux_cahnhilliard_getFormationEnergy = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - hydrogenflux_cahnhilliard_getFormationEnergy = hydrogenflux_cahnhilliard_getFormationEnergy + & - lattice_hydrogenFormationEnergy(material_phase(grain,ip,el))/ & - lattice_hydrogenVol(material_phase(grain,ip,el))/ & - lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) - enddo - - hydrogenflux_cahnhilliard_getFormationEnergy = & - hydrogenflux_cahnhilliard_getFormationEnergy/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function hydrogenflux_cahnhilliard_getFormationEnergy - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized hydrogen entropy coefficient -!-------------------------------------------------------------------------------------------------- -function hydrogenflux_cahnhilliard_getEntropicCoeff(ip,el) - use lattice, only: & - lattice_hydrogenVol, & - lattice_hydrogenSurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_homog, & - material_phase, & - temperature, & - thermalMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - hydrogenflux_cahnhilliard_getEntropicCoeff - integer(pInt) :: & - grain - - hydrogenflux_cahnhilliard_getEntropicCoeff = 0.0_pReal - do grain = 1, homogenization_Ngrains(material_homog(ip,el)) - hydrogenflux_cahnhilliard_getEntropicCoeff = hydrogenflux_cahnhilliard_getEntropicCoeff + & - kB/ & - lattice_hydrogenVol(material_phase(grain,ip,el))/ & - lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) - enddo - - hydrogenflux_cahnhilliard_getEntropicCoeff = & - hydrogenflux_cahnhilliard_getEntropicCoeff* & - temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))/ & - homogenization_Ngrains(material_homog(ip,el)) - -end function hydrogenflux_cahnhilliard_getEntropicCoeff - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized kinematic contribution to chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCh, Ch, ip, el) - use lattice, only: & - lattice_hydrogenSurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_homog, & - phase_kinematics, & - phase_Nkinematics, & - material_phase, & - KINEMATICS_hydrogen_strain_ID - use crystallite, only: & - crystallite_Tstar_v, & - crystallite_Fi0, & - crystallite_Fi - use kinematics_hydrogen_strain, only: & - kinematics_hydrogen_strain_ChemPotAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Ch - real(pReal), intent(out) :: & - KPot, dKPot_dCh - real(pReal) :: & - my_KPot, my_dKPot_dCh - integer(pInt) :: & - grain, kinematics - - KPot = 0.0_pReal - dKPot_dCh = 0.0_pReal - do grain = 1_pInt,homogenization_Ngrains(material_homog(ip,el)) - do kinematics = 1_pInt, phase_Nkinematics(material_phase(grain,ip,el)) - select case (phase_kinematics(kinematics,material_phase(grain,ip,el))) - case (KINEMATICS_hydrogen_strain_ID) - call kinematics_hydrogen_strain_ChemPotAndItsTangent(my_KPot, my_dKPot_dCh, & - crystallite_Tstar_v(1:6,grain,ip,el), & - crystallite_Fi0(1:3,1:3,grain,ip,el), & - crystallite_Fi (1:3,1:3,grain,ip,el), & - grain,ip, el) - - case default - my_KPot = 0.0_pReal - my_dKPot_dCh = 0.0_pReal - - end select - KPot = KPot + my_KPot/lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) - dKPot_dCh = dKPot_dCh + my_dKPot_dCh/lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) - enddo - enddo - - KPot = KPot/homogenization_Ngrains(material_homog(ip,el)) - dKPot_dCh = dKPot_dCh/homogenization_Ngrains(material_homog(ip,el)) - -end subroutine hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine hydrogenflux_cahnhilliard_getChemPotAndItsTangent(ChemPot,dChemPot_dCh,Ch,ip,el) - use numerics, only: & - hydrogenBoundPenalty, & - hydrogenPolyOrder - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Ch - real(pReal), intent(out) :: & - ChemPot, & - dChemPot_dCh - real(pReal) :: & - kBT, KPot, dKPot_dCh - integer(pInt) :: & - o - - ChemPot = hydrogenflux_cahnhilliard_getFormationEnergy(ip,el) - dChemPot_dCh = 0.0_pReal - kBT = hydrogenflux_cahnhilliard_getEntropicCoeff(ip,el) - do o = 1_pInt, hydrogenPolyOrder - ChemPot = ChemPot + kBT*((2.0_pReal*Ch - 1.0_pReal)**real(2_pInt*o-1_pInt,pReal))/ & - real(2_pInt*o-1_pInt,pReal) - dChemPot_dCh = dChemPot_dCh + 2.0_pReal*kBT*(2.0_pReal*Ch - 1.0_pReal)**real(2_pInt*o-2_pInt,pReal) - enddo - - call hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCh, Ch, ip, el) - ChemPot = ChemPot + KPot - dChemPot_dCh = dChemPot_dCh + dKPot_dCh - - if (Ch < 0.0_pReal) then - ChemPot = ChemPot - 3.0_pReal*hydrogenBoundPenalty*Ch*Ch - dChemPot_dCh = dChemPot_dCh - 6.0_pReal*hydrogenBoundPenalty*Ch - elseif (Ch > 1.0_pReal) then - ChemPot = ChemPot + 3.0_pReal*hydrogenBoundPenalty*(1.0_pReal - Ch)*(1.0_pReal - Ch) - dChemPot_dCh = dChemPot_dCh - 6.0_pReal*hydrogenBoundPenalty*(1.0_pReal - Ch) - endif - -end subroutine hydrogenflux_cahnhilliard_getChemPotAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief updates hydrogen concentration with solution from Cahn-Hilliard PDE for solute transport -!-------------------------------------------------------------------------------------------------- -subroutine hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate(Ch,Chdot,ip,el) - use material, only: & - mappingHomogenization, & - hydrogenConc, & - hydrogenConcRate, & - hydrogenfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Ch, & - Chdot - integer(pInt) :: & - homog, & - offset - - homog = mappingHomogenization(2,ip,el) - offset = hydrogenfluxMapping(homog)%p(ip,el) - hydrogenConc (homog)%p(offset) = Ch - hydrogenConcRate(homog)%p(offset) = Chdot - -end subroutine hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of hydrogen transport results -!-------------------------------------------------------------------------------------------------- -function hydrogenflux_cahnhilliard_postResults(ip,el) - use material, only: & - mappingHomogenization, & - hydrogenflux_typeInstance, & - hydrogenConc, & - hydrogenfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(hydrogenflux_cahnhilliard_sizePostResults(hydrogenflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & - hydrogenflux_cahnhilliard_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = hydrogenfluxMapping(homog)%p(ip,el) - instance = hydrogenflux_typeInstance(homog) - - c = 0_pInt - hydrogenflux_cahnhilliard_postResults = 0.0_pReal - - do o = 1_pInt,hydrogenflux_cahnhilliard_Noutput(instance) - select case(hydrogenflux_cahnhilliard_outputID(o,instance)) - - case (hydrogenConc_ID) - hydrogenflux_cahnhilliard_postResults(c+1_pInt) = hydrogenConc(homog)%p(offset) - c = c + 1 - end select - enddo -end function hydrogenflux_cahnhilliard_postResults - -end module hydrogenflux_cahnhilliard diff --git a/code/hydrogenflux_isoconc.f90 b/code/hydrogenflux_isoconc.f90 deleted file mode 100644 index 74759d4c3..000000000 --- a/code/hydrogenflux_isoconc.f90 +++ /dev/null @@ -1,63 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for constant hydrogen concentration -!-------------------------------------------------------------------------------------------------- -module hydrogenflux_isoconc - - implicit none - private - - public :: & - hydrogenflux_isoconc_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine hydrogenflux_isoconc_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- hydrogenflux_'//HYDROGENFLUX_isoconc_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (hydrogenflux_type(homog) == HYDROGENFLUX_isoconc_ID) then - NofMyHomog = count(material_homog == homog) - hydrogenfluxState(homog)%sizeState = 0_pInt - hydrogenfluxState(homog)%sizePostResults = 0_pInt - allocate(hydrogenfluxState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) - allocate(hydrogenfluxState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) - allocate(hydrogenfluxState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) - - deallocate(hydrogenConc (homog)%p) - deallocate(hydrogenConcRate(homog)%p) - allocate (hydrogenConc (homog)%p(1), source=hydrogenflux_initialCh(homog)) - allocate (hydrogenConcRate(homog)%p(1), source=0.0_pReal) - - endif myhomog - enddo initializeInstances - - -end subroutine hydrogenflux_isoconc_init - -end module hydrogenflux_isoconc diff --git a/code/kinematics/CMakeLists.txt b/code/kinematics/CMakeLists.txt index 17e1a7dd7..f387c5d31 100644 --- a/code/kinematics/CMakeLists.txt +++ b/code/kinematics/CMakeLists.txt @@ -10,3 +10,8 @@ set (KINEMATICS "kinematics_cleavage_opening" foreach (p ${KINEMATICS}) add_library (${p} MODULE "${p}.f90") endforeach (p) + +# set libraries/modules for linking +foreach (p ${KINEMATICS}) + set (AUX_LIB ${AUX_LIB} ${p}) +endforeach (p) \ No newline at end of file diff --git a/code/kinematics_cleavage_opening.f90 b/code/kinematics_cleavage_opening.f90 deleted file mode 100644 index 945e2d08a..000000000 --- a/code/kinematics_cleavage_opening.f90 +++ /dev/null @@ -1,303 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from opening of cleavage planes -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_cleavage_opening - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_cleavage_opening_sizePostResults, & !< cumulative size of post results - kinematics_cleavage_opening_offset, & !< which kinematics is my current damage mechanism? - kinematics_cleavage_opening_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_cleavage_opening_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_cleavage_opening_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_cleavage_opening_Noutput !< number of outputs per instance of this damage - - integer(pInt), dimension(:), allocatable, private :: & - kinematics_cleavage_opening_totalNcleavage !< total number of cleavage systems - - integer(pInt), dimension(:,:), allocatable, private :: & - kinematics_cleavage_opening_Ncleavage !< number of cleavage systems per family - - real(pReal), dimension(:), allocatable, private :: & - kinematics_cleavage_opening_sdot_0, & - kinematics_cleavage_opening_N - - real(pReal), dimension(:,:), allocatable, private :: & - kinematics_cleavage_opening_critDisp, & - kinematics_cleavage_opening_critLoad - - public :: & - kinematics_cleavage_opening_init, & - kinematics_cleavage_opening_LiAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_cleavage_opening_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_cleavage_opening_label, & - KINEMATICS_cleavage_opening_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - use lattice, only: & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_cleavage_opening_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_cleavage_opening_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_cleavage_opening_offset(material_Nphase), source=0_pInt) - allocate(kinematics_cleavage_opening_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_cleavage_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_cleavage_opening_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_cleavage_opening_ID) & - kinematics_cleavage_opening_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_cleavage_opening_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_output(maxval(phase_Noutput),maxNinstance)) - kinematics_cleavage_opening_output = '' - allocate(kinematics_cleavage_opening_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(kinematics_cleavage_opening_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(kinematics_cleavage_opening_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_totalNcleavage(maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_sdot_0(maxNinstance), source=0.0_pReal) - allocate(kinematics_cleavage_opening_N(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_cleavage_opening_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('anisobrittle_sdot0') - kinematics_cleavage_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisobrittle_ratesensitivity') - kinematics_cleavage_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('ncleavage') ! - Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_CleavageFamilies - kinematics_cleavage_opening_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticaldisplacement') - do j = 1_pInt, Nchunks_CleavageFamilies - kinematics_cleavage_opening_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticalload') - do j = 1_pInt, Nchunks_CleavageFamilies - kinematics_cleavage_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then - instance = kinematics_cleavage_opening_instance(phase) - kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & - min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested - kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance)) - kinematics_cleavage_opening_totalNcleavage(instance) = sum(kinematics_cleavage_opening_Ncleavage(:,instance)) ! how many cleavage systems altogether - if (kinematics_cleavage_opening_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_cleavage_opening_LABEL//')') - if (any(kinematics_cleavage_opening_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//KINEMATICS_cleavage_opening_LABEL//')') - if (any(kinematics_cleavage_opening_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//KINEMATICS_cleavage_opening_LABEL//')') - if (kinematics_cleavage_opening_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_cleavage_opening_LABEL//')') - endif myPhase - enddo sanityChecks - -end subroutine kinematics_cleavage_opening_init - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) - use prec, only: & - tol_math_check - use material, only: & - phaseAt, phasememberAt, & - material_homog, & - damage, & - damageMapping - use lattice, only: & - lattice_Scleavage, & - lattice_Scleavage_v, & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola-Kirchhoff stress - real(pReal), intent(out), dimension(3,3) :: & - Ld !< damage velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) - integer(pInt) :: & - phase, & - constituent, & - instance, & - homog, damageOffset, & - f, i, index_myFamily, k, l, m, n - real(pReal) :: & - traction_d, traction_t, traction_n, traction_crit, & - udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = kinematics_cleavage_opening_instance(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - Ld = 0.0_pReal - dLd_dTstar3333 = 0.0_pReal - do f = 1_pInt,lattice_maxNcleavageFamily - index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family - do i = 1_pInt,kinematics_cleavage_opening_Ncleavage(f,instance) ! process each (active) cleavage system in family - traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) - traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) - traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) - traction_crit = kinematics_cleavage_opening_critLoad(f,instance)* & - damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) - udotd = & - sign(1.0_pReal,traction_d)* & - kinematics_cleavage_opening_sdot_0(instance)* & - (max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) - if (abs(udotd) > tol_math_check) then - Ld = Ld + udotd*lattice_Scleavage(1:3,1:3,1,index_myFamily+i,phase) - dudotd_dt = sign(1.0_pReal,traction_d)*udotd*kinematics_cleavage_opening_N(instance)/ & - max(0.0_pReal, abs(traction_d) - traction_crit) - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotd_dt*lattice_Scleavage(k,l,1,index_myFamily+i,phase)* & - lattice_Scleavage(m,n,1,index_myFamily+i,phase) - endif - - udott = & - sign(1.0_pReal,traction_t)* & - kinematics_cleavage_opening_sdot_0(instance)* & - (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) - if (abs(udott) > tol_math_check) then - Ld = Ld + udott*lattice_Scleavage(1:3,1:3,2,index_myFamily+i,phase) - dudott_dt = sign(1.0_pReal,traction_t)*udott*kinematics_cleavage_opening_N(instance)/ & - max(0.0_pReal, abs(traction_t) - traction_crit) - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudott_dt*lattice_Scleavage(k,l,2,index_myFamily+i,phase)* & - lattice_Scleavage(m,n,2,index_myFamily+i,phase) - endif - - udotn = & - sign(1.0_pReal,traction_n)* & - kinematics_cleavage_opening_sdot_0(instance)* & - (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) - if (abs(udotn) > tol_math_check) then - Ld = Ld + udotn*lattice_Scleavage(1:3,1:3,3,index_myFamily+i,phase) - dudotn_dt = sign(1.0_pReal,traction_n)*udotn*kinematics_cleavage_opening_N(instance)/ & - max(0.0_pReal, abs(traction_n) - traction_crit) - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotn_dt*lattice_Scleavage(k,l,3,index_myFamily+i,phase)* & - lattice_Scleavage(m,n,3,index_myFamily+i,phase) - endif - - enddo - enddo - -end subroutine kinematics_cleavage_opening_LiAndItsTangent - -end module kinematics_cleavage_opening diff --git a/code/kinematics_hydrogen_strain.f90 b/code/kinematics_hydrogen_strain.f90 deleted file mode 100644 index ceb3b1ef3..000000000 --- a/code/kinematics_hydrogen_strain.f90 +++ /dev/null @@ -1,264 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from interstitial hydrogen -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_hydrogen_strain - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_hydrogen_strain_sizePostResults, & !< cumulative size of post results - kinematics_hydrogen_strain_offset, & !< which kinematics is my current damage mechanism? - kinematics_hydrogen_strain_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_hydrogen_strain_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_hydrogen_strain_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_hydrogen_strain_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - kinematics_hydrogen_strain_coeff - - public :: & - kinematics_hydrogen_strain_init, & - kinematics_hydrogen_strain_initialStrain, & - kinematics_hydrogen_strain_LiAndItsTangent, & - kinematics_hydrogen_strain_ChemPotAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_hydrogen_strain_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_hydrogen_strain_label, & - KINEMATICS_hydrogen_strain_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_hydrogen_strain_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_hydrogen_strain_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_hydrogen_strain_offset(material_Nphase), source=0_pInt) - allocate(kinematics_hydrogen_strain_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_hydrogen_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_hydrogen_strain_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_hydrogen_strain_ID) & - kinematics_hydrogen_strain_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_hydrogen_strain_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_hydrogen_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_hydrogen_strain_output(maxval(phase_Noutput),maxNinstance)) - kinematics_hydrogen_strain_output = '' - allocate(kinematics_hydrogen_strain_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_hydrogen_strain_coeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_hydrogen_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_hydrogen_strain_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('hydrogen_strain_coeff') - kinematics_hydrogen_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - -end subroutine kinematics_hydrogen_strain_init - -!-------------------------------------------------------------------------------------------------- -!> @brief report initial hydrogen strain based on current hydrogen conc deviation from -!> equillibrium (0) -!-------------------------------------------------------------------------------------------------- -pure function kinematics_hydrogen_strain_initialStrain(ipc, ip, el) - use math, only: & - math_I3 - use material, only: & - material_phase, & - material_homog, & - hydrogenConc, & - hydrogenfluxMapping - use lattice, only: & - lattice_equilibriumHydrogenConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - kinematics_hydrogen_strain_initialStrain !< initial thermal strain (should be small strain, though) - integer(pInt) :: & - phase, & - homog, offset, instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_hydrogen_strain_instance(phase) - homog = material_homog(ip,el) - offset = hydrogenfluxMapping(homog)%p(ip,el) - - kinematics_hydrogen_strain_initialStrain = & - (hydrogenConc(homog)%p(offset) - lattice_equilibriumHydrogenConcentration(phase)) * & - kinematics_hydrogen_strain_coeff(instance)* math_I3 - -end function kinematics_hydrogen_strain_initialStrain - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_hydrogen_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - hydrogenConc, & - hydrogenConcRate, & - hydrogenfluxMapping - use math, only: & - math_I3 - use lattice, only: & - lattice_equilibriumHydrogenConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out), dimension(3,3) :: & - Li !< thermal velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) - integer(pInt) :: & - phase, & - instance, & - homog, offset - real(pReal) :: & - Ch, ChEq, ChDot - - phase = material_phase(ipc,ip,el) - instance = kinematics_hydrogen_strain_instance(phase) - homog = material_homog(ip,el) - offset = hydrogenfluxMapping(homog)%p(ip,el) - Ch = hydrogenConc(homog)%p(offset) - ChDot = hydrogenConcRate(homog)%p(offset) - ChEq = lattice_equilibriumHydrogenConcentration(phase) - - Li = ChDot*math_I3* & - kinematics_hydrogen_strain_coeff(instance)/ & - (1.0_pReal + kinematics_hydrogen_strain_coeff(instance)*(Ch - ChEq)) - dLi_dTstar3333 = 0.0_pReal - -end subroutine kinematics_hydrogen_strain_LiAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the kinematic contribution to hydrogen chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCh, Tstar_v, Fi0, Fi, ipc, ip, el) - use material, only: & - material_phase - use math, only: & - math_inv33, & - math_mul33x33, & - math_Mandel6to33, & - math_transpose33 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v - real(pReal), intent(in), dimension(3,3) :: & - Fi0, Fi - real(pReal), intent(out) :: & - ChemPot, dChemPot_dCh - integer(pInt) :: & - phase, & - instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_hydrogen_strain_instance(phase) - - ChemPot = -kinematics_hydrogen_strain_coeff(instance)* & - sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & - math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) - dChemPot_dCh = 0.0_pReal - -end subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent - -end module kinematics_hydrogen_strain diff --git a/code/kinematics_slipplane_opening.f90 b/code/kinematics_slipplane_opening.f90 deleted file mode 100644 index 8b49e1cf3..000000000 --- a/code/kinematics_slipplane_opening.f90 +++ /dev/null @@ -1,323 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from opening of slip planes -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_slipplane_opening - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_slipplane_opening_sizePostResults, & !< cumulative size of post results - kinematics_slipplane_opening_offset, & !< which kinematics is my current damage mechanism? - kinematics_slipplane_opening_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_slipplane_opening_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_slipplane_opening_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_slipplane_opening_Noutput !< number of outputs per instance of this damage - - integer(pInt), dimension(:), allocatable, private :: & - kinematics_slipplane_opening_totalNslip !< total number of slip systems - - integer(pInt), dimension(:,:), allocatable, private :: & - kinematics_slipplane_opening_Nslip !< number of slip systems per family - - real(pReal), dimension(:), allocatable, private :: & - kinematics_slipplane_opening_sdot_0, & - kinematics_slipplane_opening_N - - real(pReal), dimension(:,:), allocatable, private :: & - kinematics_slipplane_opening_critPlasticStrain, & - kinematics_slipplane_opening_critLoad - - public :: & - kinematics_slipplane_opening_init, & - kinematics_slipplane_opening_LiAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_slipplane_opening_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_slipplane_opening_label, & - KINEMATICS_slipplane_opening_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - use lattice, only: & - lattice_maxNslipFamily, & - lattice_NslipSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_slipplane_opening_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_slipplane_opening_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_slipplane_opening_offset(material_Nphase), source=0_pInt) - allocate(kinematics_slipplane_opening_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_slipplane_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_slipplane_opening_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_slipplane_opening_ID) & - kinematics_slipplane_opening_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_slipplane_opening_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_slipplane_opening_output(maxval(phase_Noutput),maxNinstance)) - kinematics_slipplane_opening_output = '' - allocate(kinematics_slipplane_opening_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(kinematics_slipplane_opening_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(kinematics_slipplane_opening_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_totalNslip(maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_N(maxNinstance), source=0.0_pReal) - allocate(kinematics_slipplane_opening_sdot_0(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_slipplane_opening_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('nslip') ! - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - kinematics_slipplane_opening_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_sdot0') - kinematics_slipplane_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalplasticstrain') - do j = 1_pInt, Nchunks_SlipFamilies - kinematics_slipplane_opening_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_ratesensitivity') - kinematics_slipplane_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalload') - do j = 1_pInt, Nchunks_SlipFamilies - kinematics_slipplane_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then - instance = kinematics_slipplane_opening_instance(phase) - kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested - kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance)) - kinematics_slipplane_opening_totalNslip(instance) = sum(kinematics_slipplane_opening_Nslip(:,instance)) - if (kinematics_slipplane_opening_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_slipplane_opening_LABEL//')') - if (any(kinematics_slipplane_opening_critPlasticStrain(:,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//KINEMATICS_slipplane_opening_LABEL//')') - if (kinematics_slipplane_opening_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_slipplane_opening_LABEL//')') - endif myPhase - enddo sanityChecks - - -end subroutine kinematics_slipplane_opening_init - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) - use prec, only: & - tol_math_check - use lattice, only: & - lattice_maxNslipFamily, & - lattice_NslipSystem, & - lattice_sd, & - lattice_st, & - lattice_sn - use material, only: & - phaseAt, phasememberAt, & - material_homog, & - damage, & - damageMapping - use math, only: & - math_Plain3333to99, & - math_I3, & - math_identity4th, & - math_symmetric33, & - math_Mandel33to6, & - math_tensorproduct33, & - math_det33, & - math_mul33x33 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola-Kirchhoff stress - real(pReal), intent(out), dimension(3,3) :: & - Ld !< damage velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) - real(pReal), dimension(3,3) :: & - projection_d, projection_t, projection_n !< projection modes 3x3 tensor - real(pReal), dimension(6) :: & - projection_d_v, projection_t_v, projection_n_v !< projection modes 3x3 vector - integer(pInt) :: & - phase, & - constituent, & - instance, & - homog, damageOffset, & - f, i, index_myFamily, k, l, m, n - real(pReal) :: & - traction_d, traction_t, traction_n, traction_crit, & - udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = kinematics_slipplane_opening_instance(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - Ld = 0.0_pReal - dLd_dTstar3333 = 0.0_pReal - do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,phase)) ! at which index starts my family - do i = 1_pInt,kinematics_slipplane_opening_Nslip(f,instance) ! process each (active) slip system in family - projection_d = math_tensorproduct33(lattice_sd(1:3,index_myFamily+i,phase),& - lattice_sn(1:3,index_myFamily+i,phase)) - projection_t = math_tensorproduct33(lattice_st(1:3,index_myFamily+i,phase),& - lattice_sn(1:3,index_myFamily+i,phase)) - projection_n = math_tensorproduct33(lattice_sn(1:3,index_myFamily+i,phase),& - lattice_sn(1:3,index_myFamily+i,phase)) - - projection_d_v(1:6) = math_Mandel33to6(math_symmetric33(projection_d(1:3,1:3))) - projection_t_v(1:6) = math_Mandel33to6(math_symmetric33(projection_t(1:3,1:3))) - projection_n_v(1:6) = math_Mandel33to6(math_symmetric33(projection_n(1:3,1:3))) - - traction_d = dot_product(Tstar_v,projection_d_v(1:6)) - traction_t = dot_product(Tstar_v,projection_t_v(1:6)) - traction_n = dot_product(Tstar_v,projection_n_v(1:6)) - - traction_crit = kinematics_slipplane_opening_critLoad(f,instance)* & - damage(homog)%p(damageOffset) ! degrading critical load carrying capacity by damage - - udotd = & - sign(1.0_pReal,traction_d)* & - kinematics_slipplane_opening_sdot_0(instance)* & - (abs(traction_d)/traction_crit - & - abs(traction_d)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) - if (abs(udotd) > tol_math_check) then - Ld = Ld + udotd*projection_d - dudotd_dt = udotd*kinematics_slipplane_opening_N(instance)/traction_d - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotd_dt*projection_d(k,l)*projection_d(m,n) - endif - - udott = & - sign(1.0_pReal,traction_t)* & - kinematics_slipplane_opening_sdot_0(instance)* & - (abs(traction_t)/traction_crit - & - abs(traction_t)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) - if (abs(udott) > tol_math_check) then - Ld = Ld + udott*projection_t - dudott_dt = udott*kinematics_slipplane_opening_N(instance)/traction_t - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudott_dt*projection_t(k,l)*projection_t(m,n) - endif - udotn = & - kinematics_slipplane_opening_sdot_0(instance)* & - (max(0.0_pReal,traction_n)/traction_crit - & - max(0.0_pReal,traction_n)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) - if (abs(udotn) > tol_math_check) then - Ld = Ld + udotn*projection_n - dudotn_dt = udotn*kinematics_slipplane_opening_N(instance)/traction_n - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotn_dt*projection_n(k,l)*projection_n(m,n) - endif - enddo - enddo - -end subroutine kinematics_slipplane_opening_LiAndItsTangent - -end module kinematics_slipplane_opening diff --git a/code/kinematics_thermal_expansion.f90 b/code/kinematics_thermal_expansion.f90 deleted file mode 100644 index b99c499f3..000000000 --- a/code/kinematics_thermal_expansion.f90 +++ /dev/null @@ -1,228 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from thermal expansion -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_thermal_expansion - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_thermal_expansion_sizePostResults, & !< cumulative size of post results - kinematics_thermal_expansion_offset, & !< which kinematics is my current damage mechanism? - kinematics_thermal_expansion_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_thermal_expansion_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_thermal_expansion_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_thermal_expansion_Noutput !< number of outputs per instance of this damage - -! enum, bind(c) ! ToDo kinematics need state machinery to deal with sizePostResult -! enumerator :: undefined_ID, & ! possible remedy is to decouple having state vars from having output -! thermalexpansionrate_ID ! which means to separate user-defined types tState + tOutput... -! end enum - public :: & - kinematics_thermal_expansion_init, & - kinematics_thermal_expansion_initialStrain, & - kinematics_thermal_expansion_LiAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_thermal_expansion_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_thermal_expansion_label, & - KINEMATICS_thermal_expansion_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - character(len=65536) :: & - tag = '', & - output = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_thermal_expansion_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_thermal_expansion_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_thermal_expansion_offset(material_Nphase), source=0_pInt) - allocate(kinematics_thermal_expansion_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_thermal_expansion_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_thermal_expansion_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_thermal_expansion_ID) & - kinematics_thermal_expansion_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_thermal_expansion_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_thermal_expansion_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_thermal_expansion_output(maxval(phase_Noutput),maxNinstance)) - kinematics_thermal_expansion_output = '' - allocate(kinematics_thermal_expansion_Noutput(maxNinstance), source=0_pInt) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_thermal_expansion_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_thermal_expansion_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key... - select case(tag) -! case ('(output)') -! output = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) ! ...and corresponding output -! select case(output) -! case ('thermalexpansionrate') -! kinematics_thermal_expansion_Noutput(instance) = kinematics_thermal_expansion_Noutput(instance) + 1_pInt -! kinematics_thermal_expansion_outputID(kinematics_thermal_expansion_Noutput(instance),instance) = & -! thermalexpansionrate_ID -! kinematics_thermal_expansion_output(kinematics_thermal_expansion_Noutput(instance),instance) = output -! ToDo add sizePostResult loop afterwards... - - end select - endif; endif - enddo parsingFile - -end subroutine kinematics_thermal_expansion_init - -!-------------------------------------------------------------------------------------------------- -!> @brief report initial thermal strain based on current temperature deviation from reference -!-------------------------------------------------------------------------------------------------- -pure function kinematics_thermal_expansion_initialStrain(ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - temperature, & - thermalMapping - use lattice, only: & - lattice_thermalExpansion33, & - lattice_referenceTemperature - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - kinematics_thermal_expansion_initialStrain !< initial thermal strain (should be small strain, though) - integer(pInt) :: & - phase, & - homog, offset - - phase = material_phase(ipc,ip,el) - homog = material_homog(ip,el) - offset = thermalMapping(homog)%p(ip,el) - - kinematics_thermal_expansion_initialStrain = & - (temperature(homog)%p(offset) - lattice_referenceTemperature(phase)) * & - lattice_thermalExpansion33(1:3,1:3,phase) - -end function kinematics_thermal_expansion_initialStrain - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - temperature, & - temperatureRate, & - thermalMapping - use lattice, only: & - lattice_thermalExpansion33, & - lattice_referenceTemperature - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out), dimension(3,3) :: & - Li !< thermal velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor defined to be zero) - integer(pInt) :: & - phase, & - homog, offset - real(pReal) :: & - T, TRef, TDot - - phase = material_phase(ipc,ip,el) - homog = material_homog(ip,el) - offset = thermalMapping(homog)%p(ip,el) - T = temperature(homog)%p(offset) - TDot = temperatureRate(homog)%p(offset) - TRef = lattice_referenceTemperature(phase) - - Li = TDot* & - lattice_thermalExpansion33(1:3,1:3,phase)/ & - (1.0_pReal + lattice_thermalExpansion33(1:3,1:3,phase)*(T - TRef)) - dLi_dTstar3333 = 0.0_pReal - -end subroutine kinematics_thermal_expansion_LiAndItsTangent - -end module kinematics_thermal_expansion diff --git a/code/kinematics_vacancy_strain.f90 b/code/kinematics_vacancy_strain.f90 deleted file mode 100644 index 899bccd9f..000000000 --- a/code/kinematics_vacancy_strain.f90 +++ /dev/null @@ -1,265 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from vacancy point defects -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_vacancy_strain - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_vacancy_strain_sizePostResults, & !< cumulative size of post results - kinematics_vacancy_strain_offset, & !< which kinematics is my current damage mechanism? - kinematics_vacancy_strain_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_vacancy_strain_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_vacancy_strain_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_vacancy_strain_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - kinematics_vacancy_strain_coeff - - public :: & - kinematics_vacancy_strain_init, & - kinematics_vacancy_strain_initialStrain, & - kinematics_vacancy_strain_LiAndItsTangent, & - kinematics_vacancy_strain_ChemPotAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_vacancy_strain_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_vacancy_strain_label, & - KINEMATICS_vacancy_strain_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_vacancy_strain_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_vacancy_strain_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_vacancy_strain_offset(material_Nphase), source=0_pInt) - allocate(kinematics_vacancy_strain_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_vacancy_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_vacancy_strain_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_vacancy_strain_ID) & - kinematics_vacancy_strain_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_vacancy_strain_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_vacancy_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_vacancy_strain_output(maxval(phase_Noutput),maxNinstance)) - kinematics_vacancy_strain_output = '' - allocate(kinematics_vacancy_strain_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_vacancy_strain_coeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_vacancy_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_vacancy_strain_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('vacancy_strain_coeff') - kinematics_vacancy_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - -end subroutine kinematics_vacancy_strain_init - -!-------------------------------------------------------------------------------------------------- -!> @brief report initial vacancy strain based on current vacancy conc deviation from equillibrium -!-------------------------------------------------------------------------------------------------- -pure function kinematics_vacancy_strain_initialStrain(ipc, ip, el) - use math, only: & - math_I3 - use material, only: & - material_phase, & - material_homog, & - vacancyConc, & - vacancyfluxMapping - use lattice, only: & - lattice_equilibriumVacancyConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - kinematics_vacancy_strain_initialStrain !< initial thermal strain (should be small strain, though) - integer(pInt) :: & - phase, & - homog, offset, instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_vacancy_strain_instance(phase) - homog = material_homog(ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - - kinematics_vacancy_strain_initialStrain = & - (vacancyConc(homog)%p(offset) - lattice_equilibriumVacancyConcentration(phase)) * & - kinematics_vacancy_strain_coeff(instance)* math_I3 - -end function kinematics_vacancy_strain_initialStrain - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_vacancy_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - vacancyConc, & - vacancyConcRate, & - vacancyfluxMapping - use math, only: & - math_I3 - use lattice, only: & - lattice_equilibriumVacancyConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out), dimension(3,3) :: & - Li !< thermal velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) - integer(pInt) :: & - phase, & - instance, & - homog, offset - real(pReal) :: & - Cv, CvEq, CvDot - - phase = material_phase(ipc,ip,el) - instance = kinematics_vacancy_strain_instance(phase) - homog = material_homog(ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - - Cv = vacancyConc(homog)%p(offset) - CvDot = vacancyConcRate(homog)%p(offset) - CvEq = lattice_equilibriumvacancyConcentration(phase) - - Li = CvDot*math_I3* & - kinematics_vacancy_strain_coeff(instance)/ & - (1.0_pReal + kinematics_vacancy_strain_coeff(instance)*(Cv - CvEq)) - - dLi_dTstar3333 = 0.0_pReal - -end subroutine kinematics_vacancy_strain_LiAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the kinematic contribution to vacancy chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_vacancy_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCv, Tstar_v, Fi0, Fi, ipc, ip, el) - use material, only: & - material_phase - use math, only: & - math_inv33, & - math_mul33x33, & - math_Mandel6to33, & - math_transpose33 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v - real(pReal), intent(in), dimension(3,3) :: & - Fi0, Fi - real(pReal), intent(out) :: & - ChemPot, dChemPot_dCv - integer(pInt) :: & - phase, & - instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_vacancy_strain_instance(phase) - - ChemPot = -kinematics_vacancy_strain_coeff(instance)* & - sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & - math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) - dChemPot_dCv = 0.0_pReal - -end subroutine kinematics_vacancy_strain_ChemPotAndItsTangent - -end module kinematics_vacancy_strain diff --git a/code/plastic/CMakeLists.txt b/code/plastic/CMakeLists.txt index 6c65481c3..3b6593c07 100644 --- a/code/plastic/CMakeLists.txt +++ b/code/plastic/CMakeLists.txt @@ -9,8 +9,13 @@ set (PLASTIC "plastic_dislotwin" "plastic_none" "plastic_phenoplus" ) - + # compile module foreach (p ${PLASTIC}) add_library (${p} MODULE "${p}.f90") endforeach (p) + +# set libraries/modules for linking +foreach (p ${PLASTIC}) + set (AUX_LIB ${AUX_LIB} ${p}) +endforeach (p) \ No newline at end of file diff --git a/code/plastic_disloUCLA.f90 b/code/plastic_disloUCLA.f90 deleted file mode 100644 index d95a5e6a4..000000000 --- a/code/plastic_disloUCLA.f90 +++ /dev/null @@ -1,2116 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author David Cereceda, Lawrence Livermore National Laboratory -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incoprorating dislocation and twinning physics -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module plastic_disloUCLA - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_disloUCLA_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_disloUCLA_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_disloUCLA_output !< name of each post result output - - real(pReal), parameter, private :: & - kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_disloUCLA_Noutput !< number of outputs per instance of this plasticity - - integer(pInt), dimension(:), allocatable, private :: & - plastic_disloUCLA_totalNslip, & !< total number of active slip systems for each instance - plastic_disloUCLA_totalNtwin !< total number of active twin systems for each instance - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_disloUCLA_Nslip, & !< number of active slip systems for each family and instance - plastic_disloUCLA_Ntwin !< number of active twin systems for each family and instance - - real(pReal), dimension(:), allocatable, private :: & - plastic_disloUCLA_CAtomicVolume, & !< atomic volume in Bugers vector unit - plastic_disloUCLA_D0, & !< prefactor for self-diffusion coefficient - plastic_disloUCLA_Qsd, & !< activation energy for dislocation climb - plastic_disloUCLA_GrainSize, & !< grain size - plastic_disloUCLA_MaxTwinFraction, & !< maximum allowed total twin volume fraction - plastic_disloUCLA_CEdgeDipMinDistance, & !< - plastic_disloUCLA_Cmfptwin, & !< - plastic_disloUCLA_Cthresholdtwin, & !< - plastic_disloUCLA_SolidSolutionStrength, & !< Strength due to elements in solid solution - plastic_disloUCLA_L0, & !< Length of twin nuclei in Burgers vectors - plastic_disloUCLA_xc, & !< critical distance for formation of twin nucleus - plastic_disloUCLA_VcrossSlip, & !< cross slip volume - plastic_disloUCLA_SFE_0K, & !< stacking fault energy at zero K - plastic_disloUCLA_dSFE_dT, & !< temperature dependance of stacking fault energy - plastic_disloUCLA_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful - plastic_disloUCLA_aTolRho, & !< absolute tolerance for integration of dislocation density - plastic_disloUCLA_aTolTwinFrac !< absolute tolerance for integration of twin volume fraction - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_disloUCLA_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_disloUCLA_Ctwin3333 !< twin elasticity matrix for each instance - real(pReal), dimension(:,:), allocatable, private :: & - plastic_disloUCLA_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance - plastic_disloUCLA_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance - plastic_disloUCLA_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance - plastic_disloUCLA_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance - plastic_disloUCLA_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance - plastic_disloUCLA_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance - plastic_disloUCLA_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance - plastic_disloUCLA_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance - plastic_disloUCLA_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance - plastic_disloUCLA_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance - plastic_disloUCLA_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance - plastic_disloUCLA_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance - plastic_disloUCLA_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance - plastic_disloUCLA_tau_r, & !< stress to bring partial close together for each twin system and instance - plastic_disloUCLA_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance - plastic_disloUCLA_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance - plastic_disloUCLA_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_disloUCLA_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_disloUCLA_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance - plastic_disloUCLA_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance - plastic_disloUCLA_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_disloUCLA_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance - plastic_disloUCLA_pPerSlipFamily, & !< p-exponent in glide velocity - plastic_disloUCLA_qPerSlipFamily, & !< q-exponent in glide velocity - !* mobility law parameters - plastic_disloUCLA_kinkheight, & !< height of the kink pair - plastic_disloUCLA_omega, & !< attempt frequency for kink pair nucleation - plastic_disloUCLA_kinkwidth, & !< width of the kink pair - plastic_disloUCLA_dislolength, & !< dislocation length (lamda) - plastic_disloUCLA_friction, & !< friction coeff. B (kMC) - !* - plastic_disloUCLA_rPerTwinFamily, & !< r-exponent in twin nucleation rate - plastic_disloUCLA_nonSchmidCoeff !< non-Schmid coefficients (bcc) - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_disloUCLA_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance - plastic_disloUCLA_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance - plastic_disloUCLA_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance - plastic_disloUCLA_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance - plastic_disloUCLA_forestProjectionEdge !< matrix of forest projections of edge dislocations for each instance - - enum, bind(c) - enumerator :: undefined_ID, & - edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID, & - twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_disloUCLA_outputID !< ID of each post result output - - type, private :: tDisloUCLAState - real(pReal), pointer, dimension(:,:) :: & - rhoEdge, & - rhoEdgeDip, & - accshear_slip, & - twinFraction, & - accshear_twin, & - invLambdaSlip, & - invLambdaSlipTwin, & - invLambdaTwin, & - mfp_slip, & - mfp_twin, & - threshold_stress_slip, & - threshold_stress_twin, & - twinVolume - end type - type(tDisloUCLAState ), allocatable, dimension(:), private :: & - state, & - state0, & - dotState - - public :: & - plastic_disloUCLA_init, & - plastic_disloUCLA_homogenizedC, & - plastic_disloUCLA_microstructure, & - plastic_disloUCLA_LpAndItsTangent, & - plastic_disloUCLA_dotState, & - plastic_disloUCLA_postResults - private :: & - plastic_disloUCLA_stateInit, & - plastic_disloUCLA_aTolState - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333, & - math_mul3x3 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_DISLOUCLA_label, & - PLASTICITY_DISLOUCLA_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,& - f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & - offset_slip, index_myFamily, index_otherFamily, & - startIndex, endIndex - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOUCLA_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOUCLA_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_disloUCLA_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(plastic_disloUCLA_output(maxval(phase_Noutput),maxNinstance)) - plastic_disloUCLA_output = '' - allocate(plastic_disloUCLA_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_disloUCLA_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_CAtomicVolume(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_D0(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Qsd(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_GrainSize(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_MaxTwinFraction(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Cmfptwin(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Cthresholdtwin(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_SolidSolutionStrength(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_L0(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_xc(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_VcrossSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_aTolRho(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_aTolTwinFrac(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_SFE_0K(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_dSFE_dT(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default - allocate(plastic_disloUCLA_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_kinkheight(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_omega(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_kinkwidth(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_dislolength(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_friction(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_disloUCLA_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_disloUCLA_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), source=0.0_pReal) - - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - if(allocated(tempPerTwin)) deallocate(tempPerTwin) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - allocate(tempPerTwin(Nchunks_TwinFamilies)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('edge_density') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_density_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('dipole_density') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = dipole_density_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_slip','shearrate_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('edge_dipole_distance') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_dipole_distance_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stress_exponent') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = stress_exponent_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('twin_fraction') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = twin_fraction_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_twin','shearrate_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip system families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - plastic_disloUCLA_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip',& - 'kink_height','omega','kink_width','dislolength','friction_coeff') - do j = 1_pInt, Nchunks_SlipFamilies - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('rhoedge0') - plastic_disloUCLA_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('rhoedgedip0') - plastic_disloUCLA_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('slipburgers') - plastic_disloUCLA_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('qedge') - plastic_disloUCLA_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('v0') - plastic_disloUCLA_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('clambdaslip') - plastic_disloUCLA_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau_peierls') - if (lattice_structure(phase) /= LATTICE_bcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOUCLA_label//')') - plastic_disloUCLA_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('p_slip') - plastic_disloUCLA_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('q_slip') - plastic_disloUCLA_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('kink_height') - plastic_disloUCLA_kinkheight(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('omega') - plastic_disloUCLA_omega(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('kink_width') - plastic_disloUCLA_kinkwidth(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('dislolength') - plastic_disloUCLA_dislolength(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('friction_coeff') - plastic_disloUCLA_friction(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on slip number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_disloUCLA_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ndot0','twinsize','twinburgers','r_twin') - do j = 1_pInt, Nchunks_TwinFamilies - tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('ndot0') - if (lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOUCLA_label//')') - plastic_disloUCLA_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinsize') - plastic_disloUCLA_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinburgers') - plastic_disloUCLA_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('r_twin') - plastic_disloUCLA_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip','interactionslipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_disloUCLA_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin','interactionsliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_disloUCLA_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip','interactiontwinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_disloUCLA_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin','interactiontwintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_disloUCLA_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt,Nchunks_nonSchmid - plastic_disloUCLA_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin systems - case ('grainsize') - plastic_disloUCLA_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('maxtwinfraction') - plastic_disloUCLA_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('d0') - plastic_disloUCLA_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('qsd') - plastic_disloUCLA_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_rho') - plastic_disloUCLA_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_disloUCLA_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cmfptwin') - plastic_disloUCLA_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cthresholdtwin') - plastic_disloUCLA_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('solidsolutionstrength') - plastic_disloUCLA_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('l0') - plastic_disloUCLA_L0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('xc') - plastic_disloUCLA_xc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('vcrossslip') - plastic_disloUCLA_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cedgedipmindistance') - plastic_disloUCLA_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('catomicvolume') - plastic_disloUCLA_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('sfe_0k') - plastic_disloUCLA_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dsfe_dt') - plastic_disloUCLA_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dipoleformationfactor') - plastic_disloUCLA_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then - instance = phase_plasticityInstance(phase) - if (sum(plastic_disloUCLA_Nslip(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOUCLA_label//')') - if (sum(plastic_disloUCLA_Ntwin(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOUCLA_label//')') - do f = 1_pInt,lattice_maxNslipFamily - if (plastic_disloUCLA_Nslip(f,instance) > 0_pInt) then - if (plastic_disloUCLA_rhoEdge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_rhoEdgeDip0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_v0PerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOUCLA_label//')') - endif - enddo - do f = 1_pInt,lattice_maxNtwinFamily - if (plastic_disloUCLA_Ntwin(f,instance) > 0_pInt) then - if (plastic_disloUCLA_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='ndot0 ('//PLASTICITY_DISLOUCLA_label//')') - endif - enddo - if (plastic_disloUCLA_CAtomicVolume(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_D0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_Qsd(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOUCLA_label//')') - if (sum(plastic_disloUCLA_Ntwin(:,instance)) > 0_pInt) then - if (abs(plastic_disloUCLA_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & - abs(plastic_disloUCLA_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & - lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_aTolTwinFrac(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOUCLA_label//')') - endif - if (abs(plastic_disloUCLA_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & - plastic_disloUCLA_dipoleFormationFactor(instance) /= 1.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOUCLA_label//')') - -!-------------------------------------------------------------------------------------------------- -! Determine total number of active slip or twin systems - plastic_disloUCLA_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_disloUCLA_Nslip(:,instance)) - plastic_disloUCLA_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_disloUCLA_Ntwin(:,instance)) - plastic_disloUCLA_totalNslip(instance) = sum(plastic_disloUCLA_Nslip(:,instance)) - plastic_disloUCLA_totalNtwin(instance) = sum(plastic_disloUCLA_Ntwin(:,instance)) - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - maxTotalNslip = maxval(plastic_disloUCLA_totalNslip) - maxTotalNtwin = maxval(plastic_disloUCLA_totalNtwin) - - allocate(plastic_disloUCLA_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_tau_r(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) - - allocate(plastic_disloUCLA_interactionMatrix_SlipSlip(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from slip activity - maxval(plastic_disloUCLA_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_interactionMatrix_SlipTwin(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from twin activity - maxval(plastic_disloUCLA_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_interactionMatrix_TwinSlip(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_disloUCLA_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_interactionMatrix_TwinTwin(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_disloUCLA_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & - source=0.0_pReal) - allocate(plastic_disloUCLA_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) - - allocate(state(maxNinstance)) - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - myPhase2: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then - NofMyPhase=count(material_phase==phase) - instance = phase_plasticityInstance(phase) - - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputs: do o = 1_pInt,plastic_disloUCLA_Noutput(instance) - select case(plastic_disloUCLA_outputID(o,instance)) - case(edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID & - ) - mySize = ns - case(twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID & - ) - mySize = nt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - plastic_disloUCLA_sizePostResult(o,instance) = mySize - plastic_disloUCLA_sizePostResults(instance) = plastic_disloUCLA_sizePostResults(instance) + mySize - endif - enddo outputs - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - - sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & - + int(size(['twinFraction','accsheartwin']),pInt) * nt - sizeDeltaState = 0_pInt - sizeState = sizeDotState & - + int(size(['invLambdaSlip ','invLambdaSlipTwin ',& - 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & - + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& - 'twinVolume ']),pInt) * nt - - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_disloUCLA_sizePostResults(instance) - plasticState(phase)%nSlip = plastic_disloucla_totalNslip(instance) - plasticState(phase)%nTwin = plastic_disloucla_totalNtwin(instance) - plasticState(phase)%nTrans= 0_pInt - allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - offset_slip = 2_pInt*plasticState(phase)%nSlip - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) - !* Process slip related parameters ------------------------------------------------ - - mySlipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - mySlipSystems: do j = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - - !* Burgers vector, - ! dislocation velocity prefactor, - ! mean free path prefactor, - ! and minimum dipole distance - - plastic_disloUCLA_burgersPerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_burgersPerSlipFamily(f,instance) - - plastic_disloUCLA_QedgePerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_QedgePerSlipFamily(f,instance) - - plastic_disloUCLA_v0PerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_v0PerSlipFamily(f,instance) - - plastic_disloUCLA_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_CLambdaSlipPerSlipFamily(f,instance) - - !* Calculation of forest projections for edge dislocations - !* Interaction matrices - - otherSlipFamilies: do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) - otherSlipSystems: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) - plastic_disloUCLA_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & - abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & - lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) - plastic_disloUCLA_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo otherSlipSystems; enddo otherSlipFamilies - - otherTwinFamilies: do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) - otherTwinSystems: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) - plastic_disloUCLA_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo otherTwinSystems; enddo otherTwinFamilies - - enddo mySlipSystems - enddo mySlipFamilies - - !* Process twin related parameters ------------------------------------------------ - - myTwinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(plastic_disloUCLA_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list - myTwinSystems: do j = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) - - !* Burgers vector, - ! nucleation rate prefactor, - ! and twin size - - plastic_disloUCLA_burgersPerTwinSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_burgersPerTwinFamily(f,instance) - - plastic_disloUCLA_Ndot0PerTwinSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) - - plastic_disloUCLA_twinsizePerTwinSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_twinsizePerTwinFamily(f,instance) - - !* Rotate twin elasticity matrices - index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list - do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt - do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt - plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & - plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & - lattice_C3333(p,q,r,s,instance) * & - lattice_Qtwin(l,p,index_otherFamily+j,phase) * & - lattice_Qtwin(m,q,index_otherFamily+j,phase) * & - lattice_Qtwin(n,r,index_otherFamily+j,phase) * & - lattice_Qtwin(o,s,index_otherFamily+j,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo; enddo - plastic_disloUCLA_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & - math_Mandel3333to66(plastic_disloUCLA_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) - - !* Interaction matrices - otherSlipFamilies2: do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) - otherSlipSystems2: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) - plastic_disloUCLA_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo otherSlipSystems2; enddo otherSlipFamilies2 - - otherTwinFamilies2: do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) - otherTwinSystems2: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) - plastic_disloUCLA_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo otherTwinSystems2; enddo otherTwinFamilies2 - - enddo myTwinSystems - enddo myTwinFamilies - - startIndex=1_pInt - endIndex=ns - state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+ns - state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+ns - state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+nt - state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+nt - state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+ns - state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) - - call plastic_disloUCLA_stateInit(phase,instance) - call plastic_disloUCLA_aTolState(phase,instance) - endif myPhase2 - - enddo initializeInstances - -end subroutine plastic_disloUCLA_init - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_stateInit(ph,instance) - use math, only: & - pi - use lattice, only: & - lattice_maxNslipFamily, & - lattice_mu - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - real(pReal), dimension(plasticState(ph)%sizeState) :: tempState - - integer(pInt) :: i,j,f,ns,nt, index_myFamily - real(pReal), dimension(plastic_disloUCLA_totalNslip(instance)) :: & - rhoEdge0, & - rhoEdgeDip0, & - invLambdaSlip0, & - MeanFreePathSlip0, & - tauSlipThreshold0 - real(pReal), dimension(plastic_disloUCLA_totalNtwin(instance)) :: & - MeanFreePathTwin0,TwinVolume0 - tempState = 0.0_pReal - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables - do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - rhoEdge0(index_myFamily+1_pInt: & - index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & - plastic_disloUCLA_rhoEdge0(f,instance) - rhoEdgeDip0(index_myFamily+1_pInt: & - index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & - plastic_disloUCLA_rhoEdgeDip0(f,instance) - enddo - - tempState(1_pInt:ns) = rhoEdge0 - tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent slip microstructural variables - forall (i = 1_pInt:ns) & - invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_forestProjectionEdge(1:ns,i,instance)))/ & - plastic_disloUCLA_CLambdaSlipPerSlipSystem(i,instance) - tempState(3_pInt*ns+2_pInt*nt+1:4_pInt*ns+2_pInt*nt) = invLambdaSlip0 - - forall (i = 1_pInt:ns) & - MeanFreePathSlip0(i) = & - plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_disloUCLA_GrainSize(instance)) - tempState(5_pInt*ns+3_pInt*nt+1:6_pInt*ns+3_pInt*nt) = MeanFreePathSlip0 - - forall (i = 1_pInt:ns) & - tauSlipThreshold0(i) = & - lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(i,instance) * & - sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_interactionMatrix_SlipSlip(i,1:ns,instance))) - - tempState(6_pInt*ns+4_pInt*nt+1:7_pInt*ns+4_pInt*nt) = tauSlipThreshold0 - - - -!-------------------------------------------------------------------------------------------------- -! initialize dependent twin microstructural variables - forall (j = 1_pInt:nt) & - MeanFreePathTwin0(j) = plastic_disloUCLA_GrainSize(instance) - tempState(6_pInt*ns+3_pInt*nt+1_pInt:6_pInt*ns+4_pInt*nt) = MeanFreePathTwin0 - - forall (j = 1_pInt:nt) & - TwinVolume0(j) = & - (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) - tempState(7_pInt*ns+5_pInt*nt+1_pInt:7_pInt*ns+6_pInt*nt) = TwinVolume0 - -plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) - -end subroutine plastic_disloUCLA_stateInit - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - ph, & - instance ! number specifying the current instance of the plasticity - - ! Tolerance state for dislocation densities - plasticState(ph)%aTolState(1_pInt:2_pInt*plastic_disloUCLA_totalNslip(instance)) = & - plastic_disloUCLA_aTolRho(instance) - - ! Tolerance state for accumulated shear due to slip - plasticState(ph)%aTolState(2_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & - 3_pInt*plastic_disloUCLA_totalNslip(instance))=1e6_pReal - - - ! Tolerance state for twin volume fraction - plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & - 3_pInt*plastic_disloUCLA_totalNslip(instance)+& - plastic_disloUCLA_totalNtwin(instance)) = & - plastic_disloUCLA_aTolTwinFrac(instance) - -! Tolerance state for accumulated shear due to twin - plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+ & - plastic_disloUCLA_totalNtwin(instance)+1_pInt: & - 3_pInt*plastic_disloUCLA_totalNslip(instance)+ & - 2_pInt*plastic_disloUCLA_totalNtwin(instance)) = 1e6_pReal - -end subroutine plastic_disloUCLA_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenized elasticity matrix -!-------------------------------------------------------------------------------------------------- -function plastic_disloUCLA_homogenizedC(ipc,ip,el) - use material, only: & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_C66 - - implicit none - real(pReal), dimension(6,6) :: & - plastic_disloUCLA_homogenizedC - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,i, & - ph, & - of - real(pReal) :: sumf - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - !* Homogenized elasticity matrix - plastic_disloUCLA_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) - do i=1_pInt,nt - plastic_disloUCLA_homogenizedC = plastic_disloUCLA_homogenizedC & - + state(instance)%twinFraction(i,of)*plastic_disloUCLA_Ctwin66(1:6,1:6,i,instance) - enddo - -end function plastic_disloUCLA_homogenizedC - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_microstructure(temperature,ipc,ip,el) - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - phaseAt, phasememberAt - use lattice, only: & - lattice_mu, & - lattice_nu - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - temperature !< temperature at IP - - integer(pInt) :: & - instance, & - ns,nt,s,t, & - ph, & - of - real(pReal) :: & - sumf,sfe,x0 - real(pReal), dimension(plastic_disloUCLA_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Stacking fault energy - sfe = plastic_disloUCLA_SFE_0K(instance) + & - plastic_disloUCLA_dSFE_dT(instance) * Temperature - - !* rescaled twin volume fraction for topology - forall (t = 1_pInt:nt) & - fOverStacksize(t) = & - state(instance)%twinFraction(t,of)/plastic_disloUCLA_twinsizePerTwinSystem(t,instance) - - !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation - forall (s = 1_pInt:ns) & - state(instance)%invLambdaSlip(s,of) = & - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_disloUCLA_forestProjectionEdge(1:ns,s,instance)))/ & - plastic_disloUCLA_CLambdaSlipPerSlipSystem(s,instance) - !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation - !$OMP CRITICAL (evilmatmul) - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal - if (nt > 0_pInt .and. ns > 0_pInt) & - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & - matmul(plastic_disloUCLA_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin - !$OMP CRITICAL (evilmatmul) - if (nt > 0_pInt) & - state(instance)%invLambdaTwin(1_pInt:nt,of) = & - matmul(plastic_disloUCLA_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* mean free path between 2 obstacles seen by a moving dislocation - do s = 1_pInt,ns - if (nt > 0_pInt) then - state(instance)%mfp_slip(s,of) = & - plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+plastic_disloUCLA_GrainSize(instance)*& - (state(instance)%invLambdaSlip(s,of)+state(instance)%invLambdaSlipTwin(s,of))) - else - state(instance)%mfp_slip(s,of) = & - plastic_disloUCLA_GrainSize(instance)/& - (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) - endif - enddo - - !* mean free path between 2 obstacles seen by a growing twin - forall (t = 1_pInt:nt) & - state(instance)%mfp_twin(t,of) = & - (plastic_disloUCLA_Cmfptwin(instance)*plastic_disloUCLA_GrainSize(instance))/& - (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*state(instance)%invLambdaTwin(t,of)) - - !* threshold stress for dislocation motion - forall (s = 1_pInt:ns) & - state(instance)%threshold_stress_slip(s,of) = & - lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(s,instance)*& - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_disloUCLA_interactionMatrix_SlipSlip(s,1:ns,instance))) - - !* threshold stress for growing twin - forall (t = 1_pInt:nt) & - state(instance)%threshold_stress_twin(t,of) = & - plastic_disloUCLA_Cthresholdtwin(instance)*& - (sfe/(3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance))+& - 3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& - (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(t,instance))) - - !* final twin volume after growth - forall (t = 1_pInt:nt) & - state(instance)%twinVolume(t,of) = & - (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(t,instance)*state(instance)%mfp_twin(t,of)**(2.0_pReal) - - !* equilibrium seperation of partial dislocations - do t = 1_pInt,nt - x0 = lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& - (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) - plastic_disloUCLA_tau_r(t,instance)= & - lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& - (1/(x0+plastic_disloUCLA_xc(instance))+cos(pi/3.0_pReal)/x0) !!! used where?? - enddo - -end subroutine plastic_disloUCLA_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - math_Plain3333to99, & - math_Mandel6to33, & - math_Mandel33to6, & - math_spectralDecompositionSym33, & - math_symmetric33, & - math_mul33x3 - use material, only: & - material_phase, & - phase_plasticityInstance, & - !plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily,& - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid, & - lattice_shearTwin, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - integer(pInt), intent(in) :: ipc,ip,el - real(pReal), intent(in) :: Temperature - real(pReal), dimension(6), intent(in) :: Tstar_v - real(pReal), dimension(3,3), intent(out) :: Lp - real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 - - integer(pInt) :: instance,ph,of,ns,nt,f,i,j,k,l,m,n,index_myFamily,s1,s2 - real(pReal) :: sumf,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0, & - tau_slip_pos,tau_slip_neg,vel_slip,dvel_slip,& - dgdot_dtauslip_pos,dgdot_dtauslip_neg,dgdot_dtautwin,tau_twin,gdot_twin,stressRatio - real(pReal), dimension(3,3,2) :: & - nonSchmid_tensor - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar3333 - real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip_pos,gdot_slip_neg - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Dislocation glide part - gdot_slip_pos = 0.0_pReal - gdot_slip_neg = 0.0_pReal - dgdot_dtauslip_pos = 0.0_pReal - dgdot_dtauslip_neg = 0.0_pReal - - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j+1_pInt - !* Boltzmann ratio - BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& - plastic_disloUCLA_v0PerSlipSystem(j,instance) - !* Resolved shear stress on slip system - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k, index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) - enddo nonSchmidSystems - - significantPostitiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratio - stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_pos & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_pos(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_pos) - - !* Derivatives of shear rates - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_pos & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_pos & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - dgdot_dtauslip_pos = DotGamma0 * dvel_slip - - endif significantPostitiveStress - significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratio - stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_neg & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_neg(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_neg) - - !* Derivatives of shear rates - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_neg & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_neg & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - - dgdot_dtauslip_neg = DotGamma0 * dvel_slip - - endif significantNegativeStress - !* Plastic velocity gradient for dislocation glide - Lp = Lp + (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + (dgdot_dtauslip_pos*nonSchmid_tensor(m,n,1)+& - dgdot_dtauslip_neg*nonSchmid_tensor(m,n,2))*0.5_pReal*& - lattice_Sslip(k,l,1,index_myFamily+i,ph) - enddo slipSystems - enddo slipFamilies - -!-------------------------------------------------------------------------------------------------- -! correct Lp and dLp_dTstar3333 for twinned fraction - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - Lp = Lp * (1.0_pReal - sumf) - dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf) - -!-------------------------------------------------------------------------------------------------- -! Mechanical twinning part - gdot_twin = 0.0_pReal - dgdot_dtautwin = 0.0_pReal - j = 0_pInt - twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) - j = j+1_pInt - !* Resolved shear stress on twin system - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_twin > tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then - Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive gdot_slip_pos (= gdot_slip_neg) - abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) - else - Ndot0=0.0_pReal - end if - case default - Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) - end select - gdot_twin = & - (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) - dgdot_dtautwin = ((gdot_twin*plastic_disloUCLA_rPerTwinFamily(f,instance))/tau_twin)*StressRatio_r - endif - - !* Plastic velocity gradient for mechanical twinning - Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin*& - lattice_Stwin(k,l,index_myFamily+i,ph)*& - lattice_Stwin(m,n,index_myFamily+i,ph) - enddo twinSystems - enddo twinFamilies - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - -end subroutine plastic_disloUCLA_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_dotState(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid, & - lattice_sheartwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,f,i,j,k,index_myFamily,s1,s2, & - ph, & - of - real(pReal) :: & - sumf, & - stressRatio_p,& - BoltzmannRatio,& - DotGamma0,& - stressRatio, & - EdgeDipMinDistance,& - AtomicVolume,& - VacancyDiffusion,& - StressRatio_r,& - Ndot0,& - tau_slip_pos,& - tau_slip_neg,& - DotRhoMultiplication,& - EdgeDipDistance, & - DotRhoEdgeDipAnnihilation, & - DotRhoEdgeEdgeAnnihilation, & - ClimbVelocity, & - DotRhoEdgeDipClimb, & - DotRhoDipFormation, & - tau_twin, & - vel_slip, & - gdot_slip - real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip_pos, gdot_slip_neg - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - plasticState(ph)%dotState(:,of) = 0.0_pReal - - !* Dislocation density evolution - gdot_slip_pos = 0.0_pReal - gdot_slip_neg = 0.0_pReal - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j+1_pInt - !* Boltzmann ratio - BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& - plastic_disloUCLA_v0PerSlipSystem(j,instance) - !* Resolved shear stress on slip system - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - - significantPositiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_pos & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_pos(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_pos) - endif significantPositiveStress - significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_neg & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_neg(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_neg) - endif significantNegativeStress - gdot_slip = (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal - !* Multiplication - DotRhoMultiplication = abs(gdot_slip)/& - (plastic_disloUCLA_burgersPerSlipSystem(j,instance)* & - state(instance)%mfp_slip(j,of)) - - !* Dipole formation - EdgeDipMinDistance = & - plastic_disloUCLA_CEdgeDipMinDistance(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance) - if (abs(tau_slip_pos) <= tiny(0.0_pReal)) then - DotRhoDipFormation = 0.0_pReal - else - EdgeDipDistance = & - (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(tau_slip_pos)) - if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) - if (EdgeDipDistance tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then - Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) - abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) - else - Ndot0=0.0_pReal - end if - case default - Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) - end select - - dotState(instance)%twinFraction(j, of) = & - (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*& - state(instance)%twinVolume(j, of)*Ndot0*exp(-StressRatio_r) - !* Dotstate for accumulated shear due to twin - dotState(instance)%accshear_twin(j,of) = dotState(ph)%twinFraction(j,of) * & - lattice_sheartwin(index_myfamily+i,ph) - endif - enddo twinSystems - enddo twinFamilies - -end subroutine plastic_disloUCLA_dotState - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_disloUCLA_postResults(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance,& - !plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid, & - lattice_shearTwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(plastic_disloUCLA_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_disloUCLA_postResults - - integer(pInt) :: & - instance,& - ns,nt,& - f,o,i,c,j,k,index_myFamily,& - s1,s2, & - ph, & - of - real(pReal) :: sumf,tau_twin,StressRatio_p,StressRatio_pminus1,& - BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0,stressRatio - real(pReal) :: dvel_slip, vel_slip - real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip_pos,dgdot_dtauslip_pos,tau_slip_pos,gdot_slip_neg,dgdot_dtauslip_neg,tau_slip_neg - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(ph)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Required output - c = 0_pInt - plastic_disloUCLA_postResults = 0.0_pReal - - do o = 1_pInt,plastic_disloUCLA_Noutput(instance) - select case(plastic_disloUCLA_outputID(o,instance)) - - case (edge_density_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) - c = c + ns - case (dipole_density_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) - c = c + ns - case (shear_rate_slip_ID,shear_rate_twin_ID,stress_exponent_ID) - gdot_slip_pos = 0.0_pReal - gdot_slip_neg = 0.0_pReal - dgdot_dtauslip_pos = 0.0_pReal - dgdot_dtauslip_neg = 0.0_pReal - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j + 1_pInt - !* Boltzmann ratio - BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& - plastic_disloUCLA_v0PerSlipSystem(j,instance) - !* Resolved shear stress on slip system - tau_slip_pos(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - tau_slip_neg(j) = tau_slip_pos(j) - - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - - significantPositiveTau: if((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then - !* Stress ratio - stressRatio = ((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_pos(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_pos(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_pos(j)) - !* Derivatives of shear rates - - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_pos(j) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_pos(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - - dgdot_dtauslip_pos(j) = DotGamma0 * dvel_slip - - endif significantPositiveTau - significantNegativeTau: if((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_neg(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_neg(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_neg(j)) - !* Derivatives of shear rates - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_neg(j) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_neg(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - - - dgdot_dtauslip_neg(j) = DotGamma0 * dvel_slip - - endif significantNegativeTau - enddo slipSystems - enddo slipFamilies - - if (plastic_disloUCLA_outputID(o,instance) == shear_rate_slip_ID) then - plastic_disloUCLA_postResults(c+1:c+ns) = (gdot_slip_pos + gdot_slip_neg)*0.5_pReal - c = c + ns - elseif (plastic_disloUCLA_outputID(o,instance) == shear_rate_twin_ID) then - if (nt > 0_pInt) then - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1,plastic_disloUCLA_Ntwin(f,instance) - j = j + 1_pInt - - !* Resolved shear stress on twin system - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - !* Stress ratios - StressRatio_r = (state(instance)%threshold_stress_twin(j, of)/ & - tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) - - !* Shear rates due to twin - if ( tau_twin > 0.0_pReal ) then - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then - Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) - abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_disloUCLA_L0(instance)*& - plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) - else - Ndot0=0.0_pReal - end if - - case default - Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) - end select - plastic_disloUCLA_postResults(c+j) = & - (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) - endif - enddo twinSystems1 - enddo twinFamilies1 - endif - c = c + nt - elseif(plastic_disloUCLA_outputID(o,instance) == stress_exponent_ID) then - do j = 1_pInt, ns - if (abs(gdot_slip_pos(j)+gdot_slip_neg(j))<=tiny(0.0_pReal)) then - plastic_disloUCLA_postResults(c+j) = 0.0_pReal - else - plastic_disloUCLA_postResults(c+j) = (tau_slip_pos(j)+tau_slip_neg(j))/& - (gdot_slip_pos(j)+gdot_slip_neg(j))*& - (dgdot_dtauslip_pos(j)+dgdot_dtauslip_neg(j))* 0.5_pReal - endif - enddo - c = c + ns - endif - - case (accumulated_shear_slip_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & - state(instance)%accshear_slip(1_pInt:ns, of) - c = c + ns - case (mfp_slip_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) =& - state(instance)%mfp_slip(1_pInt:ns, of) - c = c + ns - case (resolved_stress_slip_ID) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j + 1_pInt - plastic_disloUCLA_postResults(c+j) =& - dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - enddo slipSystems1; enddo slipFamilies1 - c = c + ns - case (threshold_stress_slip_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & - state(instance)%threshold_stress_slip(1_pInt:ns,of) - c = c + ns - case (edge_dipole_distance_ID) - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems2: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j + 1_pInt - plastic_disloUCLA_postResults(c+j) = & - (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) - plastic_disloUCLA_postResults(c+j)=min(plastic_disloUCLA_postResults(c+j),& - state(instance)%mfp_slip(j,of)) - enddo slipSystems2; enddo slipFamilies2 - c = c + ns - case (twin_fraction_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt, of) - c = c + nt - - case (accumulated_shear_twin_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt, of) - c = c + nt - - case (mfp_twin_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt, of) - c = c + nt - - case (resolved_stress_twin_ID) - if (nt > 0_pInt) then - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) - j = j + 1_pInt - plastic_disloUCLA_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - enddo twinSystems2; enddo twinFamilies2 - endif - c = c + nt - case (threshold_stress_twin_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt, of) - c = c + nt - end select - enddo -end function plastic_disloUCLA_postResults - -end module plastic_disloUCLA diff --git a/code/plastic_dislotwin.f90 b/code/plastic_dislotwin.f90 deleted file mode 100644 index 532312bfd..000000000 --- a/code/plastic_dislotwin.f90 +++ /dev/null @@ -1,2542 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incoprorating dislocation and twinning physics -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module plastic_dislotwin - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_dislotwin_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_dislotwin_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_dislotwin_output !< name of each post result output - - real(pReal), parameter, private :: & - kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_dislotwin_Noutput !< number of outputs per instance of this plasticity - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_dislotwin_totalNslip, & !< total number of active slip systems for each instance - plastic_dislotwin_totalNtwin, & !< total number of active twin systems for each instance - plastic_dislotwin_totalNtrans !< number of active transformation systems - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_dislotwin_Nslip, & !< number of active slip systems for each family and instance - plastic_dislotwin_Ntwin, & !< number of active twin systems for each family and instance - plastic_dislotwin_Ntrans !< number of active transformation systems for each family and instance - - real(pReal), dimension(:), allocatable, private :: & - plastic_dislotwin_CAtomicVolume, & !< atomic volume in Bugers vector unit - plastic_dislotwin_D0, & !< prefactor for self-diffusion coefficient - plastic_dislotwin_Qsd, & !< activation energy for dislocation climb - plastic_dislotwin_GrainSize, & !< grain size - plastic_dislotwin_pShearBand, & !< p-exponent in shearband velocity - plastic_dislotwin_qShearBand, & !< q-exponent in shearband velocity - plastic_dislotwin_MaxTwinFraction, & !< maximum allowed total twin volume fraction - plastic_dislotwin_CEdgeDipMinDistance, & !< - plastic_dislotwin_Cmfptwin, & !< - plastic_dislotwin_Cthresholdtwin, & !< - plastic_dislotwin_SolidSolutionStrength, & !< Strength due to elements in solid solution - plastic_dislotwin_L0_twin, & !< Length of twin nuclei in Burgers vectors - plastic_dislotwin_L0_trans, & !< Length of trans nuclei in Burgers vectors - plastic_dislotwin_xc_twin, & !< critical distance for formation of twin nucleus - plastic_dislotwin_xc_trans, & !< critical distance for formation of trans nucleus - plastic_dislotwin_VcrossSlip, & !< cross slip volume - plastic_dislotwin_sbResistance, & !< value for shearband resistance (might become an internal state variable at some point) - plastic_dislotwin_sbVelocity, & !< value for shearband velocity_0 - plastic_dislotwin_sbQedge, & !< value for shearband systems Qedge - plastic_dislotwin_SFE_0K, & !< stacking fault energy at zero K - plastic_dislotwin_dSFE_dT, & !< temperature dependance of stacking fault energy - plastic_dislotwin_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful - plastic_dislotwin_aTolRho, & !< absolute tolerance for integration of dislocation density - plastic_dislotwin_aTolTwinFrac, & !< absolute tolerance for integration of twin volume fraction - plastic_dislotwin_aTolTransFrac, & !< absolute tolerance for integration of trans volume fraction - plastic_dislotwin_deltaG, & !< Free energy difference between austensite and martensite - plastic_dislotwin_Cmfptrans, & !< - plastic_dislotwin_Cthresholdtrans, & !< - plastic_dislotwin_transStackHeight !< Stack height of hex nucleus - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctwin3333 !< twin elasticity matrix for each instance - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctrans66 !< trans elasticity matrix in Mandel notation for each instance - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctrans3333 !< trans elasticity matrix for each instance - real(pReal), dimension(:,:), allocatable, private :: & - plastic_dislotwin_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance - plastic_dislotwin_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance - plastic_dislotwin_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance - plastic_dislotwin_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance - plastic_dislotwin_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance - plastic_dislotwin_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance - plastic_dislotwin_burgersPerTransFamily, & !< absolute length of burgers vector [m] for each trans family and instance - plastic_dislotwin_burgersPerTransSystem, & !< absolute length of burgers vector [m] for each trans system and instance - plastic_dislotwin_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance - plastic_dislotwin_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance - plastic_dislotwin_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance - plastic_dislotwin_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance - plastic_dislotwin_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance - plastic_dislotwin_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance - plastic_dislotwin_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance - plastic_dislotwin_Ndot0PerTransFamily, & !< trans nucleation rate [1/m³s] for each trans family and instance - plastic_dislotwin_Ndot0PerTransSystem, & !< trans nucleation rate [1/m³s] for each trans system and instance - plastic_dislotwin_tau_r_twin, & !< stress to bring partial close together for each twin system and instance - plastic_dislotwin_tau_r_trans, & !< stress to bring partial close together for each trans system and instance - plastic_dislotwin_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance - plastic_dislotwin_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance - plastic_dislotwin_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_dislotwin_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_dislotwin_lamellarsizePerTransFamily, & !< martensite lamellar thickness [m] for each trans family and instance - plastic_dislotwin_lamellarsizePerTransSystem, & !< martensite lamellar thickness [m] for each trans system and instance - plastic_dislotwin_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance - plastic_dislotwin_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance - plastic_dislotwin_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_dislotwin_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance - plastic_dislotwin_interaction_SlipTrans, & !< coefficients for slip-trans interaction for each interaction type and instance - plastic_dislotwin_interaction_TransSlip, & !< coefficients for trans-slip interaction for each interaction type and instance - plastic_dislotwin_interaction_TransTrans, & !< coefficients for trans-trans interaction for each interaction type and instance - plastic_dislotwin_pPerSlipFamily, & !< p-exponent in glide velocity - plastic_dislotwin_qPerSlipFamily, & !< q-exponent in glide velocity - plastic_dislotwin_rPerTwinFamily, & !< r-exponent in twin nucleation rate - plastic_dislotwin_sPerTransFamily !< s-exponent in trans nucleation rate - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_dislotwin_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance - plastic_dislotwin_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance - plastic_dislotwin_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance - plastic_dislotwin_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance - plastic_dislotwin_interactionMatrix_SlipTrans, & !< interaction matrix of slip systems with trans systems for each instance - plastic_dislotwin_interactionMatrix_TransSlip, & !< interaction matrix of trans systems with slip systems for each instance - plastic_dislotwin_interactionMatrix_TransTrans, & !< interaction matrix of the different trans systems for each instance - plastic_dislotwin_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance - plastic_dislotwin_projectionMatrix_Trans !< matrix for projection of slip system shear on fault band (twin) systems for each instance - - real(pReal), dimension(:,:,:,:,:), allocatable, private :: & - plastic_dislotwin_sbSv - - enum, bind(c) - enumerator :: undefined_ID, & - edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID, & - twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID, & - resolved_stress_shearband_ID, & - shear_rate_shearband_ID, & - sb_eigenvalues_ID, & - sb_eigenvectors_ID, & - stress_trans_fraction_ID, & - strain_trans_fraction_ID, & - trans_fraction_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_dislotwin_outputID !< ID of each post result output - type, private :: tDislotwinState - real(pReal), pointer, dimension(:,:) :: & - rhoEdge, & - rhoEdgeDip, & - accshear_slip, & - twinFraction, & - accshear_twin, & - stressTransFraction, & - strainTransFraction , & - invLambdaSlip, & - invLambdaSlipTwin, & - invLambdaTwin, & - invLambdaSlipTrans, & - invLambdaTrans, & - mfp_slip, & - mfp_twin, & - mfp_trans, & - threshold_stress_slip, & - threshold_stress_twin, & - threshold_stress_trans, & - twinVolume, & - martensiteVolume - end type - type(tDislotwinState), allocatable, dimension(:), private :: & - state, & - state0, & - dotState - - public :: & - plastic_dislotwin_init, & - plastic_dislotwin_homogenizedC, & - plastic_dislotwin_microstructure, & - plastic_dislotwin_LpAndItsTangent, & - plastic_dislotwin_dotState, & - plastic_dislotwin_postResults - private :: & - plastic_dislotwin_stateInit, & - plastic_dislotwin_aTolState - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333, & - math_mul3x3 - use mesh, only: & - mesh_maxNips, & - mesh_NcpElems - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - homogenization_maxNgrains, & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_DISLOTWIN_label, & - PLASTICITY_DISLOTWIN_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,maxTotalNtrans,& - f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt,nr, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipTrans = 0_pInt, Nchunks_TransSlip = 0_pInt, Nchunks_TransTrans = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_TransFamilies = 0_pInt, & - offset_slip, index_myFamily, index_otherFamily, & - startIndex, endIndex - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin, tempPerTrans - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOTWIN_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOTWIN_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_dislotwin_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(plastic_dislotwin_output(maxval(phase_Noutput),maxNinstance)) - plastic_dislotwin_output = '' - allocate(plastic_dislotwin_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_dislotwin_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_totalNtrans(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_CAtomicVolume(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_D0(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Qsd(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_GrainSize(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_pShearBand(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_qShearBand(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_MaxTwinFraction(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cmfptwin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cthresholdtwin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_SolidSolutionStrength(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_L0_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_L0_trans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_xc_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_xc_trans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_VcrossSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_aTolRho(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_aTolTwinFrac(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_aTolTransFrac(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_sbResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_sbVelocity(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_sbQedge(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_SFE_0K(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_dSFE_dT(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default - allocate(plastic_dislotwin_deltaG(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cmfptrans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cthresholdtrans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_transStackHeight(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTransFamily(lattice_maxNtransFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTransFamily(lattice_maxNtransFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_SlipTrans(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TransSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TransTrans(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_sbSv(6,6,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) - allocate(plastic_dislotwin_lamellarsizePerTransFamily(lattice_maxNtransFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_sPerTransFamily(lattice_maxNtransFamily,maxNinstance),source=0.0_pReal) - - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) - Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase)> 0_pInt) - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_SlipTrans = maxval(lattice_interactionSlipTrans(:,:,phase)) - Nchunks_TransSlip = maxval(lattice_interactionTransSlip(:,:,phase)) - Nchunks_TransTrans = maxval(lattice_interactionTransTrans(:,:,phase)) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - if(allocated(tempPerTwin)) deallocate(tempPerTwin) - if(allocated(tempPerTrans)) deallocate(tempPerTrans) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - allocate(tempPerTwin(Nchunks_TwinFamilies)) - allocate(tempPerTrans(Nchunks_TransFamilies)) - endif - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('edge_density') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_density_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('dipole_density') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = dipole_density_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_slip','shearrate_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('edge_dipole_distance') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_dipole_distance_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stress_exponent') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_exponent_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('twin_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = twin_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_twin','shearrate_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_shearband') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_shearband_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_shearband','shearrate_shearband') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_shearband_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('sb_eigenvalues') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvalues_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('sb_eigenvectors') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvectors_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stress_trans_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_trans_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('strain_trans_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = strain_trans_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('trans_fraction','total_trans_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = trans_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip system families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - plastic_dislotwin_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip') - do j = 1_pInt, Nchunks_SlipFamilies - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('rhoedge0') - plastic_dislotwin_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('rhoedgedip0') - plastic_dislotwin_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('slipburgers') - plastic_dislotwin_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('qedge') - plastic_dislotwin_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('v0') - plastic_dislotwin_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('clambdaslip') - plastic_dislotwin_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau_peierls') - if (lattice_structure(phase) /= LATTICE_bcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOTWIN_label//')') - plastic_dislotwin_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('p_slip') - plastic_dislotwin_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('q_slip') - plastic_dislotwin_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on slip number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_dislotwin_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ndot0_twin','twinsize','twinburgers','r_twin') - do j = 1_pInt, Nchunks_TwinFamilies - tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('ndot0_twin') - if (lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') - plastic_dislotwin_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinsize') - plastic_dislotwin_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinburgers') - plastic_dislotwin_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('r_twin') - plastic_dislotwin_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of transformation system families - case ('ntrans') - if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & - call IO_warning(53_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - Nchunks_TransFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TransFamilies - plastic_dislotwin_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ndot0_trans','lamellarsize','transburgers','s_trans') - do j = 1_pInt, Nchunks_TransFamilies - tempPerTrans(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('ndot0_trans') - if (lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') - plastic_dislotwin_Ndot0PerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - case ('lamellarsize') - plastic_dislotwin_lamellarsizePerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - case ('transburgers') - plastic_dislotwin_burgersPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - case ('s_trans') - plastic_dislotwin_sPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip','interactionslipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_dislotwin_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin','interactionsliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_dislotwin_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip','interactiontwinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_dislotwin_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin','interactiontwintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_dislotwin_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptrans','interactionsliptrans') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTrans) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_SlipTrans - plastic_dislotwin_interaction_SlipTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_transslip','interactiontransslip') - if (chunkPos(1) < 1_pInt + Nchunks_TransSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TransSlip - plastic_dislotwin_interaction_TransSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_transtrans','interactiontranstrans') - if (chunkPos(1) < 1_pInt + Nchunks_TransTrans) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TransTrans - plastic_dislotwin_interaction_TransTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin/trans systems - case ('grainsize') - plastic_dislotwin_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('maxtwinfraction') - plastic_dislotwin_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('p_shearband') - plastic_dislotwin_pShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('q_shearband') - plastic_dislotwin_qShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('d0') - plastic_dislotwin_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('qsd') - plastic_dislotwin_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_rho') - plastic_dislotwin_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_dislotwin_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_transfrac') - plastic_dislotwin_aTolTransFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cmfptwin') - plastic_dislotwin_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cthresholdtwin') - plastic_dislotwin_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('solidsolutionstrength') - plastic_dislotwin_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('l0_twin') - plastic_dislotwin_L0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('l0_trans') - plastic_dislotwin_L0_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('xc_twin') - plastic_dislotwin_xc_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('xc_trans') - plastic_dislotwin_xc_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('vcrossslip') - plastic_dislotwin_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cedgedipmindistance') - plastic_dislotwin_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('catomicvolume') - plastic_dislotwin_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('sfe_0k') - plastic_dislotwin_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dsfe_dt') - plastic_dislotwin_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dipoleformationfactor') - plastic_dislotwin_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('shearbandresistance') - plastic_dislotwin_sbResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('shearbandvelocity') - plastic_dislotwin_sbVelocity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('qedgepersbsystem') - plastic_dislotwin_sbQedge(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('deltag') - plastic_dislotwin_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cmfptrans') - plastic_dislotwin_Cmfptrans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cthresholdtrans') - plastic_dislotwin_Cthresholdtrans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('transstackheight') - plastic_dislotwin_transStackHeight(instance) = IO_floatValue(line,chunkPos,2_pInt) - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then - instance = phase_plasticityInstance(phase) - - if (sum(plastic_dislotwin_Nslip(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOTWIN_label//')') - if (sum(plastic_dislotwin_Ntwin(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOTWIN_label//')') - if (sum(plastic_dislotwin_Ntrans(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Ntrans ('//PLASTICITY_DISLOTWIN_label//')') - do f = 1_pInt,lattice_maxNslipFamily - if (plastic_dislotwin_Nslip(f,instance) > 0_pInt) then - if (plastic_dislotwin_rhoEdge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_rhoEdgeDip0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_v0PerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOTWIN_label//')') - endif - enddo - do f = 1_pInt,lattice_maxNtwinFamily - if (plastic_dislotwin_Ntwin(f,instance) > 0_pInt) then - if (plastic_dislotwin_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='ndot0_twin ('//PLASTICITY_DISLOTWIN_label//')') - endif - enddo - if (plastic_dislotwin_CAtomicVolume(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_D0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_Qsd(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOTWIN_label//')') - if (sum(plastic_dislotwin_Ntwin(:,instance)) > 0_pInt) then - if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & - abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & - lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_aTolTwinFrac(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOTWIN_label//')') - endif - if (sum(plastic_dislotwin_Ntrans(:,instance)) > 0_pInt) then - if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & - abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & - lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_aTolTransFrac(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolTransFrac ('//PLASTICITY_DISLOTWIN_label//')') - endif - if (plastic_dislotwin_sbResistance(instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sbResistance ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_sbVelocity(instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sbVelocity ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & - plastic_dislotwin_pShearBand(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='pShearBand ('//PLASTICITY_DISLOTWIN_label//')') - if (abs(plastic_dislotwin_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & - plastic_dislotwin_dipoleFormationFactor(instance) /= 1.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & - plastic_dislotwin_qShearBand(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='qShearBand ('//PLASTICITY_DISLOTWIN_label//')') - -!-------------------------------------------------------------------------------------------------- -! Determine total number of active slip or twin systems - plastic_dislotwin_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_dislotwin_Nslip(:,instance)) - plastic_dislotwin_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_dislotwin_Ntwin(:,instance)) - plastic_dislotwin_Ntrans(:,instance)= min(lattice_NtransSystem(:,phase),plastic_dislotwin_Ntrans(:,instance)) - plastic_dislotwin_totalNslip(instance) = sum(plastic_dislotwin_Nslip(:,instance)) - plastic_dislotwin_totalNtwin(instance) = sum(plastic_dislotwin_Ntwin(:,instance)) - plastic_dislotwin_totalNtrans(instance) = sum(plastic_dislotwin_Ntrans(:,instance)) - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - maxTotalNslip = maxval(plastic_dislotwin_totalNslip) - maxTotalNtwin = maxval(plastic_dislotwin_totalNtwin) - maxTotalNtrans = maxval(plastic_dislotwin_totalNtrans) - - allocate(plastic_dislotwin_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_tau_r_twin(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_tau_r_trans(maxTotalNtrans, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_lamellarsizePerTransSystem(maxTotalNtrans, maxNinstance),source=0.0_pReal) - - allocate(plastic_dislotwin_interactionMatrix_SlipSlip(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from slip activity - maxval(plastic_dislotwin_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_SlipTwin(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from twin activity - maxval(plastic_dislotwin_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TwinSlip(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_dislotwin_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TwinTwin(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_dislotwin_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_SlipTrans(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from trans activity - maxval(plastic_dislotwin_totalNtrans),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TransSlip(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from slip activity - maxval(plastic_dislotwin_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TransTrans(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from trans activity - maxval(plastic_dislotwin_totalNtrans),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_projectionMatrix_Trans(maxTotalNtrans,maxTotalNslip,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ctrans66(6,6,maxTotalNtrans,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ctrans3333(3,3,3,3,maxTotalNtrans,maxNinstance), source=0.0_pReal) - - allocate(state(maxNinstance)) - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - myPhase2: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then - NofMyPhase=count(material_phase==phase) - instance = phase_plasticityInstance(phase) - - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_dislotwin_Noutput(instance) - select case(plastic_dislotwin_outputID(o,instance)) - case(edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID & - ) - mySize = ns - case(twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID & - ) - mySize = nt - case(resolved_stress_shearband_ID, & - shear_rate_shearband_ID & - ) - mySize = 6_pInt - case(sb_eigenvalues_ID) - mySize = 3_pInt - case(sb_eigenvectors_ID) - mySize = 9_pInt - case(stress_trans_fraction_ID, & - strain_trans_fraction_ID, & - trans_fraction_ID & - ) - mySize = nr - end select - - if (mySize > 0_pInt) then ! any meaningful output found - plastic_dislotwin_sizePostResult(o,instance) = mySize - plastic_dislotwin_sizePostResults(instance) = plastic_dislotwin_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - - sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & - + int(size(['twinFraction','accsheartwin']),pInt) * nt & - + int(size(['stressTransFraction','strainTransFraction']),pInt) * nr - sizeDeltaState = 0_pInt - sizeState = sizeDotState & - + int(size(['invLambdaSlip ','invLambdaSlipTwin ','invLambdaSlipTrans',& - 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & - + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& - 'twinVolume ']),pInt) * nt & - + int(size(['invLambdaTrans ','meanFreePathTrans','tauTransThreshold', & - 'martensiteVolume ']),pInt) * nr - - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_dislotwin_sizePostResults(instance) - plasticState(phase)%nSlip = plastic_dislotwin_totalNslip(instance) - plasticState(phase)%nTwin = plastic_dislotwin_totalNtwin(instance) - plasticState(phase)%nTrans= plastic_dislotwin_totalNtrans(instance) - allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - offset_slip = 2_pInt*plasticState(phase)%nslip - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) - - !* Process slip related parameters ------------------------------------------------ - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - slipSystemsLoop: do j = 1_pInt,plastic_dislotwin_Nslip(f,instance) - - !* Burgers vector, - ! dislocation velocity prefactor, - ! mean free path prefactor, - ! and minimum dipole distance - - plastic_dislotwin_burgersPerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_burgersPerSlipFamily(f,instance) - - plastic_dislotwin_QedgePerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_QedgePerSlipFamily(f,instance) - - plastic_dislotwin_v0PerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_v0PerSlipFamily(f,instance) - - plastic_dislotwin_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_CLambdaSlipPerSlipFamily(f,instance) - - !* Calculation of forest projections for edge dislocations - !* Interaction matrices - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_dislotwin_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & - abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & - lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) - plastic_dislotwin_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_dislotwin_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtransFamily - index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) - plastic_dislotwin_interactionMatrix_SlipTrans(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_SlipTrans(lattice_interactionSlipTrans( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo slipSystemsLoop - enddo slipFamiliesLoop - - !* Process twin related parameters ------------------------------------------------ - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(plastic_dislotwin_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list - twinSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntwin(f,instance) - - !* Burgers vector, - ! nucleation rate prefactor, - ! and twin size - - plastic_dislotwin_burgersPerTwinSystem(index_myFamily+j,instance) = & - plastic_dislotwin_burgersPerTwinFamily(f,instance) - - plastic_dislotwin_Ndot0PerTwinSystem(index_myFamily+j,instance) = & - plastic_dislotwin_Ndot0PerTwinFamily(f,instance) - - plastic_dislotwin_twinsizePerTwinSystem(index_myFamily+j,instance) = & - plastic_dislotwin_twinsizePerTwinFamily(f,instance) - - !* Rotate twin elasticity matrices - index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list - do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt - do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt - plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & - plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & - lattice_C3333(p,q,r,s,instance) * & - lattice_Qtwin(l,p,index_otherFamily+j,phase) * & - lattice_Qtwin(m,q,index_otherFamily+j,phase) * & - lattice_Qtwin(n,r,index_otherFamily+j,phase) * & - lattice_Qtwin(o,s,index_otherFamily+j,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo; enddo - plastic_dislotwin_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & - math_Mandel3333to66(plastic_dislotwin_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) - - !* Interaction matrices - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_dislotwin_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_dislotwin_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo twinSystemsLoop - enddo twinFamiliesLoop - - !* Process transformation related parameters ------------------------------------------------ - transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily - index_myFamily = sum(plastic_dislotwin_Ntrans(1:f-1_pInt,instance)) ! index in truncated trans system list - transSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntrans(f,instance) - - !* Burgers vector, - ! nucleation rate prefactor, - ! and martensite size - - plastic_dislotwin_burgersPerTransSystem(index_myFamily+j,instance) = & - plastic_dislotwin_burgersPerTransFamily(f,instance) - - plastic_dislotwin_Ndot0PerTransSystem(index_myFamily+j,instance) = & - plastic_dislotwin_Ndot0PerTransFamily(f,instance) - - plastic_dislotwin_lamellarsizePerTransSystem(index_myFamily+j,instance) = & - plastic_dislotwin_lamellarsizePerTransFamily(f,instance) - - !* Rotate trans elasticity matrices - index_otherFamily = sum(lattice_NtransSystem(1:f-1_pInt,phase)) ! index in full lattice trans list - do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt - do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt - plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) = & - plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) + & - lattice_trans_C3333(p,q,r,s,instance) * & - lattice_Qtrans(l,p,index_otherFamily+j,phase) * & - lattice_Qtrans(m,q,index_otherFamily+j,phase) * & - lattice_Qtrans(n,r,index_otherFamily+j,phase) * & - lattice_Qtrans(o,s,index_otherFamily+j,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo; enddo - plastic_dislotwin_Ctrans66(1:6,1:6,index_myFamily+j,instance) = & - math_Mandel3333to66(plastic_dislotwin_Ctrans3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) - - !* Interaction matrices - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_dislotwin_interactionMatrix_TransSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TransSlip(lattice_interactionTransSlip( & - sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtransFamily - index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) - plastic_dislotwin_interactionMatrix_TransTrans(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TransTrans(lattice_interactionTransTrans( & - sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - !* Projection matrices for shear from slip systems to fault-band (twin) systems for strain-induced martensite nucleation - select case(trans_lattice_structure(phase)) - case (LATTICE_bcc_ID) - do o = 1_pInt,lattice_maxNtransFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (trans) - plastic_dislotwin_projectionMatrix_Trans(index_myFamily+j,index_otherFamily+k,instance) = & - lattice_projectionTrans( sum(lattice_NtransSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, phase) - enddo; enddo - end select - - enddo transSystemsLoop - enddo transFamiliesLoop - - startIndex=1_pInt - endIndex=ns - state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%stressTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%stressTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%stressTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%strainTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%strainTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%strainTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlipTrans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlipTrans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%invLambdaTrans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaTrans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%mfp_trans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_trans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%threshold_stress_trans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_trans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%martensiteVolume=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%martensiteVolume=>plasticState(phase)%state0(startIndex:endIndex,:) - - call plastic_dislotwin_stateInit(phase,instance) - call plastic_dislotwin_aTolState(phase,instance) - endif myPhase2 - - enddo initializeInstances -end subroutine plastic_dislotwin_init - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_stateInit(ph,instance) - use math, only: & - pi - use lattice, only: & - lattice_maxNslipFamily, & - lattice_mu - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - real(pReal), dimension(plasticState(ph)%sizeState) :: tempState - - integer(pInt) :: i,j,f,ns,nt,nr, index_myFamily - real(pReal), dimension(plastic_dislotwin_totalNslip(instance)) :: & - rhoEdge0, & - rhoEdgeDip0, & - invLambdaSlip0, & - MeanFreePathSlip0, & - tauSlipThreshold0 - real(pReal), dimension(plastic_dislotwin_totalNtwin(instance)) :: & - MeanFreePathTwin0,TwinVolume0 - real(pReal), dimension(plastic_dislotwin_totalNtrans(instance)) :: & - MeanFreePathTrans0,MartensiteVolume0 - tempState = 0.0_pReal - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables - do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - rhoEdge0(index_myFamily+1_pInt: & - index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & - plastic_dislotwin_rhoEdge0(f,instance) - rhoEdgeDip0(index_myFamily+1_pInt: & - index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & - plastic_dislotwin_rhoEdgeDip0(f,instance) - enddo - - tempState(1_pInt:ns) = rhoEdge0 - tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent slip microstructural variables - forall (i = 1_pInt:ns) & - invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_forestProjectionEdge(1:ns,i,instance)))/ & - plastic_dislotwin_CLambdaSlipPerSlipSystem(i,instance) - tempState(3_pInt*ns+2_pInt*nt+2_pInt*nr+1:4_pInt*ns+2_pInt*nt+2_pInt*nr) = invLambdaSlip0 - - forall (i = 1_pInt:ns) & - MeanFreePathSlip0(i) = & - plastic_dislotwin_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_dislotwin_GrainSize(instance)) - tempState(6_pInt*ns+3_pInt*nt+3_pInt*nr+1:7_pInt*ns+3_pInt*nt+3_pInt*nr) = MeanFreePathSlip0 - - forall (i = 1_pInt:ns) & - tauSlipThreshold0(i) = & - lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(i,instance) * & - sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_interactionMatrix_SlipSlip(i,1:ns,instance))) - - tempState(7_pInt*ns+4_pInt*nt+4_pInt*nr+1:8_pInt*ns+4_pInt*nt+4_pInt*nr) = tauSlipThreshold0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent twin microstructural variables - forall (j = 1_pInt:nt) & - MeanFreePathTwin0(j) = plastic_dislotwin_GrainSize(instance) - tempState(7_pInt*ns+3_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+3_pInt*nr) = MeanFreePathTwin0 - - forall (j = 1_pInt:nt) & - TwinVolume0(j) = & - (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) - tempState(8_pInt*ns+5_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+5_pInt*nr) = TwinVolume0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent trans microstructural variables - forall (j = 1_pInt:nr) & - MeanFreePathTrans0(j) = plastic_dislotwin_GrainSize(instance) - tempState(7_pInt*ns+4_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+4_pInt*nr) = MeanFreePathTrans0 - - forall (j = 1_pInt:nr) & - MartensiteVolume0(j) = & - (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(j,instance)*MeanFreePathTrans0(j)**(2.0_pReal) - tempState(8_pInt*ns+6_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+6_pInt*nr) = MartensiteVolume0 - -plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) - -end subroutine plastic_dislotwin_stateInit - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - ph, & - instance ! number specifying the current instance of the plasticity - - integer(pInt) :: ns, nt, nr - - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - ! Tolerance state for dislocation densities - plasticState(ph)%aTolState(1_pInt: & - 2_pInt*ns) = plastic_dislotwin_aTolRho(instance) - - ! Tolerance state for accumulated shear due to slip - plasticState(ph)%aTolState(2_pInt*ns+1_pInt: & - 3_pInt*ns)=1.0e6_pReal - - ! Tolerance state for twin volume fraction - plasticState(ph)%aTolState(3_pInt*ns+1_pInt: & - 3_pInt*ns+nt) = plastic_dislotwin_aTolTwinFrac(instance) - - ! Tolerance state for accumulated shear due to twin - plasticState(ph)%aTolState(3_pInt*ns+nt+1_pInt: & - 3_pInt*ns+2_pInt*nt) = 1.0e6_pReal - -! Tolerance state for stress-assisted martensite volume fraction - plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+1_pInt: & - 3_pInt*ns+2_pInt*nt+nr) = plastic_dislotwin_aTolTransFrac(instance) - -! Tolerance state for strain-induced martensite volume fraction - plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+nr+1_pInt: & - 3_pInt*ns+2_pInt*nt+2_pInt*nr) = plastic_dislotwin_aTolTransFrac(instance) - -end subroutine plastic_dislotwin_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenized elasticity matrix -!-------------------------------------------------------------------------------------------------- -function plastic_dislotwin_homogenizedC(ipc,ip,el) - use material, only: & - phase_plasticityInstance, & - phaseAt, phasememberAt - use lattice, only: & - lattice_C66 - - implicit none - real(pReal), dimension(6,6) :: & - plastic_dislotwin_homogenizedC - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,nr,i, & - ph, & - of - real(pReal) :: sumf, sumftr - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - - !* Homogenized elasticity matrix - plastic_dislotwin_homogenizedC = (1.0_pReal-sumf-sumftr)*lattice_C66(1:6,1:6,ph) - do i=1_pInt,nt - plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & - + state(instance)%twinFraction(i,of)*plastic_dislotwin_Ctwin66(1:6,1:6,i,instance) - enddo - do i=1_pInt,nr - plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & - + (state(instance)%stressTransFraction(i,of) + state(instance)%strainTransFraction(i,of))*& - plastic_dislotwin_Ctrans66(1:6,1:6,i,instance) - enddo - - end function plastic_dislotwin_homogenizedC - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_microstructure(temperature,ipc,ip,el) - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - !plasticState, & !!!!delete - phaseAt, phasememberAt - use lattice, only: & - lattice_mu, & - lattice_nu - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - temperature !< temperature at IP - - integer(pInt) :: & - instance, & - ns,nt,nr,s,t,r, & - ph, & - of - real(pReal) :: & - sumf,sfe,x0,sumftr - real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize - real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - ftransOverLamellarSize - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - - !* Stacking fault energy - sfe = plastic_dislotwin_SFE_0K(instance) + & - plastic_dislotwin_dSFE_dT(instance) * Temperature - - !* rescaled twin volume fraction for topology - forall (t = 1_pInt:nt) & - fOverStacksize(t) = & - state(instance)%twinFraction(t,of)/plastic_dislotwin_twinsizePerTwinSystem(t,instance) - - !* rescaled trans volume fraction for topology - forall (r = 1_pInt:nr) & - ftransOverLamellarSize(r) = & - (state(instance)%stressTransFraction(r,of)+state(instance)%strainTransFraction(r,of))/& - plastic_dislotwin_lamellarsizePerTransSystem(r,instance) - - !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation - forall (s = 1_pInt:ns) & - state(instance)%invLambdaSlip(s,of) = & - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_dislotwin_forestProjectionEdge(1:ns,s,instance)))/ & - plastic_dislotwin_CLambdaSlipPerSlipSystem(s,instance) - - !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation - !$OMP CRITICAL (evilmatmul) - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal - if (nt > 0_pInt .and. ns > 0_pInt) & - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & - matmul(plastic_dislotwin_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin - !$OMP CRITICAL (evilmatmul) - if (nt > 0_pInt) & - state(instance)%invLambdaTwin(1_pInt:nt,of) = & - matmul(plastic_dislotwin_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* 1/mean free distance between 2 martensite lamellar from different systems seen by a moving dislocation - state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = 0.0_pReal - if (nr > 0_pInt .and. ns > 0_pInt) & - state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = & - matmul(plastic_dislotwin_interactionMatrix_SlipTrans(1:ns,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) - - !* 1/mean free distance between 2 martensite stacks from different systems seen by a growing martensite (1/lambda_trans) - if (nr > 0_pInt) & - state(instance)%invLambdaTrans(1_pInt:nr,of) = & - matmul(plastic_dislotwin_interactionMatrix_TransTrans(1:nr,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) - - !* mean free path between 2 obstacles seen by a moving dislocation - do s = 1_pInt,ns - if ((nt > 0_pInt) .or. (nr > 0_pInt)) then - state(instance)%mfp_slip(s,of) = & - plastic_dislotwin_GrainSize(instance)/(1.0_pReal+plastic_dislotwin_GrainSize(instance)*& - (state(instance)%invLambdaSlip(s,of) + & - state(instance)%invLambdaSlipTwin(s,of) + & - state(instance)%invLambdaSlipTrans(s,of))) - else - state(instance)%mfp_slip(s,of) = & - plastic_dislotwin_GrainSize(instance)/& - (1.0_pReal+plastic_dislotwin_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) !!!!!! correct? - endif - enddo - - !* mean free path between 2 obstacles seen by a growing twin - forall (t = 1_pInt:nt) & - state(instance)%mfp_twin(t,of) = & - plastic_dislotwin_Cmfptwin(instance)*plastic_dislotwin_GrainSize(instance)/& - (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(ph)%invLambdaTwin(t,of)) - - !* mean free path between 2 obstacles seen by a growing martensite - forall (r = 1_pInt:nr) & - state(instance)%mfp_trans(r,of) = & - plastic_dislotwin_Cmfptrans(instance)*plastic_dislotwin_GrainSize(instance)/& - (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(instance)%invLambdaTrans(r,of)) - - !* threshold stress for dislocation motion - forall (s = 1_pInt:ns) & - state(instance)%threshold_stress_slip(s,of) = & - lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(s,instance)*& - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_dislotwin_interactionMatrix_SlipSlip(s,1:ns,instance))) - - !* threshold stress for growing twin - forall (t = 1_pInt:nt) & - state(instance)%threshold_stress_twin(t,of) = & - plastic_dislotwin_Cthresholdtwin(instance)* & - (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)) & - + 3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& - (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(t,instance)) & - ) - - !* threshold stress for growing martensite - forall (r = 1_pInt:nr) & - state(instance)%threshold_stress_trans(r,of) = & - plastic_dislotwin_Cthresholdtrans(instance)* & - (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & - + 3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)*lattice_mu(ph)/& - (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(r,instance))& - + plastic_dislotwin_transStackHeight(instance)*plastic_dislotwin_deltaG(instance)/ & - (3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & - ) - - !* final twin volume after growth - forall (t = 1_pInt:nt) & - state(instance)%twinVolume(t,of) = & - (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(t,instance)*& - state(instance)%mfp_twin(t,of)**(2.0_pReal) - - !* final martensite volume after growth - forall (r = 1_pInt:nr) & - state(instance)%martensiteVolume(r,of) = & - (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(r,instance)*& - state(instance)%mfp_trans(r,of)**(2.0_pReal) - - !* equilibrium separation of partial dislocations (twin) - do t = 1_pInt,nt - x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& - (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) - plastic_dislotwin_tau_r_twin(t,instance)= & - lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& - (1/(x0+plastic_dislotwin_xc_twin(instance))+cos(pi/3.0_pReal)/x0) - enddo - - !* equilibrium separation of partial dislocations (trans) - do r = 1_pInt,nr - x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)**(2.0_pReal)/& - (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) - plastic_dislotwin_tau_r_trans(r,instance)= & - lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)/(2.0_pReal*pi)*& - (1/(x0+plastic_dislotwin_xc_trans(instance))+cos(pi/3.0_pReal)/x0) - enddo - -end subroutine plastic_dislotwin_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - math_Plain3333to99, & - math_Mandel6to33, & - math_Mandel33to6, & - math_spectralDecompositionSym, & - math_tensorproduct33, & - math_symmetric33, & - math_mul33x3 - use material, only: & - material_phase, & - phase_plasticityInstance, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_Strans, & - lattice_Strans_v, & - lattice_maxNslipFamily,& - lattice_maxNtwinFamily, & - lattice_maxNtransFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NtransSystem, & - lattice_shearTwin, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - integer(pInt), intent(in) :: ipc,ip,el - real(pReal), intent(in) :: Temperature - real(pReal), dimension(6), intent(in) :: Tstar_v - real(pReal), dimension(3,3), intent(out) :: Lp - real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 - - integer(pInt) :: instance,ph,of,ns,nt,nr,f,i,j,k,l,m,n,index_myFamily,s1,s2 - real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0_twin,stressRatio, & - Ndot0_trans,StressRatio_s - real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 - real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,dgdot_dtauslip,tau_slip - real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,dgdot_dtautwin,tau_twin - real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_trans,dgdot_dtautrans,tau_trans - real(pReal), dimension(6) :: gdot_sb,dgdot_dtausb,tau_sb - real(pReal), dimension(3,3) :: eigVectors, sb_Smatrix - real(pReal), dimension(3) :: eigValues, sb_s, sb_m - logical :: error - real(pReal), dimension(3,6), parameter :: & - sb_sComposition = & - reshape(real([& - 1, 0, 1, & - 1, 0,-1, & - 1, 1, 0, & - 1,-1, 0, & - 0, 1, 1, & - 0, 1,-1 & - ],pReal),[ 3,6]), & - sb_mComposition = & - reshape(real([& - 1, 0,-1, & - 1, 0,+1, & - 1,-1, 0, & - 1, 1, 0, & - 0, 1,-1, & - 0, 1, 1 & - ],pReal),[ 3,6]) - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Dislocation glide part - gdot_slip = 0.0_pReal - dgdot_dtauslip = 0.0_pReal - j = 0_pInt - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystemsLoop: do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on slip system - tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - - if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) - StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0 & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_dislotwin_qPerSlipFamily(f,instance)) & - * sign(1.0_pReal,tau_slip(j)) - - !* Derivatives of shear rates - dgdot_dtauslip(j) = & - abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& - *plastic_dislotwin_qPerSlipFamily(f,instance)/& - (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) - endif - - !* Plastic velocity gradient for dislocation glide - Lp = Lp + gdot_slip(j)*lattice_Sslip(:,:,1,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& - lattice_Sslip(k,l,1,index_myFamily+i,ph)*& - lattice_Sslip(m,n,1,index_myFamily+i,ph) - enddo slipSystemsLoop - enddo slipFamiliesLoop - -!-------------------------------------------------------------------------------------------------- -! correct Lp and dLp_dTstar3333 for twinned and transformed fraction - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - Lp = Lp * (1.0_pReal - sumf - sumftr) - dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf - sumftr) - -!-------------------------------------------------------------------------------------------------- -! Shear banding (shearband) part - if(abs(plastic_dislotwin_sbVelocity(instance)) > tiny(0.0_pReal) .and. & - abs(plastic_dislotwin_sbResistance(instance)) > tiny(0.0_pReal)) then - gdot_sb = 0.0_pReal - dgdot_dtausb = 0.0_pReal - call math_spectralDecompositionSym(math_Mandel6to33(Tstar_v),eigValues,eigVectors,error) - do j = 1_pInt,6_pInt - sb_s = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_sComposition(1:3,j)) - sb_m = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_mComposition(1:3,j)) - sb_Smatrix = math_tensorproduct33(sb_s,sb_m) - plastic_dislotwin_sbSv(1:6,j,ipc,ip,el) = math_Mandel33to6(math_symmetric33(sb_Smatrix)) - - !* Calculation of Lp - !* Resolved shear stress on shear banding system - tau_sb(j) = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) - - !* Stress ratios - if (abs(tau_sb(j)) < tol_math_check) then - StressRatio_p = 0.0_pReal - StressRatio_pminus1 = 0.0_pReal - else - StressRatio_p = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& - **plastic_dislotwin_pShearBand(instance) - StressRatio_pminus1 = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& - **(plastic_dislotwin_pShearBand(instance)-1.0_pReal) - endif - - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = plastic_dislotwin_sbVelocity(instance) - - !* Shear rates due to shearband - gdot_sb(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qShearBand(instance))*sign(1.0_pReal,tau_sb(j)) - - !* Derivatives of shear rates - dgdot_dtausb(j) = & - ((abs(gdot_sb(j))*BoltzmannRatio*& - plastic_dislotwin_pShearBand(instance)*plastic_dislotwin_qShearBand(instance))/& - plastic_dislotwin_sbResistance(instance))*& - StressRatio_pminus1*(1_pInt-StressRatio_p)**(plastic_dislotwin_qShearBand(instance)-1.0_pReal) - - !* Plastic velocity gradient for shear banding - Lp = Lp + gdot_sb(j)*sb_Smatrix - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtausb(j)*& - sb_Smatrix(k,l)*& - sb_Smatrix(m,n) - enddo - end if - -!-------------------------------------------------------------------------------------------------- -! Mechanical twinning part - gdot_twin = 0.0_pReal - dgdot_dtautwin = 0.0_pReal - j = 0_pInt - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on twin system - tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_twin(j) > tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then - Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(ph)%rhoEdgeDip(s2,of))+& !!!!! correct? - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) - else - Ndot0_twin=0.0_pReal - end if - case default - Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) - end select - gdot_twin(j) = & - (1.0_pReal-sumf-sumftr)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) - dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_dislotwin_rPerTwinFamily(f,instance))/tau_twin(j))*StressRatio_r - endif - - !* Plastic velocity gradient for mechanical twinning - Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& - lattice_Stwin(k,l,index_myFamily+i,ph)*& - lattice_Stwin(m,n,index_myFamily+i,ph) - enddo twinSystemsLoop - enddo twinFamiliesLoop - - !* Phase transformation part - gdot_trans = 0.0_pReal - dgdot_dtautrans = 0.0_pReal - j = 0_pInt - transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily - index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family - transSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) - j = j+1_pInt - - !* Resolved shear stress on transformation system - tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_trans(j) > tol_math_check) then - StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) - !* Shear rates and their derivatives due to transformation - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then - Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !!!!! correct? - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) - else - Ndot0_trans=0.0_pReal - end if - case default - Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) - end select - gdot_trans(j) = & - (1.0_pReal-sumf-sumftr)*& - state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) - dgdot_dtautrans(j) = ((gdot_trans(j)*plastic_dislotwin_sPerTransFamily(f,instance))/tau_trans(j))*StressRatio_s - endif - - !* Plastic velocity gradient for phase transformation - Lp = Lp + gdot_trans(j)*lattice_Strans(:,:,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautrans(j)*& - lattice_Strans(k,l,index_myFamily+i,ph)*& - lattice_Strans(m,n,index_myFamily+i,ph) - - enddo transSystemsLoop - enddo transFamiliesLoop - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - -end subroutine plastic_dislotwin_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_dotState(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_Strans_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_maxNtransFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NtransSystem, & - lattice_sheartwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - lattice_fccTobcc_transNucleationTwinPair, & - lattice_fccTobcc_shearCritTrans, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,nr,f,i,j,index_myFamily,s1,s2, & - ph, & - of - real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,& - EdgeDipMinDistance,AtomicVolume,VacancyDiffusion,StressRatio_r,Ndot0_twin,stressRatio,& - Ndot0_trans,StressRatio_s,EdgeDipDistance, ClimbVelocity,DotRhoEdgeDipClimb,DotRhoEdgeDipAnnihilation, & - DotRhoDipFormation,DotRhoMultiplication,DotRhoEdgeEdgeAnnihilation - real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,tau_slip - - real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - tau_twin - real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - tau_trans - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - plasticState(instance)%dotState(:,of) = 0.0_pReal - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - - !* Dislocation density evolution - gdot_slip = 0.0_pReal - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - !* Resolved shear stress on slip system - tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - - if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) - StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - plasticState(ph)%state(j, of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)** & - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau_slip(j)) - endif - !* Multiplication - DotRhoMultiplication = abs(gdot_slip(j))/& - (plastic_dislotwin_burgersPerSlipSystem(j,instance)*state(instance)%mfp_slip(j,of)) - !* Dipole formation - EdgeDipMinDistance = & - plastic_dislotwin_CEdgeDipMinDistance(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance) - if (abs(tau_slip(j)) <= tiny(0.0_pReal)) then - DotRhoDipFormation = 0.0_pReal - else - EdgeDipDistance = & - (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(tau_slip(j))) - if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) - if (EdgeDipDistance tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/& - tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then - Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) - else - Ndot0_twin=0.0_pReal - end if - case default - Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) - end select - dotState(instance)%twinFraction(j,of) = & - (1.0_pReal-sumf-sumftr)*& - state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) - !* Dotstate for accumulated shear due to twin - dotState(instance)%accshear_twin(j,of) = dotState(instance)%twinFraction(j,of) * & - lattice_sheartwin(index_myfamily+i,ph) - endif - enddo - enddo - - !* Transformation volume fraction evolution - j = 0_pInt - do f = 1_pInt,lattice_maxNtransFamily ! loop over all trans families - index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) ! process each (active) trans system in family - j = j+1_pInt - - !* Resolved shear stress on transformation system - tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_trans(j) > tol_math_check) then - StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/& - tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) - !* Shear rates and their derivatives due to transformation - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then - Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) - else - Ndot0_trans=0.0_pReal - end if - case default - Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) - end select - dotState(instance)%strainTransFraction(j,of) = & - (1.0_pReal-sumf-sumftr)*& - state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) - !* Dotstate for accumulated shear due to transformation - !dotState(instance)%accshear_trans(j,of) = dotState(instance)%strainTransFraction(j,of) * & - ! lattice_sheartrans(index_myfamily+i,ph) - endif - - enddo - enddo - -end subroutine plastic_dislotwin_dotState - - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_dislotwin_postResults(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi, & - math_Mandel6to33, & - math_eigenvaluesSym33, & - math_spectralDecompositionSym33 - use material, only: & - material_phase, & - phase_plasticityInstance,& - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_shearTwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(plastic_dislotwin_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_dislotwin_postResults - integer(pInt) :: & - instance,& - ns,nt,nr,& - f,o,i,c,j,index_myFamily,& - s1,s2, & - ph, & - of - real(pReal) :: sumf,tau,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0_twin,dgdot_dtauslip, & - stressRatio - real(preal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip - real(pReal), dimension(3,3) :: eigVectors - real(pReal), dimension (3) :: eigValues - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Required output - c = 0_pInt - plastic_dislotwin_postResults = 0.0_pReal - do o = 1_pInt,plastic_dislotwin_Noutput(instance) - select case(plastic_dislotwin_outputID(o,instance)) - - case (edge_density_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) - c = c + ns - case (dipole_density_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) - c = c + ns - case (shear_rate_slip_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt ! could be taken from state by now! - - !* Resolved shear stress on slip system - tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - !* Stress ratios - if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau)-state(ph)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) - StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - plastic_dislotwin_postResults(c+j) = & - DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) - else - plastic_dislotwin_postResults(c+j) = 0.0_pReal - endif - - enddo ; enddo - c = c + ns - case (accumulated_shear_slip_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = & - state(instance)%accshear_slip(1_pInt:ns,of) - c = c + ns - case (mfp_slip_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) =& - state(instance)%mfp_slip(1_pInt:ns,of) - c = c + ns - case (resolved_stress_slip_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - plastic_dislotwin_postResults(c+j) =& - dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - enddo; enddo - c = c + ns - case (threshold_stress_slip_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = & - state(instance)%threshold_stress_slip(1_pInt:ns,of) - c = c + ns - case (edge_dipole_distance_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - plastic_dislotwin_postResults(c+j) = & - (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) - plastic_dislotwin_postResults(c+j)=min(plastic_dislotwin_postResults(c+j),& - state(instance)%mfp_slip(j,of)) - ! plastic_dislotwin_postResults(c+j)=max(plastic_dislotwin_postResults(c+j),& - ! plasticState(ph)%state(4*ns+2*nt+2*nr+j, of)) - enddo; enddo - c = c + ns - case (resolved_stress_shearband_ID) - do j = 1_pInt,6_pInt ! loop over all shearband families - plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v, & - plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) - enddo - c = c + 6_pInt - case (shear_rate_shearband_ID) - do j = 1_pInt,6_pInt ! loop over all shearbands - !* Resolved shear stress on shearband system - tau = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) - !* Stress ratios - if (abs(tau) < tol_math_check) then - StressRatio_p = 0.0_pReal - StressRatio_pminus1 = 0.0_pReal - else - StressRatio_p = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& - plastic_dislotwin_pShearBand(instance) - StressRatio_pminus1 = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& - (plastic_dislotwin_pShearBand(instance)-1.0_pReal) - endif - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = plastic_dislotwin_sbVelocity(instance) - ! Shear rate due to shear band - plastic_dislotwin_postResults(c+j) = & - DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**plastic_dislotwin_qShearBand(instance))*& - sign(1.0_pReal,tau) - enddo - c = c + 6_pInt - case (twin_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt,of) - c = c + nt - case (shear_rate_twin_ID) - if (nt > 0_pInt) then - - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - - !* Resolved shear stress on slip system - tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - !* Stress ratios - if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) - else - gdot_slip(j) = 0.0_pReal - endif - enddo;enddo - - j = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily ! loop over all twin families - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1,plastic_dislotwin_Ntwin(f,instance) ! process each (active) twin system in family - j = j + 1_pInt - - tau = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - - !* Shear rates due to twin - if ( tau > 0.0_pReal ) then - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau < plastic_dislotwin_tau_r_twin(j,instance)) then - Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_twin(instance)*& - plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_twin(j,instance)-tau))) - else - Ndot0_twin=0.0_pReal - end if - case default - Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) - end select - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau) & - **plastic_dislotwin_rPerTwinFamily(f,instance) - plastic_dislotwin_postResults(c+j) = & - (plastic_dislotwin_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) - endif - - enddo ; enddo - endif - c = c + nt - case (accumulated_shear_twin_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt,of) - c = c + nt - case (mfp_twin_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt,of) - c = c + nt - case (resolved_stress_twin_ID) - if (nt > 0_pInt) then - j = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily ! loop over all slip families - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - enddo; enddo - endif - c = c + nt - case (threshold_stress_twin_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt,of) - c = c + nt - case (stress_exponent_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - - !* Resolved shear stress on slip system - tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) - - !* Derivatives of shear rates - dgdot_dtauslip = & - abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& - *plastic_dislotwin_qPerSlipFamily(f,instance)/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) - - else - gdot_slip(j) = 0.0_pReal - dgdot_dtauslip = 0.0_pReal - endif - - !* Stress exponent - if (abs(gdot_slip(j))<=tiny(0.0_pReal)) then - plastic_dislotwin_postResults(c+j) = 0.0_pReal - else - plastic_dislotwin_postResults(c+j) = (tau/gdot_slip(j))*dgdot_dtauslip - endif - enddo ; enddo - c = c + ns - case (sb_eigenvalues_ID) - plastic_dislotwin_postResults(c+1_pInt:c+3_pInt) = math_eigenvaluesSym33(math_Mandel6to33(Tstar_v)) - c = c + 3_pInt - case (sb_eigenvectors_ID) - call math_spectralDecompositionSym33(math_Mandel6to33(Tstar_v),eigValues,eigVectors) - plastic_dislotwin_postResults(c+1_pInt:c+9_pInt) = reshape(eigVectors,[9]) - c = c + 9_pInt - case (stress_trans_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nr) = & - state(instance)%stressTransFraction(1_pInt:nr,of) - c = c + nr - case (strain_trans_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nr) = & - state(instance)%strainTransFraction(1_pInt:nr,of) - c = c + nr - case (trans_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nr) = & - state(instance)%stressTransFraction(1_pInt:nr,of) + & - state(instance)%strainTransFraction(1_pInt:nr,of) - c = c + nr - end select - enddo -end function plastic_dislotwin_postResults - -end module plastic_dislotwin \ No newline at end of file diff --git a/code/plastic_isotropic.f90 b/code/plastic_isotropic.f90 deleted file mode 100644 index 13481b9a7..000000000 --- a/code/plastic_isotropic.f90 +++ /dev/null @@ -1,678 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for isotropic (ISOTROPIC) plasticity -!> @details Isotropic (ISOTROPIC) Plasticity which resembles the phenopowerlaw plasticity without -!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an -!! untextured polycrystal -!-------------------------------------------------------------------------------------------------- -module plastic_isotropic -#ifdef HDF - use hdf5, only: & - HID_T -#endif - - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_isotropic_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_isotropic_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_isotropic_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_isotropic_Noutput !< number of outputs per instance - - enum, bind(c) - enumerator :: undefined_ID, & - flowstress_ID, & - strainrate_ID - end enum - - type, private :: tParameters !< container type for internal constitutive parameters - integer(kind(undefined_ID)), allocatable, dimension(:) :: & - outputID - real(pReal) :: & - fTaylor, & - tau0, & - gdot0, & - n, & - h0, & - h0_slopeLnRate, & - tausat, & - a, & - aTolFlowstress, & - aTolShear , & - tausat_SinhFitA, & - tausat_SinhFitB, & - tausat_SinhFitC, & - tausat_SinhFitD - logical :: & - dilatation - end type - - type(tParameters), dimension(:), allocatable, private :: param !< containers of constitutive parameters (len Ninstance) - - type, private :: tIsotropicState !< internal state aliases - real(pReal), pointer, dimension(:) :: & ! scalars along NipcMyInstance - flowstress, & - accumulatedShear - end type - type, private :: tIsotropicAbsTol !< internal alias for abs tolerance in state - real(pReal), pointer :: & ! scalars along NipcMyInstance - flowstress, & - accumulatedShear - end type - type(tIsotropicState), allocatable, dimension(:), private :: & !< state aliases per instance - state, & - state0, & - dotState - type(tIsotropicAbsTol), allocatable, dimension(:), private :: & !< state aliases per instance - stateAbsTol - - public :: & - plastic_isotropic_init, & - plastic_isotropic_LpAndItsTangent, & - plastic_isotropic_LiAndItsTangent, & - plastic_isotropic_dotState, & - plastic_isotropic_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic - use numerics, only: & - analyticJaco, & - worldrank, & - numerics_integrator - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_ISOTROPIC_label, & - PLASTICITY_ISOTROPIC_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - - use lattice - - implicit none - integer(pInt), intent(in) :: fileUnit - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - o, & - phase, & - instance, & - maxNinstance, & - mySize, & - sizeDotState, & - sizeState, & - sizeDeltaState - character(len=65536) :: & - tag = '', & - outputtag = '', & - line = '', & - extmsg = '' - integer(pInt) :: NipcMyPhase - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_ISOTROPIC_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_ISOTROPIC_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_isotropic_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_isotropic_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) - allocate(plastic_isotropic_output(maxval(phase_Noutput), maxNinstance)) - plastic_isotropic_output = '' - allocate(plastic_isotropic_Noutput(maxNinstance), source=0_pInt) - - allocate(param(maxNinstance)) ! one container of parameters per instance - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - phase = phase + 1_pInt ! advance section counter - if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then - instance = phase_plasticityInstance(phase) - - endif - cycle ! skip to next line - endif - if (phase > 0_pInt) then; if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - allocate(param(instance)%outputID(phase_Noutput(phase))) ! allocate space for IDs of every requested output - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - extmsg = trim(tag)//' ('//PLASTICITY_ISOTROPIC_label//')' ! prepare error message identifier - - select case(tag) - case ('(output)') - outputtag = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - select case(outputtag) - case ('flowstress') - plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt - param(instance)%outputID (plastic_isotropic_Noutput(instance)) = flowstress_ID - plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag - case ('strainrate') - plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt - param(instance)%outputID (plastic_isotropic_Noutput(instance)) = strainrate_ID - plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag - - end select - - case ('/dilatation/') - param(instance)%dilatation = .true. - - case ('tau0') - param(instance)%tau0 = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%tau0 < 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('gdot0') - param(instance)%gdot0 = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%gdot0 <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('n') - param(instance)%n = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%n <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('h0') - param(instance)%h0 = IO_floatValue(line,chunkPos,2_pInt) - - case ('h0_slope','slopelnrate') - param(instance)%h0_slopeLnRate = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat') - param(instance)%tausat = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%tausat <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('tausat_sinhfita') - param(instance)%tausat_SinhFitA = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat_sinhfitb') - param(instance)%tausat_SinhFitB = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat_sinhfitc') - param(instance)%tausat_SinhFitC = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat_sinhfitd') - param(instance)%tausat_SinhFitD = IO_floatValue(line,chunkPos,2_pInt) - - case ('a', 'w0') - param(instance)%a = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%a <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('taylorfactor') - param(instance)%fTaylor = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%fTaylor <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('atol_flowstress') - param(instance)%aTolFlowstress = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%aTolFlowstress <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('atol_shear') - param(instance)%aTolShear = IO_floatValue(line,chunkPos,2_pInt) - - case default - - end select - endif; endif - enddo parsingFile - - allocate(state(maxNinstance)) ! internal state aliases - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - allocate(stateAbsTol(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop over every plasticity - myPhase: if (phase_plasticity(phase) == PLASTICITY_isotropic_ID) then ! isolate instances of own constitutive description - NipcMyPhase = count(material_phase == phase) ! number of own material points (including point components ipc) - instance = phase_plasticityInstance(phase) -!-------------------------------------------------------------------------------------------------- -! sanity checks - if (param(instance)%aTolShear <= 0.0_pReal) & - param(instance)%aTolShear = 1.0e-6_pReal ! default absolute tolerance 1e-6 - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) - select case(param(instance)%outputID(o)) - case(flowstress_ID,strainrate_ID) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_isotropic_sizePostResult(o,instance) = mySize - plastic_isotropic_sizePostResults(instance) = & - plastic_isotropic_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = 2_pInt ! flowstress, accumulated_shear - sizeDotState = sizeState ! both evolve - sizeDeltaState = 0_pInt ! no sudden jumps in state - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_isotropic_sizePostResults(instance) - plasticState(phase)%nSlip = 1 - plasticState(phase)%nTwin = 0 - plasticState(phase)%nTrans= 0 - allocate(plasticState(phase)%aTolState ( sizeState)) - - allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase),source=0.0_pReal) - - allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase),source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase),source=0.0_pReal) - -!-------------------------------------------------------------------------------------------------- -! globally required state aliases - plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NipcMyPhase) - plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NipcMyPhase) - -!-------------------------------------------------------------------------------------------------- -! locally defined state aliases - state(instance)%flowstress => plasticState(phase)%state (1,1:NipcMyPhase) - state0(instance)%flowstress => plasticState(phase)%state0 (1,1:NipcMyPhase) - dotState(instance)%flowstress => plasticState(phase)%dotState (1,1:NipcMyPhase) - stateAbsTol(instance)%flowstress => plasticState(phase)%aTolState(1) - - state(instance)%accumulatedShear => plasticState(phase)%state (2,1:NipcMyPhase) - state0(instance)%accumulatedShear => plasticState(phase)%state0 (2,1:NipcMyPhase) - dotState(instance)%accumulatedShear => plasticState(phase)%dotState (2,1:NipcMyPhase) - stateAbsTol(instance)%accumulatedShear => plasticState(phase)%aTolState(2) - -!-------------------------------------------------------------------------------------------------- -! init state - state0(instance)%flowstress = param(instance)%tau0 - state0(instance)%accumulatedShear = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! init absolute state tolerances - stateAbsTol(instance)%flowstress = param(instance)%aTolFlowstress - stateAbsTol(instance)%accumulatedShear = param(instance)%aTolShear - - endif myPhase - enddo initializeInstances - -end subroutine plastic_isotropic_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_g - use math, only: & - math_mul6x6, & - math_Mandel6to33, & - math_Plain3333to99, & - math_deviatoric33, & - math_mul33xx33, & - math_transpose33 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(3,3) :: & - Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal) :: & - gamma_dot, & !< strainrate - norm_Tstar_dev, & !< euclidean norm of Tstar_dev - squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev - integer(pInt) :: & - instance, of, & - k, l, m, n - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - - Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress - squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) - norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) - - if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero - Lp = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - else - gamma_dot = param(instance)%gdot0 & - * ( sqrt(1.5_pReal) * norm_Tstar_dev / param(instance)%fTaylor / state(instance)%flowstress(of) ) & - **param(instance)%n - - Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/param(instance)%fTaylor - - if (iand(debug_level(debug_constitutive), debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i8,1x,i2,1x,i3)') '<< CONST isotropic >> at el ip g ',el,ip,ipc - write(6,'(/,a,/,3(12x,3(f12.4,1x)/))') '<< CONST isotropic >> Tstar (dev) / MPa', & - math_transpose33(Tstar_dev_33(1:3,1:3))*1.0e-6_pReal - write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> norm Tstar / MPa', norm_Tstar_dev*1.0e-6_pReal - write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> gdot', gamma_dot - end if -!-------------------------------------------------------------------------------------------------- -! Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & - Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal - forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & - dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal - dLp_dTstar99 = math_Plain3333to99(gamma_dot / param(instance)%fTaylor * & - dLp_dTstar_3333 / norm_Tstar_dev) - end if -end subroutine plastic_isotropic_LpAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_LiAndItsTangent(Li,dLi_dTstar_3333,Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6, & - math_Mandel6to33, & - math_Plain3333to99, & - math_spherical33, & - math_mul33xx33 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Li !< plastic velocity gradient - - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(3,3) :: & - Tstar_sph_33 !< sphiatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor - real(pReal), dimension(3,3,3,3), intent(out) :: & - dLi_dTstar_3333 !< derivative of Li with respect to Tstar as 4th order tensor - real(pReal) :: & - gamma_dot, & !< strainrate - norm_Tstar_sph, & !< euclidean norm of Tstar_sph - squarenorm_Tstar_sph !< square of the euclidean norm of Tstar_sph - integer(pInt) :: & - instance, of, & - k, l, m, n - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - - Tstar_sph_33 = math_spherical33(math_Mandel6to33(Tstar_v)) ! spherical part of 2nd Piola-Kirchhoff stress - squarenorm_Tstar_sph = math_mul33xx33(Tstar_sph_33,Tstar_sph_33) - norm_Tstar_sph = sqrt(squarenorm_Tstar_sph) - - if (param(instance)%dilatation) then - if (norm_Tstar_sph <= 0.0_pReal) then ! Tstar == 0 --> both Li and dLi_dTstar are zero - Li = 0.0_pReal - dLi_dTstar_3333 = 0.0_pReal - else - gamma_dot = param(instance)%gdot0 & - * (sqrt(1.5_pReal) * norm_Tstar_sph / param(instance)%fTaylor / state(instance)%flowstress(of) ) & - **param(instance)%n - - Li = Tstar_sph_33/norm_Tstar_sph * gamma_dot/param(instance)%fTaylor - - !-------------------------------------------------------------------------------------------------- - ! Calculation of the tangent of Li - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLi_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & - Tstar_sph_33(k,l)*Tstar_sph_33(m,n) / squarenorm_Tstar_sph - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLi_dTstar_3333(k,l,k,l) = dLi_dTstar_3333(k,l,k,l) + 1.0_pReal - - dLi_dTstar_3333 = gamma_dot / param(instance)%fTaylor * & - dLi_dTstar_3333 / norm_Tstar_sph - endif - endif - -end subroutine plastic_isotropic_LiAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_dotState(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6) :: & - Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - gamma_dot, & !< strainrate - hardening, & !< hardening coefficient - saturation, & !< saturation flowstress - norm_Tstar_v !< euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of !< shortcut notation for offset position in state array - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - -!-------------------------------------------------------------------------------------------------- -! norm of (deviatoric) 2nd Piola-Kirchhoff stress - if (param(instance)%dilatation) then - norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) - else - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - end if -!-------------------------------------------------------------------------------------------------- -! strain rate - gamma_dot = param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & - / &!----------------------------------------------------------------------------------- - (param(instance)%fTaylor*state(instance)%flowstress(of) ))**param(instance)%n - -!-------------------------------------------------------------------------------------------------- -! hardening coefficient - if (abs(gamma_dot) > 1e-12_pReal) then - if (abs(param(instance)%tausat_SinhFitA) <= tiny(0.0_pReal)) then - saturation = param(instance)%tausat - else - saturation = ( param(instance)%tausat & - + ( log( ( gamma_dot / param(instance)%tausat_SinhFitA& - )**(1.0_pReal / param(instance)%tausat_SinhFitD)& - + sqrt( ( gamma_dot / param(instance)%tausat_SinhFitA & - )**(2.0_pReal / param(instance)%tausat_SinhFitD) & - + 1.0_pReal ) & - ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) - )**(1.0_pReal / param(instance)%tausat_SinhFitC) & - / ( param(instance)%tausat_SinhFitB & - * (gamma_dot / param(instance)%gdot0)**(1.0_pReal / param(instance)%n) & - ) & - ) - endif - hardening = ( param(instance)%h0 + param(instance)%h0_slopeLnRate * log(gamma_dot) ) & - * abs( 1.0_pReal - state(instance)%flowstress(of)/saturation )**param(instance)%a & - * sign(1.0_pReal, 1.0_pReal - state(instance)%flowstress(of)/saturation) - else - hardening = 0.0_pReal - endif - - dotState(instance)%flowstress (of) = hardening * gamma_dot - dotState(instance)%accumulatedShear(of) = gamma_dot - -end subroutine plastic_isotropic_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_isotropic_postResults(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(plastic_isotropic_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_isotropic_postResults - - real(pReal), dimension(6) :: & - Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - norm_Tstar_v ! euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of, & !< shortcut notation for offset position in state array - c, & - o - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - -!-------------------------------------------------------------------------------------------------- -! norm of (deviatoric) 2nd Piola-Kirchhoff stress - if (param(instance)%dilatation) then - norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) - else - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - end if - - c = 0_pInt - plastic_isotropic_postResults = 0.0_pReal - - outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) - select case(param(instance)%outputID(o)) - case (flowstress_ID) - plastic_isotropic_postResults(c+1_pInt) = state(instance)%flowstress(of) - c = c + 1_pInt - case (strainrate_ID) - plastic_isotropic_postResults(c+1_pInt) = & - param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & - / &!---------------------------------------------------------------------------------- - (param(instance)%fTaylor * state(instance)%flowstress(of)) ) ** param(instance)%n - c = c + 1_pInt - end select - enddo outputsLoop - -end function plastic_isotropic_postResults - - -end module plastic_isotropic diff --git a/code/plastic_j2.f90 b/code/plastic_j2.f90 deleted file mode 100644 index 89c022cc9..000000000 --- a/code/plastic_j2.f90 +++ /dev/null @@ -1,579 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for isotropic (J2) plasticity -!> @details Isotropic (J2) Plasticity which resembles the phenopowerlaw plasticity without -!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an -!! untextured polycrystal -!-------------------------------------------------------------------------------------------------- -module plastic_j2 -#ifdef HDF - use hdf5, only: & - HID_T -#endif - - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_j2_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_j2_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_j2_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_j2_Noutput !< number of outputs per instance - real(pReal), dimension(:), allocatable, private :: & - plastic_j2_fTaylor, & !< Taylor factor - plastic_j2_tau0, & !< initial plastic stress - plastic_j2_gdot0, & !< reference velocity - plastic_j2_n, & !< Visco-plastic parameter -!-------------------------------------------------------------------------------------------------- -! h0 as function of h0 = A + B log (gammadot) - plastic_j2_h0, & - plastic_j2_h0_slopeLnRate, & - plastic_j2_tausat, & !< final plastic stress - plastic_j2_a, & - plastic_j2_aTolResistance, & - plastic_j2_aTolShear, & -!-------------------------------------------------------------------------------------------------- -! tausat += (asinh((gammadot / SinhFitA)**(1 / SinhFitD)))**(1 / SinhFitC) / (SinhFitB * (gammadot / gammadot0)**(1/n)) - plastic_j2_tausat_SinhFitA, & !< fitting parameter for normalized strain rate vs. stress function - plastic_j2_tausat_SinhFitB, & !< fitting parameter for normalized strain rate vs. stress function - plastic_j2_tausat_SinhFitC, & !< fitting parameter for normalized strain rate vs. stress function - plastic_j2_tausat_SinhFitD !< fitting parameter for normalized strain rate vs. stress function - - enum, bind(c) - enumerator :: undefined_ID, & - flowstress_ID, & - strainrate_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_j2_outputID !< ID of each post result output - - -#ifdef HDF - type plastic_j2_tOutput - real(pReal), dimension(:), allocatable, private :: & - flowstress, & - strainrate - logical :: flowstressActive = .false., strainrateActive = .false. ! if we can write the output block wise, this is not needed anymore because we can do an if(allocated(xxx)) - end type plastic_j2_tOutput - type(plastic_j2_tOutput), allocatable, dimension(:) :: plastic_j2_Output2 -integer(HID_T), allocatable, dimension(:) :: outID -#endif - - - public :: & - plastic_j2_init, & - plastic_j2_LpAndItsTangent, & - plastic_j2_dotState, & - plastic_j2_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_j2_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) -#ifdef HDF - use hdf5 -#endif - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic - use numerics, only: & - analyticJaco, & - worldrank, & - numerics_integrator - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_error, & - IO_timeStamp, & -#ifdef HDF - tempResults, & - HDF5_addGroup, & - HDF5_addScalarDataset,& -#endif - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_J2_label, & - PLASTICITY_J2_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - - use lattice - - implicit none - integer(pInt), intent(in) :: fileUnit - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - o, & - phase, & - maxNinstance, & - instance, & - mySize, & - sizeDotState, & - sizeState, & - sizeDeltaState - character(len=65536) :: & - tag = '', & - line = '' - integer(pInt) :: NofMyPhase - -#ifdef HDF - character(len=5) :: & - str1 - integer(HID_T) :: ID,ID2,ID4 -#endif - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_J2_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_J2_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - -#ifdef HDF - allocate(plastic_j2_Output2(maxNinstance)) - allocate(outID(maxNinstance)) -#endif - - allocate(plastic_j2_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_j2_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) - allocate(plastic_j2_output(maxval(phase_Noutput), maxNinstance)) - plastic_j2_output = '' - allocate(plastic_j2_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_j2_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_j2_fTaylor(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tau0(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_gdot0(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_n(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_h0(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_h0_slopeLnRate(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_a(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_aTolResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_aTolShear (maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitA(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitB(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitC(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitD(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - phase = phase + 1_pInt ! advance section counter - if (phase_plasticity(phase) == PLASTICITY_J2_ID) then - instance = phase_plasticityInstance(phase) -#ifdef HDF - outID(instance)=HDF5_addGroup(str1,tempResults) -#endif - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_J2_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('flowstress') - plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt - plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = flowstress_ID - plastic_j2_output(plastic_j2_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) -#ifdef HDF - call HDF5_addScalarDataset(outID(instance),myConstituents,'flowstress','MPa') - allocate(plastic_j2_Output2(instance)%flowstress(myConstituents)) - plastic_j2_Output2(instance)%flowstressActive = .true. -#endif - case ('strainrate') - plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt - plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = strainrate_ID - plastic_j2_output(plastic_j2_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) -#ifdef HDF - call HDF5_addScalarDataset(outID(instance),myConstituents,'strainrate','1/s') - allocate(plastic_j2_Output2(instance)%strainrate(myConstituents)) - plastic_j2_Output2(instance)%strainrateActive = .true. -#endif - case default - - end select - case ('tau0') - plastic_j2_tau0(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_tau0(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('gdot0') - plastic_j2_gdot0(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_gdot0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('n') - plastic_j2_n(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_n(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('h0') - plastic_j2_h0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_slope','slopelnrate') - plastic_j2_h0_slopeLnRate(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat') - plastic_j2_tausat(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_tausat(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('tausat_sinhfita') - plastic_j2_tausat_SinhFitA(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat_sinhfitb') - plastic_j2_tausat_SinhFitB(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat_sinhfitc') - plastic_j2_tausat_SinhFitC(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat_sinhfitd') - plastic_j2_tausat_SinhFitD(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('a', 'w0') - plastic_j2_a(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_a(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('taylorfactor') - plastic_j2_fTaylor(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_fTaylor(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('atol_resistance') - plastic_j2_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_aTolResistance(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('atol_shear') - plastic_j2_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case default - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_j2_ID) then - NofMyPhase=count(material_phase==phase) - instance = phase_plasticityInstance(phase) -!-------------------------------------------------------------------------------------------------- -! sanity checks - if (plastic_j2_aTolShear(instance) <= 0.0_pReal) & - plastic_j2_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) - select case(plastic_j2_outputID(o,instance)) - case(flowstress_ID,strainrate_ID) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_j2_sizePostResult(o,instance) = mySize - plastic_j2_sizePostResults(instance) = & - plastic_j2_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = 2_pInt - sizeDotState = sizeState - sizeDeltaState = 0_pInt - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_j2_sizePostResults(instance) - plasticState(phase)%nSlip = 1 - plasticState(phase)%nTwin = 0 - plasticState(phase)%nTrans= 0 - allocate(plasticState(phase)%aTolState ( sizeState)) - plasticState(phase)%aTolState(1) = plastic_j2_aTolResistance(instance) - plasticState(phase)%aTolState(2) = plastic_j2_aTolShear(instance) - allocate(plasticState(phase)%state0 ( sizeState,NofMyPhase)) - plasticState(phase)%state0(1,1:NofMyPhase) = plastic_j2_tau0(instance) - plasticState(phase)%state0(2,1:NofMyPhase) = 0.0_pReal - allocate(plasticState(phase)%partionedState0 ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase),source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase),source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NofMyPhase) - endif myPhase - enddo initializeInstances - -end subroutine plastic_j2_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_j2_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6, & - math_Mandel6to33, & - math_Plain3333to99, & - math_deviatoric33, & - math_mul33xx33 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(3,3) :: & - Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal) :: & - gamma_dot, & !< strainrate - norm_Tstar_dev, & !< euclidean norm of Tstar_dev - squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & - k, l, m, n - - instance = phase_plasticityInstance(material_phase(ipc,ip,el)) - Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress - squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) - norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) - - if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero - Lp = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - else - gamma_dot = plastic_j2_gdot0(instance) & - * (sqrt(1.5_pReal) * norm_Tstar_dev / (plastic_j2_fTaylor(instance) * & - plasticState(phaseAt(ipc,ip,el))%state(1,phasememberAt(ipc,ip,el)))) & - **plastic_j2_n(instance) - - Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/plastic_j2_fTaylor(instance) - -!-------------------------------------------------------------------------------------------------- -! Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,m,n) = (plastic_j2_n(instance)-1.0_pReal) * & - Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal - forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & - dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal - dLp_dTstar99 = math_Plain3333to99(gamma_dot / plastic_j2_fTaylor(instance) * & - dLp_dTstar_3333 / norm_Tstar_dev) - end if -end subroutine plastic_j2_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_j2_dotState(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6) :: & - Tstar_dev_v !< deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - gamma_dot, & !< strainrate - hardening, & !< hardening coefficient - saturation, & !< saturation resistance - norm_Tstar_dev !< euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of, & !< shortcut notation for offset position in state array - ph !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(material_phase(ipc,ip,el)) - -!-------------------------------------------------------------------------------------------------- -! norm of deviatoric part of 2nd Piola-Kirchhoff stress - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - -!-------------------------------------------------------------------------------------------------- -! strain rate - gamma_dot = plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & - / &!----------------------------------------------------------------------------------- - (plastic_j2_fTaylor(instance)*plasticState(ph)%state(1,of)) )**plastic_j2_n(instance) - -!-------------------------------------------------------------------------------------------------- -! hardening coefficient - if (abs(gamma_dot) > 1e-12_pReal) then - if (abs(plastic_j2_tausat_SinhFitA(instance)) <= tiny(0.0_pReal)) then - saturation = plastic_j2_tausat(instance) - else - saturation = ( plastic_j2_tausat(instance) & - + ( log( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance)& - )**(1.0_pReal / plastic_j2_tausat_SinhFitD(instance))& - + sqrt( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance) & - )**(2.0_pReal / plastic_j2_tausat_SinhFitD(instance)) & - + 1.0_pReal ) & - ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) - )**(1.0_pReal / plastic_j2_tausat_SinhFitC(instance)) & - / ( plastic_j2_tausat_SinhFitB(instance) & - * (gamma_dot / plastic_j2_gdot0(instance))**(1.0_pReal / plastic_j2_n(instance)) & - ) & - ) - endif - hardening = ( plastic_j2_h0(instance) + plastic_j2_h0_slopeLnRate(instance) * log(gamma_dot) ) & - * abs( 1.0_pReal - plasticState(ph)%state(1,of)/saturation )**plastic_j2_a(instance) & - * sign(1.0_pReal, 1.0_pReal - plasticState(ph)%state(1,of)/saturation) - else - hardening = 0.0_pReal - endif - - plasticState(ph)%dotState(1,of) = hardening * gamma_dot - plasticState(ph)%dotState(2,of) = gamma_dot - -end subroutine plastic_j2_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_j2_postResults(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(plastic_j2_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_j2_postResults - - real(pReal), dimension(6) :: & - Tstar_dev_v ! deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - norm_Tstar_dev ! euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of, & !< shortcut notation for offset position in state array - ph, & !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) - c, & - o - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(material_phase(ipc,ip,el)) - -!-------------------------------------------------------------------------------------------------- -! calculate deviatoric part of 2nd Piola-Kirchhoff stress and its norm - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - - c = 0_pInt - plastic_j2_postResults = 0.0_pReal - - outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) - select case(plastic_j2_outputID(o,instance)) - case (flowstress_ID) - plastic_j2_postResults(c+1_pInt) = plasticState(ph)%state(1,of) - c = c + 1_pInt - case (strainrate_ID) - plastic_j2_postResults(c+1_pInt) = & - plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & - / &!---------------------------------------------------------------------------------- - (plastic_j2_fTaylor(instance) * plasticState(ph)%state(1,of)) ) ** plastic_j2_n(instance) - c = c + 1_pInt - end select - enddo outputsLoop - -end function plastic_j2_postResults - - -end module plastic_j2 diff --git a/code/plastic_none.f90 b/code/plastic_none.f90 deleted file mode 100644 index f624a80a2..000000000 --- a/code/plastic_none.f90 +++ /dev/null @@ -1,109 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for purely elastic material -!-------------------------------------------------------------------------------------------------- -module plastic_none - use prec, only: & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_none_sizePostResults - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_none_sizePostResult !< size of each post result output - - public :: & - plastic_none_init - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_none_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic - use IO, only: & - IO_timeStamp - use numerics, only: & - worldrank, & - numerics_integrator - use material, only: & - phase_plasticity, & - PLASTICITY_NONE_label, & - material_phase, & - plasticState, & - PLASTICITY_none_ID - - implicit none - - integer(pInt) :: & - maxNinstance, & - phase, & - NofMyPhase, & - sizeState, & - sizeDotState, & - sizeDeltaState - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONE_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_none_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - if (phase_plasticity(phase) == PLASTICITY_none_ID) then - NofMyPhase=count(material_phase==phase) - - sizeState = 0_pInt - plasticState(phase)%sizeState = sizeState - sizeDotState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - sizeDeltaState = 0_pInt - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = 0_pInt - plasticState(phase)%nSlip = 0_pInt - plasticState(phase)%nTwin = 0_pInt - plasticState(phase)%nTrans = 0_pInt - allocate(plasticState(phase)%aTolState (sizeState)) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase)) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase)) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase)) - allocate(plasticState(phase)%state (sizeState,NofMyPhase)) - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase)) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase)) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase)) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase)) - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase)) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase)) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase)) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase)) - endif - enddo initializeInstances - - allocate(plastic_none_sizePostResults(maxNinstance), source=0_pInt) - -end subroutine plastic_none_init - -end module plastic_none diff --git a/code/plastic_nonlocal.f90 b/code/plastic_nonlocal.f90 deleted file mode 100644 index 1922c08e2..000000000 --- a/code/plastic_nonlocal.f90 +++ /dev/null @@ -1,4031 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Christoph Kords, 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 -!> @brief material subroutine for plasticity including dislocation flux -!-------------------------------------------------------------------------------------------------- -module plastic_nonlocal - use prec, only: & - pReal, & - pInt - - implicit none - private - character(len=22), dimension(11), parameter, private :: & - BASICSTATES = ['rhoSglEdgePosMobile ', & - 'rhoSglEdgeNegMobile ', & - 'rhoSglScrewPosMobile ', & - 'rhoSglScrewNegMobile ', & - 'rhoSglEdgePosImmobile ', & - 'rhoSglEdgeNegImmobile ', & - 'rhoSglScrewPosImmobile', & - 'rhoSglScrewNegImmobile', & - 'rhoDipEdge ', & - 'rhoDipScrew ', & - 'accumulatedshear ' ] !< list of "basic" microstructural state variables that are independent from other state variables - - character(len=16), dimension(3), parameter, private :: & - DEPENDENTSTATES = ['rhoForest ', & - 'tauThreshold ', & - 'tauBack ' ] !< list of microstructural state variables that depend on other state variables - - character(len=20), dimension(6), parameter, private :: & - OTHERSTATES = ['velocityEdgePos ', & - 'velocityEdgeNeg ', & - 'velocityScrewPos ', & - 'velocityScrewNeg ', & - 'maxDipoleHeightEdge ', & - 'maxDipoleHeightScrew' ] !< list of other dependent state variables that are not updated by microstructure - - real(pReal), parameter, private :: & - KB = 1.38e-23_pReal !< Physical parameter, Boltzmann constant in J/Kelvin - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_nonlocal_sizeDotState, & !< number of dotStates = number of basic state variables - plastic_nonlocal_sizeDependentState, & !< number of dependent state variables - plastic_nonlocal_sizeState, & !< total number of state variables - plastic_nonlocal_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_nonlocal_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_nonlocal_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_nonlocal_Noutput !< number of outputs per instance of this plasticity - - integer(pInt), dimension(:,:), allocatable, private :: & - iGamma, & !< state indices for accumulated shear - iRhoF, & !< state indices for forest density - iTauF, & !< state indices for critical resolved shear stress - iTauB !< state indices for backstress - integer(pInt), dimension(:,:,:), allocatable, private :: & - iRhoU, & !< state indices for unblocked density - iRhoB, & !< state indices for blocked density - iRhoD, & !< state indices for dipole density - iV, & !< state indices for dislcation velocities - iD !< state indices for stable dipole height - - integer(pInt), dimension(:), allocatable, public, protected :: & - totalNslip !< total number of active slip systems for each instance - - integer(pInt), dimension(:,:), allocatable, private :: & - Nslip, & !< number of active slip systems for each family and instance - slipFamily, & !< lookup table relating active slip system to slip family for each instance - slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance - colinearSystem !< colinear system to the active slip system (only valid for fcc!) - - real(pReal), dimension(:), allocatable, private :: & - atomicVolume, & !< atomic volume - Dsd0, & !< prefactor for self-diffusion coefficient - selfDiffusionEnergy, & !< activation enthalpy for diffusion - aTolRho, & !< absolute tolerance for dislocation density in state integration - aTolShear, & !< absolute tolerance for accumulated shear in state integration - significantRho, & !< density considered significant - significantN, & !< number of dislocations considered significant - cutoffRadius, & !< cutoff radius for dislocation stress - doublekinkwidth, & !< width of a doubkle kink in multiples of the burgers vector length b - solidSolutionEnergy, & !< activation energy for solid solution in J - solidSolutionSize, & !< solid solution obstacle size in multiples of the burgers vector length - solidSolutionConcentration, & !< concentration of solid solution in atomic parts - pParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) - qParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) - viscosity, & !< viscosity for dislocation glide in Pa s - fattack, & !< attack frequency in Hz - rhoSglScatter, & !< standard deviation of scatter in initial dislocation density - surfaceTransmissivity, & !< transmissivity at free surface - grainboundaryTransmissivity, & !< transmissivity at grain boundary (identified by different texture) - CFLfactor, & !< safety factor for CFL flux condition - fEdgeMultiplication, & !< factor that determines how much edge dislocations contribute to multiplication (0...1) - rhoSglRandom, & - rhoSglRandomBinning, & - linetensionEffect, & - edgeJogFactor - - real(pReal), dimension(:,:), allocatable, private :: & - rhoSglEdgePos0, & !< initial edge_pos dislocation density per slip system for each family and instance - rhoSglEdgeNeg0, & !< initial edge_neg dislocation density per slip system for each family and instance - rhoSglScrewPos0, & !< initial screw_pos dislocation density per slip system for each family and instance - rhoSglScrewNeg0, & !< initial screw_neg dislocation density per slip system for each family and instance - rhoDipEdge0, & !< initial edge dipole dislocation density per slip system for each family and instance - rhoDipScrew0, & !< initial screw dipole dislocation density per slip system for each family and instance - lambda0PerSlipFamily, & !< mean free path prefactor for each family and instance - lambda0, & !< mean free path prefactor for each slip system and instance - burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each family and instance - burgers, & !< absolute length of burgers vector [m] for each slip system and instance - interactionSlipSlip !< coefficients for slip-slip interaction for each interaction type and instance - - real(pReal), dimension(:,:,:), allocatable, private :: & - minDipoleHeightPerSlipFamily, & !< minimum stable edge/screw dipole height for each family and instance - minDipoleHeight, & !< minimum stable edge/screw dipole height for each slip system and instance - peierlsStressPerSlipFamily, & !< Peierls stress (edge and screw) - peierlsStress, & !< Peierls stress (edge and screw) - forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance - forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance - interactionMatrixSlipSlip !< interaction matrix of the different slip systems for each instance - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - lattice2slip, & !< orthogonal transformation matrix from lattice coordinate system to slip coordinate system (passive rotation !!!) - rhoDotEdgeJogsOutput, & - sourceProbability - - real(pReal), dimension(:,:,:,:,:), allocatable, private :: & - rhoDotFluxOutput, & - rhoDotMultiplicationOutput, & - rhoDotSingle2DipoleGlideOutput, & - rhoDotAthermalAnnihilationOutput, & - rhoDotThermalAnnihilationOutput, & - nonSchmidProjection !< combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) - - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - compatibility !< slip system compatibility between me and my neighbors - - real(pReal), dimension(:,:), allocatable, private :: & - nonSchmidCoeff - - logical, dimension(:), allocatable, private :: & - shortRangeStressCorrection, & !< flag indicating the use of the short range stress correction by a excess density gradient term - probabilisticMultiplication - - enum, bind(c) - enumerator :: undefined_ID, & - rho_ID, & - delta_ID, & - rho_edge_ID, & - rho_screw_ID, & - rho_sgl_ID, & - delta_sgl_ID, & - rho_sgl_edge_ID, & - rho_sgl_edge_pos_ID, & - rho_sgl_edge_neg_ID, & - rho_sgl_screw_ID, & - rho_sgl_screw_pos_ID, & - rho_sgl_screw_neg_ID, & - rho_sgl_mobile_ID, & - rho_sgl_edge_mobile_ID, & - rho_sgl_edge_pos_mobile_ID, & - rho_sgl_edge_neg_mobile_ID, & - rho_sgl_screw_mobile_ID, & - rho_sgl_screw_pos_mobile_ID, & - rho_sgl_screw_neg_mobile_ID, & - rho_sgl_immobile_ID, & - rho_sgl_edge_immobile_ID, & - rho_sgl_edge_pos_immobile_ID, & - rho_sgl_edge_neg_immobile_ID, & - rho_sgl_screw_immobile_ID, & - rho_sgl_screw_pos_immobile_ID, & - rho_sgl_screw_neg_immobile_ID, & - rho_dip_ID, & - delta_dip_ID, & - rho_dip_edge_ID, & - rho_dip_screw_ID, & - excess_rho_ID, & - excess_rho_edge_ID, & - excess_rho_screw_ID, & - rho_forest_ID, & - shearrate_ID, & - resolvedstress_ID, & - resolvedstress_external_ID, & - resolvedstress_back_ID, & - resistance_ID, & - rho_dot_ID, & - rho_dot_sgl_ID, & - rho_dot_sgl_mobile_ID, & - rho_dot_dip_ID, & - rho_dot_gen_ID, & - rho_dot_gen_edge_ID, & - rho_dot_gen_screw_ID, & - rho_dot_sgl2dip_ID, & - rho_dot_sgl2dip_edge_ID, & - rho_dot_sgl2dip_screw_ID, & - rho_dot_ann_ath_ID, & - rho_dot_ann_the_ID, & - rho_dot_ann_the_edge_ID, & - rho_dot_ann_the_screw_ID, & - rho_dot_edgejogs_ID, & - rho_dot_flux_ID, & - rho_dot_flux_mobile_ID, & - rho_dot_flux_edge_ID, & - rho_dot_flux_screw_ID, & - velocity_edge_pos_ID, & - velocity_edge_neg_ID, & - velocity_screw_pos_ID, & - velocity_screw_neg_ID, & - slipdirectionx_ID, & - slipdirectiony_ID, & - slipdirectionz_ID, & - slipnormalx_ID, & - slipnormaly_ID, & - slipnormalz_ID, & - fluxdensity_edge_posx_ID, & - fluxdensity_edge_posy_ID, & - fluxdensity_edge_posz_ID, & - fluxdensity_edge_negx_ID, & - fluxdensity_edge_negy_ID, & - fluxdensity_edge_negz_ID, & - fluxdensity_screw_posx_ID, & - fluxdensity_screw_posy_ID, & - fluxdensity_screw_posz_ID, & - fluxdensity_screw_negx_ID, & - fluxdensity_screw_negy_ID, & - fluxdensity_screw_negz_ID, & - maximumdipoleheight_edge_ID, & - maximumdipoleheight_screw_ID, & - accumulatedshear_ID, & - dislocationstress_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_nonlocal_outputID !< ID of each post result output - - public :: & - plastic_nonlocal_init, & - plastic_nonlocal_stateInit, & - plastic_nonlocal_aTolState, & - plastic_nonlocal_microstructure, & - plastic_nonlocal_LpAndItsTangent, & - plastic_nonlocal_dotState, & - plastic_nonlocal_deltaState, & - plastic_nonlocal_updateCompatibility, & - plastic_nonlocal_postResults - - private :: & - plastic_nonlocal_kinetics, & - plastic_nonlocal_dislocationstress - - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_init(fileUnit) -use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) -use math, only: math_Mandel3333to66, & - math_Voigt66to3333, & - math_mul3x3, & - math_transpose33 -use IO, only: IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF -use debug, only: debug_level, & - debug_constitutive, & - debug_levelBasic -use mesh, only: mesh_NcpElems, & - mesh_maxNips, & - mesh_maxNipNeighbors -use material, only: phase_plasticity, & - homogenization_maxNgrains, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_NONLOCAL_label, & - PLASTICITY_NONLOCAL_ID, & - plasticState, & - MATERIAL_partPhase ,& - material_phase -use lattice -use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - -implicit none -integer(pInt), intent(in) :: fileUnit - -!*** local variables -integer(pInt), allocatable, dimension(:) :: chunkPos -integer(pInt) :: phase, & - maxNinstances, & - maxTotalNslip, & - f, & ! index of my slip family - instance, & ! index of my instance of this plasticity - l, & - ns, & ! short notation for total number of active slip systems for the current instance - o, & ! index of my output - s, & ! index of my slip system - s1, & ! index of my slip system - s2, & ! index of my slip system - it, & ! index of my interaction type - t, & ! index of dislocation type - c, & ! index of dislocation character - Nchunks_SlipSlip = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, & - Nchunks_nonSchmid = 0_pInt, & - mySize = 0_pInt ! to suppress warnings, safe as init is called only once - character(len=65536) :: & - tag = '', & - line = '' - - integer(pInt) :: sizeState, sizeDotState,sizeDependentState, sizeDeltaState - - - integer(pInt) :: NofMyPhase - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONLOCAL_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) - if (maxNinstances == 0) return ! we don't have to do anything if there's no instance for this constitutive law - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstances - -!*** memory allocation for global variables - -allocate(plastic_nonlocal_sizeDotState(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizeDependentState(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizeState(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizePostResults(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizePostResult(maxval(phase_Noutput), maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_Noutput(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_output(maxval(phase_Noutput), maxNinstances)) - plastic_nonlocal_output = '' -allocate(plastic_nonlocal_outputID(maxval(phase_Noutput), maxNinstances), source=undefined_ID) -allocate(Nslip(lattice_maxNslipFamily,maxNinstances), source=0_pInt) -allocate(slipFamily(lattice_maxNslip,maxNinstances), source=0_pInt) -allocate(slipSystemLattice(lattice_maxNslip,maxNinstances), source=0_pInt) -allocate(totalNslip(maxNinstances), source=0_pInt) -allocate(atomicVolume(maxNinstances), source=0.0_pReal) -allocate(Dsd0(maxNinstances), source=-1.0_pReal) -allocate(selfDiffusionEnergy(maxNinstances), source=0.0_pReal) -allocate(aTolRho(maxNinstances), source=0.0_pReal) -allocate(aTolShear(maxNinstances), source=0.0_pReal) -allocate(significantRho(maxNinstances), source=0.0_pReal) -allocate(significantN(maxNinstances), source=0.0_pReal) -allocate(cutoffRadius(maxNinstances), source=-1.0_pReal) -allocate(doublekinkwidth(maxNinstances), source=0.0_pReal) -allocate(solidSolutionEnergy(maxNinstances), source=0.0_pReal) -allocate(solidSolutionSize(maxNinstances), source=0.0_pReal) -allocate(solidSolutionConcentration(maxNinstances), source=0.0_pReal) -allocate(pParam(maxNinstances), source=1.0_pReal) -allocate(qParam(maxNinstances), source=1.0_pReal) -allocate(viscosity(maxNinstances), source=0.0_pReal) -allocate(fattack(maxNinstances), source=0.0_pReal) -allocate(rhoSglScatter(maxNinstances), source=0.0_pReal) -allocate(rhoSglRandom(maxNinstances), source=0.0_pReal) -allocate(rhoSglRandomBinning(maxNinstances), source=1.0_pReal) -allocate(surfaceTransmissivity(maxNinstances), source=1.0_pReal) -allocate(grainboundaryTransmissivity(maxNinstances), source=-1.0_pReal) -allocate(CFLfactor(maxNinstances), source=2.0_pReal) -allocate(fEdgeMultiplication(maxNinstances), source=0.0_pReal) -allocate(linetensionEffect(maxNinstances), source=0.0_pReal) -allocate(edgeJogFactor(maxNinstances), source=1.0_pReal) -allocate(shortRangeStressCorrection(maxNinstances), source=.false.) -allocate(probabilisticMultiplication(maxNinstances), source=.false.) - -allocate(rhoSglEdgePos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoSglEdgeNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoSglScrewPos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoSglScrewNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoDipEdge0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoDipScrew0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) -allocate(lambda0PerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) -allocate(interactionSlipSlip(lattice_maxNinteraction,maxNinstances), source=0.0_pReal) -allocate(minDipoleHeightPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=-1.0_pReal) -allocate(peierlsStressPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=0.0_pReal) -allocate(nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstances), source=0.0_pReal) - - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through phases of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_SlipSlip = maxval(lattice_InteractionSlipSlip(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - endif - cycle - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then ! one of my phases. do not short-circuit here (.and. with next if statement). It's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('rho') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('delta') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('delta_sgl') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_sgl_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_pos_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_neg_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_pos_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_neg_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_pos_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_neg_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_pos_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_neg_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('delta_dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dip_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dip_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('excess_rho') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('excess_rho_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('excess_rho_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_forest') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_forest_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = shearrate_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_external') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_external_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_back') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_back_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resistance_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_gen') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_gen_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_gen_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl2dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl2dip_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl2dip_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_ath') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_ath_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_the') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_the_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_the_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_edgejogs') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_edgejogs_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_edge_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_edge_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_screw_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_screw_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipdirection.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipdirection.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectiony_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipdirection.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipnormal.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipnormal.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormaly_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipnormal.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_pos.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_pos.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_pos.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_neg.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_neg.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_neg.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_pos.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_pos.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_pos.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_neg.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_neg.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_neg.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('maximumdipoleheight_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('maximumdipoleheight_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear','accumulated_shear') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = accumulatedshear_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('dislocationstress') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = dislocationstress_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - case ('nslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do f = 1_pInt, Nchunks_SlipFamilies - Nslip(f,instance) = IO_intValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosgledgepos0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglEdgePos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosgledgeneg0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglEdgeNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosglscrewpos0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglScrewPos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosglscrewneg0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglScrewNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhodipedge0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoDipEdge0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhodipscrew0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoDipScrew0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('lambda0') - do f = 1_pInt, Nchunks_SlipFamilies - lambda0PerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('burgers') - do f = 1_pInt, Nchunks_SlipFamilies - burgersPerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('cutoffradius','r') - cutoffRadius(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('minimumdipoleheightedge','ddipminedge') - do f = 1_pInt, Nchunks_SlipFamilies - minDipoleHeightPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('minimumdipoleheightscrew','ddipminscrew') - do f = 1_pInt, Nchunks_SlipFamilies - minDipoleHeightPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('atomicvolume') - atomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('selfdiffusionprefactor','dsd0') - Dsd0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('selfdiffusionenergy','qsd') - selfDiffusionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('atol_rho','atol_density','absolutetolerancedensity','absolutetolerance_density') - aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('atol_shear','atol_plasticshear','atol_accumulatedshear','absolutetoleranceshear','absolutetolerance_shear') - aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('significantrho','significant_rho','significantdensity','significant_density') - significantRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('significantn','significant_n','significantdislocations','significant_dislcations') - significantN(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('interaction_slipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') - do it = 1_pInt,Nchunks_SlipSlip - interactionSlipSlip(it,instance) = IO_floatValue(line,chunkPos,1_pInt+it) - enddo - case('linetension','linetensioneffect','linetension_effect') - linetensionEffect(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('edgejog','edgejogs','edgejogeffect','edgejog_effect') - edgeJogFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('peierlsstressedge','peierlsstress_edge') - do f = 1_pInt, Nchunks_SlipFamilies - peierlsStressPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('peierlsstressscrew','peierlsstress_screw') - do f = 1_pInt, Nchunks_SlipFamilies - peierlsStressPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('doublekinkwidth') - doublekinkwidth(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('solidsolutionenergy') - solidSolutionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('solidsolutionsize') - solidSolutionSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('solidsolutionconcentration') - solidSolutionConcentration(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('p') - pParam(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('q') - qParam(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('viscosity','glideviscosity') - viscosity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('attackfrequency','fattack') - fattack(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('rhosglscatter') - rhoSglScatter(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('rhosglrandom') - rhoSglRandom(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('rhosglrandombinning') - rhoSglRandomBinning(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('surfacetransmissivity') - surfaceTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('grainboundarytransmissivity') - grainboundaryTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('cflfactor') - CFLfactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('fedgemultiplication','edgemultiplicationfactor','edgemultiplication') - fEdgeMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('shortrangestresscorrection') - shortRangeStressCorrection(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_label//')') - do f = 1_pInt,Nchunks_nonSchmid - nonSchmidCoeff(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('probabilisticmultiplication','randomsources','randommultiplication','discretesources') - probabilisticMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then - instance = phase_plasticityInstance(phase) - if (sum(Nslip(:,instance)) <= 0_pInt) & - call IO_error(211_pInt,ext_msg='Nslip ('//PLASTICITY_NONLOCAL_label//')') - do o = 1_pInt,maxval(phase_Noutput) - if(len(plastic_nonlocal_output(o,instance)) > 64_pInt) & - call IO_error(666_pInt) - enddo - do f = 1_pInt,lattice_maxNslipFamily - if (Nslip(f,instance) > 0_pInt) then - if (rhoSglEdgePos0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglEdgePos0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglEdgeNeg0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglEdgeNeg0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglScrewPos0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglScrewPos0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglScrewNeg0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglScrewNeg0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoDipEdge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoDipEdge0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoDipScrew0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoDipScrew0 ('//PLASTICITY_NONLOCAL_label//')') - if (burgersPerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='Burgers ('//PLASTICITY_NONLOCAL_label//')') - if (lambda0PerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='lambda0 ('//PLASTICITY_NONLOCAL_label//')') - if (minDipoleHeightPerSlipFamily(f,1,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='minimumDipoleHeightEdge ('//PLASTICITY_NONLOCAL_label//')') - if (minDipoleHeightPerSlipFamily(f,2,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='minimumDipoleHeightScrew ('//PLASTICITY_NONLOCAL_label//')') - if (peierlsStressPerSlipFamily(f,1,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='peierlsStressEdge ('//PLASTICITY_NONLOCAL_label//')') - if (peierlsStressPerSlipFamily(f,2,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='peierlsStressScrew ('//PLASTICITY_NONLOCAL_label//')') - endif - enddo - if (any(interactionSlipSlip(1:maxval(lattice_interactionSlipSlip(:,:,phase)),instance) < 0.0_pReal)) & - call IO_error(211_pInt,ext_msg='interaction_SlipSlip ('//PLASTICITY_NONLOCAL_label//')') - if (linetensionEffect(instance) < 0.0_pReal .or. linetensionEffect(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='linetension ('//PLASTICITY_NONLOCAL_label//')') - if (edgeJogFactor(instance) < 0.0_pReal .or. edgeJogFactor(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='edgejog ('//PLASTICITY_NONLOCAL_label//')') - if (cutoffRadius(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='r ('//PLASTICITY_NONLOCAL_label//')') - if (atomicVolume(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='atomicVolume ('//PLASTICITY_NONLOCAL_label//')') - if (Dsd0(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='selfDiffusionPrefactor ('//PLASTICITY_NONLOCAL_label//')') - if (selfDiffusionEnergy(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='selfDiffusionEnergy ('//PLASTICITY_NONLOCAL_label//')') - if (aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='aTol_rho ('//PLASTICITY_NONLOCAL_label//')') - if (aTolShear(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='aTol_shear ('//PLASTICITY_NONLOCAL_label//')') - if (significantRho(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='significantRho ('//PLASTICITY_NONLOCAL_label//')') - if (significantN(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='significantN ('//PLASTICITY_NONLOCAL_label//')') - if (doublekinkwidth(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='doublekinkwidth ('//PLASTICITY_NONLOCAL_label//')') - if (solidSolutionEnergy(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='solidSolutionEnergy ('//PLASTICITY_NONLOCAL_label//')') - if (solidSolutionSize(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='solidSolutionSize ('//PLASTICITY_NONLOCAL_label//')') - if (solidSolutionConcentration(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='solidSolutionConcentration ('//PLASTICITY_NONLOCAL_label//')') - if (pParam(instance) <= 0.0_pReal .or. pParam(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='p ('//PLASTICITY_NONLOCAL_label//')') - if (qParam(instance) < 1.0_pReal .or. qParam(instance) > 2.0_pReal) & - call IO_error(211_pInt,ext_msg='q ('//PLASTICITY_NONLOCAL_label//')') - if (viscosity(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='viscosity ('//PLASTICITY_NONLOCAL_label//')') - if (fattack(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='attackFrequency ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglScatter(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglScatter ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglRandom(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglRandom ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglRandomBinning(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglRandomBinning ('//PLASTICITY_NONLOCAL_label//')') - if (surfaceTransmissivity(instance) < 0.0_pReal .or. surfaceTransmissivity(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='surfaceTransmissivity ('//PLASTICITY_NONLOCAL_label//')') - if (grainboundaryTransmissivity(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='grainboundaryTransmissivity ('//PLASTICITY_NONLOCAL_label//')') - if (CFLfactor(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='CFLfactor ('//PLASTICITY_NONLOCAL_label//')') - if (fEdgeMultiplication(instance) < 0.0_pReal .or. fEdgeMultiplication(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='edgemultiplicationfactor ('//PLASTICITY_NONLOCAL_label//')') - - - !*** determine total number of active slip systems - Nslip(1:lattice_maxNslipFamily,instance) = min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase), & - Nslip(1:lattice_maxNslipFamily,instance) ) ! we can't use more slip systems per family than specified in lattice - totalNslip(instance) = sum(Nslip(1:lattice_maxNslipFamily,instance)) - endif myPhase -enddo sanityChecks - - -!*** allocation of variables whose size depends on the total number of active slip systems - -maxTotalNslip = maxval(totalNslip) - -allocate(iRhoU(maxTotalNslip,4,maxNinstances), source=0_pInt) -allocate(iRhoB(maxTotalNslip,4,maxNinstances), source=0_pInt) -allocate(iRhoD(maxTotalNslip,2,maxNinstances), source=0_pInt) -allocate(iV(maxTotalNslip,4,maxNinstances), source=0_pInt) -allocate(iD(maxTotalNslip,2,maxNinstances), source=0_pInt) -allocate(iGamma(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(iRhoF(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(iTauF(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(iTauB(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(burgers(maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(lambda0(maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(minDipoleHeight(maxTotalNslip,2,maxNinstances), source=-1.0_pReal) -allocate(forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(lattice2slip(1:3, 1:3, maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(sourceProbability(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=2.0_pReal) - -allocate(rhoDotFluxOutput(maxTotalNslip,8,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotMultiplicationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotSingle2DipoleGlideOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotAthermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotThermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotEdgeJogsOutput(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) - -allocate(compatibility(2,maxTotalNslip,maxTotalNslip,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(peierlsStress(maxTotalNslip,2,maxNinstances), source=0.0_pReal) -allocate(colinearSystem(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - NofMyPhase=count(material_phase==phase) - myPhase2: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID .and. NofMyPhase/=0) then - instance = phase_plasticityInstance(phase) - !*** Inverse lookup of my slip system family and the slip system in lattice - - l = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily - do s = 1_pInt,Nslip(f,instance) - l = l + 1_pInt - slipFamily(l,instance) = f - slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt, phase)) + s - enddo; enddo - - - !*** determine size of state array - - ns = totalNslip(instance) - - sizeDotState = int(size(BASICSTATES),pInt) * ns - sizeDependentState = int(size(DEPENDENTSTATES),pInt) * ns - sizeState = sizeDotState + sizeDependentState & - + int(size(OTHERSTATES),pInt) * ns - sizeDeltaState = sizeDotState - - !*** determine indices to state array - - l = 0_pInt - do t = 1_pInt,4_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iRhoU(s,t,instance) = l - enddo - enddo - do t = 1_pInt,4_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iRhoB(s,t,instance) = l - enddo - enddo - do c = 1_pInt,2_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iRhoD(s,c,instance) = l - enddo - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iGamma(s,instance) = l - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iRhoF(s,instance) = l - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iTauF(s,instance) = l - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iTauB(s,instance) = l - enddo - do t = 1_pInt,4_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iV(s,t,instance) = l - enddo - enddo - do c = 1_pInt,2_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iD(s,c,instance) = l - enddo - enddo - if (iD(ns,2,instance) /= sizeState) & ! check if last index is equal to size of state - call IO_error(0_pInt, ext_msg = 'state indices not properly set ('//PLASTICITY_NONLOCAL_label//')') - - - !*** determine size of postResults array - - outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) - select case(plastic_nonlocal_outputID(o,instance)) - case( rho_ID, & - delta_ID, & - rho_edge_ID, & - rho_screw_ID, & - rho_sgl_ID, & - delta_sgl_ID, & - rho_sgl_edge_ID, & - rho_sgl_edge_pos_ID, & - rho_sgl_edge_neg_ID, & - rho_sgl_screw_ID, & - rho_sgl_screw_pos_ID, & - rho_sgl_screw_neg_ID, & - rho_sgl_mobile_ID, & - rho_sgl_edge_mobile_ID, & - rho_sgl_edge_pos_mobile_ID, & - rho_sgl_edge_neg_mobile_ID, & - rho_sgl_screw_mobile_ID, & - rho_sgl_screw_pos_mobile_ID, & - rho_sgl_screw_neg_mobile_ID, & - rho_sgl_immobile_ID, & - rho_sgl_edge_immobile_ID, & - rho_sgl_edge_pos_immobile_ID, & - rho_sgl_edge_neg_immobile_ID, & - rho_sgl_screw_immobile_ID, & - rho_sgl_screw_pos_immobile_ID, & - rho_sgl_screw_neg_immobile_ID, & - rho_dip_ID, & - delta_dip_ID, & - rho_dip_edge_ID, & - rho_dip_screw_ID, & - excess_rho_ID, & - excess_rho_edge_ID, & - excess_rho_screw_ID, & - rho_forest_ID, & - shearrate_ID, & - resolvedstress_ID, & - resolvedstress_external_ID, & - resolvedstress_back_ID, & - resistance_ID, & - rho_dot_ID, & - rho_dot_sgl_ID, & - rho_dot_sgl_mobile_ID, & - rho_dot_dip_ID, & - rho_dot_gen_ID, & - rho_dot_gen_edge_ID, & - rho_dot_gen_screw_ID, & - rho_dot_sgl2dip_ID, & - rho_dot_sgl2dip_edge_ID, & - rho_dot_sgl2dip_screw_ID, & - rho_dot_ann_ath_ID, & - rho_dot_ann_the_ID, & - rho_dot_ann_the_edge_ID, & - rho_dot_ann_the_screw_ID, & - rho_dot_edgejogs_ID, & - rho_dot_flux_ID, & - rho_dot_flux_mobile_ID, & - rho_dot_flux_edge_ID, & - rho_dot_flux_screw_ID, & - velocity_edge_pos_ID, & - velocity_edge_neg_ID, & - velocity_screw_pos_ID, & - velocity_screw_neg_ID, & - slipdirectionx_ID, & - slipdirectiony_ID, & - slipdirectionz_ID, & - slipnormalx_ID, & - slipnormaly_ID, & - slipnormalz_ID, & - fluxdensity_edge_posx_ID, & - fluxdensity_edge_posy_ID, & - fluxdensity_edge_posz_ID, & - fluxdensity_edge_negx_ID, & - fluxdensity_edge_negy_ID, & - fluxdensity_edge_negz_ID, & - fluxdensity_screw_posx_ID, & - fluxdensity_screw_posy_ID, & - fluxdensity_screw_posz_ID, & - fluxdensity_screw_negx_ID, & - fluxdensity_screw_negy_ID, & - fluxdensity_screw_negz_ID, & - maximumdipoleheight_edge_ID, & - maximumdipoleheight_screw_ID, & - accumulatedshear_ID ) - mySize = totalNslip(instance) - case(dislocationstress_ID) - mySize = 6_pInt - case default - end select - - if (mySize > 0_pInt) then ! any meaningful output found - plastic_nonlocal_sizePostResult(o,instance) = mySize - plastic_nonlocal_sizePostResults(instance) = plastic_nonlocal_sizePostResults(instance) + mySize - endif - enddo outputsLoop - - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_nonlocal_sizePostResults(instance) - plasticState(phase)%nonlocal = .true. - plasticState(phase)%nSlip = totalNslip(instance) - plasticState(phase)%nTwin = 0_pInt - plasticState(phase)%nTrans= 0_pInt - allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) - - do s1 = 1_pInt,ns - f = slipFamily(s1,instance) - - !*** burgers vector, mean free path prefactor and minimum dipole distance for each slip system - - burgers(s1,instance) = burgersPerSlipFamily(f,instance) - lambda0(s1,instance) = lambda0PerSlipFamily(f,instance) - minDipoleHeight(s1,1:2,instance) = minDipoleHeightPerSlipFamily(f,1:2,instance) - peierlsStress(s1,1:2,instance) = peierlsStressPerSlipFamily(f,1:2,instance) - - do s2 = 1_pInt,ns - - !*** calculation of forest projections for edge and screw dislocations. s2 acts as forest for s1 - - forestProjectionEdge(s1,s2,instance) & - = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & - lattice_st(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of edge dislocations is the projection of (t = b x n) onto the slip normal of the respective slip plane - - forestProjectionScrew(s1,s2,instance) & - = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & - lattice_sd(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of screw dislocations is the projection of b onto the slip normal of the respective splip plane - - !*** calculation of interaction matrices - - interactionMatrixSlipSlip(s1,s2,instance) & - = interactionSlipSlip(lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & - slipSystemLattice(s2,instance), & - phase), instance) - - !*** colinear slip system (only makes sense for fcc like it is defined here) - - if (lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & - slipSystemLattice(s2,instance), & - phase) == 3_pInt) then - colinearSystem(s1,instance) = s2 - endif - - enddo - - !*** rotation matrix from lattice configuration to slip system - - lattice2slip(1:3,1:3,s1,instance) & - = math_transpose33( reshape([ lattice_sd(1:3, slipSystemLattice(s1,instance), phase), & - -lattice_st(1:3, slipSystemLattice(s1,instance), phase), & - lattice_sn(1:3, slipSystemLattice(s1,instance), phase)], [3,3])) - enddo - - - !*** combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) - !* four types t: - !* 1) positive screw at positive resolved stress - !* 2) positive screw at negative resolved stress - !* 3) negative screw at positive resolved stress - !* 4) negative screw at negative resolved stress - - do s = 1_pInt,ns - do l = 1_pInt,lattice_NnonSchmid(phase) - nonSchmidProjection(1:3,1:3,1,s,instance) = nonSchmidProjection(1:3,1:3,1,s,instance) & - + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l,slipSystemLattice(s,instance),phase) - nonSchmidProjection(1:3,1:3,2,s,instance) = nonSchmidProjection(1:3,1:3,2,s,instance) & - + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l+1,slipSystemLattice(s,instance),phase) - enddo - nonSchmidProjection(1:3,1:3,3,s,instance) = -nonSchmidProjection(1:3,1:3,2,s,instance) - nonSchmidProjection(1:3,1:3,4,s,instance) = -nonSchmidProjection(1:3,1:3,1,s,instance) - forall (t = 1:4) & - nonSchmidProjection(1:3,1:3,t,s,instance) = nonSchmidProjection(1:3,1:3,t,s,instance) & - + lattice_Sslip(1:3,1:3,1,slipSystemLattice(s,instance),phase) - enddo - - call plastic_nonlocal_aTolState(phase,instance) - endif myPhase2 - - enddo initializeInstances - -end subroutine plastic_nonlocal_init - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- - -subroutine plastic_nonlocal_stateInit() -use IO, only: IO_error -use lattice, only: lattice_maxNslipFamily -use math, only: math_sampleGaussVar -use mesh, only: mesh_ipVolume, & - mesh_NcpElems, & - mesh_element, & - FE_Nips, & - FE_geomtype -use material, only: material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticity ,& - PLASTICITY_NONLOCAL_ID -implicit none - -integer(pInt) :: e, & - i, & - ns, & ! short notation for total number of active slip systems - f, & ! index of lattice family - from, & - upto, & - s, & ! index of slip system - t, & - j, & - instance, & - maxNinstances -real(pReal), dimension(2) :: noise -real(pReal), dimension(4) :: rnd -real(pReal) meanDensity, & - totalVolume, & - densityBinning, & - minimumIpVolume - -maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) - -do instance = 1_pInt,maxNinstances - ns = totalNslip(instance) - - ! randomly distribute dislocation segments on random slip system and of random type in the volume - if (rhoSglRandom(instance) > 0.0_pReal) then - - ! get the total volume of the instance - - minimumIpVolume = huge(1.0_pReal) - totalVolume = 0.0_pReal - do e = 1_pInt,mesh_NcpElems - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & - .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then - totalVolume = totalVolume + mesh_ipVolume(i,e) - minimumIpVolume = min(minimumIpVolume, mesh_ipVolume(i,e)) - endif - enddo - enddo - densityBinning = rhoSglRandomBinning(instance) / minimumIpVolume ** (2.0_pReal / 3.0_pReal) - - ! subsequently fill random ips with dislocation segments until we reach the desired overall density - - meanDensity = 0.0_pReal - do while(meanDensity < rhoSglRandom(instance)) - call random_number(rnd) - e = nint(rnd(1)*real(mesh_NcpElems,pReal)+0.5_pReal,pInt) - i = nint(rnd(2)*real(FE_Nips(FE_geomtype(mesh_element(2,e))),pReal)+0.5_pReal,pInt) - if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & - .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then - s = nint(rnd(3)*real(ns,pReal)+0.5_pReal,pInt) - t = nint(rnd(4)*4.0_pReal+0.5_pReal,pInt) - meanDensity = meanDensity + densityBinning * mesh_ipVolume(i,e) / totalVolume - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) = & - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) & - + densityBinning - endif - enddo - ! homogeneous distribution of density with some noise - else - do e = 1_pInt,mesh_NcpElems - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & - .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then - do f = 1_pInt,lattice_maxNslipFamily - from = 1_pInt + sum(Nslip(1:f-1_pInt,instance)) - upto = sum(Nslip(1:f,instance)) - do s = from,upto - do j = 1_pInt,2_pInt - noise(j) = math_sampleGaussVar(0.0_pReal, rhoSglScatter(instance)) - enddo - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,1,instance),phasememberAt(1,i,e)) = & - rhoSglEdgePos0(f,instance) + noise(1) - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,2,instance),phasememberAt(1,i,e)) = & - rhoSglEdgeNeg0(f,instance) + noise(1) - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,3,instance),phasememberAt(1,i,e)) = & - rhoSglScrewPos0(f,instance) + noise(2) - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,4,instance),phasememberAt(1,i,e)) = & - rhoSglScrewNeg0(f,instance) + noise(2) - enddo - plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,1,instance),phasememberAt(1,i,e)) = & - rhoDipEdge0(f,instance) - plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,2,instance),phasememberAt(1,i,e)) = & - rhoDipScrew0(f,instance) - enddo - endif - enddo - enddo - endif -enddo - -end subroutine plastic_nonlocal_stateInit - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - integer(pInt) :: & - ns, & - t, c - - ns = totalNslip(instance) - forall (t = 1_pInt:4_pInt) - plasticState(ph)%aTolState(iRhoU(1:ns,t,instance)) = aTolRho(instance) - plasticState(ph)%aTolState(iRhoB(1:ns,t,instance)) = aTolRho(instance) - end forall - forall (c = 1_pInt:2_pInt) & - plasticState(ph)%aTolState(iRhoD(1:ns,c,instance)) = aTolRho(instance) - - plasticState(ph)%aTolState(iGamma(1:ns,instance)) = aTolShear(instance) - -end subroutine plastic_nonlocal_aTolState - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates quantities characterizing the microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_microstructure(Fe, Fp, ip, el) -use IO, only: & - IO_error -use math, only: & - pi, & - math_mul33x3, & - math_mul3x3, & - math_inv33, & - math_transpose33 -use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use mesh, only: & - mesh_element, & - mesh_ipNeighborhood, & - mesh_ipCoordinates, & - mesh_ipVolume, & - mesh_ipAreaNormal, & - mesh_ipArea, & - FE_NipNeighbors, & - mesh_maxNipNeighbors, & - FE_geomtype, & - FE_celltype -use material, only: & - material_phase, & - phase_localPlasticity, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance -use lattice, only: & - lattice_sd, & - lattice_st, & - lattice_mu, & - lattice_nu, & - lattice_structure, & - LATTICE_bcc_ID, & - LATTICE_fcc_ID - -implicit none - -integer(pInt), intent(in) :: ip, & ! current integration point - el ! current element -real(pReal), dimension(3,3), intent(in) :: & - Fe, & ! elastic deformation gradient - Fp ! elastic deformation gradient - - integer(pInt) :: & - ph, & !< phase - of, & !< offset - np, & !< neighbor phase - no !< nieghbor offset - -integer(pInt) neighbor_el, & ! element number of neighboring material point - neighbor_ip, & ! integration point of neighboring material point - instance, & ! my instance of this plasticity - neighbor_instance, & ! instance of this plasticity of neighboring material point - neighbor_phase, & - ns, & ! total number of active slip systems at my material point - neighbor_ns, & ! total number of active slip systems at neighboring material point - c, & ! index of dilsocation character (edge, screw) - s, & ! slip system index - t, & ! index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) - dir, & - n, & - nRealNeighbors ! number of really existing neighbors -integer(pInt), dimension(2) :: neighbors -real(pReal) FVsize, & - correction, & - myRhoForest -real(pReal), dimension(2) :: rhoExcessGradient, & - rhoExcessGradient_over_rho, & - rhoTotal -real(pReal), dimension(3) :: rhoExcessDifferences, & - normal_latticeConf -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoForest, & ! forest dislocation density - tauBack, & ! back stress from pileup on same slip system - tauThreshold ! threshold shear stress -real(pReal), dimension(3,3) :: invFe, & ! inverse of elastic deformation gradient - invFp, & ! inverse of plastic deformation gradient - connections, & - invConnections -real(pReal), dimension(3,mesh_maxNipNeighbors) :: & - connection_latticeConf -real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoExcess -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - rhoDip ! dipole dislocation density (edge, screw) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))), & - totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - myInteractionMatrix ! corrected slip interaction matrix -real(pReal), dimension(2,maxval(totalNslip),mesh_maxNipNeighbors) :: & - neighbor_rhoExcess, & ! excess density at neighboring material point - neighbor_rhoTotal ! total density at neighboring material point -real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - m ! direction of dislocation motion - -ph = phaseAt(1,ip,el) -of = phasememberAt(1,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - -!*** get basic states - - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities - -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal -where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoDip) < significantRho(instance)) & - rhoDip = 0.0_pReal - -!*** calculate the forest dislocation density -!*** (= projection of screw and edge dislocations) - -forall (s = 1_pInt:ns) & - rhoForest(s) = dot_product((sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1)), & - forestProjectionEdge(s,1:ns,instance)) & - + dot_product((sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2)), & - forestProjectionScrew(s,1:ns,instance)) - - -!*** calculate the threshold shear stress for dislocation slip -!*** coefficients are corrected for the line tension effect -!*** (see Kubin,Devincre,Hoc; 2008; Modeling dislocation storage rates and mean free paths in face-centered cubic crystals) - -myInteractionMatrix = 0.0_pReal -myInteractionMatrix(1:ns,1:ns) = interactionMatrixSlipSlip(1:ns,1:ns,instance) -if (lattice_structure(ph) == LATTICE_bcc_ID .or. lattice_structure(ph) == LATTICE_fcc_ID) then ! only fcc and bcc - do s = 1_pInt,ns - myRhoForest = max(rhoForest(s),significantRho(instance)) - correction = ( 1.0_pReal - linetensionEffect(instance) & - + linetensionEffect(instance) & - * log(0.35_pReal * burgers(s,instance) * sqrt(myRhoForest)) & - / log(0.35_pReal * burgers(s,instance) * 1e6_pReal)) ** 2.0_pReal - myInteractionMatrix(s,1:ns) = correction * myInteractionMatrix(s,1:ns) - enddo -endif -forall (s = 1_pInt:ns) & - tauThreshold(s) = lattice_mu(ph) * burgers(s,instance) & - * sqrt(dot_product((sum(abs(rhoSgl),2) + sum(abs(rhoDip),2)), myInteractionMatrix(s,1:ns))) - - -!*** calculate the dislocation stress of the neighboring excess dislocation densities -!*** zero for material points of local plasticity - -tauBack = 0.0_pReal - -if (.not. phase_localPlasticity(ph) .and. shortRangeStressCorrection(instance)) then - invFe = math_inv33(Fe) - invFp = math_inv33(Fp) - rhoExcess(1,1:ns) = rhoSgl(1:ns,1) - rhoSgl(1:ns,2) - rhoExcess(2,1:ns) = rhoSgl(1:ns,3) - rhoSgl(1:ns,4) - FVsize = mesh_ipVolume(ip,el) ** (1.0_pReal/3.0_pReal) - - !* loop through my neighborhood and get the connection vectors (in lattice frame) and the excess densities - - nRealNeighbors = 0_pInt - neighbor_rhoTotal = 0.0_pReal - do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) - neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - np = phaseAt(1,neighbor_ip,neighbor_el) - no = phasememberAt(1,neighbor_ip,neighbor_el) - if (neighbor_el > 0 .and. neighbor_ip > 0) then - neighbor_phase = material_phase(1,neighbor_ip,neighbor_el) - neighbor_instance = phase_plasticityInstance(neighbor_phase) - neighbor_ns = totalNslip(neighbor_instance) - if (.not. phase_localPlasticity(neighbor_phase) & - .and. neighbor_instance == instance) then ! same instance should be same structure - if (neighbor_ns == ns) then - nRealNeighbors = nRealNeighbors + 1_pInt - forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - - neighbor_rhoExcess(c,s,n) = & - max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles - - max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) ! negative mobiles - neighbor_rhoTotal(c,s,n) = & - max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles - + max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) & ! negative mobiles - + abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads - + abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance), no)) & ! negative deads - + max(plasticState(np)%state(iRhoD(s,c,neighbor_instance), no), 0.0_pReal) ! dipoles - - endforall - connection_latticeConf(1:3,n) = & - math_mul33x3(invFe, mesh_ipCoordinates(1:3,neighbor_ip,neighbor_el) & - - mesh_ipCoordinates(1:3,ip,el)) - normal_latticeConf = math_mul33x3(math_transpose33(invFp), mesh_ipAreaNormal(1:3,n,ip,el)) - if (math_mul3x3(normal_latticeConf,connection_latticeConf(1:3,n)) < 0.0_pReal) then ! neighboring connection points in opposite direction to face normal: must be periodic image - connection_latticeConf(1:3,n) = normal_latticeConf * mesh_ipVolume(ip,el) & - / mesh_ipArea(n,ip,el) ! instead take the surface normal scaled with the diameter of the cell - endif - else - ! different number of active slip systems - call IO_error(-1_pInt,ext_msg='different number of active slip systems in neighboring IPs of same crystal structure') - endif - else - ! local neighbor or different lattice structure or different constitution instance -> use central values instead - connection_latticeConf(1:3,n) = 0.0_pReal - neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess - endif - else - ! free surface -> use central values instead - connection_latticeConf(1:3,n) = 0.0_pReal - neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess - endif - enddo - - - !* loop through the slip systems and calculate the dislocation gradient by - !* 1. interpolation of the excess density in the neighorhood - !* 2. interpolation of the dead dislocation density in the central volume - - m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) - m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) - - do s = 1_pInt,ns - - !* gradient from interpolation of neighboring excess density - - do c = 1_pInt,2_pInt - do dir = 1_pInt,3_pInt - neighbors(1) = 2_pInt * dir - 1_pInt - neighbors(2) = 2_pInt * dir - connections(dir,1:3) = connection_latticeConf(1:3,neighbors(1)) & - - connection_latticeConf(1:3,neighbors(2)) - rhoExcessDifferences(dir) = neighbor_rhoExcess(c,s,neighbors(1)) & - - neighbor_rhoExcess(c,s,neighbors(2)) - enddo - invConnections = math_inv33(connections) - if (all(abs(invConnections) <= tiny(0.0_pReal))) & ! check for failed in version (math_inv33 returns 0) and avoid floating point equality comparison - call IO_error(-1_pInt,ext_msg='back stress calculation: inversion error') - rhoExcessGradient(c) = math_mul3x3(m(1:3,s,c), & - math_mul33x3(invConnections,rhoExcessDifferences)) - enddo - - !* plus gradient from deads - - do t = 1_pInt,4_pInt - c = (t - 1_pInt) / 2_pInt + 1_pInt - rhoExcessGradient(c) = rhoExcessGradient(c) + rhoSgl(s,t+4_pInt) / FVsize - enddo - - !* normalized with the total density - - rhoExcessGradient_over_rho = 0.0_pReal - forall (c = 1_pInt:2_pInt) & - rhoTotal(c) = (sum(abs(rhoSgl(s,[2*c-1,2*c,2*c+3,2*c+4]))) + rhoDip(s,c) & - + sum(neighbor_rhoTotal(c,s,:))) / real(1_pInt + nRealNeighbors,pReal) - forall (c = 1_pInt:2_pInt, rhoTotal(c) > 0.0_pReal) & - rhoExcessGradient_over_rho(c) = rhoExcessGradient(c) / rhoTotal(c) - - !* gives the local stress correction when multiplied with a factor - - tauBack(s) = - lattice_mu(ph) * burgers(s,instance) / (2.0_pReal * pi) & - * (rhoExcessGradient_over_rho(1) / (1.0_pReal - lattice_nu(ph)) & - + rhoExcessGradient_over_rho(2)) - - enddo -endif - - -!*** set dependent states -plasticState(ph)%state(iRhoF(1:ns,instance),of) = rhoForest -plasticState(ph)%state(iTauF(1:ns,instance),of) = tauThreshold -plasticState(ph)%state(iTauB(1:ns,instance),of) = tauBack - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_microstructure at el ip ',el,ip - write(6,'(a,/,12x,12(e10.3,1x))') '<< CONST >> rhoForest', rhoForest - write(6,'(a,/,12x,12(f10.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold/1e6 - write(6,'(a,/,12x,12(f10.5,1x),/)') '<< CONST >> tauBack / MPa', tauBack/1e6 - endif -#endif - -end subroutine plastic_nonlocal_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates kinetics -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_kinetics(v, dv_dtau, dv_dtauNS, tau, tauNS, & - tauThreshold, c, Temperature, ip, el) - -use debug, only: debug_level, & - debug_constitutive, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use material, only: material_phase, & - phase_plasticityInstance - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el, & !< current element number - c !< dislocation character (1:edge, 2:screw) -real(pReal), intent(in) :: Temperature !< temperature -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & - intent(in) :: tau, & !< resolved external shear stress (without non Schmid effects) - tauNS, & !< resolved external shear stress (including non Schmid effects) - tauThreshold !< threshold shear stress - -!*** output variables -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & - intent(out) :: v, & !< velocity - dv_dtau, & !< velocity derivative with respect to resolved shear stress (without non Schmid contributions) - dv_dtauNS !< velocity derivative with respect to resolved shear stress (including non Schmid contributions) - -!*** local variables -integer(pInt) :: instance, & !< current instance of this plasticity - ns, & !< short notation for the total number of active slip systems - s !< index of my current slip system -real(pReal) tauRel_P, & - tauRel_S, & - tauEff, & !< effective shear stress - tPeierls, & !< waiting time in front of a peierls barriers - tSolidSolution, & !< waiting time in front of a solid solution obstacle - vViscous, & !< viscous glide velocity - dtPeierls_dtau, & !< derivative with respect to resolved shear stress - dtSolidSolution_dtau, & !< derivative with respect to resolved shear stress - meanfreepath_S, & !< mean free travel distance for dislocations between two solid solution obstacles - meanfreepath_P, & !< mean free travel distance for dislocations between two Peierls barriers - jumpWidth_P, & !< depth of activated area - jumpWidth_S, & !< depth of activated area - activationLength_P, & !< length of activated dislocation line - activationLength_S, & !< length of activated dislocation line - activationVolume_P, & !< volume that needs to be activated to overcome barrier - activationVolume_S, & !< volume that needs to be activated to overcome barrier - activationEnergy_P, & !< energy that is needed to overcome barrier - activationEnergy_S, & !< energy that is needed to overcome barrier - criticalStress_P, & !< maximum obstacle strength - criticalStress_S, & !< maximum obstacle strength - mobility !< dislocation mobility - - -instance = phase_plasticityInstance(material_phase(1_pInt,ip,el)) -ns = totalNslip(instance) - -v = 0.0_pReal -dv_dtau = 0.0_pReal -dv_dtauNS = 0.0_pReal - - -if (Temperature > 0.0_pReal) then - do s = 1_pInt,ns - if (abs(tau(s)) > tauThreshold(s)) then - - !* Peierls contribution - !* Effective stress includes non Schmid constributions - !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity - - tauEff = max(0.0_pReal, abs(tauNS(s)) - tauThreshold(s)) ! ensure that the effective stress is positive - meanfreepath_P = burgers(s,instance) - jumpWidth_P = burgers(s,instance) - activationLength_P = doublekinkwidth(instance) * burgers(s,instance) - activationVolume_P = activationLength_P * jumpWidth_P * burgers(s,instance) - criticalStress_P = peierlsStress(s,c,instance) - activationEnergy_P = criticalStress_P * activationVolume_P - tauRel_P = min(1.0_pReal, tauEff / criticalStress_P) ! ensure that the activation probability cannot become greater than one - tPeierls = 1.0_pReal / fattack(instance) & - * exp(activationEnergy_P / (KB * Temperature) & - * (1.0_pReal - tauRel_P**pParam(instance))**qParam(instance)) - if (tauEff < criticalStress_P) then - dtPeierls_dtau = tPeierls * pParam(instance) * qParam(instance) * activationVolume_P / (KB * Temperature) & - * (1.0_pReal - tauRel_P**pParam(instance))**(qParam(instance)-1.0_pReal) & - * tauRel_P**(pParam(instance)-1.0_pReal) - else - dtPeierls_dtau = 0.0_pReal - endif - - - !* Contribution from solid solution strengthening - !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity - - tauEff = abs(tau(s)) - tauThreshold(s) - meanfreepath_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) - jumpWidth_S = solidSolutionSize(instance) * burgers(s,instance) - activationLength_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) - activationVolume_S = activationLength_S * jumpWidth_S * burgers(s,instance) - activationEnergy_S = solidSolutionEnergy(instance) - criticalStress_S = activationEnergy_S / activationVolume_S - tauRel_S = min(1.0_pReal, tauEff / criticalStress_S) ! ensure that the activation probability cannot become greater than one - tSolidSolution = 1.0_pReal / fattack(instance) & - * exp(activationEnergy_S / (KB * Temperature) & - * (1.0_pReal - tauRel_S**pParam(instance))**qParam(instance)) - if (tauEff < criticalStress_S) then - dtSolidSolution_dtau = tSolidSolution * pParam(instance) * qParam(instance) & - * activationVolume_S / (KB * Temperature) & - * (1.0_pReal - tauRel_S**pParam(instance))**(qParam(instance)-1.0_pReal) & - * tauRel_S**(pParam(instance)-1.0_pReal) - else - dtSolidSolution_dtau = 0.0_pReal - endif - - - !* viscous glide velocity - - tauEff = abs(tau(s)) - tauThreshold(s) - mobility = burgers(s,instance) / viscosity(instance) - vViscous = mobility * tauEff - - - !* Mean velocity results from waiting time at peierls barriers and solid solution obstacles with respective meanfreepath of - !* free flight at glide velocity in between. - !* adopt sign from resolved stress - - v(s) = sign(1.0_pReal,tau(s)) & - / (tPeierls / meanfreepath_P + tSolidSolution / meanfreepath_S + 1.0_pReal / vViscous) - dv_dtau(s) = v(s) * v(s) * (dtSolidSolution_dtau / meanfreepath_S & - + mobility / (vViscous * vViscous)) - dv_dtauNS(s) = v(s) * v(s) * dtPeierls_dtau / meanfreepath_P - endif - enddo -endif - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_kinetics at el ip',el,ip - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold / 1e6_pReal - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tau / MPa', tau / 1e6_pReal - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauNS / MPa', tauNS / 1e6_pReal - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> v / 1e-3m/s', v * 1e3 - write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtau', dv_dtau - write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtauNS', dv_dtauNS - endif -#endif - -end subroutine plastic_nonlocal_kinetics - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_LpAndItsTangent(Lp, dLp_dTstar99, Tstar_v, Temperature, ip, el) - -use math, only: math_Plain3333to99, & - math_mul6x6, & - math_mul33xx33, & - math_Mandel6to33 -use debug, only: debug_level, & - debug_constitutive, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use material, only: material_phase, & - plasticState, & - phaseAt, phasememberAt,& - phase_plasticityInstance -use lattice, only: lattice_Sslip, & - lattice_Sslip_v, & - lattice_NnonSchmid -use mesh, only: mesh_ipVolume - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el !< current element number -real(pReal), intent(in) :: Temperature !< temperature -real(pReal), dimension(6), intent(in) :: Tstar_v !< 2nd Piola-Kirchhoff stress in Mandel notation - - -!*** output variables -real(pReal), dimension(3,3), intent(out) :: Lp !< plastic velocity gradient -real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 !< derivative of Lp with respect to Tstar (9x9 matrix) - -!*** local variables -integer(pInt) instance, & !< current instance of this plasticity - ns, & !< short notation for the total number of active slip systems - i, & - j, & - k, & - l, & - ph, & !phase number - of, & !offset - t, & !< dislocation type - s, & !< index of my current slip system - sLattice !< index of my current slip system according to lattice order -real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 !< derivative of Lp with respect to Tstar (3x3x3x3 matrix) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl !< single dislocation densities (including blocked) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - v, & !< velocity - tauNS, & !< resolved shear stress including non Schmid and backstress terms - dv_dtau, & !< velocity derivative with respect to the shear stress - dv_dtauNS !< velocity derivative with respect to the shear stress -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - tau, & !< resolved shear stress including backstress terms - gdotTotal, & !< shear rate - tauBack, & !< back stress from dislocation gradients on same slip system - tauThreshold !< threshold shear stress -!*** shortcut for mapping -ph = phaseAt(1_pInt,ip,el) -of = phasememberAt(1_pInt,ip,el) - -!*** initialize local variables - -Lp = 0.0_pReal -dLp_dTstar3333 = 0.0_pReal - -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - - -!*** shortcut to state variables - - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - - rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) -endforall -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal - -tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) -tauThreshold = plasticState(ph)%state(iTauF(1:ns,instance),of) - - -!*** get resolved shear stress -!*** for screws possible non-schmid contributions are also taken into account - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) - tauNS(s,1) = tau(s) - tauNS(s,2) = tau(s) - if (tau(s) > 0.0_pReal) then - tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,1,s,instance)) - tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,3,s,instance)) - else - tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,2,s,instance)) - tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,4,s,instance)) - endif -enddo -forall (t = 1_pInt:4_pInt) & - tauNS(1:ns,t) = tauNS(1:ns,t) + tauBack ! add backstress -tau = tau + tauBack ! add backstress - - -!*** get dislocation velocity and its tangent and store the velocity in the state array - -! edges -call plastic_nonlocal_kinetics(v(1:ns,1), dv_dtau(1:ns,1), dv_dtauNS(1:ns,1), & - tau(1:ns), tauNS(1:ns,1), tauThreshold(1:ns), & - 1_pInt, Temperature, ip, el) -v(1:ns,2) = v(1:ns,1) -dv_dtau(1:ns,2) = dv_dtau(1:ns,1) -dv_dtauNS(1:ns,2) = dv_dtauNS(1:ns,1) - -!screws -if (lattice_NnonSchmid(ph) == 0_pInt) then ! no non-Schmid contributions - forall(t = 3_pInt:4_pInt) - v(1:ns,t) = v(1:ns,1) - dv_dtau(1:ns,t) = dv_dtau(1:ns,1) - dv_dtauNS(1:ns,t) = dv_dtauNS(1:ns,1) - endforall -else ! take non-Schmid contributions into account - do t = 3_pInt,4_pInt - call plastic_nonlocal_kinetics(v(1:ns,t), dv_dtau(1:ns,t), dv_dtauNS(1:ns,t), & - tau(1:ns), tauNS(1:ns,t), tauThreshold(1:ns), & - 2_pInt , Temperature, ip, el) - enddo -endif - - -!*** store velocity in state - -forall (t = 1_pInt:4_pInt) & - plasticState(ph)%state(iV(1:ns,t,instance),of) = v(1:ns,t) -!*** Bauschinger effect - -forall (s = 1_pInt:ns, t = 5_pInt:8_pInt, rhoSgl(s,t) * v(s,t-4_pInt) < 0.0_pReal) & - rhoSgl(s,t-4_pInt) = rhoSgl(s,t-4_pInt) + abs(rhoSgl(s,t)) - - -!*** Calculation of Lp and its tangent - -gdotTotal = sum(rhoSgl(1:ns,1:4) * v, 2) * burgers(1:ns,instance) - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - Lp = Lp + gdotTotal(s) * lattice_Sslip(1:3,1:3,1,sLattice,ph) - - ! Schmid contributions to tangent - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & - + lattice_Sslip(i,j,1,sLattice,ph) * lattice_Sslip(k,l,1,sLattice,ph) & - * sum(rhoSgl(s,1:4) * dv_dtau(s,1:4)) * burgers(s,instance) - - ! non Schmid contributions to tangent - if (tau(s) > 0.0_pReal) then - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & - + lattice_Sslip(i,j,1,sLattice,ph) & - * ( nonSchmidProjection(k,l,1,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & - + nonSchmidProjection(k,l,3,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & - * burgers(s,instance) - else - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & - + lattice_Sslip(i,j,1,sLattice,ph) & - * ( nonSchmidProjection(k,l,2,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & - + nonSchmidProjection(k,l,4,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & - * burgers(s,instance) - endif -enddo -dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_LpandItsTangent at el ip',el,ip - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> gdot total / 1e-3',gdotTotal*1e3_pReal - write(6,'(a,/,3(12x,3(f12.7,1x),/))') '<< CONST >> Lp',transpose(Lp) - endif -#endif - -end subroutine plastic_nonlocal_LpAndItsTangent - - - -!-------------------------------------------------------------------------------------------------- -!> @brief (instantaneous) incremental change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_deltaState(Tstar_v,ip,el) -use debug, only: debug_level, & - debug_constitutive, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use math, only: pi, & - math_mul6x6 -use lattice, only: lattice_Sslip_v ,& - lattice_mu, & - lattice_nu -use mesh, only: mesh_ipVolume -use material, only: material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - -implicit none -integer(pInt), intent(in) :: ip, & ! current grain number - el ! current element number -real(pReal), dimension(6), intent(in) :: Tstar_v ! current 2nd Piola-Kirchhoff stress in Mandel notation - - - integer(pInt) :: & - ph, & !< phase - of !< offset - -integer(pInt) ::instance, & ! current instance of this plasticity - ns, & ! short notation for the total number of active slip systems - c, & ! character of dislocation - t, & ! type of dislocation - s, & ! index of my current slip system - sLattice ! index of my current slip system according to lattice order -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),10) :: & - deltaRho, & ! density increment - deltaRhoRemobilization, & ! density increment by remobilization - deltaRhoDipole2SingleStress ! density increment by dipole dissociation (by stress change) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),8) :: & - rhoSgl ! current single dislocation densities (positive/negative screw and edge without dipoles) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),4) :: & - v ! dislocation glide velocity -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - tau, & ! current resolved shear stress - tauBack ! current back stress from pileups on same slip system -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),2) :: & - rhoDip, & ! current dipole dislocation densities (screw and edge dipoles) - dLower, & ! minimum stable dipole distance for edges and screws - dUpper, & ! current maximum stable dipole distance for edges and screws - dUpperOld, & ! old maximum stable dipole distance for edges and screws - deltaDUpper ! change in maximum stable dipole distance for edges and screws - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_deltaState at el ip ',el,ip -#endif - - ph = phaseAt(1,ip,el) - of = phasememberAt(1,ip,el) - instance = phase_plasticityInstance(ph) - ns = totalNslip(instance) - - -!*** shortcut to state variables - - forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) - v(s,t) = plasticState(ph)%state(iV(s,t,instance),of) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities - dUpperOld(s,c) = plasticState(ph)%state(iD(s,c,instance),of) -endforall - tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) - -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal -where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoDip) < significantRho(instance)) & - rhoDip = 0.0_pReal - - - - -!**************************************************************************** -!*** dislocation remobilization (bauschinger effect) - -deltaRhoRemobilization = 0.0_pReal -do t = 1_pInt,4_pInt - do s = 1_pInt,ns - if (rhoSgl(s,t+4_pInt) * v(s,t) < 0.0_pReal) then - deltaRhoRemobilization(s,t) = abs(rhoSgl(s,t+4_pInt)) - rhoSgl(s,t) = rhoSgl(s,t) + abs(rhoSgl(s,t+4_pInt)) - deltaRhoRemobilization(s,t+4_pInt) = - rhoSgl(s,t+4_pInt) - rhoSgl(s,t+4_pInt) = 0.0_pReal - endif - enddo -enddo - - - -!**************************************************************************** -!*** calculate dipole formation and dissociation by stress change - -!*** calculate limits for stable dipole height - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) - if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal -enddo -dLower = minDipoleHeight(1:ns,1:2,instance) -dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & - / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) -dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) / (4.0_pReal * pi * abs(tau)) - - -forall (c = 1_pInt:2_pInt) - where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& - abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & - + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & - dUpper(1:ns,c)) -end forall -dUpper = max(dUpper,dLower) -deltaDUpper = dUpper - dUpperOld - - -!*** dissociation by stress increase -deltaRhoDipole2SingleStress = 0.0_pReal -forall (c=1_pInt:2_pInt, s=1_pInt:ns, deltaDUpper(s,c) < 0.0_pReal .and. & - abs(dUpperOld(s,c) - dLower(s,c)) > tiny(0.0_pReal)) & - deltaRhoDipole2SingleStress(s,8_pInt+c) = rhoDip(s,c) * deltaDUpper(s,c) & - / (dUpperOld(s,c) - dLower(s,c)) - -forall (t=1_pInt:4_pInt) & - deltaRhoDipole2SingleStress(1_pInt:ns,t) = -0.5_pReal & - * deltaRhoDipole2SingleStress(1_pInt:ns,(t-1_pInt)/2_pInt+9_pInt) - - -!*** store new maximum dipole height in state - -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - plasticState(ph)%state(iD(s,c,instance),of) = dUpper(s,c) - - - -!**************************************************************************** -!*** assign the changes in the dislocation densities to deltaState - -deltaRho = deltaRhoRemobilization & - + deltaRhoDipole2SingleStress -plasticState(ph)%deltaState(:,of) = 0.0_pReal -forall (s = 1:ns, t = 1_pInt:4_pInt) - plasticState(ph)%deltaState(iRhoU(s,t,instance),of)= deltaRho(s,t) - plasticState(ph)%deltaState(iRhoB(s,t,instance),of) = deltaRho(s,t+4_pInt) -endforall -forall (s = 1:ns, c = 1_pInt:2_pInt) & - plasticState(ph)%deltaState(iRhoD(s,c,instance),of) = deltaRho(s,c+8_pInt) - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation remobilization', deltaRhoRemobilization(1:ns,1:8) - write(6,'(a,/,10(12x,12(e12.5,1x),/),/)') '<< CONST >> dipole dissociation by stress increase', deltaRhoDipole2SingleStress - endif -#endif - -end subroutine plastic_nonlocal_deltaState - -!--------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!--------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_dotState(Tstar_v, Fe, Fp, Temperature, & - timestep,subfrac, ip,el) - -use prec, only: DAMASK_NaN -use numerics, only: numerics_integrationMode, & - numerics_timeSyncing -use IO, only: IO_error -use debug, only: debug_level, & - debug_constitutive, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_g, & - debug_i, & - debug_e -use math, only: math_mul6x6, & - math_mul3x3, & - math_mul33x3, & - math_mul33x33, & - math_inv33, & - math_det33, & - math_transpose33, & - pi -use mesh, only: mesh_NcpElems, & - mesh_maxNips, & - mesh_element, & - mesh_ipNeighborhood, & - mesh_ipVolume, & - mesh_ipArea, & - mesh_ipAreaNormal, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype -use material, only: homogenization_maxNgrains, & - material_phase, & - phase_plasticityInstance, & - phase_localPlasticity, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticity ,& - PLASTICITY_NONLOCAL_ID -use lattice, only: lattice_Sslip_v, & - lattice_sd, & - lattice_st ,& - lattice_mu, & - lattice_nu, & - lattice_structure, & - LATTICE_bcc_ID, & - LATTICE_fcc_ID - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el !< current element number -real(pReal), intent(in) :: Temperature, & !< temperature - timestep !< substepped crystallite time increment -real(pReal), dimension(6), intent(in) :: Tstar_v !< current 2nd Piola-Kirchhoff stress in Mandel notation -real(pReal), dimension(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - subfrac !< fraction of timestep at the beginning of the substepped crystallite time increment -real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - Fe, & !< elastic deformation gradient - Fp !< plastic deformation gradient - - -!*** local variables -integer(pInt) :: ph, & - instance, & !< current instance of this plasticity - neighbor_instance, & !< instance of my neighbor's plasticity - ns, & !< short notation for the total number of active slip systems - c, & !< character of dislocation - n, & !< index of my current neighbor - neighbor_el, & !< element number of my neighbor - neighbor_ip, & !< integration point of my neighbor - neighbor_n, & !< neighbor index pointing to me when looking from my neighbor - opposite_neighbor, & !< index of my opposite neighbor - opposite_ip, & !< ip of my opposite neighbor - opposite_el, & !< element index of my opposite neighbor - opposite_n, & !< neighbor index pointing to me when looking from my opposite neighbor - t, & !< type of dislocation - o,& !< offset shortcut - no,& !< neighbour offset shortcut - p,& !< phase shortcut - np,& !< neighbour phase shortcut - topp, & !< type of dislocation with opposite sign to t - s, & !< index of my current slip system - sLattice !< index of my current slip system according to lattice order -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),10) :: & - rhoDot, & !< density evolution - rhoDotMultiplication, & !< density evolution by multiplication - rhoDotFlux, & !< density evolution by flux - rhoDotSingle2DipoleGlide, & !< density evolution by dipole formation (by glide) - rhoDotAthermalAnnihilation, & !< density evolution by athermal annihilation - rhoDotThermalAnnihilation !< density evolution by thermal annihilation -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) - rhoSglOriginal, & - neighbor_rhoSgl, & !< current single dislocation densities of neighboring ip (positive/negative screw and edge without dipoles) - rhoSgl0, & !< single dislocation densities at start of cryst inc (positive/negative screw and edge without dipoles) - my_rhoSgl !< single dislocation densities of central ip (positive/negative screw and edge without dipoles) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - v, & !< current dislocation glide velocity - v0, & !< dislocation glide velocity at start of cryst inc - my_v, & !< dislocation glide velocity of central ip - neighbor_v, & !< dislocation glide velocity of enighboring ip - gdot !< shear rates -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoForest, & !< forest dislocation density - tauThreshold, & !< threshold shear stress - tau, & !< current resolved shear stress - tauBack, & !< current back stress from pileups on same slip system - vClimb, & !< climb velocity of edge dipoles - nSources -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) - rhoDipOriginal, & - dLower, & !< minimum stable dipole distance for edges and screws - dUpper !< current maximum stable dipole distance for edges and screws -real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - m !< direction of dislocation motion -real(pReal), dimension(3,3) :: my_F, & !< my total deformation gradient - neighbor_F, & !< total deformation gradient of my neighbor - my_Fe, & !< my elastic deformation gradient - neighbor_Fe, & !< elastic deformation gradient of my neighbor - Favg !< average total deformation gradient of me and my neighbor -real(pReal), dimension(3) :: normal_neighbor2me, & !< interface normal pointing from my neighbor to me in neighbor's lattice configuration - normal_neighbor2me_defConf, & !< interface normal pointing from my neighbor to me in shared deformed configuration - normal_me2neighbor, & !< interface normal pointing from me to my neighbor in my lattice configuration - normal_me2neighbor_defConf !< interface normal pointing from me to my neighbor in shared deformed configuration -real(pReal) area, & !< area of the current interface - transmissivity, & !< overall transmissivity of dislocation flux to neighboring material point - lineLength, & !< dislocation line length leaving the current interface - selfDiffusion, & !< self diffusion - rnd, & - meshlength -logical considerEnteringFlux, & - considerLeavingFlux - - - p = phaseAt(1,ip,el) - o = phasememberAt(1,ip,el) - - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_dotState at el ip ',el,ip -#endif - -ph = material_phase(1_pInt,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - -tau = 0.0_pReal -gdot = 0.0_pReal - - -!*** shortcut to state variables - - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) - v(s,t) = plasticState(p)%state(iV (s,t,instance),o) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - rhoDip(s,c) = max(plasticState(p)%state(iRhoD(s,c,instance),o), 0.0_pReal) ! ensure positive dipole densities -endforall -rhoForest = plasticState(p)%state(iRhoF(1:ns,instance),o) -tauThreshold = plasticState(p)%state(iTauF(1:ns,instance),o) -tauBack = plasticState(p)%state(iTauB(1:ns,instance),o) - -rhoSglOriginal = rhoSgl -rhoDipOriginal = rhoDip -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal -where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoDip) < significantRho(instance)) & - rhoDip = 0.0_pReal - -if (numerics_timeSyncing) then - forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl0(s,t) = max(plasticState(p)%state0(iRhoU(s,t,instance),o), 0.0_pReal) - rhoSgl0(s,t+4_pInt) = plasticState(p)%state0(iRhoB(s,t,instance),o) - v0(s,t) = plasticState(p)%state0(iV (s,t,instance),o) - endforall - where (abs(rhoSgl0) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl0) < significantRho(instance)) & - rhoSgl0 = 0.0_pReal -endif - - - -!*** sanity check for timestep - -if (timestep <= 0.0_pReal) then ! if illegal timestep... Why here and not on function entry?? - plasticState(p)%dotState = 0.0_pReal ! ...return without doing anything (-> zero dotState) - return -endif - - - -!**************************************************************************** -!*** Calculate shear rate - -forall (t = 1_pInt:4_pInt) & - gdot(1_pInt:ns,t) = rhoSgl(1_pInt:ns,t) * burgers(1:ns,instance) * v(1:ns,t) - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> rho / 1/m^2', rhoSgl, rhoDip - write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> gdot / 1/s',gdot - endif -#endif - - - -!**************************************************************************** -!*** calculate limits for stable dipole height - -do s = 1_pInt,ns ! loop over slip systems - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) - if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal -enddo - -dLower = minDipoleHeight(1:ns,1:2,instance) -dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & - / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) -dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & - / (4.0_pReal * pi * abs(tau)) -forall (c = 1_pInt:2_pInt) - where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& - abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & - + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & - dUpper(1:ns,c)) -end forall -dUpper = max(dUpper,dLower) - -!**************************************************************************** -!*** calculate dislocation multiplication - -rhoDotMultiplication = 0.0_pReal -if (lattice_structure(ph) == LATTICE_bcc_ID) then ! BCC - forall (s = 1:ns, sum(abs(v(s,1:4))) > 0.0_pReal) - rhoDotMultiplication(s,1:2) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication - * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path - ! * 2.0_pReal * sum(abs(v(s,3:4))) / sum(abs(v(s,1:4))) ! ratio of screw to overall velocity determines edge generation - rhoDotMultiplication(s,3:4) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication - * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path - ! * 2.0_pReal * sum(abs(v(s,1:2))) / sum(abs(v(s,1:4))) ! ratio of edge to overall velocity determines screw generation - endforall - -else ! ALL OTHER STRUCTURES - if (probabilisticMultiplication(instance)) then - meshlength = mesh_ipVolume(ip,el)**0.333_pReal - where(sum(rhoSgl(1:ns,1:4),2) > 0.0_pReal) - nSources = (sum(rhoSgl(1:ns,1:2),2) * fEdgeMultiplication(instance) + sum(rhoSgl(1:ns,3:4),2)) & - / sum(rhoSgl(1:ns,1:4),2) * meshlength / lambda0(1:ns,instance)*sqrt(rhoForest(1:ns)) - elsewhere - nSources = meshlength / lambda0(1:ns,instance) * sqrt(rhoForest(1:ns)) - endwhere - do s = 1_pInt,ns - if (nSources(s) < 1.0_pReal) then - if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal) then - call random_number(rnd) - sourceProbability(s,1_pInt,ip,el) = rnd - !$OMP FLUSH(sourceProbability) - endif - if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal - nSources(s)) then - rhoDotMultiplication(s,1:4) = sum(rhoSglOriginal(s,1:4) * abs(v(s,1:4))) / meshlength - endif - else - sourceProbability(s,1_pInt,ip,el) = 2.0_pReal - rhoDotMultiplication(s,1:4) = & - (sum(abs(gdot(s,1:2))) * fEdgeMultiplication(instance) + sum(abs(gdot(s,3:4)))) & - / burgers(s,instance) * sqrt(rhoForest(s)) / lambda0(s,instance) - endif - enddo -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) & - write(6,'(a,/,4(12x,12(f12.5,1x),/,/))') '<< CONST >> sources', nSources -#endif - else - rhoDotMultiplication(1:ns,1:4) = spread( & - (sum(abs(gdot(1:ns,1:2)),2) * fEdgeMultiplication(instance) + sum(abs(gdot(1:ns,3:4)),2)) & - * sqrt(rhoForest(1:ns)) / lambda0(1:ns,instance) / burgers(1:ns,instance), 2, 4) - endif -endif - - - -!**************************************************************************** -!*** calculate dislocation fluxes (only for nonlocal plasticity) - -rhoDotFlux = 0.0_pReal -!? why needed here -if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then ! only for nonlocal plasticity - - !*** check CFL (Courant-Friedrichs-Lewy) condition for flux - - if (any( abs(gdot) > 0.0_pReal & ! any active slip system ... - .and. CFLfactor(instance) * abs(v) * timestep & - > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el)))) then ! ...with velocity above critical value (we use the reference volume and area for simplicity here) -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then - write(6,'(a,i5,a,i2)') '<< CONST >> CFL condition not fullfilled at el ',el,' ip ',ip - write(6,'(a,e10.3,a,e10.3)') '<< CONST >> velocity is at ', & - maxval(abs(v), abs(gdot) > 0.0_pReal & - .and. CFLfactor(instance) * abs(v) * timestep & - > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el))), & - ' at a timestep of ',timestep - write(6,'(a)') '<< CONST >> enforcing cutback !!!' - endif -#endif - plasticState(p)%dotState = DAMASK_NaN ! -> return NaN and, hence, enforce cutback - return - endif - - - !*** be aware of the definition of lattice_st = lattice_sd x lattice_sn !!! - !*** opposite sign to our p vector in the (s,p,n) triplet !!! - - m(1:3,1:ns,1) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) - m(1:3,1:ns,2) = -lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) - m(1:3,1:ns,3) = -lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) - m(1:3,1:ns,4) = lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) - - my_Fe = Fe(1:3,1:3,1_pInt,ip,el) - my_F = math_mul33x33(my_Fe, Fp(1:3,1:3,1_pInt,ip,el)) - - do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) ! loop through my neighbors -! write(6,*) 'c' - neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - neighbor_n = mesh_ipNeighborhood(3,n,ip,el) - np = phaseAt(1,neighbor_ip,neighbor_el) - no = phasememberAt(1,neighbor_ip,neighbor_el) - - opposite_neighbor = n + mod(n,2_pInt) - mod(n+1_pInt,2_pInt) - opposite_el = mesh_ipNeighborhood(1,opposite_neighbor,ip,el) - opposite_ip = mesh_ipNeighborhood(2,opposite_neighbor,ip,el) - opposite_n = mesh_ipNeighborhood(3,opposite_neighbor,ip,el) - - if (neighbor_n > 0_pInt) then ! if neighbor exists, average deformation gradient - neighbor_instance = phase_plasticityInstance(material_phase(1_pInt,neighbor_ip,neighbor_el)) - neighbor_Fe = Fe(1:3,1:3,1_pInt,neighbor_ip,neighbor_el) - neighbor_F = math_mul33x33(neighbor_Fe, Fp(1:3,1:3,1_pInt,neighbor_ip,neighbor_el)) - Favg = 0.5_pReal * (my_F + neighbor_F) - else ! if no neighbor, take my value as average - Favg = my_F - endif - - - !* FLUX FROM MY NEIGHBOR TO ME - !* This is only considered, if I have a neighbor of nonlocal plasticity - !* (also nonlocal constitutive law with local properties) that is at least a little bit - !* compatible. - !* If it's not at all compatible, no flux is arriving, because everything is dammed in front of - !* my neighbor's interface. - !* The entering flux from my neighbor will be distributed on my slip systems according to the - !*compatibility - - considerEnteringFlux = .false. - neighbor_v = 0.0_pReal ! needed for check of sign change in flux density below - neighbor_rhoSgl = 0.0_pReal - if (neighbor_n > 0_pInt) then - if (phase_plasticity(material_phase(1,neighbor_ip,neighbor_el)) == PLASTICITY_NONLOCAL_ID & - .and. any(compatibility(:,:,:,n,ip,el) > 0.0_pReal)) & - considerEnteringFlux = .true. - endif - - if (considerEnteringFlux) then - if(numerics_timeSyncing .and. (subfrac(1_pInt,neighbor_ip,neighbor_el) /= subfrac(1_pInt,ip,el))) & - then ! for timesyncing: in case of a timestep at the interface we have to use "state0" to make sure that fluxes n both sides are equal - forall (s = 1:ns, t = 1_pInt:4_pInt) - - neighbor_v(s,t) = plasticState(np)%state0(iV (s,t,neighbor_instance),no) - neighbor_rhoSgl(s,t) = max(plasticState(np)%state0(iRhoU(s,t,neighbor_instance),no),0.0_pReal) - - endforall - else - forall (s = 1:ns, t = 1_pInt:4_pInt) - neighbor_v(s,t) = plasticState(np)%state(iV (s,t,neighbor_instance),no) - neighbor_rhoSgl(s,t) = max(plasticState(np)%state(iRhoU(s,t,neighbor_instance),no), & - 0.0_pReal) - endforall - endif - - where (neighbor_rhoSgl * mesh_ipVolume(neighbor_ip,neighbor_el) ** 0.667_pReal < significantN(instance) & - .or. neighbor_rhoSgl < significantRho(instance)) & - neighbor_rhoSgl = 0.0_pReal - normal_neighbor2me_defConf = math_det33(Favg) * math_mul33x3(math_inv33(transpose(Favg)), & - mesh_ipAreaNormal(1:3,neighbor_n,neighbor_ip,neighbor_el)) ! calculate the normal of the interface in (average) deformed configuration (now pointing from my neighbor to me!!!) - normal_neighbor2me = math_mul33x3(transpose(neighbor_Fe), normal_neighbor2me_defConf) & - / math_det33(neighbor_Fe) ! interface normal in the lattice configuration of my neighbor - area = mesh_ipArea(neighbor_n,neighbor_ip,neighbor_el) * norm2(normal_neighbor2me) - normal_neighbor2me = normal_neighbor2me / norm2(normal_neighbor2me) ! normalize the surface normal to unit length - do s = 1_pInt,ns - do t = 1_pInt,4_pInt - c = (t + 1_pInt) / 2 - topp = t + mod(t,2_pInt) - mod(t+1_pInt,2_pInt) - if (neighbor_v(s,t) * math_mul3x3(m(1:3,s,t), normal_neighbor2me) > 0.0_pReal & ! flux from my neighbor to me == entering flux for me - .and. v(s,t) * neighbor_v(s,t) >= 0.0_pReal ) then ! ... only if no sign change in flux density - lineLength = neighbor_rhoSgl(s,t) * neighbor_v(s,t) & - * math_mul3x3(m(1:3,s,t), normal_neighbor2me) * area ! positive line length that wants to enter through this interface - where (compatibility(c,1_pInt:ns,s,n,ip,el) > 0.0_pReal) & ! positive compatibility... - rhoDotFlux(1_pInt:ns,t) = rhoDotFlux(1_pInt:ns,t) & - + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to equally signed mobile dislocation type - * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal - where (compatibility(c,1_pInt:ns,s,n,ip,el) < 0.0_pReal) & ! ..negative compatibility... - rhoDotFlux(1_pInt:ns,topp) = rhoDotFlux(1_pInt:ns,topp) & - + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to opposite signed mobile dislocation type - * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal - endif - enddo - enddo - endif - - - !* FLUX FROM ME TO MY NEIGHBOR - !* This is not considered, if my opposite neighbor has a different constitutive law than nonlocal (still considered for nonlocal law with lcal properties). - !* Then, we assume, that the opposite(!) neighbor sends an equal amount of dislocations to me. - !* So the net flux in the direction of my neighbor is equal to zero: - !* leaving flux to neighbor == entering flux from opposite neighbor - !* In case of reduced transmissivity, part of the leaving flux is stored as dead dislocation density. - !* That means for an interface of zero transmissivity the leaving flux is fully converted to dead dislocations. - - considerLeavingFlux = .true. - if (opposite_n > 0_pInt) then - if (phase_plasticity(material_phase(1,opposite_ip,opposite_el)) /= PLASTICITY_NONLOCAL_ID) & - considerLeavingFlux = .false. - endif - - if (considerLeavingFlux) then - - !* timeSyncing mode: If the central ip has zero subfraction, always use "state0". This is needed in case of - !* a synchronization step for the central ip, because then "state" contains the values at the end of the - !* previously converged full time step. Also, if either me or my neighbor has zero subfraction, we have to - !* use "state0" to make sure that fluxes on both sides of the (potential) timestep are equal. - my_rhoSgl = rhoSgl - my_v = v - if(numerics_timeSyncing) then - if (abs(subfrac(1_pInt,ip,el))<= tiny(0.0_pReal)) then - my_rhoSgl = rhoSgl0 - my_v = v0 - elseif (neighbor_n > 0_pInt) then - if (abs(subfrac(1_pInt,neighbor_ip,neighbor_el))<= tiny(0.0_pReal)) then - my_rhoSgl = rhoSgl0 - my_v = v0 - endif - endif - endif - - normal_me2neighbor_defConf = math_det33(Favg) & - * math_mul33x3(math_inv33(math_transpose33(Favg)), & - mesh_ipAreaNormal(1:3,n,ip,el)) ! calculate the normal of the interface in (average) deformed configuration (pointing from me to my neighbor!!!) - normal_me2neighbor = math_mul33x3(math_transpose33(my_Fe), normal_me2neighbor_defConf) & - / math_det33(my_Fe) ! interface normal in my lattice configuration - area = mesh_ipArea(n,ip,el) * norm2(normal_me2neighbor) - normal_me2neighbor = normal_me2neighbor / norm2(normal_me2neighbor) ! normalize the surface normal to unit length - do s = 1_pInt,ns - do t = 1_pInt,4_pInt - c = (t + 1_pInt) / 2_pInt - if (my_v(s,t) * math_mul3x3(m(1:3,s,t), normal_me2neighbor) > 0.0_pReal ) then ! flux from me to my neighbor == leaving flux for me (might also be a pure flux from my mobile density to dead density if interface not at all transmissive) - if (my_v(s,t) * neighbor_v(s,t) >= 0.0_pReal) then ! no sign change in flux density - transmissivity = sum(compatibility(c,1_pInt:ns,s,n,ip,el)**2.0_pReal) ! overall transmissivity from this slip system to my neighbor - else ! sign change in flux density means sign change in stress which does not allow for dislocations to arive at the neighbor - transmissivity = 0.0_pReal - endif - lineLength = my_rhoSgl(s,t) * my_v(s,t) & - * math_mul3x3(m(1:3,s,t), normal_me2neighbor) * area ! positive line length of mobiles that wants to leave through this interface - rhoDotFlux(s,t) = rhoDotFlux(s,t) - lineLength / mesh_ipVolume(ip,el) ! subtract dislocation flux from current type - rhoDotFlux(s,t+4_pInt) = rhoDotFlux(s,t+4_pInt) & - + lineLength / mesh_ipVolume(ip,el) * (1.0_pReal - transmissivity) & - * sign(1.0_pReal, my_v(s,t)) ! dislocation flux that is not able to leave through interface (because of low transmissivity) will remain as immobile single density at the material point - endif - enddo - enddo - endif - - enddo ! neighbor loop -endif - - - -!**************************************************************************** -!*** calculate dipole formation and annihilation - -!*** formation by glide - -do c = 1_pInt,2_pInt - rhoDotSingle2DipoleGlide(1:ns,2*c-1) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile - + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile - + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) ! positive mobile --> negative immobile - - rhoDotSingle2DipoleGlide(1:ns,2*c) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile - + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile - + abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c))) ! negative mobile --> positive immobile - - rhoDotSingle2DipoleGlide(1:ns,2*c+3) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * rhoSgl(1:ns,2*c+3) * abs(gdot(1:ns,2*c)) ! negative mobile --> positive immobile - - rhoDotSingle2DipoleGlide(1:ns,2*c+4) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * rhoSgl(1:ns,2*c+4) * abs(gdot(1:ns,2*c-1)) ! positive mobile --> negative immobile - - rhoDotSingle2DipoleGlide(1:ns,c+8) = - rhoDotSingle2DipoleGlide(1:ns,2*c-1) & - - rhoDotSingle2DipoleGlide(1:ns,2*c) & - + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+3)) & - + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+4)) -enddo - - -!*** athermal annihilation - -rhoDotAthermalAnnihilation = 0.0_pReal - -forall (c=1_pInt:2_pInt) & - rhoDotAthermalAnnihilation(1:ns,c+8_pInt) = -2.0_pReal * dLower(1:ns,c) / burgers(1:ns,instance) & - * ( 2.0_pReal * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1))) & ! was single hitting single - + 2.0_pReal * (abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c)) + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) & ! was single hitting immobile single or was immobile single hit by single - + rhoDip(1:ns,c) * (abs(gdot(1:ns,2*c-1)) + abs(gdot(1:ns,2*c)))) ! single knocks dipole constituent -! annihilated screw dipoles leave edge jogs behind on the colinear system -if (lattice_structure(ph) == LATTICE_fcc_ID) & ! only fcc - forall (s = 1:ns, colinearSystem(s,instance) > 0_pInt) & - rhoDotAthermalAnnihilation(colinearSystem(s,instance),1:2) = - rhoDotAthermalAnnihilation(s,10) & - * 0.25_pReal * sqrt(rhoForest(s)) * (dUpper(s,2) + dLower(s,2)) * edgeJogFactor(instance) - - - -!*** thermally activated annihilation of edge dipoles by climb - -rhoDotThermalAnnihilation = 0.0_pReal -selfDiffusion = Dsd0(instance) * exp(-selfDiffusionEnergy(instance) / (KB * Temperature)) -vClimb = atomicVolume(instance) * selfDiffusion / ( KB * Temperature ) & - * lattice_mu(ph) / ( 2.0_pReal * PI * (1.0_pReal-lattice_nu(ph)) ) & - * 2.0_pReal / ( dUpper(1:ns,1) + dLower(1:ns,1) ) -forall (s = 1_pInt:ns, dUpper(s,1) > dLower(s,1)) & - rhoDotThermalAnnihilation(s,9) = max(- 4.0_pReal * rhoDip(s,1) * vClimb(s) / (dUpper(s,1) - dLower(s,1)), & - - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & - - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have - - - -!**************************************************************************** -!*** assign the rates of dislocation densities to my dotState -!*** if evolution rates lead to negative densities, a cutback is enforced - -rhoDot = 0.0_pReal -rhoDot = rhoDotFlux & - + rhoDotMultiplication & - + rhoDotSingle2DipoleGlide & - + rhoDotAthermalAnnihilation & - + rhoDotThermalAnnihilation - -if (numerics_integrationMode == 1_pInt) then ! save rates for output if in central integration mode - rhoDotFluxOutput(1:ns,1:8,1_pInt,ip,el) = rhoDotFlux(1:ns,1:8) - rhoDotMultiplicationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotMultiplication(1:ns,[1,3]) - rhoDotSingle2DipoleGlideOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotSingle2DipoleGlide(1:ns,9:10) - rhoDotAthermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotAthermalAnnihilation(1:ns,9:10) - rhoDotThermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotThermalAnnihilation(1:ns,9:10) - rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) = 2.0_pReal * rhoDotThermalAnnihilation(1:ns,1) -endif - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip .and. debug_g == 1_pInt)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> dislocation multiplication', & - rhoDotMultiplication(1:ns,1:4) * timestep - write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation flux', & - rhoDotFlux(1:ns,1:8) * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> dipole formation by glide', & - rhoDotSingle2DipoleGlide * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> athermal dipole annihilation', & - rhoDotAthermalAnnihilation * timestep - write(6,'(a,/,2(12x,12(e12.5,1x),/))') '<< CONST >> thermally activated dipole annihilation', & - rhoDotThermalAnnihilation(1:ns,9:10) * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> total density change', & - rhoDot * timestep - write(6,'(a,/,10(12x,12(f12.5,1x),/))') '<< CONST >> relative density change', & - rhoDot(1:ns,1:8) * timestep / (abs(rhoSglOriginal)+1.0e-10), & - rhoDot(1:ns,9:10) * timestep / (rhoDipOriginal+1.0e-10) - write(6,*) - endif -#endif - - -if ( any(rhoSglOriginal(1:ns,1:4) + rhoDot(1:ns,1:4) * timestep < -aTolRho(instance)) & - .or. any(rhoDipOriginal(1:ns,1:2) + rhoDot(1:ns,9:10) * timestep < -aTolRho(instance))) then -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then - write(6,'(a,i5,a,i2)') '<< CONST >> evolution rate leads to negative density at el ',el,' ip ',ip - write(6,'(a)') '<< CONST >> enforcing cutback !!!' - endif -#endif - plasticState(p)%dotState = DAMASK_NaN - return -else - forall (s = 1:ns, t = 1_pInt:4_pInt) - plasticState(p)%dotState(iRhoU(s,t,instance),o) = rhoDot(s,t) - plasticState(p)%dotState(iRhoB(s,t,instance),o) = rhoDot(s,t+4_pInt) - endforall - forall (s = 1:ns, c = 1_pInt:2_pInt) & - plasticState(p)%dotState(iRhoD(s,c,instance),o) = rhoDot(s,c+8_pInt) - forall (s = 1:ns) & - plasticState(p)%dotState(iGamma(s,instance),o) = sum(gdot(s,1:4)) -endif - -end subroutine plastic_nonlocal_dotState - - -!********************************************************************* -!* COMPATIBILITY UPDATE * -!* Compatibility is defined as normalized product of signed cosine * -!* of the angle between the slip plane normals and signed cosine of * -!* the angle between the slip directions. Only the largest values * -!* that sum up to a total of 1 are considered, all others are set to * -!* zero. * -!********************************************************************* -subroutine plastic_nonlocal_updateCompatibility(orientation,i,e) - -use math, only: math_mul3x3, & - math_qRot -use material, only: material_phase, & - material_texture, & - phase_localPlasticity, & - phase_plasticityInstance, & - homogenization_maxNgrains -use mesh, only: mesh_element, & - mesh_ipNeighborhood, & - mesh_maxNips, & - mesh_NcpElems, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype -use lattice, only: lattice_sn, & - lattice_sd, & - lattice_qDisorientation - -implicit none - -!* input variables -integer(pInt), intent(in) :: i, & ! ip index - e ! element index -real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - orientation ! crystal orientation in quaternions - -!* local variables -integer(pInt) Nneighbors, & ! number of neighbors - n, & ! neighbor index - neighbor_e, & ! element index of my neighbor - neighbor_i, & ! integration point index of my neighbor - ph, & - neighbor_phase, & - textureID, & - neighbor_textureID, & - instance, & ! instance of plasticity - ns, & ! number of active slip systems - s1, & ! slip system index (me) - s2 ! slip system index (my neighbor) -real(pReal), dimension(4) :: absoluteMisorientation ! absolute misorientation (without symmetry) between me and my neighbor -real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& - totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& - FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e))))) :: & - my_compatibility ! my_compatibility for current element and ip -real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & - slipNormal, & - slipDirection -real(pReal) my_compatibilitySum, & - thresholdValue, & - nThresholdValues -logical, dimension(totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & - belowThreshold - - -Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) -ph = material_phase(1,i,e) -textureID = material_texture(1,i,e) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) -slipNormal(1:3,1:ns) = lattice_sn(1:3, slipSystemLattice(1:ns,instance), ph) -slipDirection(1:3,1:ns) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) - - -!*** start out fully compatible - -my_compatibility = 0.0_pReal -forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,1:Nneighbors) = 1.0_pReal - - -!*** Loop thrugh neighbors and check whether there is any my_compatibility. - -do n = 1_pInt,Nneighbors - neighbor_e = mesh_ipNeighborhood(1,n,i,e) - neighbor_i = mesh_ipNeighborhood(2,n,i,e) - - - !* FREE SURFACE - !* Set surface transmissivity to the value specified in the material.config - - if (neighbor_e <= 0_pInt .or. neighbor_i <= 0_pInt) then - forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,n) = sqrt(surfaceTransmissivity(instance)) - cycle - endif - - - !* PHASE BOUNDARY - !* If we encounter a different nonlocal "cpfem" phase at the neighbor, - !* we consider this to be a real "physical" phase boundary, so completely incompatible. - !* If one of the two "CPFEM" phases has a local plasticity law, - !* we do not consider this to be a phase boundary, so completely compatible. - - neighbor_phase = material_phase(1,neighbor_i,neighbor_e) - if (neighbor_phase /= ph) then - if (.not. phase_localPlasticity(neighbor_phase) .and. .not. phase_localPlasticity(ph)) then - forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,n) = 0.0_pReal ! = sqrt(0.0) - endif - cycle - endif - - - !* GRAIN BOUNDARY ! - !* fixed transmissivity for adjacent ips with different texture (only if explicitly given in material.config) - - if (grainboundaryTransmissivity(instance) >= 0.0_pReal) then - neighbor_textureID = material_texture(1,neighbor_i,neighbor_e) - if (neighbor_textureID /= textureID) then - if (.not. phase_localPlasticity(neighbor_phase)) then - forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,n) = sqrt(grainboundaryTransmissivity(instance)) - endif - cycle - endif - - - !* GRAIN BOUNDARY ? - !* Compatibility defined by relative orientation of slip systems: - !* The my_compatibility value is defined as the product of the slip normal projection and the slip direction projection. - !* Its sign is always positive for screws, for edges it has the same sign as the slip normal projection. - !* Since the sum for each slip system can easily exceed one (which would result in a transmissivity larger than one), - !* only values above or equal to a certain threshold value are considered. This threshold value is chosen, such that - !* the number of compatible slip systems is minimized with the sum of the original my_compatibility values exceeding one. - !* Finally the smallest my_compatibility value is decreased until the sum is exactly equal to one. - !* All values below the threshold are set to zero. - else - absoluteMisorientation = lattice_qDisorientation(orientation(1:4,1,i,e), & - orientation(1:4,1,neighbor_i,neighbor_e)) ! no symmetry - do s1 = 1_pInt,ns ! my slip systems - do s2 = 1_pInt,ns ! my neighbor's slip systems - my_compatibility(1,s2,s1,n) = math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2))) & - * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) - my_compatibility(2,s2,s1,n) = abs(math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2)))) & - * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) - enddo - - my_compatibilitySum = 0.0_pReal - belowThreshold = .true. - do while (my_compatibilitySum < 1.0_pReal .and. any(belowThreshold(1:ns))) - thresholdValue = maxval(my_compatibility(2,1:ns,s1,n), belowThreshold(1:ns)) ! screws always positive - nThresholdValues = real(count(my_compatibility(2,1:ns,s1,n) == thresholdValue),pReal) - where (my_compatibility(2,1:ns,s1,n) >= thresholdValue) & - belowThreshold(1:ns) = .false. - if (my_compatibilitySum + thresholdValue * nThresholdValues > 1.0_pReal) & - where (abs(my_compatibility(1:2,1:ns,s1,n)) == thresholdValue) & ! MD: rather check below threshold? - my_compatibility(1:2,1:ns,s1,n) = sign((1.0_pReal - my_compatibilitySum) & - / nThresholdValues, my_compatibility(1:2,1:ns,s1,n)) - my_compatibilitySum = my_compatibilitySum + nThresholdValues * thresholdValue - enddo - where (belowThreshold(1:ns)) my_compatibility(1,1:ns,s1,n) = 0.0_pReal - where (belowThreshold(1:ns)) my_compatibility(2,1:ns,s1,n) = 0.0_pReal - enddo ! my slip systems cycle - endif - -enddo ! neighbor cycle - -compatibility(1:2,1:ns,1:ns,1:Nneighbors,i,e) = my_compatibility - -end subroutine plastic_nonlocal_updateCompatibility - -!********************************************************************* -!* calculates quantities characterizing the microstructure * -!********************************************************************* -function plastic_nonlocal_dislocationstress(Fe, ip, el) -use math, only: math_mul33x33, & - math_mul33x3, & - math_inv33, & - math_transpose33, & - pi -use mesh, only: mesh_NcpElems, & - mesh_maxNips, & - mesh_element, & - mesh_node0, & - mesh_cellCenterCoordinates, & - mesh_ipVolume, & - mesh_periodicSurface, & - FE_Nips, & - FE_geomtype -use material, only: homogenization_maxNgrains, & - material_phase, & - plasticState, & - phaseAt, phasememberAt,& - phase_localPlasticity, & - phase_plasticityInstance -use lattice, only: lattice_mu, & - lattice_nu - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el !< current element -real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - Fe !< elastic deformation gradient - -!*** output variables -real(pReal), dimension(3,3) :: plastic_nonlocal_dislocationstress - -!*** local variables -integer(pInt) neighbor_el, & !< element number of neighbor material point - neighbor_ip, & !< integration point of neighbor material point - instance, & !< my instance of this plasticity - neighbor_instance, & !< instance of this plasticity of neighbor material point - ph, & - neighbor_phase, & - ns, & !< total number of active slip systems at my material point - neighbor_ns, & !< total number of active slip systems at neighbor material point - c, & !< index of dilsocation character (edge, screw) - s, & !< slip system index - o,& !< offset shortcut - no,& !< neighbour offset shortcut - p,& !< phase shortcut - np,& !< neighbour phase shortcut - t, & !< index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) - dir, & - deltaX, deltaY, deltaZ, & - side, & - j -integer(pInt), dimension(2,3) :: periodicImages -real(pReal) x, y, z, & !< coordinates of connection vector in neighbor lattice frame - xsquare, ysquare, zsquare, & !< squares of respective coordinates - distance, & !< length of connection vector - segmentLength, & !< segment length of dislocations - lambda, & - R, Rsquare, Rcube, & - denominator, & - flipSign, & - neighbor_ipVolumeSideLength -real(pReal), dimension(3) :: connection, & !< connection vector between me and my neighbor in the deformed configuration - connection_neighborLattice, & !< connection vector between me and my neighbor in the lattice configuration of my neighbor - connection_neighborSlip, & !< connection vector between me and my neighbor in the slip system frame of my neighbor - maxCoord, minCoord, & - meshSize, & - coords, & !< x,y,z coordinates of cell center of ip volume - neighbor_coords !< x,y,z coordinates of cell center of neighbor ip volume -real(pReal), dimension(3,3) :: sigma, & !< dislocation stress for one slip system in neighbor material point's slip system frame - Tdislo_neighborLattice, & !< dislocation stress as 2nd Piola-Kirchhoff stress at neighbor material point - invFe, & !< inverse of my elastic deformation gradient - neighbor_invFe, & - neighborLattice2myLattice !< mapping from neighbor MPs lattice configuration to my lattice configuration -real(pReal), dimension(2,2,maxval(totalNslip)) :: & - neighbor_rhoExcess !< excess density at neighbor material point (edge/screw,mobile/dead,slipsystem) -real(pReal), dimension(2,maxval(totalNslip)) :: & - rhoExcessDead -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) - -ph = material_phase(1_pInt,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) -p = phaseAt(1,ip,el) -o = phasememberAt(1,ip,el) - -!*** get basic states - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) -endforall - - - -!*** calculate the dislocation stress of the neighboring excess dislocation densities -!*** zero for material points of local plasticity - -plastic_nonlocal_dislocationstress = 0.0_pReal - -if (.not. phase_localPlasticity(ph)) then - invFe = math_inv33(Fe(1:3,1:3,1_pInt,ip,el)) - - !* in case of periodic surfaces we have to find out how many periodic images in each direction we need - - do dir = 1_pInt,3_pInt - maxCoord(dir) = maxval(mesh_node0(dir,:)) - minCoord(dir) = minval(mesh_node0(dir,:)) - enddo - meshSize = maxCoord - minCoord - coords = mesh_cellCenterCoordinates(ip,el) - periodicImages = 0_pInt - do dir = 1_pInt,3_pInt - if (mesh_periodicSurface(dir)) then - periodicImages(1,dir) = floor((coords(dir) - cutoffRadius(instance) - minCoord(dir)) / meshSize(dir), pInt) - periodicImages(2,dir) = ceiling((coords(dir) + cutoffRadius(instance) - maxCoord(dir)) / meshSize(dir), pInt) - endif - enddo - - - !* loop through all material points (also through their periodic images if present), - !* but only consider nonlocal neighbors within a certain cutoff radius R - - do neighbor_el = 1_pInt,mesh_NcpElems - ipLoop: do neighbor_ip = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,neighbor_el))) - neighbor_phase = material_phase(1_pInt,neighbor_ip,neighbor_el) - np = phaseAt(1,neighbor_ip,neighbor_el) - no = phasememberAt(1,neighbor_ip,neighbor_el) - - if (phase_localPlasticity(neighbor_phase)) cycle - neighbor_instance = phase_plasticityInstance(neighbor_phase) - neighbor_ns = totalNslip(neighbor_instance) - neighbor_invFe = math_inv33(Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) - neighbor_ipVolumeSideLength = mesh_ipVolume(neighbor_ip,neighbor_el) ** (1.0_pReal/3.0_pReal) ! reference volume used here - - forall (s = 1_pInt:neighbor_ns, c = 1_pInt:2_pInt) - neighbor_rhoExcess(c,1,s) = plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no) & ! positive mobiles - - plasticState(np)%state(iRhoU(s,2*c,neighbor_instance),no) ! negative mobiles - neighbor_rhoExcess(c,2,s) = abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads - - abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance),no)) ! negative deads - - endforall - Tdislo_neighborLattice = 0.0_pReal - do deltaX = periodicImages(1,1),periodicImages(2,1) - do deltaY = periodicImages(1,2),periodicImages(2,2) - do deltaZ = periodicImages(1,3),periodicImages(2,3) - - - !* regular case - - if (neighbor_el /= el .or. neighbor_ip /= ip & - .or. deltaX /= 0_pInt .or. deltaY /= 0_pInt .or. deltaZ /= 0_pInt) then - - neighbor_coords = mesh_cellCenterCoordinates(neighbor_ip,neighbor_el) & - + [real(deltaX,pReal), real(deltaY,pReal), real(deltaZ,pReal)] * meshSize - connection = neighbor_coords - coords - distance = sqrt(sum(connection * connection)) - if (distance > cutoffRadius(instance)) cycle - - - !* the segment length is the minimum of the third root of the control volume and the ip distance - !* this ensures, that the central MP never sits on a neighbor dislocation segment - - connection_neighborLattice = math_mul33x3(neighbor_invFe, connection) - segmentLength = min(neighbor_ipVolumeSideLength, distance) - - - !* loop through all slip systems of the neighbor material point - !* and add up the stress contributions from egde and screw excess on these slip systems (if significant) - - do s = 1_pInt,neighbor_ns - if (all(abs(neighbor_rhoExcess(:,:,s)) < significantRho(instance))) cycle ! not significant - - - !* map the connection vector from the lattice into the slip system frame - - connection_neighborSlip = math_mul33x3(lattice2slip(1:3,1:3,s,neighbor_instance), & - connection_neighborLattice) - - - !* edge contribution to stress - sigma = 0.0_pReal - - x = connection_neighborSlip(1) - y = connection_neighborSlip(2) - z = connection_neighborSlip(3) - xsquare = x * x - ysquare = y * y - zsquare = z * z - - do j = 1_pInt,2_pInt - if (abs(neighbor_rhoExcess(1,j,s)) < significantRho(instance)) then - cycle - elseif (j > 1_pInt) then - x = connection_neighborSlip(1) & - + sign(0.5_pReal * segmentLength, & - plasticState(np)%state(iRhoB(s,1,neighbor_instance),no) & - - plasticState(np)%state(iRhoB(s,2,neighbor_instance),no)) - - xsquare = x * x - endif - - flipSign = sign(1.0_pReal, -y) - do side = 1_pInt,-1_pInt,-2_pInt - lambda = real(side,pReal) * 0.5_pReal * segmentLength - y - R = sqrt(xsquare + zsquare + lambda * lambda) - Rsquare = R * R - Rcube = Rsquare * R - denominator = R * (R + flipSign * lambda) - if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop - - sigma(1,1) = sigma(1,1) - real(side,pReal) & - * flipSign * z / denominator & - * (1.0_pReal + xsquare / Rsquare + xsquare / denominator) & - * neighbor_rhoExcess(1,j,s) - sigma(2,2) = sigma(2,2) - real(side,pReal) & - * (flipSign * 2.0_pReal * lattice_nu(ph) * z / denominator + z * lambda / Rcube) & - * neighbor_rhoExcess(1,j,s) - sigma(3,3) = sigma(3,3) + real(side,pReal) & - * flipSign * z / denominator & - * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & - * neighbor_rhoExcess(1,j,s) - sigma(1,2) = sigma(1,2) + real(side,pReal) & - * x * z / Rcube * neighbor_rhoExcess(1,j,s) - sigma(1,3) = sigma(1,3) + real(side,pReal) & - * flipSign * x / denominator & - * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & - * neighbor_rhoExcess(1,j,s) - sigma(2,3) = sigma(2,3) - real(side,pReal) & - * (lattice_nu(ph) / R - zsquare / Rcube) * neighbor_rhoExcess(1,j,s) - enddo - enddo - - !* screw contribution to stress - - x = connection_neighborSlip(1) ! have to restore this value, because position might have been adapted for edge deads before - do j = 1_pInt,2_pInt - if (abs(neighbor_rhoExcess(2,j,s)) < significantRho(instance)) then - cycle - elseif (j > 1_pInt) then - y = connection_neighborSlip(2) & - + sign(0.5_pReal * segmentLength, & - plasticState(np)%state(iRhoB(s,3,neighbor_instance),no) & - - plasticState(np)%state(iRhoB(s,4,neighbor_instance),no)) - ysquare = y * y - endif - - flipSign = sign(1.0_pReal, x) - do side = 1_pInt,-1_pInt,-2_pInt - lambda = x + real(side,pReal) * 0.5_pReal * segmentLength - R = sqrt(ysquare + zsquare + lambda * lambda) - Rsquare = R * R - Rcube = Rsquare * R - denominator = R * (R + flipSign * lambda) - if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop - - sigma(1,2) = sigma(1,2) - real(side,pReal) * flipSign * z & - * (1.0_pReal - lattice_nu(ph)) / denominator & - * neighbor_rhoExcess(2,j,s) - sigma(1,3) = sigma(1,3) + real(side,pReal) * flipSign * y & - * (1.0_pReal - lattice_nu(ph)) / denominator & - * neighbor_rhoExcess(2,j,s) - enddo - enddo - - if (all(abs(sigma) < 1.0e-10_pReal)) cycle ! SIGMA IS NOT A REAL STRESS, THATS WHY WE NEED A REALLY SMALL VALUE HERE - - !* copy symmetric parts - - sigma(2,1) = sigma(1,2) - sigma(3,1) = sigma(1,3) - sigma(3,2) = sigma(2,3) - - - !* scale stresses and map them into the neighbor material point's lattice configuration - - sigma = sigma * lattice_mu(neighbor_phase) * burgers(s,neighbor_instance) & - / (4.0_pReal * pi * (1.0_pReal - lattice_nu(neighbor_phase))) & - * mesh_ipVolume(neighbor_ip,neighbor_el) / segmentLength ! reference volume is used here (according to the segment length calculation) - Tdislo_neighborLattice = Tdislo_neighborLattice & - + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,neighbor_instance)), & - math_mul33x33(sigma, lattice2slip(1:3,1:3,s,neighbor_instance))) - - enddo ! slip system loop - - - !* special case of central ip volume - !* only consider dead dislocations - !* we assume that they all sit at a distance equal to half the third root of V - !* in direction of the according slip direction - - else - - forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - - rhoExcessDead(c,s) = plasticState(p)%state(iRhoB(s,2*c-1,instance),o) & ! positive deads (here we use symmetry: if this has negative sign it is - !treated as negative density at positive position instead of positive - !density at negative position) - + plasticState(p)%state(iRhoB(s,2*c,instance),o) ! negative deads (here we use symmetry: if this has negative sign it is - !treated as positive density at positive position instead of negative - !density at negative position) - do s = 1_pInt,ns - if (all(abs(rhoExcessDead(:,s)) < significantRho(instance))) cycle ! not significant - sigma = 0.0_pReal ! all components except for sigma13 are zero - sigma(1,3) = - (rhoExcessDead(1,s) + rhoExcessDead(2,s) * (1.0_pReal - lattice_nu(ph))) & - * neighbor_ipVolumeSideLength * lattice_mu(ph) * burgers(s,instance) & - / (sqrt(2.0_pReal) * pi * (1.0_pReal - lattice_nu(ph))) - sigma(3,1) = sigma(1,3) - - Tdislo_neighborLattice = Tdislo_neighborLattice & - + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,instance)), & - math_mul33x33(sigma, lattice2slip(1:3,1:3,s,instance))) - - enddo ! slip system loop - - endif - - enddo ! deltaZ loop - enddo ! deltaY loop - enddo ! deltaX loop - - - !* map the stress from the neighbor MP's lattice configuration into the deformed configuration - !* and back into my lattice configuration - - neighborLattice2myLattice = math_mul33x33(invFe, Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) - plastic_nonlocal_dislocationstress = plastic_nonlocal_dislocationstress & - + math_mul33x33(neighborLattice2myLattice, & - math_mul33x33(Tdislo_neighborLattice, & - math_transpose33(neighborLattice2myLattice))) - - enddo ipLoop - enddo ! element loop - -endif - -end function plastic_nonlocal_dislocationstress - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_nonlocal_postResults(Tstar_v,Fe,ip,el) - use math, only: & - math_mul6x6, & - math_mul33x3, & - math_mul33x33, & - pi - use mesh, only: & - mesh_NcpElems, & - mesh_maxNips - use material, only: & - homogenization_maxNgrains, & - material_phase, & - phaseAt, phasememberAt, & - plasticState, & - phase_plasticityInstance - use lattice, only: & - lattice_Sslip_v, & - lattice_sd, & - lattice_st, & - lattice_sn, & - lattice_mu, & - lattice_nu - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - Fe !< elastic deformation gradient - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - - real(pReal), dimension(plastic_nonlocal_sizePostResults(& - phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - plastic_nonlocal_postResults - - integer(pInt) :: & - ph, & - instance, & !< current instance of this plasticity - ns, & !< short notation for the total number of active slip systems - c, & !< character of dislocation - cs, & !< constitutive result index - o, & !< index of current output - of,& !< offset shortcut - t, & !< type of dislocation - s, & !< index of my current slip system - sLattice !< index of my current slip system according to lattice order - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) - rhoDotSgl !< evolution rate of single dislocation densities (positive/negative screw and edge without dipoles) - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - gdot, & !< shear rates - v !< velocities - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoForest, & !< forest dislocation density - tauThreshold, & !< threshold shear stress - tau, & !< current resolved shear stress - tauBack !< back stress from pileups on same slip system - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) - rhoDotDip, & !< evolution rate of dipole dislocation densities (screw and edge dipoles) - dLower, & !< minimum stable dipole distance for edges and screws - dUpper !< current maximum stable dipole distance for edges and screws - real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - m, & !< direction of dislocation motion for edge and screw (unit vector) - m_currentconf !< direction of dislocation motion for edge and screw (unit vector) in current configuration - real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - n_currentconf !< slip system normal (unit vector) in current configuration - real(pReal), dimension(3,3) :: & - sigma - -ph = phaseAt(1,ip,el) -of = phasememberAt(1,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - -cs = 0_pInt -plastic_nonlocal_postResults = 0.0_pReal - - -!* short hand notations for state variables - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = plasticState(ph)%State(iRhoU(s,t,instance),of) - rhoSgl(s,t+4_pInt) = plasticState(ph)%State(iRhoB(s,t,instance),of) - v(s,t) = plasticState(ph)%State(iV(s,t,instance),of) - rhoDotSgl(s,t) = plasticState(ph)%dotState(iRhoU(s,t,instance),of) - rhoDotSgl(s,t+4_pInt) = plasticState(ph)%dotState(iRhoB(s,t,instance),of) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - rhoDip(s,c) = plasticState(ph)%State(iRhoD(s,c,instance),of) - rhoDotDip(s,c) = plasticState(ph)%dotState(iRhoD(s,c,instance),of) -endforall -rhoForest = plasticState(ph)%State(iRhoF(1:ns,instance),of) -tauThreshold = plasticState(ph)%State(iTauF(1:ns,instance),of) -tauBack = plasticState(ph)%State(iTauB(1:ns,instance),of) - -!* Calculate shear rate - -forall (t = 1_pInt:4_pInt) & - gdot(1:ns,t) = rhoSgl(1:ns,t) * burgers(1:ns,instance) * v(1:ns,t) - - -!* calculate limits for stable dipole height - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) - if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal -enddo - -dLower = minDipoleHeight(1:ns,1:2,instance) -dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & - / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) -dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & - / (4.0_pReal * pi * abs(tau)) -forall (c = 1_pInt:2_pInt) - where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& - abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & - + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & - dUpper(1:ns,c)) -end forall -dUpper = max(dUpper,dLower) - - -!*** dislocation motion - -m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) -m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) -forall (c = 1_pInt:2_pInt, s = 1_pInt:ns) & - m_currentconf(1:3,s,c) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), m(1:3,s,c)) -forall (s = 1_pInt:ns) & - n_currentconf(1:3,s) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), & - lattice_sn(1:3,slipSystemLattice(s,instance),ph)) - - -outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) - select case(plastic_nonlocal_outputID(o,instance)) - case (rho_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) + sum(rhoDip,2) - cs = cs + ns - - case (rho_sgl_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) - cs = cs + ns - - case (rho_sgl_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,1:4)),2) - cs = cs + ns - - case (rho_sgl_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:8),2) - cs = cs + ns - - case (rho_dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDip,2) - cs = cs + ns - - case (rho_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1) - cs = cs + ns - - case (rho_sgl_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) - cs = cs + ns - - case (rho_sgl_edge_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,1:2),2) - cs = cs + ns - - case (rho_sgl_edge_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:6),2) - cs = cs + ns - - case (rho_sgl_edge_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5)) - cs = cs + ns - - case (rho_sgl_edge_pos_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) - cs = cs + ns - - case (rho_sgl_edge_pos_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,5) - cs = cs + ns - - case (rho_sgl_edge_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6)) - cs = cs + ns - - case (rho_sgl_edge_neg_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) - cs = cs + ns - - case (rho_sgl_edge_neg_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,6) - cs = cs + ns - - case (rho_dip_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,1) - cs = cs + ns - - case (rho_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2) - cs = cs + ns - - case (rho_sgl_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) - cs = cs + ns - - case (rho_sgl_screw_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,3:4),2) - cs = cs + ns - - case (rho_sgl_screw_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,7:8),2) - cs = cs + ns - - case (rho_sgl_screw_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7)) - cs = cs + ns - - case (rho_sgl_screw_pos_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) - cs = cs + ns - - case (rho_sgl_screw_pos_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,7) - cs = cs + ns - - case (rho_sgl_screw_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8)) - cs = cs + ns - - case (rho_sgl_screw_neg_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) - cs = cs + ns - - case (rho_sgl_screw_neg_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,8) - cs = cs + ns - - case (rho_dip_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,2) - cs = cs + ns - - case (excess_rho_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & - - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) & - + (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & - - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) - cs = cs + ns - - case (excess_rho_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & - - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) - cs = cs + ns - - case (excess_rho_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & - - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) - cs = cs + ns - - case (rho_forest_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoForest - cs = cs + ns - - case (delta_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2) + sum(rhoDip,2)) - cs = cs + ns - - case (delta_sgl_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2)) - cs = cs + ns - - case (delta_dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(rhoDip,2)) - cs = cs + ns - - case (shearrate_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(gdot,2) - cs = cs + ns - - case (resolvedstress_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tau - cs = cs + ns - - case (resolvedstress_back_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauBack - cs = cs + ns - - case (resolvedstress_external_ID) - do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - plastic_nonlocal_postResults(cs+s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) - enddo - cs = cs + ns - - case (resistance_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauThreshold - cs = cs + ns - - case (rho_dot_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & - + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) & - + sum(rhoDotDip,2) - cs = cs + ns - - case (rho_dot_sgl_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & - + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) - cs = cs + ns - - case (rho_dot_sgl_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) - cs = cs + ns - - case (rho_dot_dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotDip,2) - cs = cs + ns - - case (rho_dot_gen_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_gen_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_gen_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_sgl2dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_sgl2dip_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_sgl2dip_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_ath_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotAthermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotAthermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_the_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_the_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_the_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_edgejogs_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_flux_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) - cs = cs + ns - - case (rho_dot_flux_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) & - + sum(rhoDotFluxOutput(1:ns,5:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) - cs = cs + ns - - case (rho_dot_flux_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:2,1_pInt,ip,el),2) & - + sum(rhoDotFluxOutput(1:ns,5:6,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:6)),2) - cs = cs + ns - - case (rho_dot_flux_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,3:4,1_pInt,ip,el),2) & - + sum(rhoDotFluxOutput(1:ns,7:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,7:8)),2) - cs = cs + ns - - case (velocity_edge_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,1) - cs = cs + ns - - case (velocity_edge_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,2) - cs = cs + ns - - case (velocity_screw_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,3) - cs = cs + ns - - case (velocity_screw_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,4) - cs = cs + ns - - case (slipdirectionx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(1,1:ns,1) - cs = cs + ns - - case (slipdirectiony_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(2,1:ns,1) - cs = cs + ns - - case (slipdirectionz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(3,1:ns,1) - cs = cs + ns - - case (slipnormalx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(1,1:ns) - cs = cs + ns - - case (slipnormaly_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(2,1:ns) - cs = cs + ns - - case (slipnormalz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(3,1:ns) - cs = cs + ns - - case (fluxdensity_edge_posx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(1,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_posy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(2,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_posz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(3,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_negx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(1,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_negy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(2,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_negz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(3,1:ns,1) - cs = cs + ns - - case (fluxdensity_screw_posx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(1,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_posy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(2,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_posz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(3,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_negx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(1,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_negy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(2,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_negz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(3,1:ns,2) - cs = cs + ns - - case (maximumdipoleheight_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,1) - cs = cs + ns - - case (maximumdipoleheight_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,2) - cs = cs + ns - - case(dislocationstress_ID) - sigma = plastic_nonlocal_dislocationstress(Fe, ip, el) - plastic_nonlocal_postResults(cs+1_pInt) = sigma(1,1) - plastic_nonlocal_postResults(cs+2_pInt) = sigma(2,2) - plastic_nonlocal_postResults(cs+3_pInt) = sigma(3,3) - plastic_nonlocal_postResults(cs+4_pInt) = sigma(1,2) - plastic_nonlocal_postResults(cs+5_pInt) = sigma(2,3) - plastic_nonlocal_postResults(cs+6_pInt) = sigma(3,1) - cs = cs + 6_pInt - - case(accumulatedshear_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = plasticState(ph)%state(iGamma(1:ns,instance),of) - cs = cs + ns - - end select -enddo outputsLoop - -end function plastic_nonlocal_postResults - -end module plastic_nonlocal diff --git a/code/plastic_phenoplus.f90 b/code/plastic_phenoplus.f90 deleted file mode 100644 index 0a40edd84..000000000 --- a/code/plastic_phenoplus.f90 +++ /dev/null @@ -1,1419 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Chen Zhang, Michigan State University -!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw -!... fitting -!-------------------------------------------------------------------------------------------------- -module plastic_phenoplus - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenoplus_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_phenoplus_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_phenoplus_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_phenoplus_Noutput !< number of outputs per instance of this constitution - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenoplus_totalNslip, & !< no. of slip system used in simulation - plastic_phenoplus_totalNtwin, & !< no. of twin system used in simulation - plastic_phenoplus_totalNtrans !< no. of trans system used in simulation - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_phenoplus_Nslip, & !< active number of slip systems per family (input parameter, per family) - plastic_phenoplus_Ntwin, & !< active number of twin systems per family (input parameter, per family) - plastic_phenoplus_Ntrans !< active number of trans systems per family (input parameter, per family) - - real(pReal), dimension(:), allocatable, private :: & - plastic_phenoplus_gdot0_slip, & !< reference shear strain rate for slip (input parameter) - plastic_phenoplus_gdot0_twin, & !< reference shear strain rate for twin (input parameter) - plastic_phenoplus_n_slip, & !< stress exponent for slip (input parameter) - plastic_phenoplus_n_twin, & !< stress exponent for twin (input parameter) - plastic_phenoplus_spr, & !< push-up factor for slip saturation due to twinning - plastic_phenoplus_twinB, & - plastic_phenoplus_twinC, & - plastic_phenoplus_twinD, & - plastic_phenoplus_twinE, & - plastic_phenoplus_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) - plastic_phenoplus_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) - plastic_phenoplus_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) - plastic_phenoplus_a_slip, & - plastic_phenoplus_aTolResistance, & - plastic_phenoplus_aTolShear, & - plastic_phenoplus_aTolTwinfrac, & - plastic_phenoplus_aTolTransfrac, & - plastic_phenoplus_Cnuc, & !< coefficient for strain-induced martensite nucleation - plastic_phenoplus_Cdwp, & !< coefficient for double well potential - plastic_phenoplus_Cgro, & !< coefficient for stress-assisted martensite growth - plastic_phenoplus_deltaG, & !< free energy difference between austensite and martensite [MPa] - plastic_phenoplus_kappa_max !< capped kappa for each slip system - - real(pReal), dimension(:,:), allocatable, private :: & - plastic_phenoplus_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) - plastic_phenoplus_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) - plastic_phenoplus_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) - plastic_phenoplus_nonSchmidCoeff, & - - plastic_phenoplus_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) - plastic_phenoplus_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) - plastic_phenoplus_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) - plastic_phenoplus_interaction_TwinTwin !< interaction factors twin - twin (input parameter) - - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_phenoplus_hardeningMatrix_SlipSlip, & - plastic_phenoplus_hardeningMatrix_SlipTwin, & - plastic_phenoplus_hardeningMatrix_TwinSlip, & - plastic_phenoplus_hardeningMatrix_TwinTwin - - enum, bind(c) - enumerator :: undefined_ID, & - resistance_slip_ID, & - accumulatedshear_slip_ID, & - shearrate_slip_ID, & - resolvedstress_slip_ID, & - kappa_slip_ID, & - totalshear_ID, & - resistance_twin_ID, & - accumulatedshear_twin_ID, & - shearrate_twin_ID, & - resolvedstress_twin_ID, & - totalvolfrac_twin_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_phenoplus_outputID !< ID of each post result output - - public :: & - plastic_phenoplus_init, & - plastic_phenoplus_microstructure, & - plastic_phenoplus_LpAndItsTangent, & - plastic_phenoplus_dotState, & - plastic_phenoplus_postResults - private :: & - plastic_phenoplus_aTolState, & - plastic_phenoplus_stateInit - - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_PHENOPLUS_label, & - PLASTICITY_PHENOPLUS_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - maxNinstance, & - instance,phase,j,k, f,o, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & - Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & - NipcMyPhase, & - offset_slip, index_myFamily, index_otherFamily, & - mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPLUS_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPLUS_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_phenoplus_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_sizePostResult(maxval(phase_Noutput),maxNinstance), & - source=0_pInt) - allocate(plastic_phenoplus_output(maxval(phase_Noutput),maxNinstance)) - plastic_phenoplus_output = '' - allocate(plastic_phenoplus_outputID(maxval(phase_Noutput),maxNinstance),source=undefined_ID) - allocate(plastic_phenoplus_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_Ntrans(lattice_maxNtransFamily,maxNinstance),source=0_pInt) - allocate(plastic_phenoplus_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_totalNtrans(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_gdot0_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_n_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_tau0_slip(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_tausat_slip(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_gdot0_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_n_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_tau0_twin(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_spr(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinB(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinC(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinD(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinE(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_h0_SlipSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_h0_TwinSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_h0_TwinTwin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_a_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolShear(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolTwinfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolTransfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_Cnuc(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_Cdwp(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_Cgro(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_deltaG(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_kappa_max(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase - Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('resistance_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_slip','accumulated_shear_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('kappa_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = kappa_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalshear') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalshear_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_twin','accumulated_shear_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalvolfrac_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalvolfrac_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case default - - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) - do j = 1_pInt, Nchunks_SlipFamilies - plastic_phenoplus_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tausat_slip','tau0_slip') - tempPerSlip = 0.0_pReal - do j = 1_pInt, Nchunks_SlipFamilies - if (plastic_phenoplus_Nslip(j,instance) > 0_pInt) & - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('tausat_slip') - plastic_phenoplus_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau0_slip') - plastic_phenoplus_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_phenoplus_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0_twin') - do j = 1_pInt, Nchunks_TwinFamilies - if (plastic_phenoplus_Ntwin(j,instance) > 0_pInt) & - plastic_phenoplus_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of transformation families - case ('ntrans') - if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - Nchunks_TransFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TransFamilies - plastic_phenoplus_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_phenoplus_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_phenoplus_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_phenoplus_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_phenoplus_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt,Nchunks_nonSchmid - plastic_phenoplus_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin systems - case ('gdot0_slip') - plastic_phenoplus_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_slip') - plastic_phenoplus_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('a_slip', 'w0_slip') - plastic_phenoplus_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('gdot0_twin') - plastic_phenoplus_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_twin') - plastic_phenoplus_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('s_pr') - plastic_phenoplus_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_b') - plastic_phenoplus_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_c') - plastic_phenoplus_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_d') - plastic_phenoplus_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_e') - plastic_phenoplus_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_slipslip') - plastic_phenoplus_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twinslip') - plastic_phenoplus_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twintwin') - plastic_phenoplus_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_resistance') - plastic_phenoplus_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_shear') - plastic_phenoplus_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_phenoplus_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_transfrac') - plastic_phenoplus_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('kappa_max') - plastic_phenoplus_kappa_max(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cnuc') - plastic_phenoplus_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cdwp') - plastic_phenoplus_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cgro') - plastic_phenoplus_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('deltag') - plastic_phenoplus_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) - case default - - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then - instance = phase_plasticityInstance(phase) - plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested - plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance)) - plastic_phenoplus_Ntwin(1:lattice_maxNtwinFamily,instance) = & - min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested - plastic_phenoplus_Ntwin(:,instance)) - plastic_phenoplus_totalNslip(instance) = sum(plastic_phenoplus_Nslip(:,instance)) ! how many slip systems altogether - plastic_phenoplus_totalNtwin(instance) = sum(plastic_phenoplus_Ntwin(:,instance)) ! how many twin systems altogether - plastic_phenoplus_totalNtrans(instance) = sum(plastic_phenoplus_Ntrans(:,instance)) ! how many trans systems altogether - - if (any(plastic_phenoplus_tau0_slip(:,instance) < 0.0_pReal .and. & - plastic_phenoplus_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (plastic_phenoplus_gdot0_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (plastic_phenoplus_n_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (any(plastic_phenoplus_tausat_slip(:,instance) <= 0.0_pReal .and. & - plastic_phenoplus_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (any(abs(plastic_phenoplus_a_slip(instance)) <= tiny(0.0_pReal) .and. & - plastic_phenoplus_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (any(plastic_phenoplus_tau0_twin(:,instance) < 0.0_pReal .and. & - plastic_phenoplus_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPLUS_label//')') - if ( plastic_phenoplus_gdot0_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenoplus_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPLUS_label//')') - if ( plastic_phenoplus_n_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenoplus_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPLUS_label//')') - if (plastic_phenoplus_aTolResistance(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa - if (plastic_phenoplus_aTolShear(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenoplus_aTolTwinfrac(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenoplus_aTolTransfrac(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - allocate(plastic_phenoplus_hardeningMatrix_SlipSlip(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from slip activity - maxval(plastic_phenoplus_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_hardeningMatrix_SlipTwin(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from twin activity - maxval(plastic_phenoplus_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_hardeningMatrix_TwinSlip(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_phenoplus_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_hardeningMatrix_TwinTwin(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_phenoplus_totalNtwin),& - maxNinstance), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config - myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then ! only consider my phase - NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase - instance = phase_plasticityInstance(phase) ! which instance of my phase - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) - select case(plastic_phenoplus_outputID(o,instance)) - case(resistance_slip_ID, & - shearrate_slip_ID, & - accumulatedshear_slip_ID, & - resolvedstress_slip_ID, & - kappa_slip_ID & - ) - mySize = plastic_phenoplus_totalNslip(instance) - case(resistance_twin_ID, & - shearrate_twin_ID, & - accumulatedshear_twin_ID, & - resolvedstress_twin_ID & - ) - mySize = plastic_phenoplus_totalNtwin(instance) - case(totalshear_ID, & - totalvolfrac_twin_ID & - ) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_phenoplus_sizePostResult(o,instance) = mySize - plastic_phenoplus_sizePostResults(instance) = plastic_phenoplus_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = plastic_phenoplus_totalNslip(instance) & ! s_slip - + plastic_phenoplus_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) - + plastic_phenoplus_totalNslip(instance) & ! accshear_slip - + plastic_phenoplus_totalNtwin(instance) & ! accshear_twin - + plastic_phenoplus_totalNslip(instance) ! kappa - - !sizeDotState = sizeState ! same as sizeState - !QUICK FIX: the dotState cannot have redundancy, which could cause unknown error - ! explicitly specify the size of the dotState to avoid this potential - ! memory leak issue. - sizeDotState = plastic_phenoplus_totalNslip(instance) & ! s_slip - + plastic_phenoplus_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) - + plastic_phenoplus_totalNslip(instance) & ! accshear_slip - + plastic_phenoplus_totalNtwin(instance) ! accshear_twin - - sizeDeltaState = 0_pInt - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_phenoplus_sizePostResults(instance) - plasticState(phase)%nSlip =plastic_phenoplus_totalNslip(instance) - plasticState(phase)%nTwin =plastic_phenoplus_totalNtwin(instance) - plasticState(phase)%nTrans=plastic_phenoplus_totalNtrans(instance) - allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) - - offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - - do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X - index_myFamily = sum(plastic_phenoplus_Nslip(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenoplus_Nslip(f,instance) ! loop over (active) systems in my family (slip) - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenoplus_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenoplus_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - - do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X - index_myFamily = sum(plastic_phenoplus_Ntwin(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenoplus_Ntwin(f,instance) ! loop over (active) systems in my family (twin) - - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenoplus_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenoplus_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - - call plastic_phenoplus_stateInit(phase,instance) - call plastic_phenoplus_aTolState(phase,instance) - endif myPhase2 - enddo initializeInstances - -end subroutine plastic_phenoplus_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_stateInit(ph,instance) - use lattice, only: & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - integer(pInt) :: & - i - real(pReal), dimension(plasticState(ph)%sizeState) :: & - tempState - - tempState = 0.0_pReal - do i = 1_pInt,lattice_maxNslipFamily - tempState(1+sum(plastic_phenoplus_Nslip(1:i-1,instance)) : & - sum(plastic_phenoplus_Nslip(1:i ,instance))) = & - plastic_phenoplus_tau0_slip(i,instance) - enddo - - do i = 1_pInt,lattice_maxNtwinFamily - tempState(1+sum(plastic_phenoplus_Nslip(:,instance))+& - sum(plastic_phenoplus_Ntwin(1:i-1,instance)) : & - sum(plastic_phenoplus_Nslip(:,instance))+& - sum(plastic_phenoplus_Ntwin(1:i ,instance))) = & - plastic_phenoplus_tau0_twin(i,instance) - enddo - - plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array - 2, & ! along dimension 2 - size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) - -end subroutine plastic_phenoplus_stateInit - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - plasticState(ph)%aTolState(1:plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance)) = & - plastic_phenoplus_aTolResistance(instance) - plasticState(ph)%aTolState(1+plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance)) = & - plastic_phenoplus_aTolShear(instance) - plasticState(ph)%aTolState(2+plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance)) = & - plastic_phenoplus_aTolTwinFrac(instance) - plasticState(ph)%aTolState(3+plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance): & - 2+2*(plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance))) = & - plastic_phenoplus_aTolShear(instance) - -end subroutine plastic_phenoplus_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate push-up factors (kappa) for each voxel based on its neighbors -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el) - use math, only: pi, & - math_mul33x33, & - math_mul3x3, & - math_transpose33, & - math_qDot, & - math_qRot, & - indeg - - use mesh, only: mesh_element, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype, & - mesh_maxNips, & - mesh_NcpElems, & - mesh_ipNeighborhood - - use material, only: material_phase, & - material_texture, & - phase_plasticityInstance, & - phaseAt, phasememberAt, & - homogenization_maxNgrains, & - plasticState - - use lattice, only: lattice_sn, & - lattice_sd, & - lattice_qDisorientation - - !***input variables - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - orientation ! crystal orientation in quaternions - - !***local variables - integer(pInt) instance, & !my instance of this plasticity - ph, & !my phase - of, & !my spatial position in memory (offset) - textureID, & !my texture - Nneighbors, & !number of neighbors (<= 6) - vld_Nneighbors, & !number of my valid neighbors - n, & !neighbor index (for iterating through all neighbors) - ns, & !number of slip system - nt, & !number of twin system - me_slip, & !my slip system index - neighbor_el, & !element number of neighboring material point - neighbor_ip, & !integration point of neighboring material point - neighbor_n, & !I have no idea what is this - neighbor_of, & !spatial position in memory for this neighbor (offset) - neighbor_ph, & !neighbor's phase - neighbor_tex, & !neighbor's texture ID - ne_slip_ac, & !loop to find neighbor shear - ne_slip, & !slip system index for neighbor - index_kappa, & !index of pushup factors in plasticState - offset_acshear_slip, & !offset in PlasticState for the accumulative shear - j !quickly loop through slip families - - real(pReal) kappa_max, & ! - tmp_myshear_slip, & !temp storage for accumulative shear for me - mprime_cut, & !m' cutoff to consider neighboring effect - avg_acshear_ne, & !the average accumulative shear from my neighbor - tmp_mprime, & !temp holder for m' value - tmp_acshear !temp holder for accumulative shear for m' - - - real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - m_primes, & !m' between me_alpha(one) and neighbor beta(all) - me_acshear, & !temp storage for ac_shear of one particular system for me - ne_acshear !temp storage for ac_shear of one particular system for one of my neighbor - - real(pReal), dimension(3,plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - slipNormal, & - slipDirect - - real(pReal), dimension(4) :: my_orientation, & !store my orientation - neighbor_orientation, & !store my neighbor orientation - absMisorientation - - real(pReal), dimension(FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) :: & - ne_mprimes !m' between each neighbor - - !***Get my properties - Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) - ph = phaseAt(ipc,ip,el) !get my phase - of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory - textureID = material_texture(1,ip,el) !get my texture ID - instance = phase_plasticityInstance(ph) !get my instance based on phase ID - ns = plastic_phenoplus_totalNslip(instance) - nt = plastic_phenoplus_totalNtwin(instance) - offset_acshear_slip = ns + nt + 2_pInt - index_kappa = ns + nt + 2_pInt + ns + nt !location of kappa in plasticState - mprime_cut = 0.7_pReal !set by Dr.Bieler - - !***gather my accumulative shear from palsticState - FINDMYSHEAR: do j = 1_pInt,ns - me_acshear(j) = plasticState(ph)%state(offset_acshear_slip+j, of) - enddo FINDMYSHEAR - - !***gather my orientation and slip systems - my_orientation = orientation(1:4, ipc, ip, el) - slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) - slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) - kappa_max = plastic_phenoplus_kappa_max(instance) !maximum pushups allowed (READIN) - - !***calculate kappa between me and all my neighbors - LOOPMYSLIP: DO me_slip=1_pInt,ns - vld_Nneighbors = Nneighbors - tmp_myshear_slip = me_acshear(me_slip) - tmp_mprime = 0.0_pReal !highest m' from all neighbors - tmp_acshear = 0.0_pReal !accumulative shear from highest m' - - !***go through my neighbors to find highest m' - LOOPNEIGHBORS: DO n=1_pInt,Nneighbors - neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - neighbor_n = 1 !It is ipc - neighbor_of = phasememberAt( neighbor_n, neighbor_ip, neighbor_el) - neighbor_ph = phaseAt( neighbor_n, neighbor_ip, neighbor_el) - neighbor_tex = material_texture(1,neighbor_ip,neighbor_el) - neighbor_orientation = orientation(1:4, neighbor_n, neighbor_ip, neighbor_el) !ipc is always 1. - absMisorientation = lattice_qDisorientation(my_orientation, & - neighbor_orientation, & - 0_pInt) !no need for explicit calculation of symmetry - - !***find the accumulative shear for this neighbor - LOOPFINDNEISHEAR: DO ne_slip_ac=1_pInt, ns - ne_acshear(ne_slip_ac) = plasticState(ph)%state(offset_acshear_slip+ne_slip_ac, & - neighbor_of) - ENDDO LOOPFINDNEISHEAR - - !***calculate the average accumulative shear and use it as cutoff - avg_acshear_ne = SUM(ne_acshear)/ns - - !*** - IF (ph==neighbor_ph) THEN - !***walk through all the - LOOPNEIGHBORSLIP: DO ne_slip=1_pInt,ns - !***only consider slip system that is active (above average accumulative shear) - IF (ne_acshear(ne_slip) > avg_acshear_ne) THEN - m_primes(ne_slip) = abs(math_mul3x3(slipNormal(1:3,me_slip), & - math_qRot(absMisorientation, slipNormal(1:3,ne_slip)))) & - *abs(math_mul3x3(slipDirect(1:3,me_slip), & - math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) - !***find the highest m' and corresponding accumulative shear - IF (m_primes(ne_slip) > tmp_mprime) THEN - tmp_mprime = m_primes(ne_slip) - tmp_acshear = ne_acshear(ne_slip) - ENDIF - ENDIF - ENDDO LOOPNEIGHBORSLIP - - ELSE - ne_mprimes(n) = 0.0_pReal - vld_Nneighbors = vld_Nneighbors - 1_pInt - ENDIF - - ENDDO LOOPNEIGHBORS - - !***check if this element close to rim - IF (vld_Nneighbors < Nneighbors) THEN - !***rim voxel, no modification allowed - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal - ELSE - !***patch voxel, started to calculate push up factor for gamma_dot - IF ((tmp_mprime > mprime_cut) .AND. (tmp_acshear > tmp_myshear_slip)) THEN - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal / tmp_mprime - ELSE - !***minimum damping factor is 0.5 - plasticState(ph)%state(index_kappa+me_slip, of) = 0.5_pReal + tmp_mprime * 0.5_pReal - ENDIF - ENDIF - - ENDDO LOOPMYSLIP - -end subroutine plastic_phenoplus_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use math, only: & - math_Plain3333to99, & - math_Mandel6to33 - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - use material, only: & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - - integer(pInt) :: & - instance, & - nSlip, & - nTwin,index_Gamma,index_F,index_myFamily, index_kappa, & - f,i,j,k,l,m,n, & - of, & - ph - real(pReal) :: & - tau_slip_pos,tau_slip_neg, & - gdot_slip_pos,gdot_slip_neg, & - dgdot_dtauslip_pos,dgdot_dtauslip_neg, & - gdot_twin,dgdot_dtautwin,tau_twin - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal), dimension(3,3,2) :: & - nonSchmid_tensor - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - nSlip = plastic_phenoplus_totalNslip(instance) - nTwin = plastic_phenoplus_totalNtwin(instance) - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - index_kappa = nSlip + nTwin + 2_pInt +nSlip + nTwin - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Slip part - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) - enddo - - !***insert non-local effect here by modify gdot with kappa in plastic state - !***this implementation will most likely cause convergence issue - ! gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ! ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of)* & - ! plasticState(ph)%state(j+index_kappa, of))) & !in-place modification of gdot - ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) - - ! gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ! ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of)* & - ! plasticState(ph)%state(j+index_kappa, of))) & !?should we make it direction aware - ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) - - !***original calculation - gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of))) & !in-place modification of gdot - **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) - - gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of))) & !?should we make it direction aware - **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) - - !***MAGIC HERE***! - !***directly modify the amount of shear happens considering neighborhood - gdot_slip_pos = gdot_slip_pos * plasticState(ph)%state(j+index_kappa, of) - gdot_slip_neg = gdot_slip_neg * plasticState(ph)%state(j+index_kappa, of) - - Lp = Lp + (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then - dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenoplus_n_slip(instance)/tau_slip_pos - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,1) - endif - - if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then - dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenoplus_n_slip(instance)/tau_slip_neg - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,2) - endif - enddo slipSystems - enddo slipFamilies - -!-------------------------------------------------------------------------------------------------- -! Twinning part - j = 0_pInt - twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenoplus_gdot0_twin(instance)*& - (abs(tau_twin)/plasticState(ph)%state(nSlip+j,of))**& - plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_twin) > tiny(0.0_pReal)) then - dgdot_dtautwin = gdot_twin*plastic_phenoplus_n_twin(instance)/tau_twin - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & - lattice_Stwin(m,n,index_myFamily+i,ph) - endif - enddo twinSystems - enddo twinFamilies - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - - -end subroutine plastic_phenoplus_LpAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_dotState(Tstar_v,ipc,ip,el) - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_shearTwin, & - lattice_NnonSchmid - use material, only: & - material_phase, & - phaseAt, phasememberAt, & - plasticState, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - integer(pInt) :: & - instance,ph, & - nSlip,nTwin, & - f,i,j,k, & - index_Gamma,index_F,index_myFamily,& - offset_accshear_slip,offset_accshear_twin, offset_kappa, & - of - real(pReal) :: & - c_SlipSlip,c_TwinSlip,c_TwinTwin, & - ssat_offset, & - tau_slip_pos,tau_slip_neg,tau_twin - - real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip - real(pReal), dimension(plastic_phenoplus_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenoplus_totalNslip(instance) - nTwin = plastic_phenoplus_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - offset_accshear_slip = nSlip + nTwin + 2_pInt - offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip - offset_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin - plasticState(ph)%dotState(:,of) = 0.0_pReal - - -!-------------------------------------------------------------------------------------------------- -! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices - c_SlipSlip = plastic_phenoplus_h0_SlipSlip(instance)*& - (1.0_pReal + plastic_phenoplus_twinC(instance)*plasticState(ph)%state(index_F,of)**& - plastic_phenoplus_twinB(instance)) - c_TwinSlip = plastic_phenoplus_h0_TwinSlip(instance)*& - plasticState(ph)%state(index_Gamma,of)**plastic_phenoplus_twinE(instance) - c_TwinTwin = plastic_phenoplus_h0_TwinTwin(instance)*& - plasticState(ph)%state(index_F,of)**plastic_phenoplus_twinD(instance) - -!-------------------------------------------------------------------------------------------------- -! calculate left and right vectors and calculate dot gammas - ssat_offset = plastic_phenoplus_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j+1_pInt - left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part - left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part - !***original implementation - right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & - **plastic_phenoplus_a_slip(instance)& - *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) - !***modify a_slip to get nonlocal effect - ! right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & - ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & - ! **(plastic_phenoplus_a_slip(instance)*plasticState(ph)%state(j+offset_kappa, of))& - ! *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & - ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) - right_TwinSlip(j) = 1.0_pReal ! no system-dependent part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot gamma - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - gdot_slip(j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance) & - +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - enddo slipSystems1 - enddo slipFamilies1 - - - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j+1_pInt - left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part - left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part - right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part - right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot vol frac - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenoplus_gdot0_twin(instance)*& - (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& - plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - enddo twinSystems1 - enddo twinFamilies1 - -!-------------------------------------------------------------------------------------------------- -! calculate the overall hardening based on above - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j - c_SlipSlip * left_SlipSlip(j) * & - dot_product(plastic_phenoplus_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & - right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - dot_product(plastic_phenoplus_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & - right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & - abs(gdot_slip(j)) - plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) - enddo slipSystems2 - enddo slipFamilies2 - - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j - c_TwinSlip * left_TwinSlip(j) * & - dot_product(plastic_phenoplus_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & - right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - c_TwinTwin * left_TwinTwin(j) * & - dot_product(plastic_phenoplus_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & - right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 - plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & - gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) - plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) - enddo twinSystems2 - enddo twinFamilies2 - - -end subroutine plastic_phenoplus_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_phenoplus_postResults(Tstar_v,ipc,ip,el) - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - real(pReal), dimension(plastic_phenoplus_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_phenoplus_postResults - - integer(pInt) :: & - instance,ph, of, & - nSlip,nTwin, & - o,f,i,c,j,k, & - index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily,index_kappa - real(pReal) :: & - tau_slip_pos,tau_slip_neg,tau - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenoplus_totalNslip(instance) - nTwin = plastic_phenoplus_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - index_accshear_slip = nSlip + nTwin + 2_pInt + 1_pInt - index_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + 1_pInt - index_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin + 1_pInt - - plastic_phenoplus_postResults = 0.0_pReal - c = 0_pInt - - outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) - select case(plastic_phenoplus_outputID(o,instance)) - case (resistance_slip_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) - c = c + nSlip - - case (accumulatedshear_slip_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& - index_accshear_slip+nSlip-1_pInt,of) - c = c + nSlip - - case (shearrate_slip_ID) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j + 1_pInt - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo - plastic_phenoplus_postResults(c+j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance) & - +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - - enddo slipSystems1 - enddo slipFamilies1 - c = c + nSlip - - case (resolvedstress_slip_ID) - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j + 1_pInt - plastic_phenoplus_postResults(c+j) = & - dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - enddo slipSystems2 - enddo slipFamilies2 - c = c + nSlip - - case (kappa_slip_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = & - plasticState(ph)%state(index_kappa:index_kappa+nSlip-1_pInt,of) - c = c + nSlip - - case (totalshear_ID) - plastic_phenoplus_postResults(c+1_pInt) = & - plasticState(ph)%state(index_Gamma,of) - c = c + 1_pInt - - case (resistance_twin_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) - c = c + nTwin - - case (accumulatedshear_twin_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) - c = c + nTwin - - case (shearrate_twin_ID) - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j + 1_pInt - tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - plastic_phenoplus_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenoplus_gdot0_twin(instance)*& - (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& - plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) - enddo twinSystems1 - enddo twinFamilies1 - c = c + nTwin - - case (resolvedstress_twin_ID) - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j + 1_pInt - plastic_phenoplus_postResults(c+j) = & - dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - enddo twinSystems2 - enddo twinFamilies2 - c = c + nTwin - - case (totalvolfrac_twin_ID) - plastic_phenoplus_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) - c = c + 1_pInt - - end select - enddo outputsLoop - -end function plastic_phenoplus_postResults - -end module plastic_phenoplus diff --git a/code/plastic_phenopowerlaw.f90 b/code/plastic_phenopowerlaw.f90 deleted file mode 100644 index 1f8e16250..000000000 --- a/code/plastic_phenopowerlaw.f90 +++ /dev/null @@ -1,1226 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw -!! fitting -!-------------------------------------------------------------------------------------------------- -module plastic_phenopowerlaw - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenopowerlaw_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_phenopowerlaw_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_phenopowerlaw_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_phenopowerlaw_Noutput !< number of outputs per instance of this constitution - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenopowerlaw_totalNslip, & !< no. of slip system used in simulation - plastic_phenopowerlaw_totalNtwin, & !< no. of twin system used in simulation - plastic_phenopowerlaw_totalNtrans !< no. of trans system used in simulation - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_phenopowerlaw_Nslip, & !< active number of slip systems per family (input parameter, per family) - plastic_phenopowerlaw_Ntwin, & !< active number of twin systems per family (input parameter, per family) - plastic_phenopowerlaw_Ntrans !< active number of trans systems per family (input parameter, per family) - - real(pReal), dimension(:), allocatable, private :: & - plastic_phenopowerlaw_gdot0_slip, & !< reference shear strain rate for slip (input parameter) - plastic_phenopowerlaw_gdot0_twin, & !< reference shear strain rate for twin (input parameter) - plastic_phenopowerlaw_n_slip, & !< stress exponent for slip (input parameter) - plastic_phenopowerlaw_n_twin, & !< stress exponent for twin (input parameter) - plastic_phenopowerlaw_spr, & !< push-up factor for slip saturation due to twinning - plastic_phenopowerlaw_twinB, & - plastic_phenopowerlaw_twinC, & - plastic_phenopowerlaw_twinD, & - plastic_phenopowerlaw_twinE, & - plastic_phenopowerlaw_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) - plastic_phenopowerlaw_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) - plastic_phenopowerlaw_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) - plastic_phenopowerlaw_a_slip, & - plastic_phenopowerlaw_aTolResistance, & - plastic_phenopowerlaw_aTolShear, & - plastic_phenopowerlaw_aTolTwinfrac, & - plastic_phenopowerlaw_aTolTransfrac, & - plastic_phenopowerlaw_Cnuc, & !< coefficient for strain-induced martensite nucleation - plastic_phenopowerlaw_Cdwp, & !< coefficient for double well potential - plastic_phenopowerlaw_Cgro, & !< coefficient for stress-assisted martensite growth - plastic_phenopowerlaw_deltaG !< free energy difference between austensite and martensite [MPa] - - real(pReal), dimension(:,:), allocatable, private :: & - plastic_phenopowerlaw_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) - plastic_phenopowerlaw_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) - plastic_phenopowerlaw_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) - plastic_phenopowerlaw_nonSchmidCoeff, & - - plastic_phenopowerlaw_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) - plastic_phenopowerlaw_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) - plastic_phenopowerlaw_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) - plastic_phenopowerlaw_interaction_TwinTwin !< interaction factors twin - twin (input parameter) - - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_phenopowerlaw_hardeningMatrix_SlipSlip, & - plastic_phenopowerlaw_hardeningMatrix_SlipTwin, & - plastic_phenopowerlaw_hardeningMatrix_TwinSlip, & - plastic_phenopowerlaw_hardeningMatrix_TwinTwin - - enum, bind(c) - enumerator :: undefined_ID, & - resistance_slip_ID, & - accumulatedshear_slip_ID, & - shearrate_slip_ID, & - resolvedstress_slip_ID, & - totalshear_ID, & - resistance_twin_ID, & - accumulatedshear_twin_ID, & - shearrate_twin_ID, & - resolvedstress_twin_ID, & - totalvolfrac_twin_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_phenopowerlaw_outputID !< ID of each post result output - - type, private :: tPhenopowerlawState - real(pReal), pointer, dimension(:,:) :: & - s_slip, & - s_twin, & - accshear_slip, & - accshear_twin - real(pReal), pointer, dimension(:) :: & - sumGamma, & - sumF - end type - - type(tPhenopowerlawState), allocatable, dimension(:), private :: & - dotState, & - state, & - state0 - - public :: & - plastic_phenopowerlaw_init, & - plastic_phenopowerlaw_LpAndItsTangent, & - plastic_phenopowerlaw_dotState, & - plastic_phenopowerlaw_postResults - private :: & - plastic_phenopowerlaw_aTolState, & - plastic_phenopowerlaw_stateInit - - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_PHENOPOWERLAW_label, & - PLASTICITY_PHENOPOWERLAW_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - maxNinstance, & - instance,phase,j,k, f,o, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & - Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & - NipcMyPhase, & - offset_slip, index_myFamily, index_otherFamily, & - mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState, & - startIndex, endIndex - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPOWERLAW_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPOWERLAW_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - - allocate(plastic_phenopowerlaw_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_sizePostResult(maxval(phase_Noutput),maxNinstance), & - source=0_pInt) - allocate(plastic_phenopowerlaw_output(maxval(phase_Noutput),maxNinstance)) - plastic_phenopowerlaw_output = '' - allocate(plastic_phenopowerlaw_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_phenopowerlaw_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_totalNtrans(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_gdot0_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_n_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_tau0_slip(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_tausat_slip(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_phenopowerlaw_gdot0_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_n_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_tau0_twin(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_spr(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinB(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinC(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinD(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinE(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_h0_SlipSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_h0_TwinSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_h0_TwinTwin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_a_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolShear(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolTwinfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolTransfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_Cnuc(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_Cdwp(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_Cgro(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_deltaG(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase - Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('resistance_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_slip','accumulated_shear_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalshear') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalshear_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_twin','accumulated_shear_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalvolfrac_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalvolfrac_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case default - - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) - do j = 1_pInt, Nchunks_SlipFamilies - plastic_phenopowerlaw_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tausat_slip','tau0_slip') - tempPerSlip = 0.0_pReal - do j = 1_pInt, Nchunks_SlipFamilies - if (plastic_phenopowerlaw_Nslip(j,instance) > 0_pInt) & - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('tausat_slip') - plastic_phenopowerlaw_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau0_slip') - plastic_phenopowerlaw_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_phenopowerlaw_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0_twin') - do j = 1_pInt, Nchunks_TwinFamilies - if (plastic_phenopowerlaw_Ntwin(j,instance) > 0_pInt) & - plastic_phenopowerlaw_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of transformation families - case ('ntrans') - if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - Nchunks_TransFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TransFamilies - plastic_phenopowerlaw_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_phenopowerlaw_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_phenopowerlaw_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_phenopowerlaw_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_phenopowerlaw_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt,Nchunks_nonSchmid - plastic_phenopowerlaw_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin systems - case ('gdot0_slip') - plastic_phenopowerlaw_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_slip') - plastic_phenopowerlaw_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('a_slip', 'w0_slip') - plastic_phenopowerlaw_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('gdot0_twin') - plastic_phenopowerlaw_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_twin') - plastic_phenopowerlaw_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('s_pr') - plastic_phenopowerlaw_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_b') - plastic_phenopowerlaw_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_c') - plastic_phenopowerlaw_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_d') - plastic_phenopowerlaw_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_e') - plastic_phenopowerlaw_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_slipslip') - plastic_phenopowerlaw_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twinslip') - plastic_phenopowerlaw_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twintwin') - plastic_phenopowerlaw_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_resistance') - plastic_phenopowerlaw_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_shear') - plastic_phenopowerlaw_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_phenopowerlaw_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_transfrac') - plastic_phenopowerlaw_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cnuc') - plastic_phenopowerlaw_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cdwp') - plastic_phenopowerlaw_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cgro') - plastic_phenopowerlaw_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('deltag') - plastic_phenopowerlaw_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) - case default - - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then - instance = phase_plasticityInstance(phase) - plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested - plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance)) - plastic_phenopowerlaw_Ntwin(1:lattice_maxNtwinFamily,instance) = & - min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested - plastic_phenopowerlaw_Ntwin(:,instance)) - plastic_phenopowerlaw_totalNslip(instance) = sum(plastic_phenopowerlaw_Nslip(:,instance)) ! how many slip systems altogether - plastic_phenopowerlaw_totalNtwin(instance) = sum(plastic_phenopowerlaw_Ntwin(:,instance)) ! how many twin systems altogether - plastic_phenopowerlaw_totalNtrans(instance) = sum(plastic_phenopowerlaw_Ntrans(:,instance)) ! how many trans systems altogether - - if (any(plastic_phenopowerlaw_tau0_slip(:,instance) < 0.0_pReal .and. & - plastic_phenopowerlaw_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (plastic_phenopowerlaw_gdot0_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (plastic_phenopowerlaw_n_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (any(plastic_phenopowerlaw_tausat_slip(:,instance) <= 0.0_pReal .and. & - plastic_phenopowerlaw_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (any(abs(plastic_phenopowerlaw_a_slip(instance)) <= tiny(0.0_pReal) .and. & - plastic_phenopowerlaw_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (any(plastic_phenopowerlaw_tau0_twin(:,instance) < 0.0_pReal .and. & - plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') - if ( plastic_phenopowerlaw_gdot0_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') - if ( plastic_phenopowerlaw_n_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (plastic_phenopowerlaw_aTolResistance(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa - if (plastic_phenopowerlaw_aTolShear(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenopowerlaw_aTolTwinfrac(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenopowerlaw_aTolTransfrac(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - allocate(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from slip activity - maxval(plastic_phenopowerlaw_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from twin activity - maxval(plastic_phenopowerlaw_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_phenopowerlaw_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_phenopowerlaw_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(state(maxNinstance)) - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config - myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then ! only consider my phase - NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase - instance = phase_plasticityInstance(phase) ! which instance of my phase - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) - select case(plastic_phenopowerlaw_outputID(o,instance)) - case(resistance_slip_ID, & - shearrate_slip_ID, & - accumulatedshear_slip_ID, & - resolvedstress_slip_ID & - ) - mySize = plastic_phenopowerlaw_totalNslip(instance) - case(resistance_twin_ID, & - shearrate_twin_ID, & - accumulatedshear_twin_ID, & - resolvedstress_twin_ID & - ) - mySize = plastic_phenopowerlaw_totalNtwin(instance) - case(totalshear_ID, & - totalvolfrac_twin_ID & - ) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_phenopowerlaw_sizePostResult(o,instance) = mySize - plastic_phenopowerlaw_sizePostResults(instance) = plastic_phenopowerlaw_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = plastic_phenopowerlaw_totalNslip(instance) & ! s_slip - + plastic_phenopowerlaw_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) - + plastic_phenopowerlaw_totalNslip(instance) & ! accshear_slip - + plastic_phenopowerlaw_totalNtwin(instance) ! accshear_twin - - sizeDotState = sizeState - sizeDeltaState = 0_pInt - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_phenopowerlaw_sizePostResults(instance) - plasticState(phase)%nSlip =plastic_phenopowerlaw_totalNslip(instance) - plasticState(phase)%nTwin =plastic_phenopowerlaw_totalNtwin(instance) - plasticState(phase)%nTrans=plastic_phenopowerlaw_totalNtrans(instance) - allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) - - offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - - do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X - index_myFamily = sum(plastic_phenopowerlaw_Nslip(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) ! loop over (active) systems in my family (slip) - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenopowerlaw_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenopowerlaw_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - - do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X - index_myFamily = sum(plastic_phenopowerlaw_Ntwin(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) ! loop over (active) systems in my family (twin) - - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenopowerlaw_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenopowerlaw_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - startIndex = 1_pInt - endIndex = plastic_phenopowerlaw_totalNslip(instance) - state (instance)%s_slip=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%s_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%s_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex + plastic_phenopowerlaw_totalNtwin(instance) - state (instance)%s_twin=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%s_twin=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%s_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex + 1_pInt - state (instance)%sumGamma=>plasticState(phase)%state (startIndex,:) - state0 (instance)%sumGamma=>plasticState(phase)%state0 (startIndex,:) - dotState(instance)%sumGamma=>plasticState(phase)%dotState(startIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex + 1_pInt - state (instance)%sumF=>plasticState(phase)%state (startIndex,:) - state0 (instance)%sumF=>plasticState(phase)%state0 (startIndex,:) - dotState(instance)%sumF=>plasticState(phase)%dotState(startIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex +plastic_phenopowerlaw_totalNslip(instance) - state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex +plastic_phenopowerlaw_totalNtwin(instance) - state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - - call plastic_phenopowerlaw_stateInit(phase,instance) - call plastic_phenopowerlaw_aTolState(phase,instance) - endif myPhase2 - enddo initializeInstances - -end subroutine plastic_phenopowerlaw_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_stateInit(ph,instance) - use lattice, only: & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - integer(pInt) :: & - i - real(pReal), dimension(plasticState(ph)%sizeState) :: & - tempState - - tempState = 0.0_pReal - do i = 1_pInt,lattice_maxNslipFamily - tempState(1+sum(plastic_phenopowerlaw_Nslip(1:i-1,instance)) : & - sum(plastic_phenopowerlaw_Nslip(1:i ,instance))) = & - plastic_phenopowerlaw_tau0_slip(i,instance) - enddo - - do i = 1_pInt,lattice_maxNtwinFamily - tempState(1+sum(plastic_phenopowerlaw_Nslip(:,instance))+& - sum(plastic_phenopowerlaw_Ntwin(1:i-1,instance)) : & - sum(plastic_phenopowerlaw_Nslip(:,instance))+& - sum(plastic_phenopowerlaw_Ntwin(1:i ,instance))) = & - plastic_phenopowerlaw_tau0_twin(i,instance) - enddo - - plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array - 2, & ! along dimension 2 - size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) - -end subroutine plastic_phenopowerlaw_stateInit - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - plasticState(ph)%aTolState(1:plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance)) = & - plastic_phenopowerlaw_aTolResistance(instance) - plasticState(ph)%aTolState(1+plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance)) = & - plastic_phenopowerlaw_aTolShear(instance) - plasticState(ph)%aTolState(2+plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance)) = & - plastic_phenopowerlaw_aTolTwinFrac(instance) - plasticState(ph)%aTolState(3+plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance): & - 2+2*(plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance))) = & - plastic_phenopowerlaw_aTolShear(instance) - -end subroutine plastic_phenopowerlaw_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use math, only: & - math_Plain3333to99, & - math_Mandel6to33 - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - use material, only: & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - - integer(pInt) :: & - instance, & - index_myFamily, & - f,i,j,k,l,m,n, & - of, & - ph - real(pReal) :: & - tau_slip_pos,tau_slip_neg, & - gdot_slip_pos,gdot_slip_neg, & - dgdot_dtauslip_pos,dgdot_dtauslip_neg, & - gdot_twin,dgdot_dtautwin,tau_twin - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal), dimension(3,3,2) :: & - nonSchmid_tensor - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Slip part - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) - enddo - gdot_slip_pos = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & - ((abs(tau_slip_pos)/(state(instance)%s_slip(j,of))) & - **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) - - gdot_slip_neg = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & - ((abs(tau_slip_neg)/(state(instance)%s_slip(j,of))) & - **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) - - Lp = Lp + (1.0_pReal-state(instance)%sumF(of))*& ! 1-F - (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then - dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenopowerlaw_n_slip(instance)/tau_slip_pos - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,1) - endif - - if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then - dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenopowerlaw_n_slip(instance)/tau_slip_neg - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,2) - endif - enddo slipSystems - enddo slipFamilies - -!-------------------------------------------------------------------------------------------------- -! Twinning part - j = 0_pInt - twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin = (1.0_pReal-state(instance)%sumF(of))*& ! 1-F - plastic_phenopowerlaw_gdot0_twin(instance)*& - (abs(tau_twin)/state(instance)%s_twin(j,of))**& - plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_twin) > tiny(0.0_pReal)) then - dgdot_dtautwin = gdot_twin*plastic_phenopowerlaw_n_twin(instance)/tau_twin - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & - lattice_Stwin(m,n,index_myFamily+i,ph) - endif - enddo twinSystems - enddo twinFamilies - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - - -end subroutine plastic_phenopowerlaw_LpAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_dotState(Tstar_v,ipc,ip,el) - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_shearTwin, & - lattice_NnonSchmid - use material, only: & - material_phase, & - phaseAt, phasememberAt, & - plasticState, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - integer(pInt) :: & - instance,ph, & - nSlip,nTwin, & - f,i,j,k, & - index_Gamma,index_F,index_myFamily, & - offset_accshear_slip,offset_accshear_twin, & - of - real(pReal) :: & - c_SlipSlip,c_TwinSlip,c_TwinTwin, & - ssat_offset, & - tau_slip_pos,tau_slip_neg,tau_twin - - real(pReal), dimension(plastic_phenopowerlaw_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip - real(pReal), dimension(plastic_phenopowerlaw_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenopowerlaw_totalNslip(instance) - nTwin = plastic_phenopowerlaw_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - offset_accshear_slip = nSlip + nTwin + 2_pInt - offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip - plasticState(ph)%dotState(:,of) = 0.0_pReal - - -!-------------------------------------------------------------------------------------------------- -! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices - c_SlipSlip = plastic_phenopowerlaw_h0_SlipSlip(instance)*& - (1.0_pReal + plastic_phenopowerlaw_twinC(instance)*plasticState(ph)%state(index_F,of)**& - plastic_phenopowerlaw_twinB(instance)) - c_TwinSlip = plastic_phenopowerlaw_h0_TwinSlip(instance)*& - plasticState(ph)%state(index_Gamma,of)**plastic_phenopowerlaw_twinE(instance) - c_TwinTwin = plastic_phenopowerlaw_h0_TwinTwin(instance)*& - plasticState(ph)%state(index_F,of)**plastic_phenopowerlaw_twinD(instance) - -!-------------------------------------------------------------------------------------------------- -! calculate left and right vectors and calculate dot gammas - ssat_offset = plastic_phenopowerlaw_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j+1_pInt - left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part - left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part - right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) & - **plastic_phenopowerlaw_a_slip(instance)& - *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) - right_TwinSlip(j) = 1.0_pReal ! no system-dependent part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot gamma - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - gdot_slip(j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance) & - +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - enddo slipSystems1 - enddo slipFamilies1 - - - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j+1_pInt - left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part - left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part - right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part - right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot vol frac - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenopowerlaw_gdot0_twin(instance)*& - (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& - plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - enddo twinSystems1 - enddo twinFamilies1 - -!-------------------------------------------------------------------------------------------------- -! calculate the overall hardening based on above - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j - c_SlipSlip * left_SlipSlip(j) * & - dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & - right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & - right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & - abs(gdot_slip(j)) - plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) - enddo slipSystems2 - enddo slipFamilies2 - - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j - c_TwinSlip * left_TwinSlip(j) * & - dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & - right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - c_TwinTwin * left_TwinTwin(j) * & - dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & - right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 - plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & - gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) - plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) - enddo twinSystems2 - enddo twinFamilies2 - - -end subroutine plastic_phenopowerlaw_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_phenopowerlaw_postResults(Tstar_v,ipc,ip,el) - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - real(pReal), dimension(plastic_phenopowerlaw_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_phenopowerlaw_postResults - - integer(pInt) :: & - instance,ph, of, & - nSlip,nTwin, & - o,f,i,c,j,k, & - index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily - real(pReal) :: & - tau_slip_pos,tau_slip_neg,tau - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenopowerlaw_totalNslip(instance) - nTwin = plastic_phenopowerlaw_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - index_accshear_slip = nSlip + nTwin + 3_pInt - index_accshear_twin = nSlip + nTwin + 3_pInt + nSlip - - plastic_phenopowerlaw_postResults = 0.0_pReal - c = 0_pInt - - outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) - select case(plastic_phenopowerlaw_outputID(o,instance)) - case (resistance_slip_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) - c = c + nSlip - - case (accumulatedshear_slip_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& - index_accshear_slip+nSlip-1_pInt,of) - c = c + nSlip - - case (shearrate_slip_ID) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j + 1_pInt - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo - plastic_phenopowerlaw_postResults(c+j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance) & - +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - - enddo slipSystems1 - enddo slipFamilies1 - c = c + nSlip - - case (resolvedstress_slip_ID) - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j + 1_pInt - plastic_phenopowerlaw_postResults(c+j) = & - dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - enddo slipSystems2 - enddo slipFamilies2 - c = c + nSlip - - case (totalshear_ID) - plastic_phenopowerlaw_postResults(c+1_pInt) = & - plasticState(ph)%state(index_Gamma,of) - c = c + 1_pInt - - case (resistance_twin_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) - c = c + nTwin - - case (accumulatedshear_twin_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) - c = c + nTwin - case (shearrate_twin_ID) - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j + 1_pInt - tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - plastic_phenopowerlaw_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenopowerlaw_gdot0_twin(instance)*& - (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& - plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) - enddo twinSystems1 - enddo twinFamilies1 - c = c + nTwin - - case (resolvedstress_twin_ID) - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j + 1_pInt - plastic_phenopowerlaw_postResults(c+j) = & - dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - enddo twinSystems2 - enddo twinFamilies2 - c = c + nTwin - - case (totalvolfrac_twin_ID) - plastic_phenopowerlaw_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) - c = c + 1_pInt - - end select - enddo outputsLoop - -end function plastic_phenopowerlaw_postResults - -end module plastic_phenopowerlaw diff --git a/code/plastic_titanmod.f90 b/code/plastic_titanmod.f90 deleted file mode 100644 index abc6d661b..000000000 --- a/code/plastic_titanmod.f90 +++ /dev/null @@ -1,1913 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Alankar Alankar, 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 -!> @brief material subroutine for titanium -!-------------------------------------------------------------------------------------------------- -module plastic_titanmod - use prec, only: & - pReal, & - pInt - - implicit none - private - character(len=18), dimension(3), parameter, private :: & - plastic_titanmod_listBasicSlipStates = & - ['rho_edge ', 'rho_screw ', 'shear_system'] - character(len=18), dimension(1), parameter, private :: & - plastic_titanmod_listBasicTwinStates = ['gdot_twin'] - character(len=19), dimension(11), parameter, private :: & - plastic_titanmod_listDependentSlipStates = & - ['segment_edge ', 'segment_screw ', & - 'resistance_edge ', 'resistance_screw ', & - 'tau_slip ', & - 'velocity_edge ', 'velocity_screw ', & - 'gdot_slip_edge ', 'gdot_slip_screw ', & - 'stressratio_edge_p ', 'stressratio_screw_p' ] - character(len=18), dimension(2), parameter, private :: & - plastic_titanmod_listDependentTwinStates = & - ['twin_fraction', 'tau_twin '] - real(pReal), parameter, private :: & - kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin - - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_titanmod_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_titanmod_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_titanmod_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_titanmod_Noutput !< number of outputs per instance of this plasticity !< ID of the lattice structure - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_titanmod_totalNslip, & !< total number of active slip systems for each instance - plastic_titanmod_totalNtwin !< total number of active twin systems for each instance - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_titanmod_Nslip, & !< number of active slip systems for each family and instance - plastic_titanmod_Ntwin, & !< number of active twin systems for each family and instance - plastic_titanmod_slipFamily, & !< lookup table relating active slip system to slip family for each instance - plastic_titanmod_twinFamily, & !< lookup table relating active twin system to twin family for each instance - plastic_titanmod_slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance - plastic_titanmod_twinSystemLattice !< lookup table relating active twin system index to lattice twin system index for each instance - - real(pReal), dimension(:), allocatable, private :: & - plastic_titanmod_debyefrequency, & !< Debye frequency - plastic_titanmod_kinkf0, & !< - plastic_titanmod_CAtomicVolume, & !< atomic volume in Bugers vector unit - plastic_titanmod_dc, & !< prefactor for self-diffusion coefficient - plastic_titanmod_twinhpconstant, & !< activation energy for dislocation climb - plastic_titanmod_GrainSize, & !< grain size - Not being used - plastic_titanmod_MaxTwinFraction, & !< maximum allowed total twin volume fraction - plastic_titanmod_r, & !< r-exponent in twin nucleation rate - plastic_titanmod_CEdgeDipMinDistance, & !< Not being used - plastic_titanmod_Cmfptwin, & !< Not being used - plastic_titanmod_Cthresholdtwin, & !< Not being used - plastic_titanmod_aTolRho !< absolute tolerance for integration of dislocation density - - real(pReal), dimension(:,:), allocatable, private :: & - plastic_titanmod_rho_edge0, & !< initial edge dislocation density per slip system for each family and instance - plastic_titanmod_rho_screw0, & !< initial screw dislocation density per slip system for each family and instance - plastic_titanmod_shear_system0, & !< accumulated shear on each system - plastic_titanmod_burgersPerSlipFam, & !< absolute length of burgers vector [m] for each slip family and instance - plastic_titanmod_burgersPerSlipSys, & !< absolute length of burgers vector [m] for each slip system and instance - plastic_titanmod_burgersPerTwinFam, & !< absolute length of burgers vector [m] for each twin family and instance - plastic_titanmod_burgersPerTwinSys, & !< absolute length of burgers vector [m] for each twin system and instance - plastic_titanmod_f0_PerSlipFam, & !< activation energy for glide [J] for each slip family and instance - plastic_titanmod_f0_PerSlipSys, & !< activation energy for glide [J] for each slip system and instance - plastic_titanmod_twinf0_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance - plastic_titanmod_twinf0_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance - plastic_titanmod_twinshearconstant_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance - plastic_titanmod_twinshearconstant_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance - plastic_titanmod_tau0e_PerSlipFam, & !< Initial yield stress for edge dislocations per slip family - plastic_titanmod_tau0e_PerSlipSys, & !< Initial yield stress for edge dislocations per slip system - plastic_titanmod_tau0s_PerSlipFam, & !< Initial yield stress for screw dislocations per slip family - plastic_titanmod_tau0s_PerSlipSys, & !< Initial yield stress for screw dislocations per slip system - plastic_titanmod_twintau0_PerTwinFam, & !< Initial yield stress for edge dislocations per twin family - plastic_titanmod_twintau0_PerTwinSys, & !< Initial yield stress for edge dislocations per twin system - plastic_titanmod_capre_PerSlipFam, & !< Capture radii for edge dislocations per slip family - plastic_titanmod_capre_PerSlipSys, & !< Capture radii for edge dislocations per slip system - plastic_titanmod_caprs_PerSlipFam, & !< Capture radii for screw dislocations per slip family - plastic_titanmod_caprs_PerSlipSys, & !< Capture radii for screw dislocations per slip system - plastic_titanmod_pe_PerSlipFam, & !< p-exponent in glide velocity - plastic_titanmod_ps_PerSlipFam, & !< p-exponent in glide velocity - plastic_titanmod_qe_PerSlipFam, & !< q-exponent in glide velocity - plastic_titanmod_qs_PerSlipFam, & !< q-exponent in glide velocity - plastic_titanmod_pe_PerSlipSys, & !< p-exponent in glide velocity - plastic_titanmod_ps_PerSlipSys, & !< p-exponent in glide velocity - plastic_titanmod_qe_PerSlipSys, & !< q-exponent in glide velocity - plastic_titanmod_qs_PerSlipSys, & !< q-exponent in glide velocity - plastic_titanmod_twinp_PerTwinFam, & !< p-exponent in glide velocity - plastic_titanmod_twinq_PerTwinFam, & !< q-exponent in glide velocity - plastic_titanmod_twinp_PerTwinSys, & !< p-exponent in glide velocity - plastic_titanmod_twinq_PerTwinSys, & !< p-exponent in glide velocity - plastic_titanmod_v0e_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance - plastic_titanmod_v0e_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance - plastic_titanmod_v0s_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance - plastic_titanmod_v0s_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance - plastic_titanmod_twingamma0_PerTwinFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance - plastic_titanmod_twingamma0_PerTwinSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance - plastic_titanmod_kinkcriticallength_PerSlipFam, & !< screw dislocation mobility prefactor for kink-pairs per slip family - plastic_titanmod_kinkcriticallength_PerSlipSys, & !< screw dislocation mobility prefactor for kink-pairs per slip system - plastic_titanmod_twinsizePerTwinFam, & !< twin thickness [m] for each twin family and instance - plastic_titanmod_twinsizePerTwinSys, & !< twin thickness [m] for each twin system and instance - plastic_titanmod_CeLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_titanmod_CeLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_titanmod_CsLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_titanmod_CsLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_titanmod_twinLambdaSlipPerTwinFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_titanmod_twinLambdaSlipPerTwinSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_titanmod_interactionSlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance - plastic_titanmod_interaction_ee, & !< coefficients for e-e interaction for each interaction type and instance - plastic_titanmod_interaction_ss, & !< coefficients for s-s interaction for each interaction type and instance - plastic_titanmod_interaction_es, & !< coefficients for e-s-twin interaction for each interaction type and instance - plastic_titanmod_interactionSlipTwin, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_titanmod_interactionTwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_titanmod_interactionTwinTwin !< coefficients for twin-twin interaction for each interaction type and instance - - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_titanmod_interactionMatrixSlipSlip, & !< interaction matrix of the different slip systems for each instance - plastic_titanmod_interactionMatrix_ee, & !< interaction matrix of e-e for each instance - plastic_titanmod_interactionMatrix_ss, & !< interaction matrix of s-s for each instance - plastic_titanmod_interactionMatrix_es, & !< interaction matrix of e-s for each instance - plastic_titanmod_interactionMatrixSlipTwin, & !< interaction matrix of slip systems with twin systems for each instance - plastic_titanmod_interactionMatrixTwinSlip, & !< interaction matrix of twin systems with slip systems for each instance - plastic_titanmod_interactionMatrixTwinTwin, & !< interaction matrix of the different twin systems for each instance - plastic_titanmod_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance - plastic_titanmod_forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance - plastic_titanmod_TwinforestProjectionEdge, & !< matrix of forest projections of edge dislocations in twin system for each instance - plastic_titanmod_TwinforestProjectionScrew !< matrix of forest projections of screw dislocations in twin system for each instance - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_titanmod_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance - - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_titanmod_Ctwin3333 !< twin elasticity matrix for each instance - - enum, bind(c) - enumerator :: undefined_ID, & - rhoedge_ID, rhoscrew_ID, & - segment_edge_ID, segment_screw_ID, & - resistance_edge_ID, resistance_screw_ID, & - velocity_edge_ID, velocity_screw_ID, & - tau_slip_ID, & - gdot_slip_edge_ID, gdot_slip_screw_ID, & - gdot_slip_ID, & - stressratio_edge_p_ID, stressratio_screw_p_ID, & - shear_system_ID, & - twin_fraction_ID, & - shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & - rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & - rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & - shear_total_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_titanmod_outputID !< ID of each post result output - - public :: & - plastic_titanmod_microstructure, & - plastic_titanmod_stateInit, & - plastic_titanmod_init, & - plastic_titanmod_LpAndItsTangent, & - plastic_titanmod_dotState, & - plastic_titanmod_postResults, & - plastic_titanmod_homogenizedC - - contains - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66,& - math_Voigt66to3333,& - math_mul3x3 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_TITANMOD_label, & - PLASTICITY_TITANMOD_ID, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - phase, & - instance, j, k, l, m, n, p, q, r, & - f, o, & - s, s1, s2, & - t, t1, t2, & - ns, nt, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & - offset_slip, mySize, & - maxTotalNslip,maxTotalNtwin, maxNinstance - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase = 0_pInt - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_TITANMOD_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_TITANMOD_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_titanmod_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_titanmod_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) - allocate(plastic_titanmod_output(maxval(phase_Noutput),maxNinstance)) - plastic_titanmod_output = '' - allocate(plastic_titanmod_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_titanmod_Noutput(maxNinstance), source=0_pInt) - - allocate(plastic_titanmod_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_slipFamily(lattice_maxNslip,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_twinFamily(lattice_maxNtwin,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_slipSystemLattice(lattice_maxNslip,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_twinSystemLattice(lattice_maxNtwin,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_titanmod_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_titanmod_debyefrequency(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_kinkf0(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CAtomicVolume(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_dc(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinhpconstant(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_GrainSize(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_MaxTwinFraction(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_r(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Cmfptwin(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Cthresholdtwin(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_aTolRho(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_rho_edge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_rho_screw0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_shear_system0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_burgersPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_burgersPerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_f0_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_capre_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_caprs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_pe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_ps_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_kinkcriticallength_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinsizePerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CeLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CsLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_twinf0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinshearconstant_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twintau0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinp_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinq_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twingamma0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinLambdaSlipPerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_interactionSlipSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interaction_ee(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interaction_ss(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interaction_es(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionSlipTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionTwinSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionTwinTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - phase = phase + 1_pInt ! advance section counter - if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then ! one of my sections. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('rhoedge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('segment_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('segment_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('tau_slip') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = tau_slip_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('gdot_slip_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('gdot_slip_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('gdot_slip') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stressratio_edge_p') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_edge_p_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stressratio_screw_p') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_screw_p_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_system') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_system_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('twin_fraction') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = twin_fraction_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_basal') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_basal_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_prism') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_prism_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_pyra') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyra_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_pyrca') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyrca_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_basal') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_basal_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_prism') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_prism_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_pyra') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyra_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_pyrca') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyrca_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_basal') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_basal_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_prism') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_prism_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_pyra') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyra_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_pyrca') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyrca_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_total') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_total_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - case ('debyefrequency') - plastic_titanmod_debyefrequency(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('kinkf0') - plastic_titanmod_kinkf0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('nslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ntwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinFamilies) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('rho_edge0') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_rho_edge0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('rho_screw0') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_rho_screw0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('slipburgers') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_burgersPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinburgers') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_burgersPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('f0') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_f0_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinf0') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinf0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0e') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_tau0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twintau0') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twintau0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0s') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_tau0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('capre') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_capre_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('caprs') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_caprs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('v0e') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_v0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twingamma0') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twingamma0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('v0s') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_v0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('kinkcriticallength') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_kinkcriticallength_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinsize') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinsizePerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('celambdaslip') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_CeLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinlambdaslip') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinlambdaslipPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('cslambdaslip') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_CsLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('grainsize') - plastic_titanmod_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('maxtwinfraction') - plastic_titanmod_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('pe') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_pe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinp') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinp_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('ps') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_ps_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('qe') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_qe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinq') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinq_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('qs') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_qs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinshearconstant') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinshearconstant_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('dc') - plastic_titanmod_dc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twinhpconstant') - plastic_titanmod_twinhpconstant(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_rho') - plastic_titanmod_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('interactionee') - do j = 1_pInt, lattice_maxNinteraction - plastic_titanmod_interaction_ee(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interactionss') - do j = 1_pInt, lattice_maxNinteraction - plastic_titanmod_interaction_ss(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interactiones') - do j = 1_pInt, lattice_maxNinteraction - plastic_titanmod_interaction_es(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_slipslip','interactionslipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_titanmod_interactionSlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin','interactionsliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_titanmod_interactionSlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip','interactiontwinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_titanmod_interactionTwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin','interactiontwintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_titanmod_interactionTwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then - instance = phase_plasticityInstance(phase) - if (sum(plastic_titanmod_Nslip(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='nslip ('//PLASTICITY_TITANMOD_label//')') - if (sum(plastic_titanmod_Ntwin(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='ntwin ('//PLASTICITY_TITANMOD_label//')') - do f = 1_pInt,lattice_maxNslipFamily - if (plastic_titanmod_Nslip(f,instance) > 0_pInt) then - if (plastic_titanmod_rho_edge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rho_edge0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_rho_screw0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rho_screw0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_burgersPerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='slipburgers ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_f0_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='f0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_tau0e_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau0e ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_tau0s_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau0s ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_capre_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='capre ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_caprs_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='caprs ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_v0e_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0e ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_v0s_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0s ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='kinkCriticalLength ('//PLASTICITY_TITANMOD_label//')') - endif - enddo - do f = 1_pInt,lattice_maxNtwinFamily - if (plastic_titanmod_Ntwin(f,instance) > 0_pInt) then - if (plastic_titanmod_burgersPerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twinf0_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinf0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinshearconstant ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twintau0_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twintau0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twingamma0_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twingamma0 ('//PLASTICITY_TITANMOD_label//')') - endif - enddo - if (plastic_titanmod_dc(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='dc ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twinhpconstant(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinhpconstant ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTol_rho ('//PLASTICITY_TITANMOD_label//')') - -!-------------------------------------------------------------------------------------------------- -! determine total number of active slip or twin systems - plastic_titanmod_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_titanmod_Nslip(:,instance)) - plastic_titanmod_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_titanmod_Ntwin(:,instance)) - plastic_titanmod_totalNslip(instance) = sum(plastic_titanmod_Nslip(:,instance)) - plastic_titanmod_totalNtwin(instance) = sum(plastic_titanmod_Ntwin(:,instance)) - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - maxTotalNslip = maxval(plastic_titanmod_totalNslip) - maxTotalNtwin = maxval(plastic_titanmod_totalNtwin) - - allocate(plastic_titanmod_burgersPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_f0_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_capre_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_caprs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_pe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_ps_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_kinkcriticallength_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CeLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CsLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_burgersPerTwinSys(maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinf0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinshearconstant_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twintau0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinp_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinq_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twingamma0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinsizePerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinLambdaSlipPerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Ctwin66 (6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Ctwin3333 (3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrix_ee(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrix_ss(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrix_es(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrixSlipTwin(maxTotalNslip,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrixTwinSlip(maxTotalNtwin,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrixTwinTwin(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_TwinforestProjectionEdge(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_TwinforestProjectionScrew(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then - instance = phase_plasticityInstance(phase) - -!-------------------------------------------------------------------------------------------------- -! inverse lookup of slip system family - l = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily - do s = 1_pInt,plastic_titanmod_Nslip(f,instance) - l = l + 1_pInt - plastic_titanmod_slipFamily(l,instance) = f - plastic_titanmod_slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt,phase)) + s - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! inverse lookup of twin system family - l = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily - do t = 1_pInt,plastic_titanmod_Ntwin(f,instance) - l = l + 1_pInt - plastic_titanmod_twinFamily(l,instance) = f - plastic_titanmod_twinSystemLattice(l,instance) = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) + t - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! determine size of state array - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - sizeDotState = & - size(plastic_titanmod_listBasicSlipStates)*ns + & - size(plastic_titanmod_listBasicTwinStates)*nt - sizeState = sizeDotState+ & - size(plastic_titanmod_listDependentSlipStates)*ns + & - size(plastic_titanmod_listDependentTwinStates)*nt - sizeDeltaState = 0_pInt - -!-------------------------------------------------------------------------------------------------- -! determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_titanmod_Noutput(instance) - mySize = 0_pInt - select case(plastic_titanmod_outputID(o,instance)) - case(rhoedge_ID, rhoscrew_ID, & - segment_edge_ID, segment_screw_ID, & - resistance_edge_ID, resistance_screw_ID, & - velocity_edge_ID, velocity_screw_ID, & - tau_slip_ID, & - gdot_slip_edge_ID, gdot_slip_screw_ID, & - gdot_slip_ID, & - stressratio_edge_p_ID, stressratio_screw_p_ID, & - shear_system_ID) - mySize = plastic_titanmod_totalNslip(instance) - case(twin_fraction_ID) - mySize = plastic_titanmod_totalNtwin(instance) - case(shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & ! use only if all 4 slip families in hex are considered - rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & - rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & - shear_total_ID) - mySize = 1_pInt - case default - call IO_error(105_pInt,ext_msg=plastic_titanmod_output(o,instance)// & - ' ('//PLASTICITY_TITANMOD_label//')') - end select - - outputFound: if (mySize > 0_pInt) then - plastic_titanmod_sizePostResult(o,instance) = mySize - plastic_titanmod_sizePostResults(instance) = plastic_titanmod_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop -! Determine size of state array - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_titanmod_sizePostResults(instance) - plasticState(phase)%nSlip =plastic_titanmod_totalNslip(instance) - plasticState(phase)%nTwin = 0_pInt - plasticState(phase)%nTrans= 0_pInt - allocate(plasticState(phase)%aTolState (sizeState), source=plastic_titanmod_aTolRho(instance)) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - offset_slip = 2_pInt*plasticState(phase)%nSlip+1 - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) -!-------------------------------------------------------------------------------------------------- -! construction of the twin elasticity matrices - do j=1_pInt,lattice_maxNtwinFamily - do k=1_pInt,plastic_titanmod_Ntwin(j,instance) - do l=1_pInt,3_pInt ; do m=1_pInt,3_pInt ; do n=1_pInt,3_pInt ; do o=1_pInt,3_pInt - do p=1_pInt,3_pInt ; do q=1_pInt,3_pInt ; do r=1_pInt,3_pInt ; do s=1_pInt,3_pInt - plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) = & - plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) + & - lattice_C3333(p,q,r,s,phase)*& - lattice_Qtwin(l,p,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & - lattice_Qtwin(m,q,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & - lattice_Qtwin(n,r,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & - lattice_Qtwin(o,s,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo ; enddo - plastic_titanmod_Ctwin66(1:6,1:6,k,instance) = & - math_Mandel3333to66(plastic_titanmod_Ctwin3333(1:3,1:3,1:3,1:3,k,instance)) - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! Burgers vector, dislocation velocity prefactor for each slip system - do s = 1_pInt,plastic_titanmod_totalNslip(instance) - f = plastic_titanmod_slipFamily(s,instance) - - plastic_titanmod_burgersPerSlipSys(s,instance) = & - plastic_titanmod_burgersPerSlipFam(f,instance) - - plastic_titanmod_f0_PerSlipSys(s,instance) = & - plastic_titanmod_f0_PerSlipFam(f,instance) - - plastic_titanmod_tau0e_PerSlipSys(s,instance) = & - plastic_titanmod_tau0e_PerSlipFam(f,instance) - - plastic_titanmod_tau0s_PerSlipSys(s,instance) = & - plastic_titanmod_tau0s_PerSlipFam(f,instance) - - plastic_titanmod_capre_PerSlipSys(s,instance) = & - plastic_titanmod_capre_PerSlipFam(f,instance) - - plastic_titanmod_caprs_PerSlipSys(s,instance) = & - plastic_titanmod_caprs_PerSlipFam(f,instance) - - plastic_titanmod_v0e_PerSlipSys(s,instance) = & - plastic_titanmod_v0e_PerSlipFam(f,instance) - - plastic_titanmod_v0s_PerSlipSys(s,instance) = & - plastic_titanmod_v0s_PerSlipFam(f,instance) - - plastic_titanmod_kinkcriticallength_PerSlipSys(s,instance) = & - plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) - - plastic_titanmod_pe_PerSlipSys(s,instance) = & - plastic_titanmod_pe_PerSlipFam(f,instance) - - plastic_titanmod_ps_PerSlipSys(s,instance) = & - plastic_titanmod_ps_PerSlipFam(f,instance) - - plastic_titanmod_qe_PerSlipSys(s,instance) = & - plastic_titanmod_qe_PerSlipFam(f,instance) - - plastic_titanmod_qs_PerSlipSys(s,instance) = & - plastic_titanmod_qs_PerSlipFam(f,instance) - - plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance) = & - plastic_titanmod_CeLambdaSlipPerSlipFam(f,instance) - - plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance) = & - plastic_titanmod_CsLambdaSlipPerSlipFam(f,instance) - enddo - -!-------------------------------------------------------------------------------------------------- -! Burgers vector, nucleation rate prefactor and twin size for each twin system - do t = 1_pInt,plastic_titanmod_totalNtwin(instance) - f = plastic_titanmod_twinFamily(t,instance) - - plastic_titanmod_burgersPerTwinSys(t,instance) = & - plastic_titanmod_burgersPerTwinFam(f,instance) - - plastic_titanmod_twinsizePerTwinSys(t,instance) = & - plastic_titanmod_twinsizePerTwinFam(f,instance) - - plastic_titanmod_twinf0_PerTwinSys(t,instance) = & - plastic_titanmod_twinf0_PerTwinFam(f,instance) - - plastic_titanmod_twinshearconstant_PerTwinSys(t,instance) = & - plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) - - plastic_titanmod_twintau0_PerTwinSys(t,instance) = & - plastic_titanmod_twintau0_PerTwinFam(f,instance) - - plastic_titanmod_twingamma0_PerTwinSys(t,instance) = & - plastic_titanmod_twingamma0_PerTwinFam(f,instance) - - plastic_titanmod_twinp_PerTwinSys(t,instance) = & - plastic_titanmod_twinp_PerTwinFam(f,instance) - - plastic_titanmod_twinq_PerTwinSys(t,instance) = & - plastic_titanmod_twinq_PerTwinFam(f,instance) - - plastic_titanmod_twinLambdaSlipPerTwinSys(t,instance) = & - plastic_titanmod_twinLambdaSlipPerTwinFam(f,instance) - enddo - -!-------------------------------------------------------------------------------------------------- -! Construction of interaction matrices - do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) - do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) - plastic_titanmod_interactionMatrixSlipSlip(s1,s2,instance) = & - plastic_titanmod_interactionSlipSlip(lattice_interactionSlipSlip( & - plastic_titanmod_slipSystemLattice(s1,instance),& - plastic_titanmod_slipSystemLattice(s2,instance),phase),instance) - - plastic_titanmod_interactionMatrix_ee(s1,s2,instance) = & - plastic_titanmod_interaction_ee(lattice_interactionSlipSlip ( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - - plastic_titanmod_interactionMatrix_ss(s1,s2,instance) = & - plastic_titanmod_interaction_ss(lattice_interactionSlipSlip( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - - plastic_titanmod_interactionMatrix_es(s1,s2,instance) = & - plastic_titanmod_interaction_es(lattice_interactionSlipSlip( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - enddo; enddo - - do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) - do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) - plastic_titanmod_interactionMatrixSlipTwin(s1,t2,instance) = & - plastic_titanmod_interactionSlipTwin(lattice_interactionSlipTwin( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) - enddo; enddo - - do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) - do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) - plastic_titanmod_interactionMatrixTwinSlip(t1,s2,instance) = & - plastic_titanmod_interactionTwinSlip(lattice_interactionTwinSlip( & - plastic_titanmod_twinSystemLattice(t1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - enddo; enddo - - do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) - do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) - plastic_titanmod_interactionMatrixTwinTwin(t1,t2,instance) = & - plastic_titanmod_interactionTwinTwin(lattice_interactionTwinTwin( & - plastic_titanmod_twinSystemLattice(t1,instance), & - plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) - enddo; enddo - - do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) - do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for edge dislocations - plastic_titanmod_forestProjectionEdge(s1,s2,instance) = & - abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & - lattice_st(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) - -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for screw dislocations - plastic_titanmod_forestProjectionScrew(s1,s2,instance) = & - abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & - lattice_sd(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for edge dislocations in twin system - do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) - do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) - plastic_titanmod_TwinforestProjectionEdge(t1,t2,instance) = & - abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & - lattice_tt(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) - -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for screw dislocations in twin system - plastic_titanmod_TwinforestProjectionScrew(t1,t2,instance) = & - abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & - lattice_td(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) - enddo; enddo - call plastic_titanmod_stateInit(phase,instance) - endif - enddo initializeInstances - -end subroutine plastic_titanmod_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_stateInit(ph,instance) - use lattice, only: & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_mu - - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: instance !< number specifying the instance of the plasticity - integer(pInt), intent(in) :: ph !< number specifying the phase of the plasticity - - - integer(pInt) :: & - s,s0,s1, & - t,t0,t1, & - ns,nt,f - real(pReal), dimension(plastic_titanmod_totalNslip(instance)) :: & - rho_edge0, & - rho_screw0, & - shear_system0, & - segment_edge0, & - segment_screw0, & - resistance_edge0, & - resistance_screw0 - real(pReal), dimension(plastic_titanmod_totalNtwin(instance)) :: & - twingamma_dot0, & - resistance_twin0 - real(pReal), dimension(plasticState(ph)%sizeState) :: tempState !!!!!!!!!????????? check - - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - tempState = 0.0_pReal -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables for slip - s1 = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily - s0 = s1 + 1_pInt - s1 = s0 + plastic_titanmod_Nslip(f,instance) - 1_pInt - do s = s0,s1 - rho_edge0(s) = plastic_titanmod_rho_edge0(f,instance) - rho_screw0(s) = plastic_titanmod_rho_screw0(f,instance) - shear_system0(s) = 0.0_pReal - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables for twin - t1 = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily - t0 = t1 + 1_pInt - t1 = t0 + plastic_titanmod_Ntwin(f,instance) - 1_pInt - do t = t0,t1 - twingamma_dot0(t)=0.0_pReal - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! initialize dependent slip microstructural variables - forall (s = 1_pInt:ns) - segment_edge0(s) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) - segment_screw0(s) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) - resistance_edge0(s) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & - sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & - dot_product((rho_screw0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) - resistance_screw0(s) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & - sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & - dot_product((rho_screw0), plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) - end forall - - forall (t = 1_pInt:nt) & - resistance_twin0(t) = 0.0_pReal - -tempState = 0.0_pReal -tempState (1:ns) = rho_edge0 -tempState (1_pInt*ns+1_pInt:2_pInt*ns) = rho_screw0 -tempState (2_pInt*ns+1_pInt:3_pInt*ns) = shear_system0 -tempState (3_pInt*ns+1_pInt:3_pInt*ns+nt) = twingamma_dot0 -tempState (3_pInt*ns+nt+1_pInt:4_pInt*ns+nt) = segment_edge0 -tempState (4_pInt*ns+nt+1_pInt:5_pInt*ns+nt) = segment_screw0 -tempState (5_pInt*ns+nt+1_pInt:6_pInt*ns+nt) = resistance_edge0 -tempState (6_pInt*ns+nt+1_pInt:7_pInt*ns+nt) = resistance_screw0 -tempState (7_pInt*ns+nt+1_pInt:7_pInt*ns+2_pInt*nt)=resistance_twin0 - -plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) -end subroutine plastic_titanmod_stateInit - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenized elasticity matrix -!-------------------------------------------------------------------------------------------------- -function plastic_titanmod_homogenizedC(ipc,ip,el) - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_C66 - -implicit none - real(pReal), dimension(6,6) :: & - plastic_titanmod_homogenizedC - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element -real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - volumefraction_PerTwinSys - integer(pInt) :: & - ph, & - of, & - instance, & - ns, nt, & - i - real(pReal) :: & - sumf - -!-------------------------------------------------------------------------------------------------- -! shortened notation -! ph = material_phase(ipc,ip,el) - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! total twin volume fraction - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - enddo - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - -!-------------------------------------------------------------------------------------------------- -! homogenized elasticity matrix - plastic_titanmod_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) - do i=1_pInt,nt - plastic_titanmod_homogenizedC = plastic_titanmod_homogenizedC & - + volumefraction_PerTwinSys(i)*& - plastic_titanmod_Ctwin66(1:6,1:6,i,instance) - enddo - -end function plastic_titanmod_homogenizedC - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_microstructure(temperature,ipc,ip,el) - - use material, only: & - material_phase,& - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_mu - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - temperature !< temperature at IP - integer(pInt) :: & - instance, & - ns, nt, s, t, & - i, & - ph, & - of - real(pReal) :: & - sumf, & - sfe ! stacking fault energy - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - volumefraction_PerTwinSys - -!-------------------------------------------------------------------------------------------------- - -!Shortened notation - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! total twin volume fraction - forall (i = 1_pInt:nt) & - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - - sfe = 0.0002_pReal*Temperature-0.0396_pReal - -!-------------------------------------------------------------------------------------------------- -! average segment length for edge dislocations in matrix - forall (s = 1_pInt:ns) & - plasticState(ph)%state(3_pInt*ns+nt+s, of) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product(plasticState(ph)%state(1:ns, of), & - plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & - plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! average segment length for screw dislocations in matrix - forall (s = 1_pInt:ns) & - plasticState(ph)%state(4_pInt*ns+nt+s, of) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product(plasticState(ph)%state(1:ns, of), & - plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & - plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! threshold stress or slip resistance for edge dislocation motion - forall (s = 1_pInt:ns) & - plasticState(ph)%state(5_pInt*ns+nt+s, of) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& - sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& - plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & - dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& - plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! threshold stress or slip resistance for screw dislocation motion - forall (s = 1_pInt:ns) & - plasticState(ph)%state(6_pInt*ns+nt+s, of) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& - sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& - plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & - dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& - plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! threshold stress or slip resistance for dislocation motion in twin - forall (t = 1_pInt:nt) & - plasticState(ph)%state(7_pInt*ns+nt+t, of) = & - lattice_mu(ph)*plastic_titanmod_burgersPerTwinSys(t,instance)*& - (dot_product((abs(plasticState(ph)%state(2_pInt*ns+1_pInt:2_pInt*ns+nt, of))),& - plastic_titanmod_interactionMatrixTwinTwin(1:nt,t,instance))) - -! state=tempState - -end subroutine plastic_titanmod_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,temperature,ipc,ip,el) - use math, only: & - math_Plain3333to99, & - math_Mandel6to33 - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_structure, & - LATTICE_hex_ID - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at IP - integer(pInt) :: & - index_myFamily, instance, & - ns,nt, & - f,i,j,k,l,m,n, & - ph, & - of - real(pReal) :: sumf, & - StressRatio_edge_p, minusStressRatio_edge_p, StressRatio_edge_pminus1, BoltzmannRatioedge, & - StressRatio_screw_p, minusStressRatio_screw_p, StressRatio_screw_pminus1, BoltzmannRatioscrew, & - twinStressRatio_p, twinminusStressRatio_p, twinStressRatio_pminus1, BoltzmannRatiotwin, & - twinDotGamma0, bottomstress_edge, bottomstress_screw, screwvelocity_prefactor - real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 - real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,dgdot_dtauslip,tau_slip, & - edge_velocity, screw_velocity, & - gdot_slip_edge, gdot_slip_screw - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,dgdot_dtautwin,tau_twin, volumefraction_PerTwinSys - -! tempState=state - - - -!-------------------------------------------------------------------------------------------------- -! shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - - enddo - - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - - !* Dislocation glide part - gdot_slip = 0.0_pReal - gdot_slip_edge = 0.0_pReal - gdot_slip_screw = 0.0_pReal - dgdot_dtauslip = 0.0_pReal - j = 0_pInt - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on slip system - tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - if(lattice_structure(ph)==LATTICE_hex_ID) then ! only for prismatic and pyr systems in hex - screwvelocity_prefactor=plastic_titanmod_debyefrequency(instance)* & - plasticState(ph)%state(4_pInt*ns+nt+j, of)*(plastic_titanmod_burgersPerSlipSys(j,instance)/ & - plastic_titanmod_kinkcriticallength_PerSlipSys(j,instance))**2 - - !* Stress ratio for screw ! No slip resistance for screw dislocations, only Peierls stress - bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) - StressRatio_screw_p = ((abs(tau_slip(j)))/ & - ( bottomstress_screw) & - )**plastic_titanmod_ps_PerSlipSys(j,instance) - - if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then - minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p - else - minusStressRatio_screw_p=0.001_pReal - endif - - bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) - StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/ & - ( bottomstress_screw) & - )**(plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio for screw - BoltzmannRatioscrew = plastic_titanmod_kinkf0(instance)/(kB*Temperature) - - else ! if the structure is not hex or the slip family is basal - screwvelocity_prefactor=plastic_titanmod_v0s_PerSlipSys(j,instance) - bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance)+ & - plasticState(ph)%state(6*ns+nt+j, of) - StressRatio_screw_p = ((abs(tau_slip(j)))/( bottomstress_screw ))**plastic_titanmod_ps_PerSlipSys(j,instance) - - if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then - minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p - else - minusStressRatio_screw_p=0.001_pReal - endif - - StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/( bottomstress_screw))** & - (plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio for screw - BoltzmannRatioscrew = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) - - endif - - !* Stress ratio for edge - bottomstress_edge=plastic_titanmod_tau0e_PerSlipSys(j,instance)+ & - plasticState(ph)%state(5*ns+nt+j, of) - StressRatio_edge_p = ((abs(tau_slip(j)))/ & - ( bottomstress_edge) & - )**plastic_titanmod_pe_PerSlipSys(j,instance) - - if((1.0_pReal-StressRatio_edge_p)>0.001_pReal) then - minusStressRatio_edge_p=1.0_pReal-StressRatio_edge_p - else - minusStressRatio_edge_p=0.001_pReal - endif - - StressRatio_edge_pminus1 = ((abs(tau_slip(j)))/( bottomstress_edge))** & - (plastic_titanmod_pe_PerSlipSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio for edge. For screws it is defined above - BoltzmannRatioedge = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) - - screw_velocity(j) =screwvelocity_prefactor * & ! there is no v0 for screw now because it is included in the prefactor - exp(-BoltzmannRatioscrew*(minusStressRatio_screw_p)** & - plastic_titanmod_qs_PerSlipSys(j,instance)) - - edge_velocity(j) =plastic_titanmod_v0e_PerSlipSys(j,instance)*exp(-BoltzmannRatioedge* & - (minusStressRatio_edge_p)** & - plastic_titanmod_qe_PerSlipSys(j,instance)) - - !* Shear rates due to edge slip - gdot_slip_edge(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(j, of)* & - edge_velocity(j))* sign(1.0_pReal,tau_slip(j)) - !* Shear rates due to screw slip - gdot_slip_screw(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(ns+j, of) * & - screw_velocity(j))* sign(1.0_pReal,tau_slip(j)) - !Total shear rate - - gdot_slip(j) = gdot_slip_edge(j) + gdot_slip_screw(j) - - plasticState(ph)%state( 7*ns+2*nt+j, of)= edge_velocity(j) - plasticState(ph)%state( 8*ns+2*nt+j, of)= screw_velocity(j) - plasticState(ph)%state( 9*ns+2*nt+j, of)= tau_slip(j) - plasticState(ph)%state(10*ns+2*nt+j, of)= gdot_slip_edge(j) - plasticState(ph)%state(11*ns+2*nt+j, of)= gdot_slip_screw(j) - plasticState(ph)%state(12*ns+2*nt+j, of)= StressRatio_edge_p - plasticState(ph)%state(13*ns+2*nt+j, of)= StressRatio_screw_p - - !* Derivatives of shear rates - dgdot_dtauslip(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(( & - ( & - ( & - ( & - (edge_velocity(j)*plasticState(ph)%state(j, of))) * & - BoltzmannRatioedge*& - plastic_titanmod_pe_PerSlipSys(j,instance)* & - plastic_titanmod_qe_PerSlipSys(j,instance) & - )/ & - bottomstress_edge & - )*& - StressRatio_edge_pminus1*(minusStressRatio_edge_p)** & - (plastic_titanmod_qe_PerSlipSys(j,instance)-1.0_pReal) & - ) + & - ( & - ( & - ( & - (plasticState(ph)%state(ns+j, of) * screw_velocity(j)) * & - BoltzmannRatioscrew* & - plastic_titanmod_ps_PerSlipSys(j,instance)* & - plastic_titanmod_qs_PerSlipSys(j,instance) & - )/ & - bottomstress_screw & - )*& - StressRatio_screw_pminus1*(minusStressRatio_screw_p)**(plastic_titanmod_qs_PerSlipSys(j,instance)-1.0_pReal) & - ) & - ) !* sign(1.0_pReal,tau_slip(j)) - - - -!************************************************* -!sumf=0.0_pReal - !* Plastic velocity gradient for dislocation glide - Lp = Lp + (1.0_pReal - sumf)*gdot_slip(j)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& - lattice_Sslip(k,l,1,index_myFamily+i,ph)*& - lattice_Sslip(m,n,1,index_myFamily+i,ph) - enddo - enddo slipFamiliesLoop - -!* Mechanical twinning part - gdot_twin = 0.0_pReal - dgdot_dtautwin = 0.0_pReal - j = 0_pInt - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on twin system - tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - -!************************************************************************************** - !* Stress ratios -! StressRatio_r = (plasticState(ph)%state6*ns+3*nt+j, of)/tau_twin(j))**plastic_titanmod_r(instance) - - !* Shear rates and their derivatives due to twin -! if ( tau_twin(j) > 0.0_pReal ) !then -! gdot_twin(j) = 0.0_pReal!& -! (plastic_titanmod_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& -! plasticState(ph)%state(6*ns+4*nt+j, of)*plastic_titanmod_Ndot0PerTwinSys(f,instance)*exp(-StressRatio_r) -! dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_titanmod_r(instance))/tau_twin(j))*StressRatio_r -! endif -!************************************************************************************** - - !* Stress ratio for edge - twinStressRatio_p = ((abs(tau_twin(j)))/ & - ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & - )**plastic_titanmod_twinp_PerTwinSys(j,instance) - - if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then - twinminusStressRatio_p=1.0_pReal-twinStressRatio_p - else - twinminusStressRatio_p=0.001_pReal - endif - - twinStressRatio_pminus1 = ((abs(tau_twin(j)))/ & - ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & - )**(plastic_titanmod_twinp_PerTwinSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio - BoltzmannRatiotwin = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) - - !* Initial twin shear rates - TwinDotGamma0 = & - plastic_titanmod_twingamma0_PerTwinSys(j,instance) - - !* Shear rates due to twin - gdot_twin(j) =sign(1.0_pReal,tau_twin(j))*plastic_titanmod_twingamma0_PerTwinSys(j,instance)* & - exp(-BoltzmannRatiotwin*(twinminusStressRatio_p)**plastic_titanmod_twinq_PerTwinSys(j,instance)) - - - !* Derivatives of shear rates in twin - dgdot_dtautwin(j) = ( & - ( & - ( & - (abs(gdot_twin(j))) * & - BoltzmannRatiotwin*& - plastic_titanmod_twinp_PerTwinSys(j,instance)* & - plastic_titanmod_twinq_PerTwinSys(j,instance) & - )/ & - plastic_titanmod_twintau0_PerTwinSys(j,instance) & - )*& - twinStressRatio_pminus1*(twinminusStressRatio_p)** & - (plastic_titanmod_twinq_PerTwinSys(j,instance)-1.0_pReal) & - ) !* sign(1.0_pReal,tau_slip(j)) - - !* Plastic velocity gradient for mechanical twinning -! Lp = Lp + sumf*gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) - Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& - lattice_Stwin(k,l,index_myFamily+i,ph)*& - lattice_Stwin(m,n,index_myFamily+i,ph) - enddo - enddo twinFamiliesLoop - -dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) -! tempState=state - - -end subroutine plastic_titanmod_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_dotState(Tstar_v,temperature,ipc,ip,el) - use lattice, only: & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - -implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: & - index_myFamily, instance, & - ns,nt,& - f,i,j, & - ph, & - of - real(pReal) :: & - sumf,BoltzmannRatio, & - twinStressRatio_p,twinminusStressRatio_p - real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - DotRhoEdgeGeneration, & - DotRhoEdgeAnnihilation, & - DotRhoScrewGeneration, & - DotRhoScrewAnnihilation - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin, & - tau_twin, & - volumefraction_PerTwinSys - -!-------------------------------------------------------------------------------------------------- -! shortened notation - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - - enddo - - sumf = sum(abs(volumefraction_PerTwinSys(1_pInt:nt))) ! safe for nt == 0 - - plasticState(ph)%dotState(:,of) = 0.0_pReal - j = 0_pInt - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - DotRhoEdgeGeneration(j) = & ! multiplication of edge dislocations - plasticState(ph)%state(ns+j, of)*plasticState(ph)%state(8*ns+2*nt+j, of)/plasticState(ph)%state(4*ns+nt+j, of) - DotRhoScrewGeneration(j) = & ! multiplication of screw dislocations - plasticState(ph)%state(j, of)*plasticState(ph)%state(7*ns+2*nt+j, of)/plasticState(ph)%state(3*ns+nt+j, of) - DotRhoEdgeAnnihilation(j) = -((plasticState(ph)%state(j, of))**2)* & ! annihilation of edge dislocations - plastic_titanmod_capre_PerSlipSys(j,instance)*plasticState(ph)%state(7*ns+2*nt+j, of)*0.5_pReal - DotRhoScrewAnnihilation(j) = -((plasticState(ph)%state(ns+j, of))**2)* & ! annihilation of screw dislocations - plastic_titanmod_caprs_PerSlipSys(j,instance)*plasticState(ph)%state(8*ns+2*nt+j, of)*0.5_pReal - plasticState(ph)%dotState(j, of) = & ! edge dislocation density rate of change - DotRhoEdgeGeneration(j)+DotRhoEdgeAnnihilation(j) - - plasticState(ph)%dotState(ns+j, of) = & ! screw dislocation density rate of change - DotRhoScrewGeneration(j)+DotRhoScrewAnnihilation(j) - - plasticState(ph)%dotState(2*ns+j, of) = & ! sum of shear due to edge and screw - plasticState(ph)%state(10*ns+2*nt+j, of)+plasticState(ph)%state(11*ns+2*nt+j, of) - enddo - enddo slipFamiliesLoop - -!* Twin fraction evolution - j = 0_pInt - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) twin system in family - j = j+1_pInt - - !* Resolved shear stress on twin system - tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - !* Stress ratio for edge - twinStressRatio_p = ((abs(tau_twin(j)))/ & - ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & - )**(plastic_titanmod_twinp_PerTwinSys(j,instance)) - - - if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then - twinminusStressRatio_p=1.0_pReal-twinStressRatio_p - else - twinminusStressRatio_p=0.001_pReal - endif - - BoltzmannRatio = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) - - gdot_twin(j) =plastic_titanmod_twingamma0_PerTwinSys(j,instance)*exp(-BoltzmannRatio* & - (twinminusStressRatio_p)** & - plastic_titanmod_twinq_PerTwinSys(j,instance))*sign(1.0_pReal,tau_twin(j)) - - plasticState(ph)%dotState(3*ns+j, of)=gdot_twin(j) - - enddo - enddo twinFamiliesLoop - -end subroutine plastic_titanmod_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_titanmod_postResults(ipc,ip,el) - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(plastic_titanmod_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_titanmod_postResults - - integer(pInt) :: & - instance, & - ns,nt,& - o,i,c, & - ph, & - of - real(pReal) :: sumf - - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - volumefraction_PerTwinSys - -!-------------------------------------------------------------------------------------------------- -! shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - enddo - - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - - -!-------------------------------------------------------------------------------------------------- -! required output - c = 0_pInt - plastic_titanmod_postResults = 0.0_pReal - - do o = 1_pInt,plastic_titanmod_Noutput(instance) - select case(plastic_titanmod_outputID(o,instance)) - case (rhoedge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(1_pInt:ns, of) - c = c + ns - case (rhoscrew_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of) - c = c + ns - case (segment_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(3_pInt*ns+nt+1_pInt:4_pInt*ns+nt, of) - c = c + ns - case (segment_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(4_pInt*ns+nt+1_pInt:5_pInt*ns+nt, of) - c = c + ns - case (resistance_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(5_pInt*ns+nt+1_pInt:6_pInt*ns+nt, of) - c = c + ns - case (resistance_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(6_pInt*ns+nt+1_pInt:7_pInt*ns+nt, of) - c = c + ns - case (velocity_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(7*ns+2*nt+1:8*ns+2*nt, of) - c = c + ns - case (velocity_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(8*ns+2*nt+1:9*ns+2*nt, of) - c = c + ns - case (tau_slip_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(9*ns+2*nt+1:10*ns+2*nt, of)) - c = c + ns - case (gdot_slip_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) - c = c + ns - case (gdot_slip_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) - c = c + ns - case (gdot_slip_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) + & - abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) - c = c + ns - case (stressratio_edge_p_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(12*ns+2*nt+1:13*ns+2*nt, of)) - c = c + ns - case (stressratio_screw_p_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(13*ns+2*nt+1:14*ns+2*nt, of)) - c = c + ns - case (shear_system_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(2*ns+1:3*ns, of)) - c = c + ns - case (shear_basal_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:2*ns+3, of))) - c = c + 1_pInt - case (shear_prism_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+4:2*ns+6, of))) - c = c + 1_pInt - case (shear_pyra_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+7:2*ns+12, of))) - c = c + 1_pInt - case (shear_pyrca_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+13:2*ns+24, of))) - c = c + 1_pInt - - case (rhoedge_basal_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(1:3, of)) - c = c + 1_pInt - case (rhoedge_prism_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(4:6, of)) - c = c + 1_pInt - case (rhoedge_pyra_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(7:12,of)) - c = c + 1_pInt - case (rhoedge_pyrca_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(13:24, of)) - c = c + 1_pInt - - case (rhoscrew_basal_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+1:ns+3, of)) - c = c + 1_pInt - case (rhoscrew_prism_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+4:ns+6, of)) - c = c + 1_pInt - case (rhoscrew_pyra_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+7:ns+12, of)) - c = c + 1_pInt - case (rhoscrew_pyrca_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+13:ns+24, of)) - c = c + 1_pInt - case (shear_total_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:3*ns, of))) - c = c + 1_pInt - case (twin_fraction_ID) - plastic_titanmod_postResults(c+1_pInt:c+nt) = abs(volumefraction_PerTwinSys(1:nt)) - c = c + nt - end select - enddo - -end function plastic_titanmod_postResults - -end module plastic_titanmod diff --git a/code/porosity/CMakeLists.txt b/code/porosity/CMakeLists.txt index 0695a1bf5..3e62f4096 100644 --- a/code/porosity/CMakeLists.txt +++ b/code/porosity/CMakeLists.txt @@ -7,3 +7,8 @@ set (POROSITY "porosity_none" foreach (p ${POROSITY}) add_library (${p} MODULE "${p}.f90") endforeach (p) + +# set libraries/modules for linking +foreach (p ${POROSITY}) + set (AUX_LIB ${AUX_LIB} ${p}) +endforeach (p) \ No newline at end of file diff --git a/code/porosity_none.f90 b/code/porosity_none.f90 deleted file mode 100644 index 69f10a5c6..000000000 --- a/code/porosity_none.f90 +++ /dev/null @@ -1,61 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for constant porosity -!-------------------------------------------------------------------------------------------------- -module porosity_none - - implicit none - private - - public :: & - porosity_none_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine porosity_none_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- porosity_'//POROSITY_none_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (porosity_type(homog) == POROSITY_none_ID) then - NofMyHomog = count(material_homog == homog) - porosityState(homog)%sizeState = 0_pInt - porosityState(homog)%sizePostResults = 0_pInt - allocate(porosityState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) - allocate(porosityState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) - allocate(porosityState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) - - deallocate(porosity(homog)%p) - allocate (porosity(homog)%p(1), source=porosity_initialPhi(homog)) - - endif myhomog - enddo initializeInstances - - -end subroutine porosity_none_init - -end module porosity_none diff --git a/code/porosity_phasefield.f90 b/code/porosity_phasefield.f90 deleted file mode 100644 index dc8b82b76..000000000 --- a/code/porosity_phasefield.f90 +++ /dev/null @@ -1,450 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for phase field modelling of pore nucleation and growth -!> @details phase field model for pore nucleation and growth based on vacancy clustering -!-------------------------------------------------------------------------------------------------- -module porosity_phasefield - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - porosity_phasefield_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - porosity_phasefield_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - porosity_phasefield_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - porosity_phasefield_Noutput !< number of outputs per instance of this porosity - - enum, bind(c) - enumerator :: undefined_ID, & - porosity_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - porosity_phasefield_outputID !< ID of each post result output - - - public :: & - porosity_phasefield_init, & - porosity_phasefield_getFormationEnergy, & - porosity_phasefield_getSurfaceEnergy, & - porosity_phasefield_getSourceAndItsTangent, & - porosity_phasefield_getDiffusion33, & - porosity_phasefield_getMobility, & - porosity_phasefield_putPorosity, & - porosity_phasefield_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine porosity_phasefield_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - porosity_type, & - porosity_typeInstance, & - homogenization_Noutput, & - POROSITY_phasefield_label, & - POROSITY_phasefield_ID, & - material_homog, & - mappingHomogenization, & - porosityState, & - porosityMapping, & - porosity, & - porosity_initialPhi, & - material_partHomogenization, & - material_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- porosity_'//POROSITY_phasefield_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(porosity_type == POROSITY_phasefield_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(porosity_phasefield_sizePostResults(maxNinstance), source=0_pInt) - allocate(porosity_phasefield_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(porosity_phasefield_output (maxval(homogenization_Noutput),maxNinstance)) - porosity_phasefield_output = '' - allocate(porosity_phasefield_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(porosity_phasefield_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (porosity_type(section) == POROSITY_phasefield_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = porosity_typeInstance(section) ! which instance of my porosity is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('porosity') - porosity_phasefield_Noutput(instance) = porosity_phasefield_Noutput(instance) + 1_pInt - porosity_phasefield_outputID(porosity_phasefield_Noutput(instance),instance) = porosity_ID - porosity_phasefield_output(porosity_phasefield_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingHomog - - initializeInstances: do section = 1_pInt, size(porosity_type) - if (porosity_type(section) == POROSITY_phasefield_ID) then - NofMyHomog=count(material_homog==section) - instance = porosity_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,porosity_phasefield_Noutput(instance) - select case(porosity_phasefield_outputID(o,instance)) - case(porosity_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - porosity_phasefield_sizePostResult(o,instance) = mySize - porosity_phasefield_sizePostResults(instance) = porosity_phasefield_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 0_pInt - porosityState(section)%sizeState = sizeState - porosityState(section)%sizePostResults = porosity_phasefield_sizePostResults(instance) - allocate(porosityState(section)%state0 (sizeState,NofMyHomog)) - allocate(porosityState(section)%subState0(sizeState,NofMyHomog)) - allocate(porosityState(section)%state (sizeState,NofMyHomog)) - - nullify(porosityMapping(section)%p) - porosityMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(porosity(section)%p) - allocate(porosity(section)%p(NofMyHomog), source=porosity_initialPhi(section)) - - endif - - enddo initializeInstances -end subroutine porosity_phasefield_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized vacancy formation energy -!-------------------------------------------------------------------------------------------------- -function porosity_phasefield_getFormationEnergy(ip,el) - use lattice, only: & - lattice_vacancyFormationEnergy, & - lattice_vacancyVol - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - porosity_phasefield_getFormationEnergy - integer(pInt) :: & - grain - - porosity_phasefield_getFormationEnergy = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - porosity_phasefield_getFormationEnergy = porosity_phasefield_getFormationEnergy + & - lattice_vacancyFormationEnergy(material_phase(grain,ip,el))/ & - lattice_vacancyVol(material_phase(grain,ip,el)) - enddo - - porosity_phasefield_getFormationEnergy = & - porosity_phasefield_getFormationEnergy/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function porosity_phasefield_getFormationEnergy - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized pore surface energy (normalized by characteristic length) -!-------------------------------------------------------------------------------------------------- -function porosity_phasefield_getSurfaceEnergy(ip,el) - use lattice, only: & - lattice_vacancySurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - porosity_phasefield_getSurfaceEnergy - integer(pInt) :: & - grain - - porosity_phasefield_getSurfaceEnergy = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - porosity_phasefield_getSurfaceEnergy = porosity_phasefield_getSurfaceEnergy + & - lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) - enddo - - porosity_phasefield_getSurfaceEnergy = & - porosity_phasefield_getSurfaceEnergy/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function porosity_phasefield_getSurfaceEnergy - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates homogenized local driving force for pore nucleation and growth -!-------------------------------------------------------------------------------------------------- -subroutine porosity_phasefield_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) - use math, only : & - math_mul33x33, & - math_mul66x6, & - math_Mandel33to6, & - math_transpose33, & - math_I3 - use material, only: & - homogenization_Ngrains, & - material_homog, & - material_phase, & - phase_NstiffnessDegradations, & - phase_stiffnessDegradation, & - vacancyConc, & - vacancyfluxMapping, & - damage, & - damageMapping, & - STIFFNESS_DEGRADATION_damage_ID - use crystallite, only: & - crystallite_Fe - use constitutive, only: & - constitutive_homogenizedC - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - integer(pInt) :: & - phase, & - grain, & - homog, & - mech - real(pReal) :: & - phiDot, dPhiDot_dPhi, Cv, W_e, strain(6), C(6,6) - - homog = material_homog(ip,el) - Cv = vacancyConc(homog)%p(vacancyfluxMapping(homog)%p(ip,el)) - - W_e = 0.0_pReal - do grain = 1, homogenization_Ngrains(homog) - phase = material_phase(grain,ip,el) - strain = math_Mandel33to6(math_mul33x33(math_transpose33(crystallite_Fe(1:3,1:3,grain,ip,el)), & - crystallite_Fe(1:3,1:3,grain,ip,el)) - math_I3)/2.0_pReal - C = constitutive_homogenizedC(grain,ip,el) - do mech = 1_pInt, phase_NstiffnessDegradations(phase) - select case(phase_stiffnessDegradation(mech,phase)) - case (STIFFNESS_DEGRADATION_damage_ID) - C = damage(homog)%p(damageMapping(homog)%p(ip,el))* & - damage(homog)%p(damageMapping(homog)%p(ip,el))* & - C - - end select - enddo - W_e = W_e + sum(abs(strain*math_mul66x6(C,strain))) - enddo - W_e = W_e/homogenization_Ngrains(homog) - - phiDot = 2.0_pReal*(1.0_pReal - phi)*(1.0_pReal - Cv)*(1.0_pReal - Cv) - & - 2.0_pReal*phi*(W_e + Cv*porosity_phasefield_getFormationEnergy(ip,el))/ & - porosity_phasefield_getSurfaceEnergy (ip,el) - dPhiDot_dPhi = - 2.0_pReal*(1.0_pReal - Cv)*(1.0_pReal - Cv) & - - 2.0_pReal*(W_e + Cv*porosity_phasefield_getFormationEnergy(ip,el))/ & - porosity_phasefield_getSurfaceEnergy (ip,el) - -end subroutine porosity_phasefield_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized nonlocal diffusion tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function porosity_phasefield_getDiffusion33(ip,el) - use lattice, only: & - lattice_PorosityDiffusion33 - use material, only: & - homogenization_Ngrains, & - material_phase, & - mappingHomogenization - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - porosity_phasefield_getDiffusion33 - integer(pInt) :: & - homog, & - grain - - homog = mappingHomogenization(2,ip,el) - porosity_phasefield_getDiffusion33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(homog) - porosity_phasefield_getDiffusion33 = porosity_phasefield_getDiffusion33 + & - crystallite_push33ToRef(grain,ip,el,lattice_PorosityDiffusion33(1:3,1:3,material_phase(grain,ip,el))) - enddo - - porosity_phasefield_getDiffusion33 = & - porosity_phasefield_getDiffusion33/ & - homogenization_Ngrains(homog) - -end function porosity_phasefield_getDiffusion33 - -!-------------------------------------------------------------------------------------------------- -!> @brief Returns homogenized phase field mobility -!-------------------------------------------------------------------------------------------------- -real(pReal) function porosity_phasefield_getMobility(ip,el) - use mesh, only: & - mesh_element - use lattice, only: & - lattice_PorosityMobility - use material, only: & - material_phase, & - homogenization_Ngrains - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - integer(pInt) :: & - ipc - - porosity_phasefield_getMobility = 0.0_pReal - - do ipc = 1, homogenization_Ngrains(mesh_element(3,el)) - porosity_phasefield_getMobility = porosity_phasefield_getMobility + lattice_PorosityMobility(material_phase(ipc,ip,el)) - enddo - - porosity_phasefield_getMobility = porosity_phasefield_getMobility/homogenization_Ngrains(mesh_element(3,el)) - -end function porosity_phasefield_getMobility - -!-------------------------------------------------------------------------------------------------- -!> @brief updates porosity with solution from phasefield PDE -!-------------------------------------------------------------------------------------------------- -subroutine porosity_phasefield_putPorosity(phi,ip,el) - use material, only: & - material_homog, & - porosityMapping, & - porosity - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - integer(pInt) :: & - homog, & - offset - - homog = material_homog(ip,el) - offset = porosityMapping(homog)%p(ip,el) - porosity(homog)%p(offset) = phi - -end subroutine porosity_phasefield_putPorosity - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of porosity results -!-------------------------------------------------------------------------------------------------- -function porosity_phasefield_postResults(ip,el) - use material, only: & - mappingHomogenization, & - porosity_typeInstance, & - porosity - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(porosity_phasefield_sizePostResults(porosity_typeInstance(mappingHomogenization(2,ip,el)))) :: & - porosity_phasefield_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - instance = porosity_typeInstance(homog) - - c = 0_pInt - porosity_phasefield_postResults = 0.0_pReal - - do o = 1_pInt,porosity_phasefield_Noutput(instance) - select case(porosity_phasefield_outputID(o,instance)) - - case (porosity_ID) - porosity_phasefield_postResults(c+1_pInt) = porosity(homog)%p(offset) - c = c + 1 - end select - enddo -end function porosity_phasefield_postResults - -end module porosity_phasefield diff --git a/code/source/CMakeLists.txt b/code/source/CMakeLists.txt index fa54f332a..398bce557 100644 --- a/code/source/CMakeLists.txt +++ b/code/source/CMakeLists.txt @@ -1,4 +1,4 @@ -# group source +# group source set (SOURCE "source_thermal_dissipation" "source_thermal_externalheat" "source_damage_isoBrittle" @@ -14,3 +14,8 @@ set (SOURCE "source_thermal_dissipation" foreach (p ${SOURCE}) add_library (${p} MODULE "${p}.f90") endforeach (p) + +# set libraries/modules for linking +foreach (p ${SOURCE}) + set (AUX_LIB ${AUX_LIB} ${p}) +endforeach (p) \ No newline at end of file diff --git a/code/source_damage_anisoBrittle.f90 b/code/source_damage_anisoBrittle.f90 deleted file mode 100644 index a751eefdc..000000000 --- a/code/source_damage_anisoBrittle.f90 +++ /dev/null @@ -1,425 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @brief material subroutine incorporating anisotropic brittle damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_anisoBrittle - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_anisoBrittle_sizePostResults, & !< cumulative size of post results - source_damage_anisoBrittle_offset, & !< which source is my current source mechanism? - source_damage_anisoBrittle_instance !< instance of source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_anisoBrittle_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_anisoBrittle_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_anisoBrittle_Noutput !< number of outputs per instance of this source - - integer(pInt), dimension(:), allocatable, private :: & - source_damage_anisoBrittle_totalNcleavage !< total number of cleavage systems - - integer(pInt), dimension(:,:), allocatable, private :: & - source_damage_anisoBrittle_Ncleavage !< number of cleavage systems per family - - real(pReal), dimension(:), allocatable, private :: & - source_damage_anisoBrittle_aTol, & - source_damage_anisoBrittle_sdot_0, & - source_damage_anisoBrittle_N - - real(pReal), dimension(:,:), allocatable, private :: & - source_damage_anisoBrittle_critDisp, & - source_damage_anisoBrittle_critLoad - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_anisoBrittle_outputID !< ID of each post result output - - - public :: & - source_damage_anisoBrittle_init, & - source_damage_anisoBrittle_dotState, & - source_damage_anisobrittle_getRateAndItsTangent, & - source_damage_anisoBrittle_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoBrittle_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_anisoBrittle_label, & - SOURCE_damage_anisoBrittle_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - use lattice, only: & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoBrittle_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_anisoBrittle_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_anisoBrittle_offset(material_Nphase), source=0_pInt) - allocate(source_damage_anisoBrittle_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_anisoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoBrittle_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_anisoBrittle_ID) & - source_damage_anisoBrittle_offset(phase) = source - enddo - enddo - - allocate(source_damage_anisoBrittle_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_output(maxval(phase_Noutput),maxNinstance)) - source_damage_anisoBrittle_output = '' - allocate(source_damage_anisoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_anisoBrittle_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_totalNcleavage(maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_aTol(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_sdot_0(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_N(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_anisoBrittle_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('anisobrittle_drivingforce') - source_damage_anisoBrittle_Noutput(instance) = source_damage_anisoBrittle_Noutput(instance) + 1_pInt - source_damage_anisoBrittle_outputID(source_damage_anisoBrittle_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_anisoBrittle_output(source_damage_anisoBrittle_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('anisobrittle_atol') - source_damage_anisoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisobrittle_sdot0') - source_damage_anisoBrittle_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisobrittle_ratesensitivity') - source_damage_anisoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('ncleavage') ! - Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_CleavageFamilies - source_damage_anisoBrittle_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticaldisplacement') - do j = 1_pInt, Nchunks_CleavageFamilies - source_damage_anisoBrittle_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticalload') - do j = 1_pInt, Nchunks_CleavageFamilies - source_damage_anisoBrittle_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then - instance = source_damage_anisoBrittle_instance(phase) - source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & - min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested - source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance)) - source_damage_anisoBrittle_totalNcleavage(instance) = sum(source_damage_anisoBrittle_Ncleavage(:,instance)) ! how many cleavage systems altogether - if (source_damage_anisoBrittle_aTol(instance) < 0.0_pReal) & - source_damage_anisoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_anisoBrittle_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoBrittle_LABEL//')') - if (any(source_damage_anisoBrittle_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//SOURCE_damage_anisoBrittle_LABEL//')') - if (any(source_damage_anisoBrittle_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//SOURCE_damage_anisoBrittle_LABEL//')') - if (source_damage_anisoBrittle_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoBrittle_LABEL//')') - endif myPhase - enddo sanityChecks - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_anisoBrittle_instance(phase) - sourceOffset = source_damage_anisoBrittle_offset(phase) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) - select case(source_damage_anisoBrittle_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_anisoBrittle_sizePostResult(o,instance) = mySize - source_damage_anisoBrittle_sizePostResults(instance) = source_damage_anisoBrittle_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoBrittle_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_anisoBrittle_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_anisoBrittle_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoBrittle_dotState(Tstar_v, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState, & - material_homog, & - damage, & - damageMapping - use lattice, only: & - lattice_Scleavage_v, & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) - integer(pInt) :: & - phase, & - constituent, & - instance, & - sourceOffset, & - damageOffset, & - homog, & - f, i, index_myFamily - real(pReal) :: & - traction_d, traction_t, traction_n, traction_crit - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoBrittle_instance(phase) - sourceOffset = source_damage_anisoBrittle_offset(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal - do f = 1_pInt,lattice_maxNcleavageFamily - index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family - do i = 1_pInt,source_damage_anisoBrittle_Ncleavage(f,instance) ! process each (active) cleavage system in family - traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) - traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) - traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) - - traction_crit = source_damage_anisoBrittle_critLoad(f,instance)* & - damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & - source_damage_anisoBrittle_sdot_0(instance)* & - ((max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & - (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & - (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance))/ & - source_damage_anisoBrittle_critDisp(f,instance) - - enddo - enddo - -end subroutine source_damage_anisoBrittle_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_damage_anisoBrittle_offset(phase) - - localphiDot = 1.0_pReal - & - sourceState(phase)%p(sourceOffset)%state(1,constituent)*phi - - dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_anisobrittle_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_anisoBrittle_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_anisoBrittle_sizePostResults( & - source_damage_anisoBrittle_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_anisoBrittle_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoBrittle_instance(phase) - sourceOffset = source_damage_anisoBrittle_offset(phase) - - c = 0_pInt - source_damage_anisoBrittle_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) - select case(source_damage_anisoBrittle_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_anisoBrittle_postResults(c+1_pInt) = & - sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1_pInt - - end select - enddo -end function source_damage_anisoBrittle_postResults - -end module source_damage_anisoBrittle diff --git a/code/source_damage_anisoDuctile.f90 b/code/source_damage_anisoDuctile.f90 deleted file mode 100644 index 028fd479a..000000000 --- a/code/source_damage_anisoDuctile.f90 +++ /dev/null @@ -1,415 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating anisotropic ductile damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_anisoDuctile - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_anisoDuctile_sizePostResults, & !< cumulative size of post results - source_damage_anisoDuctile_offset, & !< which source is my current damage mechanism? - source_damage_anisoDuctile_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_anisoDuctile_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_anisoDuctile_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_anisoDuctile_Noutput !< number of outputs per instance of this damage - - integer(pInt), dimension(:), allocatable, private :: & - source_damage_anisoDuctile_totalNslip !< total number of slip systems - - integer(pInt), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_Nslip !< number of slip systems per family - - real(pReal), dimension(:), allocatable, private :: & - source_damage_anisoDuctile_aTol - - real(pReal), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_critPlasticStrain - - real(pReal), dimension(:), allocatable, private :: & - source_damage_anisoDuctile_sdot_0, & - source_damage_anisoDuctile_N - - real(pReal), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_critLoad - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_outputID !< ID of each post result output - - - public :: & - source_damage_anisoDuctile_init, & - source_damage_anisoDuctile_dotState, & - source_damage_anisoDuctile_getRateAndItsTangent, & - source_damage_anisoDuctile_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoDuctile_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_anisoDuctile_label, & - SOURCE_damage_anisoDuctile_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - use lattice, only: & - lattice_maxNslipFamily, & - lattice_NslipSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoDuctile_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_anisoDuctile_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_anisoDuctile_offset(material_Nphase), source=0_pInt) - allocate(source_damage_anisoDuctile_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_anisoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoDuctile_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_anisoDuctile_ID) & - source_damage_anisoDuctile_offset(phase) = source - enddo - enddo - - allocate(source_damage_anisoDuctile_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_damage_anisoDuctile_output(maxval(phase_Noutput),maxNinstance)) - source_damage_anisoDuctile_output = '' - allocate(source_damage_anisoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_anisoDuctile_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoDuctile_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(source_damage_anisoDuctile_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_totalNslip(maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_N(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoDuctile_sdot_0(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoDuctile_aTol(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_anisoDuctile_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('anisoductile_drivingforce') - source_damage_anisoDuctile_Noutput(instance) = source_damage_anisoDuctile_Noutput(instance) + 1_pInt - source_damage_anisoDuctile_outputID(source_damage_anisoDuctile_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_anisoDuctile_output(source_damage_anisoDuctile_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('anisoductile_atol') - source_damage_anisoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('nslip') ! - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - source_damage_anisoDuctile_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_sdot0') - source_damage_anisoDuctile_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalplasticstrain') - do j = 1_pInt, Nchunks_SlipFamilies - source_damage_anisoDuctile_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_ratesensitivity') - source_damage_anisoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalload') - do j = 1_pInt, Nchunks_SlipFamilies - source_damage_anisoDuctile_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, size(phase_source) - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then - instance = source_damage_anisoDuctile_instance(phase) - source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested - source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance)) - source_damage_anisoDuctile_totalNslip(instance) = sum(source_damage_anisoDuctile_Nslip(:,instance)) - if (source_damage_anisoDuctile_aTol(instance) < 0.0_pReal) & - source_damage_anisoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_anisoDuctile_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoDuctile_LABEL//')') - if (any(source_damage_anisoDuctile_critPlasticStrain(:,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//SOURCE_damage_anisoDuctile_LABEL//')') - if (source_damage_anisoDuctile_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoDuctile_LABEL//')') - endif myPhase - enddo sanityChecks - - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_anisoDuctile_instance(phase) - sourceOffset = source_damage_anisoDuctile_offset(phase) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) - select case(source_damage_anisoDuctile_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_anisoDuctile_sizePostResult(o,instance) = mySize - source_damage_anisoDuctile_sizePostResults(instance) = source_damage_anisoDuctile_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoDuctile_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_anisoDuctile_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_anisoDuctile_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoDuctile_dotState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - sourceState, & - material_homog, & - damage, & - damageMapping - use lattice, only: & - lattice_maxNslipFamily - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, & - constituent, & - sourceOffset, & - homog, damageOffset, & - instance, & - index, f, i - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoDuctile_instance(phase) - sourceOffset = source_damage_anisoDuctile_offset(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - index = 1_pInt - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal - do f = 1_pInt,lattice_maxNslipFamily - do i = 1_pInt,source_damage_anisoDuctile_Nslip(f,instance) ! process each (active) slip system in family - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & - plasticState(phase)%slipRate(index,constituent)/ & - ((damage(homog)%p(damageOffset))**source_damage_anisoDuctile_N(instance))/ & - source_damage_anisoDuctile_critPlasticStrain(f,instance) - - index = index + 1_pInt - enddo - enddo - -end subroutine source_damage_anisoDuctile_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_damage_anisoDuctile_offset(phase) - - localphiDot = 1.0_pReal - & - sourceState(phase)%p(sourceOffset)%state(1,constituent)* & - phi - - dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_anisoDuctile_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_anisoDuctile_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_anisoDuctile_sizePostResults( & - source_damage_anisoDuctile_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_anisoDuctile_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoDuctile_instance(phase) - sourceOffset = source_damage_anisoDuctile_offset(phase) - - c = 0_pInt - source_damage_anisoDuctile_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) - select case(source_damage_anisoDuctile_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_anisoDuctile_postResults(c+1_pInt) = & - sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1_pInt - - end select - enddo -end function source_damage_anisoDuctile_postResults - -end module source_damage_anisoDuctile diff --git a/code/source_damage_isoBrittle.f90 b/code/source_damage_isoBrittle.f90 deleted file mode 100644 index c063ae86f..000000000 --- a/code/source_damage_isoBrittle.f90 +++ /dev/null @@ -1,383 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incoprorating isotropic brittle damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_isoBrittle - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_isoBrittle_sizePostResults, & !< cumulative size of post results - source_damage_isoBrittle_offset, & !< which source is my current damage mechanism? - source_damage_isoBrittle_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_isoBrittle_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_isoBrittle_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_isoBrittle_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_damage_isoBrittle_aTol, & - source_damage_isoBrittle_N, & - source_damage_isoBrittle_critStrainEnergy - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_isoBrittle_outputID !< ID of each post result output - - - public :: & - source_damage_isoBrittle_init, & - source_damage_isoBrittle_deltaState, & - source_damage_isoBrittle_getRateAndItsTangent, & - source_damage_isoBrittle_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoBrittle_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_isoBrittle_label, & - SOURCE_damage_isoBrittle_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoBrittle_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_isoBrittle_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_isoBrittle_offset(material_Nphase), source=0_pInt) - allocate(source_damage_isoBrittle_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_isoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoBrittle_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_isoBrittle_ID) & - source_damage_isoBrittle_offset(phase) = source - enddo - enddo - - allocate(source_damage_isoBrittle_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_isoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_damage_isoBrittle_output(maxval(phase_Noutput),maxNinstance)) - source_damage_isoBrittle_output = '' - allocate(source_damage_isoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_isoBrittle_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_isoBrittle_critStrainEnergy(maxNinstance), source=0.0_pReal) - allocate(source_damage_isoBrittle_N(maxNinstance), source=1.0_pReal) - allocate(source_damage_isoBrittle_aTol(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_isoBrittle_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('isobrittle_drivingforce') - source_damage_isoBrittle_Noutput(instance) = source_damage_isoBrittle_Noutput(instance) + 1_pInt - source_damage_isoBrittle_outputID(source_damage_isoBrittle_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_isoBrittle_output(source_damage_isoBrittle_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('isobrittle_criticalstrainenergy') - source_damage_isoBrittle_critStrainEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isobrittle_n') - source_damage_isoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isobrittle_atol') - source_damage_isoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then - instance = source_damage_isoBrittle_instance(phase) - if (source_damage_isoBrittle_aTol(instance) < 0.0_pReal) & - source_damage_isoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_isoBrittle_critStrainEnergy(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='criticalStrainEnergy ('//SOURCE_damage_isoBrittle_LABEL//')') - endif myPhase - enddo sanityChecks - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_isoBrittle_instance(phase) - sourceOffset = source_damage_isoBrittle_offset(phase) -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) - select case(source_damage_isoBrittle_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_isoBrittle_sizePostResult(o,instance) = mySize - source_damage_isoBrittle_sizePostResults(instance) = source_damage_isoBrittle_sizePostResults(instance) + mySize - endif - enddo outputsLoop -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 1_pInt - sizeState = 1_pInt - - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoBrittle_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_isoBrittle_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_isoBrittle_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoBrittle_deltaState(C, Fe, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState, & - material_homog, & - phase_NstiffnessDegradations, & - phase_stiffnessDegradation, & - porosity, & - porosityMapping, & - STIFFNESS_DEGRADATION_porosity_ID - use math, only : & - math_mul33x33, & - math_mul66x6, & - math_Mandel33to6, & - math_transpose33, & - math_I3 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(3,3) :: & - Fe - real(pReal), intent(in), dimension(6,6) :: & - C - integer(pInt) :: & - phase, constituent, instance, sourceOffset, mech - real(pReal) :: & - strain(6), & - stiffness(6,6), & - strainenergy - - phase = phaseAt(ipc,ip,el) !< phase ID at ipc,ip,el - constituent = phasememberAt(ipc,ip,el) !< state array offset for phase ID at ipc,ip,el - ! ToDo: capability for multiple instances of SAME source within given phase. Needs Ninstance loop from here on! - instance = source_damage_isoBrittle_instance(phase) !< instance of damage_isoBrittle source - sourceOffset = source_damage_isoBrittle_offset(phase) - - stiffness = C - do mech = 1_pInt, phase_NstiffnessDegradations(phase) - select case(phase_stiffnessDegradation(mech,phase)) - case (STIFFNESS_DEGRADATION_porosity_ID) - stiffness = porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & - porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & - stiffness - end select - enddo - strain = 0.5_pReal*math_Mandel33to6(math_mul33x33(math_transpose33(Fe),Fe)-math_I3) - - strainenergy = 2.0_pReal*sum(strain*math_mul66x6(stiffness,strain))/ & - source_damage_isoBrittle_critStrainEnergy(instance) - if (strainenergy > sourceState(phase)%p(sourceOffset)%subState0(1,constituent)) then - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - strainenergy - sourceState(phase)%p(sourceOffset)%state(1,constituent) - else - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - sourceState(phase)%p(sourceOffset)%subState0(1,constituent) - & - sourceState(phase)%p(sourceOffset)%state(1,constituent) - endif - -end subroutine source_damage_isoBrittle_deltaState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoBrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, instance, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoBrittle_instance(phase) - sourceOffset = source_damage_isoBrittle_offset(phase) - - localphiDot = (1.0_pReal - phi)**(source_damage_isoBrittle_N(instance) - 1.0_pReal) - & - phi*sourceState(phase)%p(sourceOffset)%state(1,constituent) - dLocalphiDot_dPhi = - (source_damage_isoBrittle_N(instance) - 1.0_pReal)* & - (1.0_pReal - phi)**max(0.0_pReal,source_damage_isoBrittle_N(instance) - 2.0_pReal) & - - sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_isoBrittle_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_isoBrittle_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_isoBrittle_sizePostResults( & - source_damage_isoBrittle_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_isoBrittle_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoBrittle_instance(phase) - sourceOffset = source_damage_isoBrittle_offset(phase) - - c = 0_pInt - source_damage_isoBrittle_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) - select case(source_damage_isoBrittle_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_isoBrittle_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1 - - end select - enddo -end function source_damage_isoBrittle_postResults - -end module source_damage_isoBrittle diff --git a/code/source_damage_isoDuctile.f90 b/code/source_damage_isoDuctile.f90 deleted file mode 100644 index b0290264c..000000000 --- a/code/source_damage_isoDuctile.f90 +++ /dev/null @@ -1,350 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @brief material subroutine incoprorating isotropic ductile damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_isoDuctile - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_isoDuctile_sizePostResults, & !< cumulative size of post results - source_damage_isoDuctile_offset, & !< which source is my current damage mechanism? - source_damage_isoDuctile_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_isoDuctile_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_isoDuctile_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_isoDuctile_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_damage_isoDuctile_aTol, & - source_damage_isoDuctile_critPlasticStrain, & - source_damage_isoDuctile_N - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_isoDuctile_outputID !< ID of each post result output - - - public :: & - source_damage_isoDuctile_init, & - source_damage_isoDuctile_dotState, & - source_damage_isoDuctile_getRateAndItsTangent, & - source_damage_isoDuctile_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoDuctile_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_isoDuctile_label, & - SOURCE_damage_isoDuctile_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoDuctile_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_isoDuctile_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_isoDuctile_offset(material_Nphase), source=0_pInt) - allocate(source_damage_isoDuctile_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_isoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoDuctile_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_isoDuctile_ID) & - source_damage_isoDuctile_offset(phase) = source - enddo - enddo - - allocate(source_damage_isoDuctile_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_isoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_damage_isoDuctile_output(maxval(phase_Noutput),maxNinstance)) - source_damage_isoDuctile_output = '' - allocate(source_damage_isoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_isoDuctile_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_isoDuctile_critPlasticStrain(maxNinstance), source=0.0_pReal) - allocate(source_damage_isoDuctile_N(maxNinstance), source=0.0_pReal) - allocate(source_damage_isoDuctile_aTol(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_isoDuctile_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('isoductile_drivingforce') - source_damage_isoDuctile_Noutput(instance) = source_damage_isoDuctile_Noutput(instance) + 1_pInt - source_damage_isoDuctile_outputID(source_damage_isoDuctile_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_isoDuctile_output(source_damage_isoDuctile_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('isoductile_criticalplasticstrain') - source_damage_isoDuctile_critPlasticStrain(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isoductile_ratesensitivity') - source_damage_isoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isoductile_atol') - source_damage_isoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then - instance = source_damage_isoDuctile_instance(phase) - if (source_damage_isoDuctile_aTol(instance) < 0.0_pReal) & - source_damage_isoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_isoDuctile_critPlasticStrain(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='critical plastic strain ('//SOURCE_damage_isoDuctile_LABEL//')') - endif myPhase - enddo sanityChecks - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_isoDuctile_instance(phase) - sourceOffset = source_damage_isoDuctile_offset(phase) -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) - select case(source_damage_isoDuctile_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_isoDuctile_sizePostResult(o,instance) = mySize - source_damage_isoDuctile_sizePostResults(instance) = source_damage_isoDuctile_sizePostResults(instance) + mySize - endif - enddo outputsLoop -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoDuctile_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_isoDuctile_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_isoDuctile_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoDuctile_dotState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - sourceState, & - material_homog, & - damage, & - damageMapping - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, constituent, instance, homog, sourceOffset, damageOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoDuctile_instance(phase) - sourceOffset = source_damage_isoDuctile_offset(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & - sum(plasticState(phase)%slipRate(:,constituent))/ & - ((damage(homog)%p(damageOffset))**source_damage_isoDuctile_N(instance))/ & - source_damage_isoDuctile_critPlasticStrain(instance) - -end subroutine source_damage_isoDuctile_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_damage_isoDuctile_offset(phase) - - localphiDot = 1.0_pReal - & - sourceState(phase)%p(sourceOffset)%state(1,constituent)* & - phi - - dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_isoDuctile_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_isoDuctile_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_isoDuctile_sizePostResults( & - source_damage_isoDuctile_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_isoDuctile_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoDuctile_instance(phase) - sourceOffset = source_damage_isoDuctile_offset(phase) - - c = 0_pInt - source_damage_isoDuctile_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) - select case(source_damage_isoDuctile_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_isoDuctile_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1 - - end select - enddo -end function source_damage_isoDuctile_postResults - -end module source_damage_isoDuctile diff --git a/code/source_thermal_dissipation.f90 b/code/source_thermal_dissipation.f90 deleted file mode 100644 index 83ad85167..000000000 --- a/code/source_thermal_dissipation.f90 +++ /dev/null @@ -1,220 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for thermal source due to plastic dissipation -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_thermal_dissipation - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_thermal_dissipation_sizePostResults, & !< cumulative size of post results - source_thermal_dissipation_offset, & !< which source is my current thermal dissipation mechanism? - source_thermal_dissipation_instance !< instance of thermal dissipation source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_thermal_dissipation_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_thermal_dissipation_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_thermal_dissipation_Noutput !< number of outputs per instance of this source - - real(pReal), dimension(:), allocatable, private :: & - source_thermal_dissipation_coldworkCoeff - - public :: & - source_thermal_dissipation_init, & - source_thermal_dissipation_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_dissipation_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_thermal_dissipation_label, & - SOURCE_thermal_dissipation_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_dissipation_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_thermal_dissipation_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_thermal_dissipation_offset(material_Nphase), source=0_pInt) - allocate(source_thermal_dissipation_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_thermal_dissipation_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_dissipation_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == SOURCE_thermal_dissipation_ID) & - source_thermal_dissipation_offset(phase) = source - enddo - enddo - - allocate(source_thermal_dissipation_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_thermal_dissipation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_thermal_dissipation_output (maxval(phase_Noutput),maxNinstance)) - source_thermal_dissipation_output = '' - allocate(source_thermal_dissipation_Noutput(maxNinstance), source=0_pInt) - allocate(source_thermal_dissipation_coldworkCoeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_thermal_dissipation_instance(phase) ! which instance of my source is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('dissipation_coldworkcoeff') - source_thermal_dissipation_coldworkCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_thermal_dissipation_instance(phase) - sourceOffset = source_thermal_dissipation_offset(phase) - - sizeDotState = 0_pInt - sizeDeltaState = 0_pInt - sizeState = 0_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_dissipation_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_thermal_dissipation_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_dissipation_getRateAndItsTangent(TDot, dTDOT_dT, Tstar_v, Lp, ipc, ip, el) - use math, only: & - math_Mandel6to33 - use material, only: & - phaseAt, phasememberAt - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) - real(pReal), intent(in), dimension(3,3) :: & - Lp - real(pReal), intent(out) :: & - TDot, & - dTDOT_dT - integer(pInt) :: & - instance, phase, constituent - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_thermal_dissipation_instance(phase) - - TDot = source_thermal_dissipation_coldworkCoeff(instance)* & - sum(abs(math_Mandel6to33(Tstar_v)*Lp)) - dTDOT_dT = 0.0_pReal - -end subroutine source_thermal_dissipation_getRateAndItsTangent - -end module source_thermal_dissipation diff --git a/code/source_thermal_externalheat.f90 b/code/source_thermal_externalheat.f90 deleted file mode 100644 index 257012c06..000000000 --- a/code/source_thermal_externalheat.f90 +++ /dev/null @@ -1,277 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for thermal source due to plastic dissipation -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_thermal_externalheat - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_thermal_externalheat_sizePostResults, & !< cumulative size of post results - source_thermal_externalheat_offset, & !< which source is my current thermal dissipation mechanism? - source_thermal_externalheat_instance !< instance of thermal dissipation source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_thermal_externalheat_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_thermal_externalheat_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_thermal_externalheat_Noutput !< number of outputs per instance of this source - - integer(pInt), dimension(:), allocatable, private :: & - source_thermal_externalheat_nIntervals - - real(pReal), dimension(:,:), allocatable, private :: & - source_thermal_externalheat_time, & - source_thermal_externalheat_rate - - public :: & - source_thermal_externalheat_init, & - source_thermal_externalheat_dotState, & - source_thermal_externalheat_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_externalheat_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_thermal_externalheat_label, & - SOURCE_thermal_externalheat_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase,interval - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), allocatable, dimension(:,:) :: temp_time, temp_rate - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_externalheat_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_thermal_externalheat_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_thermal_externalheat_offset(material_Nphase), source=0_pInt) - allocate(source_thermal_externalheat_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_thermal_externalheat_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_externalheat_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == SOURCE_thermal_externalheat_ID) & - source_thermal_externalheat_offset(phase) = source - enddo - enddo - - allocate(source_thermal_externalheat_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_thermal_externalheat_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_thermal_externalheat_output (maxval(phase_Noutput),maxNinstance)) - source_thermal_externalheat_output = '' - allocate(source_thermal_externalheat_Noutput(maxNinstance), source=0_pInt) - allocate(source_thermal_externalheat_nIntervals(maxNinstance), source=0_pInt) - - allocate(temp_time(maxNinstance,1000), source=0.0_pReal) - allocate(temp_rate(maxNinstance,1000), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_thermal_externalheat_instance(phase) ! which instance of my source is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('externalheat_time') - if (chunkPos(1) <= 2_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//SOURCE_thermal_externalheat_label//')') - source_thermal_externalheat_nIntervals(instance) = chunkPos(1) - 2_pInt - do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt - temp_time(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) - enddo - - case ('externalheat_rate') - do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt - temp_rate(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) - enddo - - end select - endif; endif - enddo parsingFile - - allocate(source_thermal_externalheat_time(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) - allocate(source_thermal_externalheat_rate(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_thermal_externalheat_instance(phase) - sourceOffset = source_thermal_externalheat_offset(phase) - source_thermal_externalheat_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & - temp_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) - source_thermal_externalheat_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & - temp_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) - - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_externalheat_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.00001_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_thermal_externalheat_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_externalheat_dotState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, & - constituent, & - sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_thermal_externalheat_offset(phase) - - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 1.0_pReal - -end subroutine source_thermal_externalheat_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_externalheat_getRateAndItsTangent(TDot, dTDot_dT, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - TDot, & - dTDot_dT - integer(pInt) :: & - instance, phase, constituent, sourceOffset, interval - real(pReal) :: & - norm_time - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_thermal_externalheat_instance(phase) - sourceOffset = source_thermal_externalheat_offset(phase) - - do interval = 1, source_thermal_externalheat_nIntervals(instance) - norm_time = (sourceState(phase)%p(sourceOffset)%state(1,constituent) - & - source_thermal_externalheat_time(instance,interval)) / & - (source_thermal_externalheat_time(instance,interval+1) - & - source_thermal_externalheat_time(instance,interval)) - if (norm_time >= 0.0_pReal .and. norm_time < 1.0_pReal) & - TDot = source_thermal_externalheat_rate(instance,interval ) * (1.0_pReal - norm_time) + & - source_thermal_externalheat_rate(instance,interval+1) * norm_time - enddo - dTDot_dT = 0.0 - -end subroutine source_thermal_externalheat_getRateAndItsTangent - -end module source_thermal_externalheat diff --git a/code/source_vacancy_irradiation.f90 b/code/source_vacancy_irradiation.f90 deleted file mode 100644 index c4bcfba04..000000000 --- a/code/source_vacancy_irradiation.f90 +++ /dev/null @@ -1,253 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for vacancy generation due to irradiation -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_vacancy_irradiation - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_vacancy_irradiation_sizePostResults, & !< cumulative size of post results - source_vacancy_irradiation_offset, & !< which source is my current damage mechanism? - source_vacancy_irradiation_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_vacancy_irradiation_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_vacancy_irradiation_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_vacancy_irradiation_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_vacancy_irradiation_cascadeProb, & - source_vacancy_irradiation_cascadeVolume - - public :: & - source_vacancy_irradiation_init, & - source_vacancy_irradiation_deltaState, & - source_vacancy_irradiation_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_irradiation_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_vacancy_irradiation_label, & - SOURCE_vacancy_irradiation_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_irradiation_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_vacancy_irradiation_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_vacancy_irradiation_offset(material_Nphase), source=0_pInt) - allocate(source_vacancy_irradiation_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_vacancy_irradiation_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_irradiation_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_vacancy_irradiation_ID) & - source_vacancy_irradiation_offset(phase) = source - enddo - enddo - - allocate(source_vacancy_irradiation_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_vacancy_irradiation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_vacancy_irradiation_output(maxval(phase_Noutput),maxNinstance)) - source_vacancy_irradiation_output = '' - allocate(source_vacancy_irradiation_Noutput(maxNinstance), source=0_pInt) - allocate(source_vacancy_irradiation_cascadeProb(maxNinstance), source=0.0_pReal) - allocate(source_vacancy_irradiation_cascadeVolume(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_vacancy_irradiation_instance(phase) ! which instance of my vacancy is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('irradiation_cascadeprobability') - source_vacancy_irradiation_cascadeProb(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('irradiation_cascadevolume') - source_vacancy_irradiation_cascadeVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_vacancy_irradiation_instance(phase) - sourceOffset = source_vacancy_irradiation_offset(phase) - - sizeDotState = 2_pInt - sizeDeltaState = 2_pInt - sizeState = 2_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_irradiation_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_vacancy_irradiation_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_irradiation_deltaState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, constituent, sourceOffset - real(pReal) :: & - randNo - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_vacancy_irradiation_offset(phase) - - call random_number(randNo) - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - randNo - sourceState(phase)%p(sourceOffset)%state(1,constituent) - call random_number(randNo) - sourceState(phase)%p(sourceOffset)%deltaState(2,constituent) = & - randNo - sourceState(phase)%p(sourceOffset)%state(2,constituent) - -end subroutine source_vacancy_irradiation_deltaState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_irradiation_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - CvDot, dCvDot_dCv - integer(pInt) :: & - instance, phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_vacancy_irradiation_instance(phase) - sourceOffset = source_vacancy_irradiation_offset(phase) - - CvDot = 0.0_pReal - dCvDot_dCv = 0.0_pReal - if (sourceState(phase)%p(sourceOffset)%state0(1,constituent) < source_vacancy_irradiation_cascadeProb(instance)) & - CvDot = sourceState(phase)%p(sourceOffset)%state0(2,constituent)*source_vacancy_irradiation_cascadeVolume(instance) - -end subroutine source_vacancy_irradiation_getRateAndItsTangent - -end module source_vacancy_irradiation diff --git a/code/source_vacancy_phenoplasticity.f90 b/code/source_vacancy_phenoplasticity.f90 deleted file mode 100644 index f9e766b2c..000000000 --- a/code/source_vacancy_phenoplasticity.f90 +++ /dev/null @@ -1,215 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for vacancy generation due to plasticity -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_vacancy_phenoplasticity - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_vacancy_phenoplasticity_sizePostResults, & !< cumulative size of post results - source_vacancy_phenoplasticity_offset, & !< which source is my current damage mechanism? - source_vacancy_phenoplasticity_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_vacancy_phenoplasticity_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_vacancy_phenoplasticity_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_vacancy_phenoplasticity_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_vacancy_phenoplasticity_rateCoeff - - public :: & - source_vacancy_phenoplasticity_init, & - source_vacancy_phenoplasticity_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_phenoplasticity_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_vacancy_phenoplasticity_label, & - SOURCE_vacancy_phenoplasticity_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_phenoplasticity_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_vacancy_phenoplasticity_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_vacancy_phenoplasticity_offset(material_Nphase), source=0_pInt) - allocate(source_vacancy_phenoplasticity_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_vacancy_phenoplasticity_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_phenoplasticity_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_vacancy_phenoplasticity_ID) & - source_vacancy_phenoplasticity_offset(phase) = source - enddo - enddo - - allocate(source_vacancy_phenoplasticity_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_vacancy_phenoplasticity_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_vacancy_phenoplasticity_output(maxval(phase_Noutput),maxNinstance)) - source_vacancy_phenoplasticity_output = '' - allocate(source_vacancy_phenoplasticity_Noutput(maxNinstance), source=0_pInt) - allocate(source_vacancy_phenoplasticity_rateCoeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_vacancy_phenoplasticity_instance(phase) ! which instance of my vacancy is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('phenoplasticity_ratecoeff') - source_vacancy_phenoplasticity_rateCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_vacancy_phenoplasticity_instance(phase) - sourceOffset = source_vacancy_phenoplasticity_offset(phase) - - sizeDotState = 0_pInt - sizeDeltaState = 0_pInt - sizeState = 0_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_phenoplasticity_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_vacancy_phenoplasticity_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_phenoplasticity_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - plasticState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - CvDot, dCvDot_dCv - integer(pInt) :: & - instance, phase, constituent - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_vacancy_phenoplasticity_instance(phase) - - CvDot = & - source_vacancy_phenoplasticity_rateCoeff(instance)* & - sum(plasticState(phase)%slipRate(:,constituent)) - dCvDot_dCv = 0.0_pReal - -end subroutine source_vacancy_phenoplasticity_getRateAndItsTangent - -end module source_vacancy_phenoplasticity diff --git a/code/source_vacancy_thermalfluc.f90 b/code/source_vacancy_thermalfluc.f90 deleted file mode 100644 index c86406430..000000000 --- a/code/source_vacancy_thermalfluc.f90 +++ /dev/null @@ -1,255 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for vacancy generation due to thermal fluctuations -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_vacancy_thermalfluc - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_vacancy_thermalfluc_sizePostResults, & !< cumulative size of post results - source_vacancy_thermalfluc_offset, & !< which source is my current damage mechanism? - source_vacancy_thermalfluc_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_vacancy_thermalfluc_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_vacancy_thermalfluc_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_vacancy_thermalfluc_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_vacancy_thermalfluc_amplitude, & - source_vacancy_thermalfluc_normVacancyEnergy - - public :: & - source_vacancy_thermalfluc_init, & - source_vacancy_thermalfluc_deltaState, & - source_vacancy_thermalfluc_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_thermalfluc_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use lattice, only: & - lattice_vacancyFormationEnergy - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_vacancy_thermalfluc_label, & - SOURCE_vacancy_thermalfluc_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_thermalfluc_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_vacancy_thermalfluc_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_vacancy_thermalfluc_offset(material_Nphase), source=0_pInt) - allocate(source_vacancy_thermalfluc_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_vacancy_thermalfluc_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_thermalfluc_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_vacancy_thermalfluc_ID) & - source_vacancy_thermalfluc_offset(phase) = source - enddo - enddo - - allocate(source_vacancy_thermalfluc_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_vacancy_thermalfluc_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_vacancy_thermalfluc_output(maxval(phase_Noutput),maxNinstance)) - source_vacancy_thermalfluc_output = '' - allocate(source_vacancy_thermalfluc_Noutput(maxNinstance), source=0_pInt) - allocate(source_vacancy_thermalfluc_amplitude(maxNinstance), source=0.0_pReal) - allocate(source_vacancy_thermalfluc_normVacancyEnergy(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_vacancy_thermalfluc_instance(phase) ! which instance of my vacancy is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('thermalfluctuation_amplitude') - source_vacancy_thermalfluc_amplitude(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_vacancy_thermalfluc_instance(phase) - source_vacancy_thermalfluc_normVacancyEnergy(instance) = & - lattice_vacancyFormationEnergy(phase)/1.3806488e-23_pReal - sourceOffset = source_vacancy_thermalfluc_offset(phase) - - sizeDotState = 1_pInt - sizeDeltaState = 1_pInt - sizeState = 1_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_thermalfluc_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_vacancy_thermalfluc_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_thermalfluc_deltaState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, constituent, sourceOffset - real(pReal) :: & - randNo - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_vacancy_thermalfluc_offset(phase) - - call random_number(randNo) - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - randNo - 0.5_pReal - sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_vacancy_thermalfluc_deltaState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_thermalfluc_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - material_homog, & - temperature, & - thermalMapping, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - CvDot, dCvDot_dCv - integer(pInt) :: & - instance, phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_vacancy_thermalfluc_instance(phase) - sourceOffset = source_vacancy_thermalfluc_offset(phase) - - CvDot = source_vacancy_thermalfluc_amplitude(instance)* & - sourceState(phase)%p(sourceOffset)%state0(2,constituent)* & - exp(-source_vacancy_thermalfluc_normVacancyEnergy(instance)/ & - temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))) - dCvDot_dCv = 0.0_pReal - -end subroutine source_vacancy_thermalfluc_getRateAndItsTangent - -end module source_vacancy_thermalfluc diff --git a/code/spectral/CMakeLists.txt b/code/spectral/CMakeLists.txt index a11ff1303..659709917 100644 --- a/code/spectral/CMakeLists.txt +++ b/code/spectral/CMakeLists.txt @@ -5,10 +5,15 @@ set (SPECTRAL "spectral_damage" "spectral_mech_Basic" "spectral_mech_Polarisation" "spectral_thermal" - "spectral_utilities" + "spectral_utilities" ) # compile spectral solver driver module foreach (p ${SPECTRAL}) add_library (${p} MODULE "${p}.f90") endforeach (p) + +# set libraries/modules for linking +foreach (p ${SPECTRAL}) + set (AUX_LIB ${AUX_LIB} ${p}) +endforeach (p) \ No newline at end of file diff --git a/code/spectral_damage.f90 b/code/spectral_damage.f90 deleted file mode 100644 index 0b79d5e5d..000000000 --- a/code/spectral_damage.f90 +++ /dev/null @@ -1,414 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id: spectral_damage.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Shaokang Zhang, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Spectral solver for nonlocal damage -!-------------------------------------------------------------------------------------------------- -module spectral_damage - use prec, only: & - pInt, & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - use numerics, only: & - worldrank, & - worldsize - - implicit none - private -#include - - character (len=*), parameter, public :: & - spectral_damage_label = 'spectraldamage' - -!-------------------------------------------------------------------------------------------------- -! derived types - type(tSolutionParams), private :: params - -!-------------------------------------------------------------------------------------------------- -! PETSc data - SNES, private :: damage_snes - Vec, private :: solution - PetscInt, private :: xstart, xend, ystart, yend, zstart, zend - real(pReal), private, dimension(:,:,:), allocatable :: & - damage_current, & !< field of current damage - damage_lastInc, & !< field of previous damage - damage_stagInc !< field of staggered damage - -!-------------------------------------------------------------------------------------------------- -! reference diffusion tensor, mobility etc. - integer(pInt), private :: totalIter = 0_pInt !< total iteration in current increment - real(pReal), dimension(3,3), private :: D_ref - real(pReal), private :: mobility_ref - character(len=1024), private :: incInfo - - public :: & - spectral_damage_init, & - spectral_damage_solution, & - spectral_damage_forward, & - spectral_damage_destroy - external :: & - VecDestroy, & - DMDestroy, & - DMDACreate3D, & - DMCreateGlobalVector, & - DMDASNESSetFunctionLocal, & - PETScFinalize, & - SNESDestroy, & - SNESGetNumberFunctionEvals, & - SNESGetIterationNumber, & - SNESSolve, & - SNESSetDM, & - SNESGetConvergedReason, & - SNESSetConvergenceTest, & - SNESSetFromOptions, & - SNESCreate, & - MPI_Abort, & - MPI_Bcast, & - MPI_Allreduce - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields and fills them with data, potentially from restart info -!-------------------------------------------------------------------------------------------------- -subroutine spectral_damage_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_intOut, & - IO_read_realFile, & - IO_timeStamp - use spectral_utilities, only: & - wgt - use mesh, only: & - grid, & - grid3 - use damage_nonlocal, only: & - damage_nonlocal_getDiffusion33, & - damage_nonlocal_getMobility - - implicit none - DM :: damage_grid - Vec :: uBound, lBound - PetscErrorCode :: ierr - PetscObject :: dummy - integer(pInt), dimension(:), allocatable :: localK - integer(pInt) :: proc - integer(pInt) :: i, j, k, cell - character(len=100) :: snes_type - - mainProcess: if (worldrank == 0_pInt) then - write(6,'(/,a)') ' <<<+- spectral_damage init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!-------------------------------------------------------------------------------------------------- -! initialize solver specific parts of PETSc - call SNESCreate(PETSC_COMM_WORLD,damage_snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(damage_snes,'damage_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do proc = 1, worldsize - call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & !< cut off stencil at boundary - DMDA_STENCIL_BOX, & !< Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & !< global grid - 1, 1, worldsize, & - 1, 0, & !< #dof (damage phase field), ghost boundary width (domain overlap) - grid(1),grid(2),localK, & !< local grid - damage_grid,ierr) !< handle, error - CHKERRQ(ierr) - call SNESSetDM(damage_snes,damage_grid,ierr); CHKERRQ(ierr) !< connect snes to da - call DMCreateGlobalVector(damage_grid,solution,ierr); CHKERRQ(ierr) !< global solution vector (grid x 1, i.e. every def grad tensor) - call DMDASNESSetFunctionLocal(damage_grid,INSERT_VALUES,spectral_damage_formResidual,dummy,ierr) !< residual vector of same shape as solution vector - CHKERRQ(ierr) - call SNESSetFromOptions(damage_snes,ierr); CHKERRQ(ierr) !< pull it all together with additional cli arguments - call SNESGetType(damage_snes,snes_type,ierr); CHKERRQ(ierr) - if (trim(snes_type) == 'vinewtonrsls' .or. & - trim(snes_type) == 'vinewtonssls') then - call DMGetGlobalVector(damage_grid,lBound,ierr); CHKERRQ(ierr) - call DMGetGlobalVector(damage_grid,uBound,ierr); CHKERRQ(ierr) - call VecSet(lBound,0.0,ierr); CHKERRQ(ierr) - call VecSet(uBound,1.0,ierr); CHKERRQ(ierr) - call SNESVISetVariableBounds(damage_snes,lBound,uBound,ierr) !< variable bounds for variational inequalities like contact mechanics, damage etc. - call DMRestoreGlobalVector(damage_grid,lBound,ierr); CHKERRQ(ierr) - call DMRestoreGlobalVector(damage_grid,uBound,ierr); CHKERRQ(ierr) - endif - -!-------------------------------------------------------------------------------------------------- -! init fields - call DMDAGetCorners(damage_grid,xstart,ystart,zstart,xend,yend,zend,ierr) - CHKERRQ(ierr) - xend = xstart + xend - 1 - yend = ystart + yend - 1 - zend = zstart + zend - 1 - call VecSet(solution,1.0,ierr); CHKERRQ(ierr) - allocate(damage_current(grid(1),grid(2),grid3), source=1.0_pReal) - allocate(damage_lastInc(grid(1),grid(2),grid3), source=1.0_pReal) - allocate(damage_stagInc(grid(1),grid(2),grid3), source=1.0_pReal) - -!-------------------------------------------------------------------------------------------------- -! damage reference diffusion update - cell = 0_pInt - D_ref = 0.0_pReal - mobility_ref = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - D_ref = D_ref + damage_nonlocal_getDiffusion33(1,cell) - mobility_ref = mobility_ref + damage_nonlocal_getMobility(1,cell) - enddo; enddo; enddo - D_ref = D_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - mobility_ref = mobility_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - -end subroutine spectral_damage_init - -!-------------------------------------------------------------------------------------------------- -!> @brief solution for the spectral damage scheme with internal iterations -!-------------------------------------------------------------------------------------------------- -type(tSolutionState) function spectral_damage_solution(guess,timeinc,timeinc_old,loadCaseTime) - use numerics, only: & - itmax, & - err_damage_tolAbs, & - err_damage_tolRel - use spectral_utilities, only: & - tBoundaryCondition, & - Utilities_maskedCompliance, & - Utilities_updateGamma - use mesh, only: & - grid, & - grid3 - use damage_nonlocal, only: & - damage_nonlocal_putNonLocalDamage - - implicit none - -!-------------------------------------------------------------------------------------------------- -! input data for solution - real(pReal), intent(in) :: & - timeinc, & !< increment in time for current solution - timeinc_old, & !< increment in time of last increment - loadCaseTime !< remaining time of current load case - logical, intent(in) :: guess - integer(pInt) :: i, j, k, cell - PetscInt ::position - PetscReal :: minDamage, maxDamage, stagNorm, solnNorm - -!-------------------------------------------------------------------------------------------------- -! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - - spectral_damage_solution%converged =.false. - -!-------------------------------------------------------------------------------------------------- -! set module wide availabe data - params%timeinc = timeinc - params%timeincOld = timeinc_old - - call SNESSolve(damage_snes,PETSC_NULL_OBJECT,solution,ierr); CHKERRQ(ierr) - call SNESGetConvergedReason(damage_snes,reason,ierr); CHKERRQ(ierr) - - if (reason < 1) then - spectral_damage_solution%converged = .false. - spectral_damage_solution%iterationsNeeded = itmax - else - spectral_damage_solution%converged = .true. - spectral_damage_solution%iterationsNeeded = totalIter - endif - stagNorm = maxval(abs(damage_current - damage_stagInc)) - solnNorm = maxval(abs(damage_current)) - call MPI_Allreduce(MPI_IN_PLACE,stagNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) - call MPI_Allreduce(MPI_IN_PLACE,solnNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) - damage_stagInc = damage_current - spectral_damage_solution%stagConverged = stagNorm < err_damage_tolAbs & - .or. stagNorm < err_damage_tolRel*solnNorm - -!-------------------------------------------------------------------------------------------------- -! updating damage state - cell = 0_pInt !< material point = 0 - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt !< material point increase - call damage_nonlocal_putNonLocalDamage(damage_current(i,j,k),1,cell) - enddo; enddo; enddo - - call VecMin(solution,position,minDamage,ierr); CHKERRQ(ierr) - call VecMax(solution,position,maxDamage,ierr); CHKERRQ(ierr) - if (worldrank == 0) then - if (spectral_damage_solution%converged) & - write(6,'(/,a)') ' ... nonlocal damage converged .....................................' - write(6,'(/,a,f8.6,2x,f8.6,2x,f8.6,/)',advance='no') ' Minimum|Maximum|Delta Damage = ',& - minDamage, maxDamage, stagNorm - write(6,'(/,a)') ' ===========================================================================' - flush(6) - endif - -end function spectral_damage_solution - - -!-------------------------------------------------------------------------------------------------- -!> @brief forms the spectral damage residual vector -!-------------------------------------------------------------------------------------------------- -subroutine spectral_damage_formResidual(in,x_scal,f_scal,dummy,ierr) - use numerics, only: & - residualStiffness - use mesh, only: & - grid, & - grid3 - use math, only: & - math_mul33x3 - use spectral_utilities, only: & - scalarField_real, & - vectorField_real, & - utilities_FFTvectorForward, & - utilities_FFTvectorBackward, & - utilities_FFTscalarForward, & - utilities_FFTscalarBackward, & - utilities_fourierGreenConvolution, & - utilities_fourierScalarGradient, & - utilities_fourierVectorDivergence - use damage_nonlocal, only: & - damage_nonlocal_getSourceAndItsTangent,& - damage_nonlocal_getDiffusion33, & - damage_nonlocal_getMobility - - implicit none - DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & - in - PetscScalar, dimension( & - XG_RANGE,YG_RANGE,ZG_RANGE) :: & - x_scal - PetscScalar, dimension( & - X_RANGE,Y_RANGE,Z_RANGE) :: & - f_scal - PetscObject :: dummy - PetscErrorCode :: ierr - integer(pInt) :: i, j, k, cell - real(pReal) :: phiDot, dPhiDot_dPhi, mobility - - damage_current = x_scal -!-------------------------------------------------------------------------------------------------- -! evaluate polarization field - scalarField_real = 0.0_pReal - scalarField_real(1:grid(1),1:grid(2),1:grid3) = damage_current - call utilities_FFTscalarForward() - call utilities_fourierScalarGradient() !< calculate gradient of damage field - call utilities_FFTvectorBackward() - cell = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - vectorField_real(1:3,i,j,k) = math_mul33x3(damage_nonlocal_getDiffusion33(1,cell) - D_ref, & - vectorField_real(1:3,i,j,k)) - enddo; enddo; enddo - call utilities_FFTvectorForward() - call utilities_fourierVectorDivergence() !< calculate damage divergence in fourier field - call utilities_FFTscalarBackward() - cell = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - call damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, damage_current(i,j,k), 1, cell) - mobility = damage_nonlocal_getMobility(1,cell) - scalarField_real(i,j,k) = params%timeinc*scalarField_real(i,j,k) + & - params%timeinc*phiDot + & - mobility*damage_lastInc(i,j,k) - & - mobility*damage_current(i,j,k) + & - mobility_ref*damage_current(i,j,k) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! convolution of damage field with green operator - call utilities_FFTscalarForward() - call utilities_fourierGreenConvolution(D_ref, mobility_ref, params%timeinc) - call utilities_FFTscalarBackward() - where(scalarField_real(1:grid(1),1:grid(2),1:grid3) > damage_lastInc) & - scalarField_real(1:grid(1),1:grid(2),1:grid3) = damage_lastInc - where(scalarField_real(1:grid(1),1:grid(2),1:grid3) < residualStiffness) & - scalarField_real(1:grid(1),1:grid(2),1:grid3) = residualStiffness - -!-------------------------------------------------------------------------------------------------- -! constructing residual - f_scal = scalarField_real(1:grid(1),1:grid(2),1:grid3) - damage_current - -end subroutine spectral_damage_formResidual - -!-------------------------------------------------------------------------------------------------- -!> @brief spectral damage forwarding routine -!-------------------------------------------------------------------------------------------------- -subroutine spectral_damage_forward(guess,timeinc,timeinc_old,loadCaseTime) - use mesh, only: & - grid, & - grid3 - use spectral_utilities, only: & - cutBack, & - wgt - use damage_nonlocal, only: & - damage_nonlocal_putNonLocalDamage, & - damage_nonlocal_getDiffusion33, & - damage_nonlocal_getMobility - - implicit none - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - logical, intent(in) :: guess - PetscErrorCode :: ierr - integer(pInt) :: i, j, k, cell - DM :: dm_local - PetscScalar, dimension(:,:,:), pointer :: x_scal - - if (cutBack) then - damage_current = damage_lastInc - damage_stagInc = damage_lastInc -!-------------------------------------------------------------------------------------------------- -! reverting damage field state - cell = 0_pInt - call SNESGetDM(damage_snes,dm_local,ierr); CHKERRQ(ierr) - call DMDAVecGetArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with - x_scal(xstart:xend,ystart:yend,zstart:zend) = damage_current - call DMDAVecRestoreArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - call damage_nonlocal_putNonLocalDamage(damage_current(i,j,k),1,cell) - enddo; enddo; enddo - else -!-------------------------------------------------------------------------------------------------- -! update rate and forward last inc - damage_lastInc = damage_current - cell = 0_pInt - D_ref = 0.0_pReal - mobility_ref = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - D_ref = D_ref + damage_nonlocal_getDiffusion33(1,cell) - mobility_ref = mobility_ref + damage_nonlocal_getMobility(1,cell) - enddo; enddo; enddo - D_ref = D_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - mobility_ref = mobility_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - endif - - end subroutine spectral_damage_forward - -!-------------------------------------------------------------------------------------------------- -!> @brief destroy routine -!-------------------------------------------------------------------------------------------------- -subroutine spectral_damage_destroy() - - implicit none - PetscErrorCode :: ierr - - call VecDestroy(solution,ierr); CHKERRQ(ierr) - call SNESDestroy(damage_snes,ierr); CHKERRQ(ierr) - -end subroutine spectral_damage_destroy - -end module spectral_damage diff --git a/code/spectral_interface.f90 b/code/spectral_interface.f90 deleted file mode 100644 index b24c5f747..000000000 --- a/code/spectral_interface.f90 +++ /dev/null @@ -1,568 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Interfacing between the spectral solver and the material subroutines provided -!! by DAMASK -!> @details Interfacing between the spectral solver and the material subroutines provided -!> by DAMASK. Interpretating the command line arguments or, in case of called from f2py, -!> the arguments parsed to the init routine to get load case, geometry file, working -!> directory, etc. -!-------------------------------------------------------------------------------------------------- -module DAMASK_interface - use prec, only: & - pInt - - implicit none - private -#ifdef PETSc -#include -#endif - logical, public, protected :: appendToOutFile = .false. !< Append to existing spectralOut file (in case of restart, not in case of regridding) - integer(pInt), public, protected :: spectralRestartInc = 1_pInt !< Increment at which calculation starts - character(len=1024), public, protected :: & - geometryFile = '', & !< parameter given for geometry file - loadCaseFile = '' !< parameter given for load case file - character(len=1024), private :: workingDirectory !< accessed by getSolverWorkingDirectoryName for compatibility reasons - - public :: & - getSolverWorkingDirectoryName, & - getSolverJobName, & - DAMASK_interface_init - private :: & - storeWorkingDirectory, & - getGeometryFile, & - getLoadCaseFile, & - rectifyPath, & - makeRelativePath, & - getPathSep, & - IIO_stringValue, & - IIO_intValue, & - IIO_lc, & - IIO_stringPos - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief initializes the solver by interpreting the command line arguments. Also writes -!! information on computation to screen -!-------------------------------------------------------------------------------------------------- -subroutine DAMASK_interface_init(loadCaseParameterIn,geometryParameterIn) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - - implicit none - character(len=1024), optional, intent(in) :: & - loadCaseParameterIn, & !< if using the f2py variant, the -l argument of DAMASK_spectral.exe - geometryParameterIn !< if using the f2py variant, the -g argument of DAMASK_spectral.exe - character(len=1024) :: & - commandLine, & !< command line call as string - loadCaseArg ='', & !< -l argument given to DAMASK_spectral.exe - geometryArg ='', & !< -g argument given to DAMASK_spectral.exe - workingDirArg ='', & !< -w argument given to DAMASK_spectral.exe - hostName, & !< name of machine on which DAMASK_spectral.exe is execute (might require export HOSTNAME) - userName, & !< name of user calling DAMASK_spectral.exe - tag - integer :: & - i, & - worldrank = 0 - integer, allocatable, dimension(:) :: & - chunkPos - integer, dimension(8) :: & - dateAndTime ! type default integer -#ifdef PETSc - PetscErrorCode :: ierr -#endif - external :: & - quit,& - MPI_Comm_rank,& - PETScInitialize, & - MPI_abort - -!-------------------------------------------------------------------------------------------------- -! PETSc Init -#ifdef PETSc - call PetscInitialize(PETSC_NULL_CHARACTER,ierr) ! according to PETSc manual, that should be the first line in the code - CHKERRQ(ierr) ! this is a macro definition, it is case sensitive - - open(6, encoding='UTF-8') ! modern fortran compilers (gfortran >4.4, ifort >11 support it) - call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) -#endif - mainProcess: if (worldrank == 0) then - call date_and_time(values = dateAndTime) - write(6,'(/,a)') ' <<<+- DAMASK_spectral -+>>>' - write(6,'(/,a)') ' Version: '//DAMASKVERSION - write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& - dateAndTime(2),'/',& - dateAndTime(1) - write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& - dateAndTime(6),':',& - dateAndTime(7) - write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' -#include "compilation_info.f90" - endif mainProcess - - if ( present(loadcaseParameterIn) .and. present(geometryParameterIn)) then ! both mandatory parameters given in function call - geometryArg = geometryParameterIn - loadcaseArg = loadcaseParameterIn - commandLine = 'n/a' - else if ( .not.( present(loadcaseParameterIn) .and. present(geometryParameterIn))) then ! none parameters given in function call, trying to get them from command line - call get_command(commandLine) - chunkPos = IIO_stringPos(commandLine) - do i = 1, chunkPos(1) - tag = IIO_lc(IIO_stringValue(commandLine,chunkPos,i)) ! extract key - select case(tag) - case ('-h','--help') - mainProcess2: if (worldrank == 0) then - write(6,'(a)') ' #######################################################################' - write(6,'(a)') ' DAMASK_spectral:' - write(6,'(a)') ' The spectral method boundary value problem solver for' - write(6,'(a)') ' the Düsseldorf Advanced Material Simulation Kit' - write(6,'(a,/)')' #######################################################################' - write(6,'(a,/)')' Valid command line switches:' - write(6,'(a)') ' --geom (-g, --geometry)' - write(6,'(a)') ' --load (-l, --loadcase)' - write(6,'(a)') ' --workingdir (-w, --wd, --workingdirectory, -d, --directory)' - write(6,'(a)') ' --restart (-r, --rs)' - write(6,'(a)') ' --regrid (--rg)' - write(6,'(a)') ' --help (-h)' - write(6,'(/,a)')' -----------------------------------------------------------------------' - write(6,'(a)') ' Mandatory arguments:' - write(6,'(/,a)')' --geom PathToGeomFile/NameOfGeom.geom' - write(6,'(a)') ' Specifies the location of the geometry definition file,' - write(6,'(a)') ' if no extension is given, .geom will be appended.' - write(6,'(a)') ' "PathToGeomFile" will be the working directory if not specified' - write(6,'(a)') ' via --workingdir.' - write(6,'(a)') ' Make sure the file "material.config" exists in the working' - write(6,'(a)') ' directory.' - write(6,'(a)') ' For further configuration place "numerics.config"' - write(6,'(a)')' and "numerics.config" in that directory.' - write(6,'(/,a)')' --load PathToLoadFile/NameOfLoadFile.load' - write(6,'(a)') ' Specifies the location of the load case definition file,' - write(6,'(a)') ' if no extension is given, .load will be appended.' - write(6,'(/,a)')' -----------------------------------------------------------------------' - write(6,'(a)') ' Optional arguments:' - write(6,'(/,a)')' --workingdirectory PathToWorkingDirectory' - write(6,'(a)') ' Specifies the working directory and overwrites the default' - write(6,'(a)') ' "PathToGeomFile".' - write(6,'(a)') ' Make sure the file "material.config" exists in the working' - write(6,'(a)') ' directory.' - write(6,'(a)') ' For further configuration place "numerics.config"' - write(6,'(a)')' and "numerics.config" in that directory.' - write(6,'(/,a)')' --restart XX' - write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' - write(6,'(a)') ' calculate total increment No. XX.' - write(6,'(a)') ' Appends to existing results file ' - write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' - write(6,'(a)') ' Works only if the restart information for total increment' - write(6,'(a)') ' No. XX-1 is available in the working directory.' - write(6,'(/,a)')' --regrid XX' - write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' - write(6,'(a)') ' calculate total increment No. XX.' - write(6,'(a)') ' Attention: Overwrites existing results file ' - write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' - write(6,'(a)') ' Works only if the restart information for total increment' - write(6,'(a)') ' No. XX-1 is available in the working directory.' - write(6,'(/,a)')' -----------------------------------------------------------------------' - write(6,'(a)') ' Help:' - write(6,'(/,a)')' --help' - write(6,'(a,/)')' Prints this message and exits' - call quit(0_pInt) ! normal Termination - endif mainProcess2 - case ('-l', '--load', '--loadcase') - loadcaseArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) - case ('-g', '--geom', '--geometry') - geometryArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) - case ('-w', '-d', '--wd', '--directory', '--workingdir', '--workingdirectory') - workingDirArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) - case ('-r', '--rs', '--restart') - spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) - appendToOutFile = .true. - case ('--rg', '--regrid') - spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) - appendToOutFile = .false. - end select - enddo - endif - - if (len(trim(loadcaseArg)) == 0 .or. len(trim(geometryArg)) == 0) then - write(6,'(a)') ' Please specify geometry AND load case (-h for help)' - call quit(1_pInt) - endif - - workingDirectory = storeWorkingDirectory(trim(workingDirArg),trim(geometryArg)) - geometryFile = getGeometryFile(geometryArg) - loadCaseFile = getLoadCaseFile(loadCaseArg) - - call get_environment_variable('HOSTNAME',hostName) - call get_environment_variable('USER',userName) - mainProcess3: if (worldrank == 0) then - write(6,'(a,a)') ' Host name: ', trim(hostName) - write(6,'(a,a)') ' User name: ', trim(userName) - write(6,'(a,a)') ' Path separator: ', getPathSep() - write(6,'(a,a)') ' Command line call: ', trim(commandLine) - if (len(trim(workingDirArg))>0) & - write(6,'(a,a)') ' Working dir argument: ', trim(workingDirArg) - write(6,'(a,a)') ' Geometry argument: ', trim(geometryArg) - write(6,'(a,a)') ' Loadcase argument: ', trim(loadcaseArg) - write(6,'(a,a)') ' Working directory: ', trim(getSolverWorkingDirectoryName()) - write(6,'(a,a)') ' Geometry file: ', trim(geometryFile) - write(6,'(a,a)') ' Loadcase file: ', trim(loadCaseFile) - write(6,'(a,a)') ' Solver job name: ', trim(getSolverJobName()) - if (SpectralRestartInc > 1_pInt) & - write(6,'(a,i6.6)') ' Restart at increment: ', spectralRestartInc - write(6,'(a,l1,/)') ' Append to result file: ', appendToOutFile - endif mainProcess3 - -end subroutine DAMASK_interface_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief extract working directory from given argument or from location of geometry file, -!! possibly converting relative arguments to absolut path -!> @todo change working directory with call chdir(storeWorkingDirectory)? -!-------------------------------------------------------------------------------------------------- -character(len=1024) function storeWorkingDirectory(workingDirectoryArg,geometryArg) -#ifdef __INTEL_COMPILER - use IFPORT -#endif - - implicit none - character(len=*), intent(in) :: workingDirectoryArg !< working directory argument - character(len=*), intent(in) :: geometryArg !< geometry argument - character(len=1024) :: cwd - character :: pathSep - logical :: dirExists - external :: quit - integer :: error - - pathSep = getPathSep() - if (len(workingDirectoryArg)>0) then ! got working directory as input - if (workingDirectoryArg(1:1) == pathSep) then ! absolute path given as command line argument - storeWorkingDirectory = workingDirectoryArg - else - error = getcwd(cwd) ! relative path given as command line argument - storeWorkingDirectory = trim(cwd)//pathSep//workingDirectoryArg - endif - if (storeWorkingDirectory(len(trim(storeWorkingDirectory)):len(trim(storeWorkingDirectory))) & ! if path seperator is not given, append it - /= pathSep) storeWorkingDirectory = trim(storeWorkingDirectory)//pathSep -#ifdef __INTEL_COMPILER - inquire(directory = trim(storeWorkingDirectory)//'.', exist=dirExists) -#else - inquire(file = trim(storeWorkingDirectory), exist=dirExists) -#endif - if(.not. dirExists) then ! check if the directory exists - write(6,'(a20,a,a16)') ' working directory "',trim(storeWorkingDirectory),'" does not exist' - call quit(1_pInt) - endif - else ! using path to geometry file as working dir - if (geometryArg(1:1) == pathSep) then ! absolute path given as command line argument - storeWorkingDirectory = geometryArg(1:scan(geometryArg,pathSep,back=.true.)) - else - error = getcwd(cwd) ! relative path given as command line argument - storeWorkingDirectory = trim(cwd)//pathSep//& - geometryArg(1:scan(geometryArg,pathSep,back=.true.)) - endif - endif - storeWorkingDirectory = rectifyPath(storeWorkingDirectory) - -end function storeWorkingDirectory - - -!-------------------------------------------------------------------------------------------------- -!> @brief simply returns the private string workingDir -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getSolverWorkingDirectoryName() - - implicit none - getSolverWorkingDirectoryName = workingDirectory - -end function getSolverWorkingDirectoryName - - -!-------------------------------------------------------------------------------------------------- -!> @brief solver job name (no extension) as combination of geometry and load case name -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getSolverJobName() - - implicit none - integer :: posExt,posSep - character :: pathSep - character(len=1024) :: tempString - - pathSep = getPathSep() - - tempString = geometryFile - posExt = scan(tempString,'.',back=.true.) - posSep = scan(tempString,pathSep,back=.true.) - - getSolverJobName = tempString(posSep+1:posExt-1) - - tempString = loadCaseFile - posExt = scan(tempString,'.',back=.true.) - posSep = scan(tempString,pathSep,back=.true.) - - getSolverJobName = trim(getSolverJobName)//'_'//tempString(posSep+1:posExt-1) - -end function getSolverJobName - - -!-------------------------------------------------------------------------------------------------- -!> @brief basename of geometry file with extension from command line arguments -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getGeometryFile(geometryParameter) -#ifdef __INTEL_COMPILER - use IFPORT -#endif - - implicit none - character(len=1024), intent(in) :: & - geometryParameter - character(len=1024) :: & - cwd - integer :: posExt, posSep - character :: pathSep - integer :: error - - getGeometryFile = geometryParameter - pathSep = getPathSep() - posExt = scan(getGeometryFile,'.',back=.true.) - posSep = scan(getGeometryFile,pathSep,back=.true.) - - if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') ! no extension present - if (scan(getGeometryFile,pathSep) /= 1) then ! relative path given as command line argument - error = getcwd(cwd) - getGeometryFile = rectifyPath(trim(cwd)//pathSep//getGeometryFile) - else - getGeometryFile = rectifyPath(getGeometryFile) - endif - - getGeometryFile = makeRelativePath(getSolverWorkingDirectoryName(), getGeometryFile) - -end function getGeometryFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief relative path of loadcase from command line arguments -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getLoadCaseFile(loadCaseParameter) -#ifdef __INTEL_COMPILER - use IFPORT -#endif - - implicit none - character(len=1024), intent(in) :: & - loadCaseParameter - character(len=1024) :: & - cwd - integer :: posExt, posSep, error - character :: pathSep - - getLoadCaseFile = loadcaseParameter - pathSep = getPathSep() - posExt = scan(getLoadCaseFile,'.',back=.true.) - posSep = scan(getLoadCaseFile,pathSep,back=.true.) - - if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') ! no extension present - if (scan(getLoadCaseFile,pathSep) /= 1) then ! relative path given as command line argument - error = getcwd(cwd) - getLoadCaseFile = rectifyPath(trim(cwd)//pathSep//getLoadCaseFile) - else - getLoadCaseFile = rectifyPath(getLoadCaseFile) - endif - - getLoadCaseFile = makeRelativePath(getSolverWorkingDirectoryName(), getLoadCaseFile) - -end function getLoadCaseFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief remove ../ and /./ from path -!-------------------------------------------------------------------------------------------------- -function rectifyPath(path) - - implicit none - character(len=*) :: path - character(len=len_trim(path)) :: rectifyPath - character :: pathSep - integer :: i,j,k,l ! no pInt - - pathSep = getPathSep() - -!-------------------------------------------------------------------------------------------------- -! remove /./ from path - l = len_trim(path) - rectifyPath = path - do i = l,3,-1 - if (rectifyPath(i-2:i) == pathSep//'.'//pathSep) & - rectifyPath(i-1:l) = rectifyPath(i+1:l)//' ' - enddo - -!-------------------------------------------------------------------------------------------------- -! remove ../ and corresponding directory from rectifyPath - l = len_trim(rectifyPath) - i = index(rectifyPath(i:l),'..'//pathSep) - j = 0 - do while (i > j) - j = scan(rectifyPath(1:i-2),pathSep,back=.true.) - rectifyPath(j+1:l) = rectifyPath(i+3:l)//repeat(' ',2+i-j) - if (rectifyPath(j+1:j+1) == pathSep) then !search for '//' that appear in case of XXX/../../XXX - k = len_trim(rectifyPath) - rectifyPath(j+1:k-1) = rectifyPath(j+2:k) - rectifyPath(k:k) = ' ' - endif - i = j+index(rectifyPath(j+1:l),'..'//pathSep) - enddo - if(len_trim(rectifyPath) == 0) rectifyPath = pathSep - -end function rectifyPath - - -!-------------------------------------------------------------------------------------------------- -!> @brief relative path from absolute a to absolute b -!-------------------------------------------------------------------------------------------------- -character(len=1024) function makeRelativePath(a,b) - - implicit none - character (len=*) :: a,b - character :: pathSep - integer :: i,posLastCommonSlash,remainingSlashes !no pInt - - pathSep = getPathSep() - posLastCommonSlash = 0 - remainingSlashes = 0 - - do i = 1, min(1024,len_trim(a),len_trim(b)) - if (a(i:i) /= b(i:i)) exit - if (a(i:i) == pathSep) posLastCommonSlash = i - enddo - do i = posLastCommonSlash+1,len_trim(a) - if (a(i:i) == pathSep) remainingSlashes = remainingSlashes + 1 - enddo - makeRelativePath = repeat('..'//pathSep,remainingSlashes)//b(posLastCommonSlash+1:len_trim(b)) - -end function makeRelativePath - - -!-------------------------------------------------------------------------------------------------- -!> @brief counting / and \ in $PATH System variable the character occuring more often is assumed -! to be the path separator -!-------------------------------------------------------------------------------------------------- -character function getPathSep() - - implicit none - character(len=2048) :: & - path - integer(pInt) :: & - backslash = 0_pInt, & - slash = 0_pInt - integer :: i - - call get_environment_variable('PATH',path) - do i=1, len(trim(path)) - if (path(i:i)=='/') slash = slash + 1_pInt - if (path(i:i)=='\') backslash = backslash + 1_pInt - enddo - - if (backslash>slash) then - getPathSep = '\' - else - getPathSep = '/' - endif - -end function getPathSep - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_stringValue for documentation -!-------------------------------------------------------------------------------------------------- -pure function IIO_stringValue(string,chunkPos,myChunk) - - implicit none - integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - character(len=1+chunkPos(myChunk*2+1)-chunkPos(myChunk*2)) :: IIO_stringValue - character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - - - valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then - IIO_stringValue = '' - else valuePresent - IIO_stringValue = string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) - endif valuePresent - -end function IIO_stringValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_intValue for documentation -!-------------------------------------------------------------------------------------------------- -integer(pInt) pure function IIO_intValue(string,chunkPos,myChunk) - - implicit none - character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - integer(pInt), intent(in) :: myChunk !< position number of desired sub string - integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string - - - valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then - IIO_intValue = 0_pInt - else valuePresent - read(UNIT=string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)),ERR=100,FMT=*) IIO_intValue - endif valuePresent - return -100 IIO_intValue = huge(1_pInt) - -end function IIO_intValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_lc for documentation -!-------------------------------------------------------------------------------------------------- -pure function IIO_lc(string) - - implicit none - character(len=*), intent(in) :: string !< string to convert - character(len=len(string)) :: IIO_lc - - character(26), parameter :: LOWER = 'abcdefghijklmnopqrstuvwxyz' - character(26), parameter :: UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - - integer :: i,n ! no pInt (len returns default integer) - - IIO_lc = string - do i=1,len(string) - n = index(UPPER,IIO_lc(i:i)) - if (n/=0) IIO_lc(i:i) = LOWER(n:n) - enddo - -end function IIO_lc - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_stringPos for documentation -!-------------------------------------------------------------------------------------------------- -pure function IIO_stringPos(string) - - implicit none - integer(pInt), dimension(:), allocatable :: IIO_stringPos - character(len=*), intent(in) :: string !< string in which chunks are searched for - - character(len=*), parameter :: SEP=achar(44)//achar(32)//achar(9)//achar(10)//achar(13) ! comma and whitespaces - integer :: left, right ! no pInt (verify and scan return default integer) - - allocate(IIO_stringPos(1), source=0_pInt) - right = 0 - - do while (verify(string(right+1:),SEP)>0) - left = right + verify(string(right+1:),SEP) - right = left + scan(string(left:),SEP) - 2 - if ( string(left:left) == '#' ) exit - IIO_stringPos = [IIO_stringPos,int(left, pInt), int(right, pInt)] - IIO_stringPos(1) = IIO_stringPos(1)+1_pInt - enddo - -end function IIO_stringPos - - -end module diff --git a/code/spectral_mech_AL.f90 b/code/spectral_mech_AL.f90 deleted file mode 100644 index a937dcc86..000000000 --- a/code/spectral_mech_AL.f90 +++ /dev/null @@ -1,715 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief AL scheme solver -!-------------------------------------------------------------------------------------------------- -module spectral_mech_AL - use prec, only: & - pInt, & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - - implicit none - private -#include - - character (len=*), parameter, public :: & - DAMASK_spectral_solverAL_label = 'al' - -!-------------------------------------------------------------------------------------------------- -! derived types - type(tSolutionParams), private :: params - real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! PETSc data - DM, private :: da - SNES, private :: snes - Vec, private :: solution_vec - -!-------------------------------------------------------------------------------------------------- -! common pointwise data - real(pReal), private, dimension(:,:,:,:,:), allocatable :: & - F_lastInc, & !< field of previous compatible deformation gradients - F_lambda_lastInc, & !< field of previous incompatible deformation gradient - Fdot, & !< field of assumed rate of compatible deformation gradient - F_lambdaDot !< field of assumed rate of incopatible deformation gradient - -!-------------------------------------------------------------------------------------------------- -! stress, stiffness and compliance average etc. - real(pReal), private, dimension(3,3) :: & - F_aimDot, & !< assumed rate of average deformation gradient - F_aim = math_I3, & !< current prescribed deformation gradient - F_aim_lastInc = math_I3, & !< previous average deformation gradient - F_av = 0.0_pReal, & !< average incompatible def grad field - P_av = 0.0_pReal, & !< average 1st Piola--Kirchhoff stress - P_avLastEval = 0.0_pReal !< average 1st Piola--Kirchhoff stress last call of CPFEM_general - character(len=1024), private :: incInfo !< time and increment information - real(pReal), private, dimension(3,3,3,3) :: & - C_volAvg = 0.0_pReal, & !< current volume average stiffness - C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness - C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness - S = 0.0_pReal, & !< current compliance (filled up with zeros) - C_scale = 0.0_pReal, & - S_scale = 0.0_pReal - - real(pReal), private :: & - err_BC, & !< deviation from stress BC - err_curl, & !< RMS of curl of F - err_div !< RMS of div of P - logical, private :: ForwardData - integer(pInt), private :: & - totalIter = 0_pInt !< total iteration in current increment - - public :: & - AL_init, & - AL_solution, & - AL_forward, & - AL_destroy - external :: & - VecDestroy, & - DMDestroy, & - DMDACreate3D, & - DMCreateGlobalVector, & - DMDASNESSetFunctionLocal, & - PETScFinalize, & - SNESDestroy, & - SNESGetNumberFunctionEvals, & - SNESGetIterationNumber, & - SNESSolve, & - SNESSetDM, & - SNESGetConvergedReason, & - SNESSetConvergenceTest, & - SNESSetFromOptions, & - SNESCreate, & - MPI_Abort, & - MPI_Bcast, & - MPI_Allreduce - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields and fills them with data, potentially from restart info -!> @todo use sourced allocation, e.g. allocate(Fdot,source = F_lastInc) -!-------------------------------------------------------------------------------------------------- -subroutine AL_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_intOut, & - IO_read_realFile, & - IO_timeStamp - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRestart - use FEsolving, only: & - restartInc - use numerics, only: & - worldrank, & - worldsize - use DAMASK_interface, only: & - getSolverJobName - use spectral_utilities, only: & - Utilities_constitutiveResponse, & - Utilities_updateGamma, & - Utilities_updateIPcoords - use mesh, only: & - grid, & - grid3 - use math, only: & - math_invSym3333 - - implicit none - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal - - PetscErrorCode :: ierr - PetscObject :: dummy - PetscScalar, pointer, dimension(:,:,:,:) :: xx_psc, F, F_lambda - integer(pInt), dimension(:), allocatable :: localK - integer(pInt) :: proc - character(len=1024) :: rankStr - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverAL init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif - -!-------------------------------------------------------------------------------------------------- -! 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_lambda_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - allocate (F_lambdaDot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - -!-------------------------------------------------------------------------------------------------- -! PETSc Init - call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do proc = 1, worldsize - call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary - DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & ! global grid - 1 , 1, worldsize, & - 18, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) - grid(1),grid(2),localK, & ! local grid - da,ierr) ! handle, error - CHKERRQ(ierr) - call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) - call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) - call DMDASNESSetFunctionLocal(da,INSERT_VALUES,AL_formResidual,dummy,ierr) - CHKERRQ(ierr) - call SNESSetConvergenceTest(snes,AL_converged,dummy,PETSC_NULL_FUNCTION,ierr) - CHKERRQ(ierr) - call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) - -!-------------------------------------------------------------------------------------------------- -! init fields - call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! places pointer xx_psc on PETSc data - F => xx_psc(0:8,:,:,:) - F_lambda => xx_psc(9:17,:,:,:) - restart: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading values of increment ', restartInc - 1_pInt, ' from file' - flush(6) - write(rankStr,'(a1,i0)')'_',worldrank - call IO_read_realFile(777,'F'//trim(rankStr), trim(getSolverJobName()),size(F)) - read (777,rec=1) F - close (777) - call IO_read_realFile(777,'F_lastInc'//trim(rankStr), trim(getSolverJobName()),size(F_lastInc)) - read (777,rec=1) F_lastInc - close (777) - call IO_read_realFile(777,'F_lambda'//trim(rankStr),trim(getSolverJobName()),size(F_lambda)) - read (777,rec=1) F_lambda - close (777) - call IO_read_realFile(777,'F_lambda_lastInc'//trim(rankStr),& - trim(getSolverJobName()),size(F_lambda_lastInc)) - read (777,rec=1) F_lambda_lastInc - close (777) - call IO_read_realFile(777,'F_aim', trim(getSolverJobName()),size(F_aim)) - read (777,rec=1) F_aim - close (777) - call IO_read_realFile(777,'F_aim_lastInc', trim(getSolverJobName()),size(F_aim_lastInc)) - read (777,rec=1) F_aim_lastInc - close (777) - call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) - read (777,rec=1) f_aimDot - close (777) - elseif (restartInc == 1_pInt) then restart - F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity - F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) - F_lambda = F - F_lambda_lastInc = F_lastInc - endif restart - - - call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) - call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & - 0.0_pReal,P,C_volAvg,C_minMaxAvg,temp33_Real,.false.,math_I3) - nullify(F) - nullify(F_lambda) - call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! write data back to PETSc - - readRestart: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading more values of increment', restartInc - 1_pInt, 'from file' - flush(6) - call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) - read (777,rec=1) C_volAvg - close (777) - call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) - read (777,rec=1) C_volAvgLastInc - close (777) - call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) - read (777,rec=1) C_minMaxAvg - close (777) - endif readRestart - - call Utilities_updateGamma(C_minMaxAvg,.True.) - C_scale = C_minMaxAvg - S_scale = math_invSym3333(C_minMaxAvg) - -end subroutine AL_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief solution for the AL scheme with internal iterations -!-------------------------------------------------------------------------------------------------- -type(tSolutionState) function & - AL_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) - use IO, only: & - IO_error - use numerics, only: & - update_gamma - use math, only: & - math_invSym3333 - use spectral_utilities, only: & - tBoundaryCondition, & - Utilities_maskedCompliance, & - Utilities_updateGamma - use FEsolving, only: & - restartWrite, & - terminallyIll - - implicit none - -!-------------------------------------------------------------------------------------------------- -! input data for solution - real(pReal), intent(in) :: & - timeinc, & !< increment in time for current solution - timeinc_old, & !< increment in time of last increment - loadCaseTime !< remaining time of current load case - logical, intent(in) :: & - guess - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - character(len=*), intent(in) :: & - incInfoIn - real(pReal), dimension(3,3), intent(in) :: rotation_BC - -!-------------------------------------------------------------------------------------------------- -! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - - incInfo = incInfoIn - -!-------------------------------------------------------------------------------------------------- -! update stiffness (and gamma operator) - S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) - if (update_gamma) then - call Utilities_updateGamma(C_minMaxAvg,restartWrite) - C_scale = C_minMaxAvg - S_scale = math_invSym3333(C_minMaxAvg) - endif - -!-------------------------------------------------------------------------------------------------- -! set module wide availabe data - mask_stress = P_BC%maskFloat - params%P_BC = P_BC%values - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old - -!-------------------------------------------------------------------------------------------------- -! solve BVP - call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) - CHKERRQ(ierr) - -!-------------------------------------------------------------------------------------------------- -! check convergence - call SNESGetConvergedReason(snes,reason,ierr) - CHKERRQ(ierr) - AL_solution%termIll = terminallyIll - terminallyIll = .false. - if (reason == -4) call IO_error(893_pInt) - if (reason < 1) AL_solution%converged = .false. - AL_solution%iterationsNeeded = totalIter - -end function AL_solution - - -!-------------------------------------------------------------------------------------------------- -!> @brief forms the AL residual vector -!-------------------------------------------------------------------------------------------------- -subroutine AL_formResidual(in,x_scal,f_scal,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - polarAlpha, & - polarBeta, & - worldrank - use mesh, only: & - grid3, & - grid - use IO, only: & - IO_intOut - use math, only: & - math_rotate_backward33, & - math_transpose33, & - math_mul3333xx33, & - math_invSym3333, & - math_mul33x33 - use spectral_utilities, only: & - wgt, & - tensorField_real, & - utilities_FFTtensorForward, & - utilities_fourierGammaConvolution, & - utilities_FFTtensorBackward, & - Utilities_constitutiveResponse, & - Utilities_divergenceRMS, & - Utilities_curlRMS - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRotation - use homogenization, only: & - materialpoint_dPdF - use FEsolving, only: & - terminallyIll - - implicit none -!-------------------------------------------------------------------------------------------------- -! strange syntax in the next line because otherwise macros expand beyond 132 character limit - DMDALocalInfo, dimension(& - DMDA_LOCAL_INFO_SIZE) :: & - in - PetscScalar, target, dimension(3,3,2, & - XG_RANGE,YG_RANGE,ZG_RANGE) :: & - x_scal - PetscScalar, target, dimension(3,3,2, & - X_RANGE,Y_RANGE,Z_RANGE) :: & - f_scal - PetscScalar, pointer, dimension(:,:,:,:,:) :: & - F, & - F_lambda, & - residual_F, & - residual_F_lambda - PetscInt :: & - PETScIter, & - nfuncs - PetscObject :: dummy - PetscErrorCode :: ierr - integer(pInt) :: & - i, j, k, e - - F => x_scal(1:3,1:3,1,& - XG_RANGE,YG_RANGE,ZG_RANGE) - F_lambda => x_scal(1:3,1:3,2,& - XG_RANGE,YG_RANGE,ZG_RANGE) - residual_F => f_scal(1:3,1:3,1,& - X_RANGE,Y_RANGE,Z_RANGE) - residual_F_lambda => f_scal(1:3,1:3,2,& - X_RANGE,Y_RANGE,Z_RANGE) - - call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) - call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) - - F_av = sum(sum(sum(F,dim=5),dim=4),dim=3) * wgt - call MPI_Allreduce(MPI_IN_PLACE,F_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - - if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment - newIteration: if(totalIter <= PETScIter) then -!-------------------------------------------------------------------------------------------------- -! report begin of new iteration - totalIter = totalIter + 1_pInt - if (worldrank == 0_pInt) then - write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & - ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax - if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & - math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & - math_transpose33(F_aim) - flush(6) - endif - endif newIteration - -!-------------------------------------------------------------------------------------------------- -! - tensorField_real = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) - tensorField_real(1:3,1:3,i,j,k) = & - polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& - polarAlpha*math_mul33x33(F(1:3,1:3,i,j,k), & - math_mul3333xx33(C_scale,F_lambda(1:3,1:3,i,j,k) - math_I3)) - - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! doing convolution in Fourier space - call utilities_FFTtensorForward() - call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) - call utilities_FFTtensorBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - residual_F_lambda = polarBeta*F - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) - -!-------------------------------------------------------------------------------------------------- -! evaluate constitutive response - P_avLastEval = P_av - call Utilities_constitutiveResponse(F_lastInc,F - residual_F_lambda/polarBeta,params%timeinc, & - residual_F,C_volAvg,C_minMaxAvg,P_av,ForwardData,params%rotation_BC) - call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) - ForwardData = .False. - -!-------------------------------------------------------------------------------------------------- -! calculate divergence - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = residual_F - call utilities_FFTtensorForward() - err_div = Utilities_divergenceRMS() - call utilities_FFTtensorBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - e = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) - e = e + 1_pInt - residual_F(1:3,1:3,i,j,k) = math_mul3333xx33(math_invSym3333(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & - residual_F(1:3,1:3,i,j,k) - & - math_mul33x33(F(1:3,1:3,i,j,k), & - math_mul3333xx33(C_scale,F_lambda(1:3,1:3,i,j,k) - math_I3))) & - + residual_F_lambda(1:3,1:3,i,j,k) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! calculating curl - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F - call utilities_FFTtensorForward() - err_curl = Utilities_curlRMS() - call utilities_FFTtensorBackward() - -end subroutine AL_formResidual - - -!-------------------------------------------------------------------------------------------------- -!> @brief convergence check -!-------------------------------------------------------------------------------------------------- -subroutine AL_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - err_div_tolRel, & - err_div_tolAbs, & - err_curl_tolRel, & - err_curl_tolAbs, & - err_stress_tolAbs, & - err_stress_tolRel, & - worldrank - use math, only: & - math_mul3333xx33 - use FEsolving, only: & - terminallyIll - - implicit none - SNES :: snes_local - PetscInt :: PETScIter - PetscReal :: & - xnorm, & - snorm, & - fnorm - SNESConvergedReason :: reason - PetscObject :: dummy - PetscErrorCode ::ierr - real(pReal) :: & - curlTol, & - divTol, & - BC_tol - -!-------------------------------------------------------------------------------------------------- -! stress BC handling - F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc - err_BC = maxval(abs((-mask_stress+1.0_pReal)*math_mul3333xx33(C_scale,F_aim-F_av) + & - mask_stress *(P_av - params%P_BC))) ! mask = 0.0 for no bc - -!-------------------------------------------------------------------------------------------------- -! error calculation - curlTol = max(maxval(abs(F_aim-math_I3))*err_curl_tolRel,err_curl_tolAbs) - divTol = max(maxval(abs(P_av)) *err_div_tolRel,err_div_tolAbs) - BC_tol = max(maxval(abs(P_av)) *err_stress_tolrel,err_stress_tolabs) - - converged: if ((totalIter >= itmin .and. & - all([ err_div/divTol, & - err_curl/curlTol, & - err_BC/BC_tol ] < 1.0_pReal)) & - .or. terminallyIll) then - reason = 1 - elseif (totalIter >= itmax) then converged - reason = -1 - else converged - reason = 0 - endif converged - -!-------------------------------------------------------------------------------------------------- -! report - if (worldrank == 0_pInt) then - write(6,'(1/,a)') ' ... reporting .............................................................' - write(6,'(/,a,f12.2,a,es8.2,a,es9.2,a)') ' error curl = ', & - err_curl/curlTol,' (',err_curl,' -, tol =',curlTol,')' - write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & - err_div/divTol, ' (',err_div, ' / m, tol =',divTol,')' - write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error BC = ', & - err_BC/BC_tol, ' (',err_BC, ' Pa, tol =',BC_tol,')' - write(6,'(/,a)') ' ===========================================================================' - flush(6) - endif - -end subroutine AL_converged - -!-------------------------------------------------------------------------------------------------- -!> @brief forwarding routine -!-------------------------------------------------------------------------------------------------- -subroutine AL_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) - use math, only: & - math_mul33x33, & - math_mul3333xx33, & - math_transpose33, & - math_rotate_backward33 - use numerics, only: & - worldrank - use mesh, only: & - grid3, & - grid - use spectral_utilities, only: & - Utilities_calculateRate, & - Utilities_forwardField, & - Utilities_updateIPcoords, & - tBoundaryCondition, & - cutBack - use IO, only: & - IO_write_JobRealFile - use FEsolving, only: & - restartWrite - - implicit none - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - real(pReal), dimension(3,3), intent(in) :: rotation_BC - logical, intent(in) :: & - guess - PetscErrorCode :: ierr - PetscScalar, dimension(:,:,:,:), pointer :: xx_psc, F, F_lambda - integer(pInt) :: i, j, k - real(pReal), dimension(3,3) :: F_lambda33 - character(len=1024) :: rankStr - -!-------------------------------------------------------------------------------------------------- -! update coordinates and rate and forward last inc - call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr) - F => xx_psc(0:8,:,:,:) - F_lambda => xx_psc(9:17,:,:,:) - if (restartWrite) then - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' writing converged results for restart' - flush(6) - endif - write(rankStr,'(a1,i0)')'_',worldrank - call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file - write (777,rec=1) F - close (777) - call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file - write (777,rec=1) F_lastInc - close (777) - call IO_write_jobRealFile(777,'F_lambda'//trim(rankStr),size(F_lambda)) ! writing deformation gradient field to file - write (777,rec=1) F_lambda - close (777) - call IO_write_jobRealFile(777,'F_lambda_lastInc'//trim(rankStr),size(F_lambda_lastInc)) ! writing F_lastInc field to file - write (777,rec=1) F_lambda_lastInc - close (777) - if (worldrank == 0_pInt) then - call IO_write_jobRealFile(777,'F_aim',size(F_aim)) - write (777,rec=1) F_aim - close(777) - call IO_write_jobRealFile(777,'F_aim_lastInc',size(F_aim_lastInc)) - write (777,rec=1) F_aim_lastInc - close(777) - call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) - write (777,rec=1) F_aimDot - close(777) - call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) - write (777,rec=1) C_volAvg - close(777) - call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) - write (777,rec=1) C_volAvgLastInc - close(777) - endif - endif - - call utilities_updateIPcoords(F) - - if (cutBack) then - F_aim = F_aim_lastInc - F_lambda = reshape(F_lambda_lastInc,[9,grid(1),grid(2),grid3]) - F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) - C_volAvg = C_volAvgLastInc - else - ForwardData = .True. - C_volAvgLastInc = C_volAvg -!-------------------------------------------------------------------------------------------------- -! calculate rate for aim - if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F - f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) - elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed - f_aimDot = F_BC%maskFloat * F_BC%values - elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed - f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime - endif - if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old - F_aim_lastInc = F_aim - -!-------------------------------------------------------------------------------------------------- -! update coordinates and rate and forward last inc - call utilities_updateIPcoords(F) - Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & - timeinc_old,guess,F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3])) - F_lambdaDot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & - timeinc_old,guess,F_lambda_lastInc,reshape(F_lambda,[3,3,grid(1),grid(2),grid3])) - F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) - F_lambda_lastInc = reshape(F_lambda,[3,3,grid(1),grid(2),grid3]) - endif - - F_aim = F_aim + f_aimDot * timeinc - -!-------------------------------------------------------------------------------------------------- -! update local deformation gradient - F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim - math_rotate_backward33(F_aim,rotation_BC)), & - [9,grid(1),grid(2),grid3]) - F_lambda = reshape(Utilities_forwardField(timeinc,F_lambda_lastInc,F_lambdadot), & - [9,grid(1),grid(2),grid3]) ! does not have any average value as boundary condition - if (.not. guess) then ! large strain forwarding - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) - F_lambda33 = reshape(F_lambda(1:9,i,j,k),[3,3]) - F_lambda33 = math_mul3333xx33(S_scale,math_mul33x33(F_lambda33, & - math_mul3333xx33(C_scale,& - math_mul33x33(math_transpose33(F_lambda33),& - F_lambda33) -math_I3))*0.5_pReal)& - + math_I3 - F_lambda(1:9,i,j,k) = reshape(F_lambda33,[9]) - enddo; enddo; enddo - endif - call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) - -end subroutine AL_forward - -!-------------------------------------------------------------------------------------------------- -!> @brief destroy routine -!-------------------------------------------------------------------------------------------------- -subroutine AL_destroy() - use spectral_utilities, only: & - Utilities_destroy - - implicit none - PetscErrorCode :: ierr - - call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) - call SNESDestroy(snes,ierr); CHKERRQ(ierr) - call DMDestroy(da,ierr); CHKERRQ(ierr) - -end subroutine AL_destroy - -end module spectral_mech_AL diff --git a/code/spectral_mech_Basic.f90 b/code/spectral_mech_Basic.f90 deleted file mode 100644 index a8344fabe..000000000 --- a/code/spectral_mech_Basic.f90 +++ /dev/null @@ -1,569 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Basic scheme PETSc solver -!-------------------------------------------------------------------------------------------------- -module spectral_mech_basic - use prec, only: & - pInt, & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - - implicit none - private -#include - - character (len=*), parameter, public :: & - DAMASK_spectral_SolverBasicPETSC_label = 'basicpetsc' - -!-------------------------------------------------------------------------------------------------- -! derived types - type(tSolutionParams), private :: params - -!-------------------------------------------------------------------------------------------------- -! PETSc data - DM, private :: da - SNES, private :: snes - Vec, private :: solution_vec - -!-------------------------------------------------------------------------------------------------- -! common pointwise data - real(pReal), private, dimension(:,:,:,:,:), allocatable :: F_lastInc, Fdot - -!-------------------------------------------------------------------------------------------------- -! stress, stiffness and compliance average etc. - real(pReal), private, dimension(3,3) :: & - F_aim = math_I3, & - F_aim_lastIter = math_I3, & - F_aim_lastInc = math_I3, & - P_av = 0.0_pReal, & - F_aimDot=0.0_pReal - character(len=1024), private :: incInfo - real(pReal), private, dimension(3,3,3,3) :: & - C_volAvg = 0.0_pReal, & !< current volume average stiffness - C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness - C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness - S = 0.0_pReal !< current compliance (filled up with zeros) - real(pReal), private :: err_stress, err_div - logical, private :: ForwardData - integer(pInt), private :: & - totalIter = 0_pInt !< total iteration in current increment - real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal - - public :: & - basicPETSc_init, & - basicPETSc_solution, & - BasicPETSc_forward, & - basicPETSc_destroy - external :: & - VecDestroy, & - DMDestroy, & - DMDACreate3D, & - DMCreateGlobalVector, & - DMDASNESSetFunctionLocal, & - PETScFinalize, & - SNESDestroy, & - SNESGetNumberFunctionEvals, & - SNESGetIterationNumber, & - SNESSolve, & - SNESSetDM, & - SNESGetConvergedReason, & - SNESSetConvergenceTest, & - SNESSetFromOptions, & - SNESCreate, & - MPI_Abort, & - MPI_Bcast, & - MPI_Allreduce - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields and fills them with data, potentially from restart info -!-------------------------------------------------------------------------------------------------- -subroutine basicPETSc_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_intOut, & - IO_read_realFile, & - IO_timeStamp - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRestart - use FEsolving, only: & - restartInc - use numerics, only: & - worldrank, & - worldsize - use DAMASK_interface, only: & - getSolverJobName - use spectral_utilities, only: & - Utilities_constitutiveResponse, & - Utilities_updateGamma, & - utilities_updateIPcoords, & - wgt - use mesh, only: & - grid, & - grid3 - use math, only: & - math_invSym3333 - - implicit none - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P - PetscScalar, dimension(:,:,:,:), pointer :: F - PetscErrorCode :: ierr - PetscObject :: dummy - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal - integer(pInt), dimension(:), allocatable :: localK - integer(pInt) :: proc - character(len=1024) :: rankStr - - mainProcess: if (worldrank == 0_pInt) then - write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverBasicPETSc init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!-------------------------------------------------------------------------------------------------- -! 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) - -!-------------------------------------------------------------------------------------------------- -! initialize solver specific parts of PETSc - call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do proc = 1, worldsize - call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary - DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & ! global grid - 1, 1, worldsize, & - 9, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) - grid (1),grid (2),localK, & ! local grid - da,ierr) ! handle, error - CHKERRQ(ierr) - call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) - call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) ! global solution vector (grid x 9, i.e. every def grad tensor) - call DMDASNESSetFunctionLocal(da,INSERT_VALUES,BasicPETSC_formResidual,dummy,ierr) ! residual vector of same shape as solution vector - CHKERRQ(ierr) - call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) ! connect snes to da - call SNESSetConvergenceTest(snes,BasicPETSC_converged,dummy,PETSC_NULL_FUNCTION,ierr) ! specify custom convergence check function "_converged" - CHKERRQ(ierr) - call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments - -!-------------------------------------------------------------------------------------------------- -! init fields - call DMDAVecGetArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) ! get the data out of PETSc to work with - - restart: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading values of increment ', restartInc - 1_pInt, ' from file' - flush(6) - write(rankStr,'(a1,i0)')'_',worldrank - call IO_read_realFile(777,'F'//trim(rankStr),trim(getSolverJobName()),size(F)) - read (777,rec=1) F - close (777) - call IO_read_realFile(777,'F_lastInc'//trim(rankStr),trim(getSolverJobName()),size(F_lastInc)) - read (777,rec=1) F_lastInc - close (777) - call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) - read (777,rec=1) f_aimDot - close (777) - F_aim = reshape(sum(sum(sum(F,dim=4),dim=3),dim=2) * wgt, [3,3]) ! average of F - F_aim_lastInc = sum(sum(sum(F_lastInc,dim=5),dim=4),dim=3) * wgt ! average of F_lastInc - elseif (restartInc == 1_pInt) then restart - F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity - F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) - endif restart - - call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) - call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & - 0.0_pReal, & - P, & - C_volAvg,C_minMaxAvg, & ! global average of stiffness and (min+max)/2 - temp33_Real, & - .false., & - math_I3) - - call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) ! write data back to PETSc - - restartRead: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading more values of increment', restartInc - 1_pInt, 'from file' - flush(6) - call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) - read (777,rec=1) C_volAvg - close (777) - call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) - read (777,rec=1) C_volAvgLastInc - close (777) - call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) - read (777,rec=1) C_minMaxAvg - close (777) - endif restartRead - - call Utilities_updateGamma(C_minmaxAvg,.True.) - -end subroutine basicPETSc_init - -!-------------------------------------------------------------------------------------------------- -!> @brief solution for the Basic PETSC scheme with internal iterations -!-------------------------------------------------------------------------------------------------- -type(tSolutionState) function & - basicPETSc_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) - use IO, only: & - IO_error - use numerics, only: & - update_gamma - use spectral_utilities, only: & - tBoundaryCondition, & - Utilities_maskedCompliance, & - Utilities_updateGamma - use FEsolving, only: & - restartWrite, & - terminallyIll - - implicit none - -!-------------------------------------------------------------------------------------------------- -! input data for solution - real(pReal), intent(in) :: & - timeinc, & !< increment in time for current solution - timeinc_old, & !< increment in time of last increment - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - character(len=*), intent(in) :: & - incInfoIn - real(pReal), dimension(3,3), intent(in) :: rotation_BC - logical, intent(in) :: & - guess - -!-------------------------------------------------------------------------------------------------- -! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - incInfo = incInfoIn - -!-------------------------------------------------------------------------------------------------- -! update stiffness (and gamma operator) - S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) - if (update_gamma) call Utilities_updateGamma(C_minmaxAvg,restartWrite) - - -!-------------------------------------------------------------------------------------------------- -! set module wide availabe data - mask_stress = P_BC%maskFloat - params%P_BC = P_BC%values - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old - -!-------------------------------------------------------------------------------------------------- -! solve BVP - call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) - CHKERRQ(ierr) - -!-------------------------------------------------------------------------------------------------- -! check convergence - call SNESGetConvergedReason(snes,reason,ierr) - CHKERRQ(ierr) - basicPETSc_solution%termIll = terminallyIll - terminallyIll = .false. - BasicPETSc_solution%converged =.true. - if (reason == -4) call IO_error(893_pInt) - if (reason < 1) basicPETSC_solution%converged = .false. - basicPETSC_solution%iterationsNeeded = totalIter - -end function BasicPETSc_solution - - -!-------------------------------------------------------------------------------------------------- -!> @brief forms the AL residual vector -!-------------------------------------------------------------------------------------------------- -subroutine BasicPETSC_formResidual(in,x_scal,f_scal,dummy,ierr) - use numerics, only: & - itmax, & - itmin - use numerics, only: & - worldrank - use mesh, only: & - grid, & - grid3 - use math, only: & - math_rotate_backward33, & - math_transpose33, & - math_mul3333xx33 - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRotation - use spectral_utilities, only: & - tensorField_real, & - utilities_FFTtensorForward, & - utilities_FFTtensorBackward, & - utilities_fourierGammaConvolution, & - Utilities_constitutiveResponse, & - Utilities_divergenceRMS - use IO, only: & - IO_intOut - use FEsolving, only: & - terminallyIll - - implicit none - DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & - in - PetscScalar, dimension(3,3, & - XG_RANGE,YG_RANGE,ZG_RANGE) :: & - x_scal - PetscScalar, dimension(3,3, & - X_RANGE,Y_RANGE,Z_RANGE) :: & - f_scal - PetscInt :: & - PETScIter, & - nfuncs - PetscObject :: dummy - PetscErrorCode :: ierr - - call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) - call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) - - if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment - newIteration: if (totalIter <= PETScIter) then -!-------------------------------------------------------------------------------------------------- -! report begin of new iteration - totalIter = totalIter + 1_pInt - if (worldrank == 0_pInt) then - write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & - ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax - if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & - math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & - math_transpose33(F_aim) - flush(6) - endif - endif newIteration - -!-------------------------------------------------------------------------------------------------- -! evaluate constitutive response - call Utilities_constitutiveResponse(F_lastInc,x_scal,params%timeinc, & - f_scal,C_volAvg,C_minmaxAvg,P_av,ForwardData,params%rotation_BC) - call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) - ForwardData = .false. - -!-------------------------------------------------------------------------------------------------- -! stress BC handling - F_aim_lastIter = F_aim - F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc - err_stress = maxval(abs(mask_stress * (P_av - params%P_BC))) ! mask = 0.0 for no bc - -!-------------------------------------------------------------------------------------------------- -! updated deformation gradient using fix point algorithm of basic scheme - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = f_scal - call utilities_FFTtensorForward() - err_div = Utilities_divergenceRMS() - call utilities_fourierGammaConvolution(math_rotate_backward33(F_aim_lastIter-F_aim,params%rotation_BC)) - call utilities_FFTtensorBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - f_scal = tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) - -end subroutine BasicPETSc_formResidual - - -!-------------------------------------------------------------------------------------------------- -!> @brief convergence check -!-------------------------------------------------------------------------------------------------- -subroutine BasicPETSc_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - err_div_tolRel, & - err_div_tolAbs, & - err_stress_tolRel, & - err_stress_tolAbs, & - worldrank - use FEsolving, only: & - terminallyIll - - implicit none - SNES :: snes_local - PetscInt :: PETScIter - PetscReal :: & - xnorm, & - snorm, & - fnorm - SNESConvergedReason :: reason - PetscObject :: dummy - PetscErrorCode :: ierr - real(pReal) :: & - divTol, & - stressTol - - divTol = max(maxval(abs(P_av))*err_div_tolRel,err_div_tolAbs) - stressTol = max(maxval(abs(P_av))*err_stress_tolrel,err_stress_tolabs) - - converged: if ((totalIter >= itmin .and. & - all([ err_div/divTol, & - err_stress/stressTol ] < 1.0_pReal)) & - .or. terminallyIll) then - reason = 1 - elseif (totalIter >= itmax) then converged - reason = -1 - else converged - reason = 0 - endif converged - -!-------------------------------------------------------------------------------------------------- -! report - if (worldrank == 0_pInt) then - write(6,'(1/,a)') ' ... reporting .............................................................' - write(6,'(1/,a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & - err_div/divTol, ' (',err_div,' / m, tol =',divTol,')' - write(6,'(a,f12.2,a,es8.2,a,es9.2,a)') ' error stress BC = ', & - err_stress/stressTol, ' (',err_stress, ' Pa, tol =',stressTol,')' - write(6,'(/,a)') ' ===========================================================================' - flush(6) - endif - -end subroutine BasicPETSc_converged - -!-------------------------------------------------------------------------------------------------- -!> @brief forwarding routine -!-------------------------------------------------------------------------------------------------- -subroutine BasicPETSc_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) - use math, only: & - math_mul33x33 ,& - math_rotate_backward33 - use mesh, only: & - grid, & - grid3 - use spectral_utilities, only: & - Utilities_calculateRate, & - Utilities_forwardField, & - utilities_updateIPcoords, & - tBoundaryCondition, & - cutBack - use IO, only: & - IO_write_JobRealFile - use FEsolving, only: & - restartWrite - use numerics, only: & - worldrank - - implicit none - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - real(pReal), dimension(3,3), intent(in) :: rotation_BC - logical, intent(in) :: & - guess - PetscScalar, pointer :: F(:,:,:,:) - PetscErrorCode :: ierr - character(len=1024) :: rankStr - - call DMDAVecGetArrayF90(da,solution_vec,F,ierr) -!-------------------------------------------------------------------------------------------------- -! restart information for spectral solver - if (restartWrite) then - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' writing converged results for restart' - flush(6) - endif - write(rankStr,'(a1,i0)')'_',worldrank - call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file - write (777,rec=1) F - close (777) - call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file - write (777,rec=1) F_lastInc - close (777) - if (worldrank == 0_pInt) then - call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) - write (777,rec=1) F_aimDot - close(777) - call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) - write (777,rec=1) C_volAvg - close(777) - call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) - write (777,rec=1) C_volAvgLastInc - close(777) - endif - endif - - call utilities_updateIPcoords(F) - - if (cutBack) then - F_aim = F_aim_lastInc - F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) - C_volAvg = C_volAvgLastInc - else - ForwardData = .True. - C_volAvgLastInc = C_volAvg -!-------------------------------------------------------------------------------------------------- -! calculate rate for aim - if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F - f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) - elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed - f_aimDot = F_BC%maskFloat * F_BC%values - elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed - f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime - endif - if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old - F_aim_lastInc = F_aim - -!-------------------------------------------------------------------------------------------------- -! update coordinates and rate and forward last inc - call utilities_updateIPcoords(F) - Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & - timeinc_old,guess,F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3])) - F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) - endif - F_aim = F_aim + f_aimDot * timeinc - -!-------------------------------------------------------------------------------------------------- -! update local deformation gradient - F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim - math_rotate_backward33(F_aim,rotation_BC)),[9,grid(1),grid(2),grid3]) - call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) - -end subroutine BasicPETSc_forward - -!-------------------------------------------------------------------------------------------------- -!> @brief destroy routine -!-------------------------------------------------------------------------------------------------- -subroutine BasicPETSc_destroy() - use spectral_utilities, only: & - Utilities_destroy - - implicit none - PetscErrorCode :: ierr - - call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) - call SNESDestroy(snes,ierr); CHKERRQ(ierr) - call DMDestroy(da,ierr); CHKERRQ(ierr) - -end subroutine BasicPETSc_destroy - -end module spectral_mech_basic diff --git a/code/spectral_mech_Polarisation.f90 b/code/spectral_mech_Polarisation.f90 deleted file mode 100644 index a28eb5adb..000000000 --- a/code/spectral_mech_Polarisation.f90 +++ /dev/null @@ -1,712 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Polarisation scheme solver -!-------------------------------------------------------------------------------------------------- -module spectral_mech_Polarisation - use prec, only: & - pInt, & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - - implicit none - private -#include - - character (len=*), parameter, public :: & - DAMASK_spectral_solverPolarisation_label = 'polarisation' - -!-------------------------------------------------------------------------------------------------- -! derived types - type(tSolutionParams), private :: params - real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! PETSc data - DM, private :: da - SNES, private :: snes - Vec, private :: solution_vec - -!-------------------------------------------------------------------------------------------------- -! common pointwise data - real(pReal), private, dimension(:,:,:,:,:), allocatable :: & - F_lastInc, & !< field of previous compatible deformation gradients - F_tau_lastInc, & !< field of previous incompatible deformation gradient - Fdot, & !< field of assumed rate of compatible deformation gradient - F_tauDot !< field of assumed rate of incopatible deformation gradient - -!-------------------------------------------------------------------------------------------------- -! stress, stiffness and compliance average etc. - real(pReal), private, dimension(3,3) :: & - F_aimDot, & !< assumed rate of average deformation gradient - F_aim = math_I3, & !< current prescribed deformation gradient - F_aim_lastInc = math_I3, & !< previous average deformation gradient - F_av = 0.0_pReal, & !< average incompatible def grad field - P_av = 0.0_pReal, & !< average 1st Piola--Kirchhoff stress - P_avLastEval = 0.0_pReal !< average 1st Piola--Kirchhoff stress last call of CPFEM_general - character(len=1024), private :: incInfo !< time and increment information - real(pReal), private, dimension(3,3,3,3) :: & - C_volAvg = 0.0_pReal, & !< current volume average stiffness - C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness - C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness - S = 0.0_pReal, & !< current compliance (filled up with zeros) - C_scale = 0.0_pReal, & - S_scale = 0.0_pReal - - real(pReal), private :: & - err_BC, & !< deviation from stress BC - err_curl, & !< RMS of curl of F - err_div !< RMS of div of P - logical, private :: ForwardData - integer(pInt), private :: & - totalIter = 0_pInt !< total iteration in current increment - - public :: & - Polarisation_init, & - Polarisation_solution, & - Polarisation_forward, & - Polarisation_destroy - external :: & - VecDestroy, & - DMDestroy, & - DMDACreate3D, & - DMCreateGlobalVector, & - DMDASNESSetFunctionLocal, & - PETScFinalize, & - SNESDestroy, & - SNESGetNumberFunctionEvals, & - SNESGetIterationNumber, & - SNESSolve, & - SNESSetDM, & - SNESGetConvergedReason, & - SNESSetConvergenceTest, & - SNESSetFromOptions, & - SNESCreate, & - MPI_Abort, & - MPI_Bcast, & - MPI_Allreduce - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields and fills them with data, potentially from restart info -!> @todo use sourced allocation, e.g. allocate(Fdot,source = F_lastInc) -!-------------------------------------------------------------------------------------------------- -subroutine Polarisation_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_intOut, & - IO_read_realFile, & - IO_timeStamp - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRestart - use FEsolving, only: & - restartInc - use numerics, only: & - worldrank, & - worldsize - use DAMASK_interface, only: & - getSolverJobName - use spectral_utilities, only: & - Utilities_constitutiveResponse, & - Utilities_updateGamma, & - Utilities_updateIPcoords - use mesh, only: & - grid, & - grid3 - use math, only: & - math_invSym3333 - - implicit none - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal - - PetscErrorCode :: ierr - PetscObject :: dummy - PetscScalar, pointer, dimension(:,:,:,:) :: xx_psc, F, F_tau - integer(pInt), dimension(:), allocatable :: localK - integer(pInt) :: proc - character(len=1024) :: rankStr - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverPolarisation init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif - -!-------------------------------------------------------------------------------------------------- -! 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_tau_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - allocate (F_tauDot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - -!-------------------------------------------------------------------------------------------------- -! PETSc Init - call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do proc = 1, worldsize - call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary - DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & ! global grid - 1 , 1, worldsize, & - 18, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) - grid (1),grid (2),localK, & ! local grid - da,ierr) ! handle, error - CHKERRQ(ierr) - call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) - call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) - call DMDASNESSetFunctionLocal(da,INSERT_VALUES,Polarisation_formResidual,dummy,ierr) - CHKERRQ(ierr) - call SNESSetConvergenceTest(snes,Polarisation_converged,dummy,PETSC_NULL_FUNCTION,ierr) - CHKERRQ(ierr) - call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) - -!-------------------------------------------------------------------------------------------------- -! init fields - call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! places pointer xx_psc on PETSc data - F => xx_psc(0:8,:,:,:) - F_tau => xx_psc(9:17,:,:,:) - restart: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading values of increment', restartInc - 1_pInt, 'from file' - flush(6) - write(rankStr,'(a1,i0)')'_',worldrank - call IO_read_realFile(777,'F'//trim(rankStr),trim(getSolverJobName()),size(F)) - read (777,rec=1) F - close (777) - call IO_read_realFile(777,'F_lastInc'//trim(rankStr),trim(getSolverJobName()),size(F_lastInc)) - read (777,rec=1) F_lastInc - close (777) - call IO_read_realFile(777,'F_tau'//trim(rankStr),trim(getSolverJobName()),size(F_tau)) - read (777,rec=1) F_tau - close (777) - call IO_read_realFile(777,'F_tau_lastInc'//trim(rankStr),& - trim(getSolverJobName()),size(F_tau_lastInc)) - read (777,rec=1) F_tau_lastInc - close (777) - call IO_read_realFile(777,'F_aim', trim(getSolverJobName()),size(F_aim)) - read (777,rec=1) F_aim - close (777) - call IO_read_realFile(777,'F_aim_lastInc', trim(getSolverJobName()),size(F_aim_lastInc)) - read (777,rec=1) F_aim_lastInc - close (777) - call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) - read (777,rec=1) f_aimDot - close (777) - elseif (restartInc == 1_pInt) then restart - F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity - F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) - F_tau = 2.0_pReal* F - F_tau_lastInc = 2.0_pReal*F_lastInc - endif restart - - call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) - call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & - 0.0_pReal,P,C_volAvg,C_minMaxAvg,temp33_Real,.false.,math_I3) - nullify(F) - nullify(F_tau) - call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! write data back to PETSc - - readRestart: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading more values of increment', restartInc - 1_pInt, 'from file' - flush(6) - call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) - read (777,rec=1) C_volAvg - close (777) - call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) - read (777,rec=1) C_volAvgLastInc - close (777) - call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) - read (777,rec=1) C_minMaxAvg - close (777) - endif readRestart - - call Utilities_updateGamma(C_minMaxAvg,.True.) - C_scale = C_minMaxAvg - S_scale = math_invSym3333(C_minMaxAvg) - -end subroutine Polarisation_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief solution for the Polarisation scheme with internal iterations -!-------------------------------------------------------------------------------------------------- -type(tSolutionState) function & - Polarisation_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) - use IO, only: & - IO_error - use numerics, only: & - update_gamma - use math, only: & - math_invSym3333 - use spectral_utilities, only: & - tBoundaryCondition, & - Utilities_maskedCompliance, & - Utilities_updateGamma - use FEsolving, only: & - restartWrite, & - terminallyIll - - implicit none - -!-------------------------------------------------------------------------------------------------- -! input data for solution - real(pReal), intent(in) :: & - timeinc, & !< increment in time for current solution - timeinc_old, & !< increment in time of last increment - loadCaseTime !< remaining time of current load case - logical, intent(in) :: & - guess - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - character(len=*), intent(in) :: & - incInfoIn - real(pReal), dimension(3,3), intent(in) :: rotation_BC - -!-------------------------------------------------------------------------------------------------- -! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - - incInfo = incInfoIn - -!-------------------------------------------------------------------------------------------------- -! update stiffness (and gamma operator) - S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) - if (update_gamma) then - call Utilities_updateGamma(C_minMaxAvg,restartWrite) - C_scale = C_minMaxAvg - S_scale = math_invSym3333(C_minMaxAvg) - endif - -!-------------------------------------------------------------------------------------------------- -! set module wide availabe data - mask_stress = P_BC%maskFloat - params%P_BC = P_BC%values - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old - -!-------------------------------------------------------------------------------------------------- -! solve BVP - call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) - CHKERRQ(ierr) - -!-------------------------------------------------------------------------------------------------- -! check convergence - call SNESGetConvergedReason(snes,reason,ierr) - CHKERRQ(ierr) - Polarisation_solution%termIll = terminallyIll - terminallyIll = .false. - if (reason == -4) call IO_error(893_pInt) - if (reason < 1) Polarisation_solution%converged = .false. - Polarisation_solution%iterationsNeeded = totalIter - -end function Polarisation_solution - - -!-------------------------------------------------------------------------------------------------- -!> @brief forms the Polarisation residual vector -!-------------------------------------------------------------------------------------------------- -subroutine Polarisation_formResidual(in,x_scal,f_scal,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - polarAlpha, & - polarBeta, & - worldrank - use mesh, only: & - grid3, & - grid - use IO, only: & - IO_intOut - use math, only: & - math_rotate_backward33, & - math_transpose33, & - math_mul3333xx33, & - math_invSym3333, & - math_mul33x33 - use spectral_utilities, only: & - wgt, & - tensorField_real, & - utilities_FFTtensorForward, & - utilities_fourierGammaConvolution, & - utilities_FFTtensorBackward, & - Utilities_constitutiveResponse, & - Utilities_divergenceRMS, & - Utilities_curlRMS - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRotation - use homogenization, only: & - materialpoint_dPdF - use FEsolving, only: & - terminallyIll - - implicit none -!-------------------------------------------------------------------------------------------------- -! strange syntax in the next line because otherwise macros expand beyond 132 character limit - DMDALocalInfo, dimension(& - DMDA_LOCAL_INFO_SIZE) :: & - in - PetscScalar, target, dimension(3,3,2, & - XG_RANGE,YG_RANGE,ZG_RANGE) :: & - x_scal - PetscScalar, target, dimension(3,3,2, & - X_RANGE,Y_RANGE,Z_RANGE) :: & - f_scal - PetscScalar, pointer, dimension(:,:,:,:,:) :: & - F, & - F_tau, & - residual_F, & - residual_F_tau - PetscInt :: & - PETScIter, & - nfuncs - PetscObject :: dummy - PetscErrorCode :: ierr - integer(pInt) :: & - i, j, k, e - - F => x_scal(1:3,1:3,1,& - XG_RANGE,YG_RANGE,ZG_RANGE) - F_tau => x_scal(1:3,1:3,2,& - XG_RANGE,YG_RANGE,ZG_RANGE) - residual_F => f_scal(1:3,1:3,1,& - X_RANGE,Y_RANGE,Z_RANGE) - residual_F_tau => f_scal(1:3,1:3,2,& - X_RANGE,Y_RANGE,Z_RANGE) - - call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) - call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) - - F_av = sum(sum(sum(F,dim=5),dim=4),dim=3) * wgt - call MPI_Allreduce(MPI_IN_PLACE,F_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - - if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment - newIteration: if(totalIter <= PETScIter) then -!-------------------------------------------------------------------------------------------------- -! report begin of new iteration - totalIter = totalIter + 1_pInt - if (worldrank == 0_pInt) then - write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & - ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax - if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & - math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & - math_transpose33(F_aim) - flush(6) - endif - endif newIteration - -!-------------------------------------------------------------------------------------------------- -! - tensorField_real = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) - tensorField_real(1:3,1:3,i,j,k) = & - polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& - polarAlpha*math_mul33x33(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)) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! doing convolution in Fourier space - call utilities_FFTtensorForward() - call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) - call utilities_FFTtensorBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - residual_F_tau = polarBeta*F - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) - -!-------------------------------------------------------------------------------------------------- -! evaluate constitutive response - P_avLastEval = P_av - call Utilities_constitutiveResponse(F_lastInc,F - residual_F_tau/polarBeta,params%timeinc, & - residual_F,C_volAvg,C_minMaxAvg,P_av,ForwardData,params%rotation_BC) - call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) - ForwardData = .False. - -!-------------------------------------------------------------------------------------------------- -! calculate divergence - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = residual_F - call utilities_FFTtensorForward() - err_div = Utilities_divergenceRMS() - call utilities_FFTtensorBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - e = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) - e = e + 1_pInt - residual_F(1:3,1:3,i,j,k) = & - math_mul3333xx33(math_invSym3333(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & - residual_F(1:3,1:3,i,j,k) - math_mul33x33(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) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! calculating curl - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F - call utilities_FFTtensorForward() - err_curl = Utilities_curlRMS() - call utilities_FFTtensorBackward() - -end subroutine Polarisation_formResidual - - -!-------------------------------------------------------------------------------------------------- -!> @brief convergence check -!-------------------------------------------------------------------------------------------------- -subroutine Polarisation_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - err_div_tolRel, & - err_div_tolAbs, & - err_curl_tolRel, & - err_curl_tolAbs, & - err_stress_tolAbs, & - err_stress_tolRel, & - worldrank - use math, only: & - math_mul3333xx33 - use FEsolving, only: & - terminallyIll - - implicit none - SNES :: snes_local - PetscInt :: PETScIter - PetscReal :: & - xnorm, & - snorm, & - fnorm - SNESConvergedReason :: reason - PetscObject :: dummy - PetscErrorCode ::ierr - real(pReal) :: & - curlTol, & - divTol, & - BC_tol - -!-------------------------------------------------------------------------------------------------- -! stress BC handling - F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc - err_BC = maxval(abs((-mask_stress+1.0_pReal)*math_mul3333xx33(C_scale,F_aim-F_av) + & - mask_stress *(P_av - params%P_BC))) ! mask = 0.0 for no bc - -!-------------------------------------------------------------------------------------------------- -! error calculation - curlTol = max(maxval(abs(F_aim-math_I3))*err_curl_tolRel,err_curl_tolAbs) - divTol = max(maxval(abs(P_av)) *err_div_tolRel,err_div_tolAbs) - BC_tol = max(maxval(abs(P_av)) *err_stress_tolrel,err_stress_tolabs) - - converged: if ((totalIter >= itmin .and. & - all([ err_div/divTol, & - err_curl/curlTol, & - err_BC/BC_tol ] < 1.0_pReal)) & - .or. terminallyIll) then - reason = 1 - elseif (totalIter >= itmax) then converged - reason = -1 - else converged - reason = 0 - endif converged - -!-------------------------------------------------------------------------------------------------- -! report -if (worldrank == 0_pInt) then - write(6,'(1/,a)') ' ... reporting .............................................................' - write(6,'(/,a,f12.2,a,es8.2,a,es9.2,a)') ' error curl = ', & - err_curl/curlTol,' (',err_curl,' -, tol =',curlTol,')' - write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & - err_div/divTol, ' (',err_div, ' / m, tol =',divTol,')' - write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error BC = ', & - err_BC/BC_tol, ' (',err_BC, ' Pa, tol =',BC_tol,')' - write(6,'(/,a)') ' ===========================================================================' - flush(6) -endif - -end subroutine Polarisation_converged - -!-------------------------------------------------------------------------------------------------- -!> @brief forwarding routine -!-------------------------------------------------------------------------------------------------- -subroutine Polarisation_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) - use math, only: & - math_mul33x33, & - math_mul3333xx33, & - math_transpose33, & - math_rotate_backward33 - use numerics, only: & - worldrank - use mesh, only: & - grid3, & - grid - use spectral_utilities, only: & - Utilities_calculateRate, & - Utilities_forwardField, & - Utilities_updateIPcoords, & - tBoundaryCondition, & - cutBack - use IO, only: & - IO_write_JobRealFile - use FEsolving, only: & - restartWrite - - implicit none - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - real(pReal), dimension(3,3), intent(in) :: rotation_BC - logical, intent(in) :: & - guess - PetscErrorCode :: ierr - PetscScalar, dimension(:,:,:,:), pointer :: xx_psc, F, F_tau - integer(pInt) :: i, j, k - real(pReal), dimension(3,3) :: F_lambda33 - character(len=1024) :: rankStr - -!-------------------------------------------------------------------------------------------------- -! update coordinates and rate and forward last inc - call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr) - F => xx_psc(0:8,:,:,:) - F_tau => xx_psc(9:17,:,:,:) - if (restartWrite) then - if (worldrank == 0_pInt) write(6,'(/,a)') ' writing converged results for restart' - flush(6) - write(rankStr,'(a1,i0)')'_',worldrank - call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file - write (777,rec=1) F - close (777) - call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file - write (777,rec=1) F_lastInc - close (777) - call IO_write_jobRealFile(777,'F_tau'//trim(rankStr),size(F_tau)) ! writing deformation gradient field to file - write (777,rec=1) F_tau - close (777) - call IO_write_jobRealFile(777,'F_tau_lastInc'//trim(rankStr),size(F_tau_lastInc)) ! writing F_lastInc field to file - write (777,rec=1) F_tau_lastInc - close (777) - if (worldrank == 0_pInt) then - call IO_write_jobRealFile(777,'F_aim',size(F_aim)) - write (777,rec=1) F_aim - close(777) - call IO_write_jobRealFile(777,'F_aim_lastInc',size(F_aim_lastInc)) - write (777,rec=1) F_aim_lastInc - close (777) - call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) - write (777,rec=1) F_aimDot - close(777) - call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) - write (777,rec=1) C_volAvg - close(777) - call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) - write (777,rec=1) C_volAvgLastInc - close(777) - endif - endif - call utilities_updateIPcoords(F) - - if (cutBack) then - F_aim = F_aim_lastInc - F_tau= reshape(F_tau_lastInc,[9,grid(1),grid(2),grid3]) - F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) - C_volAvg = C_volAvgLastInc - else - ForwardData = .True. - C_volAvgLastInc = C_volAvg -!-------------------------------------------------------------------------------------------------- -! calculate rate for aim - if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F - f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) - elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed - f_aimDot = F_BC%maskFloat * F_BC%values - elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed - f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime - endif - if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old - F_aim_lastInc = F_aim - -!-------------------------------------------------------------------------------------------------- -! update coordinates and rate and forward last inc - call utilities_updateIPcoords(F) - Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & - timeinc_old,guess,F_lastInc, & - reshape(F,[3,3,grid(1),grid(2),grid3])) - F_tauDot = Utilities_calculateRate(math_rotate_backward33(2.0_pReal*f_aimDot,rotation_BC), & - timeinc_old,guess,F_tau_lastInc, & - reshape(F_tau,[3,3,grid(1),grid(2),grid3])) - F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) - F_tau_lastInc = reshape(F_tau,[3,3,grid(1),grid(2),grid3]) - endif - - F_aim = F_aim + f_aimDot * timeinc - -!-------------------------------------------------------------------------------------------------- -! update local deformation gradient - F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim - math_rotate_backward33(F_aim,rotation_BC)), & - [9,grid(1),grid(2),grid3]) - F_tau = reshape(Utilities_forwardField(timeinc,F_tau_lastInc,F_taudot), & ! does not have any average value as boundary condition - [9,grid(1),grid(2),grid3]) - if (.not. guess) then ! large strain forwarding - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, 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,math_mul33x33(F_lambda33, & - math_mul3333xx33(C_scale,& - math_mul33x33(math_transpose33(F_lambda33),& - F_lambda33) -math_I3))*0.5_pReal)& - + 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,xx_psc,ierr); CHKERRQ(ierr) - -end subroutine Polarisation_forward - -!-------------------------------------------------------------------------------------------------- -!> @brief destroy routine -!-------------------------------------------------------------------------------------------------- -subroutine Polarisation_destroy() - use spectral_utilities, only: & - Utilities_destroy - - implicit none - PetscErrorCode :: ierr - - call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) - call SNESDestroy(snes,ierr); CHKERRQ(ierr) - call DMDestroy(da,ierr); CHKERRQ(ierr) - -end subroutine Polarisation_destroy - -end module spectral_mech_Polarisation diff --git a/code/spectral_thermal.f90 b/code/spectral_thermal.f90 deleted file mode 100644 index 843642394..000000000 --- a/code/spectral_thermal.f90 +++ /dev/null @@ -1,419 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id: spectral_thermal.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Shaokang Zhang, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Spectral solver for thermal conduction -!-------------------------------------------------------------------------------------------------- -module spectral_thermal - use prec, only: & - pInt, & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - use numerics, only: & - worldrank, & - worldsize - - implicit none - private -#include - - character (len=*), parameter, public :: & - spectral_thermal_label = 'spectralthermal' - -!-------------------------------------------------------------------------------------------------- -! derived types - type(tSolutionParams), private :: params - -!-------------------------------------------------------------------------------------------------- -! PETSc data - SNES, private :: thermal_snes - Vec, private :: solution - PetscInt, private :: xstart, xend, ystart, yend, zstart, zend - real(pReal), private, dimension(:,:,:), allocatable :: & - temperature_current, & !< field of current temperature - temperature_lastInc, & !< field of previous temperature - temperature_stagInc !< field of staggered temperature - -!-------------------------------------------------------------------------------------------------- -! reference diffusion tensor, mobility etc. - integer(pInt), private :: totalIter = 0_pInt !< total iteration in current increment - real(pReal), dimension(3,3), private :: D_ref - real(pReal), private :: mobility_ref - character(len=1024), private :: incInfo - - public :: & - spectral_thermal_init, & - spectral_thermal_solution, & - spectral_thermal_forward, & - spectral_thermal_destroy - external :: & - VecDestroy, & - DMDestroy, & - DMDACreate3D, & - DMCreateGlobalVector, & - DMDASNESSetFunctionLocal, & - PETScFinalize, & - SNESDestroy, & - SNESGetNumberFunctionEvals, & - SNESGetIterationNumber, & - SNESSolve, & - SNESSetDM, & - SNESGetConvergedReason, & - SNESSetConvergenceTest, & - SNESSetFromOptions, & - SNESCreate, & - MPI_Abort, & - MPI_Bcast, & - MPI_Allreduce - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields and fills them with data, potentially from restart info -!-------------------------------------------------------------------------------------------------- -subroutine spectral_thermal_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_intOut, & - IO_read_realFile, & - IO_timeStamp - use spectral_utilities, only: & - wgt - use mesh, only: & - grid, & - grid3 - use thermal_conduction, only: & - thermal_conduction_getConductivity33, & - thermal_conduction_getMassDensity, & - thermal_conduction_getSpecificHeat - use material, only: & - mappingHomogenization, & - temperature, & - thermalMapping - - implicit none - integer(pInt), dimension(:), allocatable :: localK - integer(pInt) :: proc - integer(pInt) :: i, j, k, cell - DM :: thermal_grid - PetscScalar, pointer :: x_scal(:,:,:) - PetscErrorCode :: ierr - PetscObject :: dummy - - mainProcess: if (worldrank == 0_pInt) then - write(6,'(/,a)') ' <<<+- spectral_thermal init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!-------------------------------------------------------------------------------------------------- -! initialize solver specific parts of PETSc - call SNESCreate(PETSC_COMM_WORLD,thermal_snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(thermal_snes,'thermal_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do proc = 1, worldsize - call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary - DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & ! global grid - 1, 1, worldsize, & - 1, 0, & ! #dof (temperature field), ghost boundary width (domain overlap) - grid (1),grid(2),localK, & ! local grid - thermal_grid,ierr) ! handle, error - CHKERRQ(ierr) - call SNESSetDM(thermal_snes,thermal_grid,ierr); CHKERRQ(ierr) ! connect snes to da - call DMCreateGlobalVector(thermal_grid,solution ,ierr); CHKERRQ(ierr) ! global solution vector (grid x 1, i.e. every def grad tensor) - call DMDASNESSetFunctionLocal(thermal_grid,INSERT_VALUES,spectral_thermal_formResidual,dummy,ierr) ! residual vector of same shape as solution vector - CHKERRQ(ierr) - call SNESSetFromOptions(thermal_snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments - -!-------------------------------------------------------------------------------------------------- -! init fields - call DMDAGetCorners(thermal_grid,xstart,ystart,zstart,xend,yend,zend,ierr) - CHKERRQ(ierr) - xend = xstart + xend - 1 - yend = ystart + yend - 1 - zend = zstart + zend - 1 - allocate(temperature_current(grid(1),grid(2),grid3), source=0.0_pReal) - allocate(temperature_lastInc(grid(1),grid(2),grid3), source=0.0_pReal) - allocate(temperature_stagInc(grid(1),grid(2),grid3), source=0.0_pReal) - cell = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - temperature_current(i,j,k) = temperature(mappingHomogenization(2,1,cell))% & - p(thermalMapping(mappingHomogenization(2,1,cell))%p(1,cell)) - temperature_lastInc(i,j,k) = temperature_current(i,j,k) - temperature_stagInc(i,j,k) = temperature_current(i,j,k) - enddo; enddo; enddo - call DMDAVecGetArrayF90(thermal_grid,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with - x_scal(xstart:xend,ystart:yend,zstart:zend) = temperature_current - call DMDAVecRestoreArrayF90(thermal_grid,solution,x_scal,ierr); CHKERRQ(ierr) - - cell = 0_pInt - D_ref = 0.0_pReal - mobility_ref = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - D_ref = D_ref + thermal_conduction_getConductivity33(1,cell) - mobility_ref = mobility_ref + thermal_conduction_getMassDensity(1,cell)* & - thermal_conduction_getSpecificHeat(1,cell) - enddo; enddo; enddo - D_ref = D_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - mobility_ref = mobility_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - -end subroutine spectral_thermal_init - -!-------------------------------------------------------------------------------------------------- -!> @brief solution for the Basic PETSC scheme with internal iterations -!-------------------------------------------------------------------------------------------------- -type(tSolutionState) function spectral_thermal_solution(guess,timeinc,timeinc_old,loadCaseTime) - use numerics, only: & - itmax, & - err_thermal_tolAbs, & - err_thermal_tolRel - use spectral_utilities, only: & - tBoundaryCondition, & - Utilities_maskedCompliance, & - Utilities_updateGamma - use mesh, only: & - grid, & - grid3 - use thermal_conduction, only: & - thermal_conduction_putTemperatureAndItsRate - - implicit none - -!-------------------------------------------------------------------------------------------------- -! input data for solution - real(pReal), intent(in) :: & - timeinc, & !< increment in time for current solution - timeinc_old, & !< increment in time of last increment - loadCaseTime !< remaining time of current load case - logical, intent(in) :: guess - integer(pInt) :: i, j, k, cell - PetscInt :: position - PetscReal :: minTemperature, maxTemperature, stagNorm, solnNorm - -!-------------------------------------------------------------------------------------------------- -! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - - spectral_thermal_solution%converged =.false. - -!-------------------------------------------------------------------------------------------------- -! set module wide availabe data - params%timeinc = timeinc - params%timeincOld = timeinc_old - - call SNESSolve(thermal_snes,PETSC_NULL_OBJECT,solution,ierr); CHKERRQ(ierr) - call SNESGetConvergedReason(thermal_snes,reason,ierr); CHKERRQ(ierr) - - if (reason < 1) then - spectral_thermal_solution%converged = .false. - spectral_thermal_solution%iterationsNeeded = itmax - else - spectral_thermal_solution%converged = .true. - spectral_thermal_solution%iterationsNeeded = totalIter - endif - stagNorm = maxval(abs(temperature_current - temperature_stagInc)) - solnNorm = maxval(abs(temperature_current)) - call MPI_Allreduce(MPI_IN_PLACE,stagNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) - call MPI_Allreduce(MPI_IN_PLACE,solnNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) - temperature_stagInc = temperature_current - spectral_thermal_solution%stagConverged = stagNorm < err_thermal_tolAbs & - .or. stagNorm < err_thermal_tolRel*solnNorm - -!-------------------------------------------------------------------------------------------------- -! updating thermal state - cell = 0_pInt !< material point = 0 - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt !< material point increase - call thermal_conduction_putTemperatureAndItsRate(temperature_current(i,j,k), & - (temperature_current(i,j,k)-temperature_lastInc(i,j,k))/params%timeinc, & - 1,cell) - enddo; enddo; enddo - - call VecMin(solution,position,minTemperature,ierr); CHKERRQ(ierr) - call VecMax(solution,position,maxTemperature,ierr); CHKERRQ(ierr) - if (worldrank == 0) then - if (spectral_thermal_solution%converged) & - write(6,'(/,a)') ' ... thermal conduction converged ..................................' - write(6,'(/,a,f8.4,2x,f8.4,2x,f8.4,/)',advance='no') ' Minimum|Maximum|Delta Temperature = ',& - minTemperature, maxTemperature, stagNorm - write(6,'(/,a)') ' ===========================================================================' - flush(6) - endif - -end function spectral_thermal_solution - - -!-------------------------------------------------------------------------------------------------- -!> @brief forms the spectral thermal residual vector -!-------------------------------------------------------------------------------------------------- -subroutine spectral_thermal_formResidual(in,x_scal,f_scal,dummy,ierr) - use mesh, only: & - grid, & - grid3 - use math, only: & - math_mul33x3 - use spectral_utilities, only: & - scalarField_real, & - vectorField_real, & - utilities_FFTvectorForward, & - utilities_FFTvectorBackward, & - utilities_FFTscalarForward, & - utilities_FFTscalarBackward, & - utilities_fourierGreenConvolution, & - utilities_fourierScalarGradient, & - utilities_fourierVectorDivergence - use thermal_conduction, only: & - thermal_conduction_getSourceAndItsTangent, & - thermal_conduction_getConductivity33, & - thermal_conduction_getMassDensity, & - thermal_conduction_getSpecificHeat - - implicit none - DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & - in - PetscScalar, dimension( & - XG_RANGE,YG_RANGE,ZG_RANGE) :: & - x_scal - PetscScalar, dimension( & - X_RANGE,Y_RANGE,Z_RANGE) :: & - f_scal - PetscObject :: dummy - PetscErrorCode :: ierr - integer(pInt) :: i, j, k, cell - real(pReal) :: Tdot, dTdot_dT - - temperature_current = x_scal -!-------------------------------------------------------------------------------------------------- -! evaluate polarization field - scalarField_real = 0.0_pReal - scalarField_real(1:grid(1),1:grid(2),1:grid3) = temperature_current - call utilities_FFTscalarForward() - call utilities_fourierScalarGradient() !< calculate gradient of damage field - call utilities_FFTvectorBackward() - cell = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - vectorField_real(1:3,i,j,k) = math_mul33x3(thermal_conduction_getConductivity33(1,cell) - D_ref, & - vectorField_real(1:3,i,j,k)) - enddo; enddo; enddo - call utilities_FFTvectorForward() - call utilities_fourierVectorDivergence() !< calculate damage divergence in fourier field - call utilities_FFTscalarBackward() - cell = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - call thermal_conduction_getSourceAndItsTangent(Tdot, dTdot_dT, temperature_current(i,j,k), 1, cell) - scalarField_real(i,j,k) = params%timeinc*scalarField_real(i,j,k) + & - params%timeinc*Tdot + & - thermal_conduction_getMassDensity (1,cell)* & - thermal_conduction_getSpecificHeat(1,cell)*(temperature_lastInc(i,j,k) - & - temperature_current(i,j,k)) + & - mobility_ref*temperature_current(i,j,k) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! convolution of damage field with green operator - call utilities_FFTscalarForward() - call utilities_fourierGreenConvolution(D_ref, mobility_ref, params%timeinc) - call utilities_FFTscalarBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - f_scal = temperature_current - scalarField_real(1:grid(1),1:grid(2),1:grid3) - -end subroutine spectral_thermal_formResidual - -!-------------------------------------------------------------------------------------------------- -!> @brief forwarding routine -!-------------------------------------------------------------------------------------------------- -subroutine spectral_thermal_forward(guess,timeinc,timeinc_old,loadCaseTime) - use mesh, only: & - grid, & - grid3 - use spectral_utilities, only: & - cutBack, & - wgt - use thermal_conduction, only: & - thermal_conduction_putTemperatureAndItsRate, & - thermal_conduction_getConductivity33, & - thermal_conduction_getMassDensity, & - thermal_conduction_getSpecificHeat - - implicit none - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - logical, intent(in) :: guess - integer(pInt) :: i, j, k, cell - DM :: dm_local - PetscScalar, pointer :: x_scal(:,:,:) - PetscErrorCode :: ierr - - if (cutBack) then - temperature_current = temperature_lastInc - temperature_stagInc = temperature_lastInc - -!-------------------------------------------------------------------------------------------------- -! reverting thermal field state - cell = 0_pInt !< material point = 0 - call SNESGetDM(thermal_snes,dm_local,ierr); CHKERRQ(ierr) - call DMDAVecGetArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with - x_scal(xstart:xend,ystart:yend,zstart:zend) = temperature_current - call DMDAVecRestoreArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt !< material point increase - call thermal_conduction_putTemperatureAndItsRate(temperature_current(i,j,k), & - (temperature_current(i,j,k) - & - temperature_lastInc(i,j,k))/params%timeinc, & - 1,cell) - enddo; enddo; enddo - else -!-------------------------------------------------------------------------------------------------- -! update rate and forward last inc - temperature_lastInc = temperature_current - cell = 0_pInt - D_ref = 0.0_pReal - mobility_ref = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - D_ref = D_ref + thermal_conduction_getConductivity33(1,cell) - mobility_ref = mobility_ref + thermal_conduction_getMassDensity(1,cell)* & - thermal_conduction_getSpecificHeat(1,cell) - enddo; enddo; enddo - D_ref = D_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - mobility_ref = mobility_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - endif - - end subroutine spectral_thermal_forward - -!-------------------------------------------------------------------------------------------------- -!> @brief destroy routine -!-------------------------------------------------------------------------------------------------- -subroutine spectral_thermal_destroy() - - implicit none - PetscErrorCode :: ierr - - call VecDestroy(solution,ierr); CHKERRQ(ierr) - call SNESDestroy(thermal_snes,ierr); CHKERRQ(ierr) - -end subroutine spectral_thermal_destroy - -end module spectral_thermal diff --git a/code/spectral_utilities.f90 b/code/spectral_utilities.f90 deleted file mode 100644 index bde088ccb..000000000 --- a/code/spectral_utilities.f90 +++ /dev/null @@ -1,1262 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Utilities used by the different spectral solver variants -!-------------------------------------------------------------------------------------------------- -module spectral_utilities - use, intrinsic :: iso_c_binding - use prec, only: & - pReal, & - pInt - use math, only: & - math_I3 - - implicit none - private -#include - include 'fftw3-mpi.f03' - - logical, public :: cutBack =.false. !< cut back of BVP solver in case convergence is not achieved or a material point is terminally ill - integer(pInt), public, parameter :: maxPhaseFields = 2_pInt - integer(pInt), public :: nActiveFields = 0_pInt - -!-------------------------------------------------------------------------------------------------- -! field labels information - enum, bind(c) - enumerator :: FIELD_UNDEFINED_ID, & - FIELD_MECH_ID, & - FIELD_THERMAL_ID, & - FIELD_DAMAGE_ID, & - FIELD_VACANCYDIFFUSION_ID - end enum - -!-------------------------------------------------------------------------------------------------- -! grid related information information - real(pReal), public :: wgt !< weighting factor 1/Nelems - -!-------------------------------------------------------------------------------------------------- -! variables storing information for spectral method and FFTW - integer(pInt), public :: grid1Red !< grid(1)/2 - real (C_DOUBLE), public, dimension(:,:,:,:,:), pointer :: tensorField_real !< real representation (some stress or deformation) of field_fourier - complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:,:), pointer :: tensorField_fourier !< field on which the Fourier transform operates - real(C_DOUBLE), public, dimension(:,:,:,:), pointer :: vectorField_real !< vector field real representation for fftw - complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:), pointer :: vectorField_fourier !< vector field fourier representation for fftw - real(C_DOUBLE), public, dimension(:,:,:), pointer :: scalarField_real !< scalar field real representation for fftw - complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:), pointer :: scalarField_fourier !< scalar field fourier representation for fftw - complex(pReal), private, dimension(:,:,:,:,:,:,:), allocatable :: gamma_hat !< gamma operator (field) for spectral method - complex(pReal), private, dimension(:,:,:,:), allocatable :: xi1st !< wave vector field for first derivatives - complex(pReal), private, dimension(:,:,:,:), allocatable :: xi2nd !< wave vector field for second derivatives - real(pReal), private, dimension(3,3,3,3) :: C_ref !< mechanic reference stiffness - real(pReal), protected, public, dimension(3) :: scaledGeomSize !< scaled geometry size for calculation of divergence (Basic, Basic PETSc) - -!-------------------------------------------------------------------------------------------------- -! plans for FFTW - type(C_PTR), private :: & - planTensorForth, & !< FFTW MPI plan P(x) to P(k) - planTensorBack, & !< FFTW MPI plan F(k) to F(x) - planVectorForth, & !< FFTW MPI plan v(x) to v(k) - planVectorBack, & !< FFTW MPI plan v(k) to v(x) - planScalarForth, & !< FFTW MPI plan s(x) to s(k) - planScalarBack !< FFTW MPI plan s(k) to s(x) - -!-------------------------------------------------------------------------------------------------- -! variables controlling debugging - logical, private :: & - debugGeneral, & !< general debugging of spectral solver - debugRotation, & !< also printing out results in lab frame - debugPETSc !< use some in debug defined options for more verbose PETSc solution - -!-------------------------------------------------------------------------------------------------- -! derived types - type, public :: tSolutionState !< return type of solution from spectral solver variants - logical :: converged = .true. - logical :: regrid = .false. - logical :: stagConverged = .true. - logical :: termIll = .false. - integer(pInt) :: iterationsNeeded = 0_pInt - end type tSolutionState - - type, public :: tBoundaryCondition !< set of parameters defining a boundary condition - real(pReal), dimension(3,3) :: values = 0.0_pReal - real(pReal), dimension(3,3) :: maskFloat = 0.0_pReal - logical, dimension(3,3) :: maskLogical = .false. - character(len=64) :: myType = 'None' - end type tBoundaryCondition - - type, public :: tLoadCase - real(pReal), dimension (3,3) :: rotation = math_I3 !< rotation of BC - type(tBoundaryCondition) :: P, & !< stress BC - deformation !< deformation BC (Fdot or L) - real(pReal) :: time = 0.0_pReal !< length of increment - integer(pInt) :: incs = 0_pInt, & !< number of increments - outputfrequency = 1_pInt, & !< frequency of result writes - restartfrequency = 0_pInt, & !< frequency of restart writes - logscale = 0_pInt !< linear/logarithmic time inc flag - logical :: followFormerTrajectory = .true. !< follow trajectory of former loadcase - integer(kind(FIELD_UNDEFINED_ID)), allocatable :: ID(:) - end type tLoadCase - - type, public :: tSolutionParams !< @todo use here the type definition for a full loadcase including mask - real(pReal), dimension(3,3) :: P_BC, rotation_BC - real(pReal) :: timeinc - real(pReal) :: timeincOld - real(pReal) :: density - end type tSolutionParams - - type(tSolutionParams), private :: params - - type, public :: phaseFieldDataBin !< set of parameters defining a phase field - real(pReal) :: diffusion = 0.0_pReal, & !< thermal conductivity - mobility = 0.0_pReal, & !< thermal mobility - phaseField0 = 0.0_pReal !< homogeneous damage field starting condition - logical :: active = .false. - character(len=64) :: label = '' - end type phaseFieldDataBin - - enum, bind(c) - enumerator :: DERIVATIVE_CONTINUOUS_ID, & - DERIVATIVE_CENTRAL_DIFF_ID, & - DERIVATIVE_FWBW_DIFF_ID - end enum - integer(kind(DERIVATIVE_CONTINUOUS_ID)) :: & - spectral_derivative_ID - - public :: & - utilities_init, & - utilities_updateGamma, & - utilities_FFTtensorForward, & - utilities_FFTtensorBackward, & - utilities_FFTvectorForward, & - utilities_FFTvectorBackward, & - utilities_FFTscalarForward, & - utilities_FFTscalarBackward, & - utilities_fourierGammaConvolution, & - utilities_fourierGreenConvolution, & - utilities_divergenceRMS, & - utilities_curlRMS, & - utilities_fourierScalarGradient, & - utilities_fourierVectorDivergence, & - utilities_fourierVectorGradient, & - utilities_fourierTensorDivergence, & - utilities_maskedCompliance, & - utilities_constitutiveResponse, & - utilities_calculateRate, & - utilities_forwardField, & - utilities_destroy, & - utilities_updateIPcoords, & - FIELD_UNDEFINED_ID, & - FIELD_MECH_ID, & - FIELD_THERMAL_ID, & - FIELD_DAMAGE_ID - private :: & - utilities_getFreqDerivative - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, sets debug flags, create plans for FFTW -!> @details Sets the debug levels for general, divergence, restart and FFTW from the biwise coding -!> provided by the debug module to logicals. -!> Allocates all fields used by FFTW and create the corresponding plans depending on the debug -!> level chosen. -!> Initializes FFTW. -!-------------------------------------------------------------------------------------------------- -subroutine utilities_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_error, & - IO_warning, & - IO_timeStamp, & - IO_open_file - use numerics, only: & - spectral_derivative, & - fftw_planner_flag, & - fftw_timelimit, & - memory_efficient, & - petsc_defaultOptions, & - petsc_options, & - divergence_correction, & - worldrank - use debug, only: & - debug_level, & - debug_SPECTRAL, & - debug_LEVELBASIC, & - debug_SPECTRALDIVERGENCE, & - debug_SPECTRALFFTW, & - debug_SPECTRALPETSC, & - debug_SPECTRALROTATION - use debug, only: & - PETSCDEBUG - use math - use mesh, only: & - grid, & - grid3, & - grid3Offset, & - geomSize - - implicit none - - external :: & - PETScOptionsClear, & - PETScOptionsInsertString, & - MPI_Abort - - PetscErrorCode :: ierr - integer(pInt) :: i, j, k - integer(pInt), dimension(3) :: k_s - type(C_PTR) :: & - tensorField, & !< field containing data for FFTW in real and fourier space (in place) - vectorField, & !< field containing data for FFTW in real space when debugging FFTW (no in place) - scalarField !< field containing data for FFTW in real space when debugging FFTW (no in place) - integer(C_INTPTR_T), dimension(3) :: gridFFTW - integer(C_INTPTR_T) :: alloc_local, local_K, local_K_offset - integer(C_INTPTR_T), parameter :: & - scalarSize = 1_C_INTPTR_T, & - vecSize = 3_C_INTPTR_T, & - tensorSize = 9_C_INTPTR_T - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- spectral_utilities init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!-------------------------------------------------------------------------------------------------- -! set debugging parameters - debugGeneral = iand(debug_level(debug_SPECTRAL),debug_LEVELBASIC) /= 0 - debugRotation = iand(debug_level(debug_SPECTRAL),debug_SPECTRALROTATION) /= 0 - debugPETSc = iand(debug_level(debug_SPECTRAL),debug_SPECTRALPETSC) /= 0 - - if(debugPETSc .and. worldrank == 0_pInt) write(6,'(3(/,a),/)') & - ' Initializing PETSc with debug options: ', & - trim(PETScDebug), & - ' add more using the PETSc_Options keyword in numerics.config ' - flush(6) - call PetscOptionsClear(ierr); CHKERRQ(ierr) - if(debugPETSc) call PetscOptionsInsertString(trim(PETSCDEBUG),ierr); CHKERRQ(ierr) - call PetscOptionsInsertString(trim(petsc_defaultOptions),ierr); CHKERRQ(ierr) - call PetscOptionsInsertString(trim(petsc_options),ierr); CHKERRQ(ierr) - - grid1Red = grid(1)/2_pInt + 1_pInt - wgt = 1.0/real(product(grid),pReal) - - if (worldrank == 0) then - write(6,'(a,3(i12 ))') ' grid a b c: ', grid - write(6,'(a,3(es12.5))') ' size x y z: ', geomSize - endif - - select case (spectral_derivative) - case ('continuous') ! default, no weighting - spectral_derivative_ID = DERIVATIVE_CONTINUOUS_ID - case ('central_difference') ! cosine curve with 1 for avg and zero for highest freq - spectral_derivative_ID = DERIVATIVE_CENTRAL_DIFF_ID - case ('fwbw_difference') ! gradient, might need grid scaling as for cosine filter - spectral_derivative_ID = DERIVATIVE_FWBW_DIFF_ID - case default - call IO_error(892_pInt,ext_msg=trim(spectral_derivative)) - end select - -!-------------------------------------------------------------------------------------------------- -! scale dimension to calculate either uncorrected, dimension-independent, or dimension- and -! resolution-independent divergence - if (divergence_correction == 1_pInt) then - do j = 1_pInt, 3_pInt - if (j /= minloc(geomSize,1) .and. j /= maxloc(geomSize,1)) & - scaledGeomSize = geomSize/geomSize(j) - enddo - elseif (divergence_correction == 2_pInt) then - do j = 1_pInt, 3_pInt - if (j /= minloc(geomSize/grid,1) .and. j /= maxloc(geomSize/grid,1)) & - scaledGeomSize = geomSize/geomSize(j)*grid(j) - enddo - else - scaledGeomSize = geomSize - endif - - -!-------------------------------------------------------------------------------------------------- -! MPI allocation - gridFFTW = int(grid,C_INTPTR_T) - alloc_local = fftw_mpi_local_size_3d(gridFFTW(3), gridFFTW(2), gridFFTW(1)/2 +1, & - MPI_COMM_WORLD, local_K, local_K_offset) - allocate (xi1st (3,grid1Red,grid(2),grid3),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies, only half the size for first dimension - allocate (xi2nd (3,grid1Red,grid(2),grid3),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies, only half the size for first dimension - - tensorField = fftw_alloc_complex(tensorSize*alloc_local) - call c_f_pointer(tensorField, tensorField_real, [3_C_INTPTR_T,3_C_INTPTR_T, & - 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real tensor representation - call c_f_pointer(tensorField, tensorField_fourier, [3_C_INTPTR_T,3_C_INTPTR_T, & - gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T , gridFFTW(2),local_K]) ! place a pointer for a fourier tensor representation - - vectorField = fftw_alloc_complex(vecSize*alloc_local) - call c_f_pointer(vectorField, vectorField_real, [3_C_INTPTR_T,& - 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real vector representation - call c_f_pointer(vectorField, vectorField_fourier,[3_C_INTPTR_T,& - gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T, gridFFTW(2),local_K]) ! place a pointer for a fourier vector representation - - scalarField = fftw_alloc_complex(scalarSize*alloc_local) ! allocate data for real representation (no in place transform) - call c_f_pointer(scalarField, scalarField_real, & - [2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1),gridFFTW(2),local_K]) ! place a pointer for a real scalar representation - call c_f_pointer(scalarField, scalarField_fourier, & - [ gridFFTW(1)/2_C_INTPTR_T + 1 ,gridFFTW(2),local_K]) ! place a pointer for a fourier scarlar representation - -!-------------------------------------------------------------------------------------------------- -! tensor MPI fftw plans - planTensorForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order - tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock - tensorField_real, tensorField_fourier, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planTensorForth)) call IO_error(810, ext_msg='planTensorForth') - planTensorBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order - tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock - tensorField_fourier,tensorField_real, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision - if (.not. C_ASSOCIATED(planTensorBack)) call IO_error(810, ext_msg='planTensorBack') - -!-------------------------------------------------------------------------------------------------- -! vector MPI fftw plans - planVectorForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order - vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock - vectorField_real, vectorField_fourier, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planVectorForth)) call IO_error(810, ext_msg='planVectorForth') - planVectorBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order - vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock - vectorField_fourier,vectorField_real, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision - if (.not. C_ASSOCIATED(planVectorBack)) call IO_error(810, ext_msg='planVectorBack') - -!-------------------------------------------------------------------------------------------------- -! scalar MPI fftw plans - planScalarForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order - scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock - scalarField_real, scalarField_fourier, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planScalarForth)) call IO_error(810, ext_msg='planScalarForth') - planScalarBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order, no. of transforms - scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock - scalarField_fourier,scalarField_real, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planScalarBack)) call IO_error(810, ext_msg='planScalarBack') - -!-------------------------------------------------------------------------------------------------- -! general initialization of FFTW (see manual on fftw.org for more details) - if (pReal /= C_DOUBLE .or. pInt /= C_INT) call IO_error(0_pInt,ext_msg='Fortran to C') ! check for correct precision in C - call fftw_set_timelimit(fftw_timelimit) ! set timelimit for plan creation - - if (debugGeneral .and. worldrank == 0_pInt) write(6,'(/,a)') ' FFTW initialized' - flush(6) - -!-------------------------------------------------------------------------------------------------- -! calculation of discrete angular frequencies, ordered as in FFTW (wrap around) - do k = grid3Offset+1_pInt, grid3Offset+grid3 - k_s(3) = k - 1_pInt - if(k > grid(3)/2_pInt + 1_pInt) k_s(3) = k_s(3) - grid(3) ! running from 0,1,...,N/2,N/2+1,-N/2,-N/2+1,...,-1 - do j = 1_pInt, grid(2) - k_s(2) = j - 1_pInt - if(j > grid(2)/2_pInt + 1_pInt) k_s(2) = k_s(2) - grid(2) ! running from 0,1,...,N/2,N/2+1,-N/2,-N/2+1,...,-1 - do i = 1_pInt, grid1Red - k_s(1) = i - 1_pInt ! symmetry, junst running from 0,1,...,N/2,N/2+1 - xi2nd(1:3,i,j,k-grid3Offset) = utilities_getFreqDerivative(k_s) ! if divergence_correction is set, frequencies are calculated on unit length - where(mod(grid,2)==0 .and. [i,j,k] == grid/2+1 .and. & - spectral_derivative_ID == DERIVATIVE_CONTINUOUS_ID) ! for even grids, set the Nyquist Freq component to 0.0 - xi1st(1:3,i,j,k-grid3Offset) = cmplx(0.0_pReal,0.0_pReal,pReal) - elsewhere - xi1st(1:3,i,j,k-grid3Offset) = xi2nd(1:3,i,j,k-grid3Offset) - endwhere - enddo; enddo; enddo - - if(memory_efficient) then ! allocate just single fourth order tensor - allocate (gamma_hat(3,3,3,3,1,1,1), source = cmplx(0.0_pReal,0.0_pReal,pReal)) - else ! precalculation of gamma_hat field - allocate (gamma_hat(3,3,3,3,grid1Red,grid(2),grid3), source = cmplx(0.0_pReal,0.0_pReal,pReal)) - endif - -end subroutine utilities_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief updates references stiffness and potentially precalculated gamma operator -!> @details Sets the current reference stiffness to the stiffness given as an argument. -!> If the gamma operator is precalculated, it is calculated with this stiffness. -!> In case of a on-the-fly calculation, only the reference stiffness is updated. -!> Also writes out the current reference stiffness for restart. -!-------------------------------------------------------------------------------------------------- -subroutine utilities_updateGamma(C,saveReference) - use IO, only: & - IO_write_jobRealFile - use numerics, only: & - memory_efficient, & - worldrank - use mesh, only: & - grid3Offset, & - grid3,& - grid - use math, only: & - math_det33, & - math_invert - - implicit none - real(pReal), intent(in), dimension(3,3,3,3) :: C !< input stiffness to store as reference stiffness - logical , intent(in) :: saveReference !< save reference stiffness to file for restart - complex(pReal), dimension(3,3) :: temp33_complex, xiDyad_cmplx - real(pReal), dimension(6,6) :: matA, matInvA - integer(pInt) :: & - i, j, k, & - l, m, n, o - logical :: ierr - - C_ref = C - if (saveReference) then - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' writing reference stiffness to file' - flush(6) - call IO_write_jobRealFile(777,'C_ref',size(C_ref)) - write (777,rec=1) C_ref - close(777) - endif - endif - - if(.not. memory_efficient) then - gamma_hat = cmplx(0.0_pReal,0.0_pReal,pReal) ! for the singular point and any non invertible A - do k = grid3Offset+1_pInt, grid3Offset+grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid1Red - if (any([i,j,k] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - xiDyad_cmplx(l,m) = conjg(-xi1st(l,i,j,k-grid3Offset))*xi1st(m,i,j,k-grid3Offset) - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_complex(l,m) = sum(C_ref(l,1:3,m,1:3)*xiDyad_cmplx) - matA(1:3,1:3) = real(temp33_complex); matA(4:6,4:6) = real(temp33_complex) - matA(1:3,4:6) = aimag(temp33_complex); matA(4:6,1:3) = -aimag(temp33_complex) - if (abs(math_det33(matA(1:3,1:3))) > 1e-16) then - call math_invert(6_pInt, matA, matInvA, ierr) - temp33_complex = cmplx(matInvA(1:3,1:3),matInvA(1:3,4:6),pReal) - forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, o=1_pInt:3_pInt) & - gamma_hat(l,m,n,o,i,j,k-grid3Offset) = temp33_complex(l,n)* & - conjg(-xi1st(o,i,j,k-grid3Offset))*xi1st(m,i,j,k-grid3Offset) - endif - endif - enddo; enddo; enddo - endif - -end subroutine utilities_updateGamma - -!-------------------------------------------------------------------------------------------------- -!> @brief forward FFT of data in field_real to field_fourier -!> @details Does an unweighted filtered FFT transform from real to complex -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTtensorForward() - implicit none - -!-------------------------------------------------------------------------------------------------- -! doing the tensor FFT - call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) - -end subroutine utilities_FFTtensorForward - - -!-------------------------------------------------------------------------------------------------- -!> @brief backward FFT of data in field_fourier to field_real -!> @details Does an weighted inverse FFT transform from complex to real -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTtensorBackward() - implicit none - - call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real) - tensorField_real = tensorField_real * wgt ! normalize the result by number of elements - -end subroutine utilities_FFTtensorBackward - -!-------------------------------------------------------------------------------------------------- -!> @brief forward FFT of data in scalarField_real to scalarField_fourier -!> @details Does an unweighted filtered FFT transform from real to complex -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTscalarForward() - implicit none - -!-------------------------------------------------------------------------------------------------- -! doing the scalar FFT - call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier) - -end subroutine utilities_FFTscalarForward - - -!-------------------------------------------------------------------------------------------------- -!> @brief backward FFT of data in scalarField_fourier to scalarField_real -!> @details Does an weighted inverse FFT transform from complex to real -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTscalarBackward() - implicit none - - call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) - scalarField_real = scalarField_real * wgt ! normalize the result by number of elements - -end subroutine utilities_FFTscalarBackward - - -!-------------------------------------------------------------------------------------------------- -!> @brief forward FFT of data in field_real to field_fourier with highest freqs. removed -!> @details Does an unweighted filtered FFT transform from real to complex. -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTvectorForward() - implicit none - -!-------------------------------------------------------------------------------------------------- -! doing the vector FFT - call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier) - -end subroutine utilities_FFTvectorForward - - -!-------------------------------------------------------------------------------------------------- -!> @brief backward FFT of data in field_fourier to field_real -!> @details Does an weighted inverse FFT transform from complex to real -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTvectorBackward() - implicit none - - call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) - vectorField_real = vectorField_real * wgt ! normalize the result by number of elements - -end subroutine utilities_FFTvectorBackward - - -!-------------------------------------------------------------------------------------------------- -!> @brief doing convolution gamma_hat * field_real, ensuring that average value = fieldAim -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierGammaConvolution(fieldAim) - use numerics, only: & - memory_efficient - use math, only: & - math_det33, & - math_invert - use numerics, only: & - worldrank - use mesh, only: & - grid3, & - grid, & - grid3Offset - - implicit none - real(pReal), intent(in), dimension(3,3) :: fieldAim !< desired average value of the field after convolution - complex(pReal), dimension(3,3) :: temp33_complex, xiDyad_cmplx - real(pReal) :: matA(6,6), matInvA(6,6) - - integer(pInt) :: & - i, j, k, & - l, m, n, o - logical :: ierr - - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' ... doing gamma convolution ...............................................' - flush(6) - endif - -!-------------------------------------------------------------------------------------------------- -! do the actual spectral method calculation (mechanical equilibrium) - memoryEfficient: if(memory_efficient) then - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid1Red - if (any([i,j,k+grid3Offset] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - xiDyad_cmplx(l,m) = conjg(-xi1st(l,i,j,k))*xi1st(m,i,j,k) - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_complex(l,m) = sum(C_ref(l,1:3,m,1:3)*xiDyad_cmplx) - matA(1:3,1:3) = real(temp33_complex); matA(4:6,4:6) = real(temp33_complex) - matA(1:3,4:6) = aimag(temp33_complex); matA(4:6,1:3) = -aimag(temp33_complex) - if (abs(math_det33(matA(1:3,1:3))) > 1e-16) then - call math_invert(6_pInt, matA, matInvA, ierr) - temp33_complex = cmplx(matInvA(1:3,1:3),matInvA(1:3,4:6),pReal) - forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, o=1_pInt:3_pInt) & - gamma_hat(l,m,n,o,1,1,1) = temp33_complex(l,n)*conjg(-xi1st(o,i,j,k))*xi1st(m,i,j,k) - else - gamma_hat(1:3,1:3,1:3,1:3,1,1,1) = cmplx(0.0_pReal,0.0_pReal,pReal) - endif - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3,1,1,1)*tensorField_fourier(1:3,1:3,i,j,k)) - tensorField_fourier(1:3,1:3,i,j,k) = temp33_Complex - endif - enddo; enddo; enddo - else memoryEfficient - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3,i,j,k) * tensorField_fourier(1:3,1:3,i,j,k)) - tensorField_fourier(1:3,1:3,i,j,k) = temp33_Complex - enddo; enddo; enddo - endif memoryEfficient - - if (grid3Offset == 0_pInt) & - tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim/wgt,0.0_pReal,pReal) - -end subroutine utilities_fourierGammaConvolution - - -!-------------------------------------------------------------------------------------------------- -!> @brief doing convolution DamageGreenOp_hat * field_real -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierGreenConvolution(D_ref, mobility_ref, deltaT) - - use math, only: & - math_mul33x3, & - PI - use mesh, only: & - grid, & - grid3 - - implicit none - real(pReal), dimension(3,3), intent(in) :: D_ref !< desired average value of the field after convolution - real(pReal), intent(in) :: mobility_ref, deltaT !< desired average value of the field after convolution - complex(pReal) :: GreenOp_hat - integer(pInt) :: i, j, k - -!-------------------------------------------------------------------------------------------------- -! do the actual spectral method calculation - do k = 1_pInt, grid3; do j = 1_pInt, grid(2) ;do i = 1_pInt, grid1Red - GreenOp_hat = cmplx(1.0_pReal,0.0_pReal,pReal)/ & - (cmplx(mobility_ref,0.0_pReal,pReal) + & - deltaT*sum(conjg(xi1st(1:3,i,j,k))*matmul(D_ref,xi1st(1:3,i,j,k)))) ! why not use dot_product - scalarField_fourier(i,j,k) = scalarField_fourier(i,j,k)*GreenOp_hat - enddo; enddo; enddo - -end subroutine utilities_fourierGreenConvolution - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate root mean square of divergence of field_fourier -!-------------------------------------------------------------------------------------------------- -real(pReal) function utilities_divergenceRMS() - use numerics, only: & - worldrank - use mesh, only: & - geomSize, & - grid, & - grid3 - - implicit none - integer(pInt) :: i, j, k - PetscErrorCode :: ierr - - external :: & - MPI_Allreduce - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' ... calculating divergence ................................................' - flush(6) - endif - -!-------------------------------------------------------------------------------------------------- -! calculating RMS divergence criterion in Fourier space - utilities_divergenceRMS = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2) - do i = 2_pInt, grid1Red -1_pInt ! Has somewhere a conj. complex counterpart. Therefore count it twice. - utilities_divergenceRMS = utilities_divergenceRMS & - + 2.0_pReal*(sum (real(matmul(tensorField_fourier(1:3,1:3,i,j,k),& ! (sqrt(real(a)**2 + aimag(a)**2))**2 = real(a)**2 + aimag(a)**2. do not take square root and square again - conjg(-xi1st(1:3,i,j,k))*geomSize/scaledGeomSize))**2.0_pReal)& ! --> sum squared L_2 norm of vector - +sum(aimag(matmul(tensorField_fourier(1:3,1:3,i,j,k),& - conjg(-xi1st(1:3,i,j,k))*geomSize/scaledGeomSize))**2.0_pReal)) - enddo - utilities_divergenceRMS = utilities_divergenceRMS & ! these two layers (DC and Nyquist) do not have a conjugate complex counterpart (if grid(1) /= 1) - + sum( real(matmul(tensorField_fourier(1:3,1:3,1 ,j,k), & - conjg(-xi1st(1:3,1,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & - + sum(aimag(matmul(tensorField_fourier(1:3,1:3,1 ,j,k), & - conjg(-xi1st(1:3,1,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & - + sum( real(matmul(tensorField_fourier(1:3,1:3,grid1Red,j,k), & - conjg(-xi1st(1:3,grid1Red,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & - + sum(aimag(matmul(tensorField_fourier(1:3,1:3,grid1Red,j,k), & - conjg(-xi1st(1:3,grid1Red,j,k))*geomSize/scaledGeomSize))**2.0_pReal) - enddo; enddo - if(grid(1) == 1_pInt) utilities_divergenceRMS = utilities_divergenceRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 - call MPI_Allreduce(MPI_IN_PLACE,utilities_divergenceRMS,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - utilities_divergenceRMS = sqrt(utilities_divergenceRMS) * wgt ! RMS in real space calculated with Parsevals theorem from Fourier space - - -end function utilities_divergenceRMS - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate max of curl of field_fourier -!-------------------------------------------------------------------------------------------------- -real(pReal) function utilities_curlRMS() - use numerics, only: & - worldrank - use mesh, only: & - geomSize, & - grid, & - grid3 - - implicit none - integer(pInt) :: i, j, k, l - complex(pReal), dimension(3,3) :: curl_fourier - PetscErrorCode :: ierr - - external :: & - MPI_Reduce, & - MPI_Allreduce - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' ... calculating curl ......................................................' - flush(6) - endif - - !-------------------------------------------------------------------------------------------------- -! calculating max curl criterion in Fourier space - utilities_curlRMS = 0.0_pReal - - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); - do i = 2_pInt, grid1Red - 1_pInt - do l = 1_pInt, 3_pInt - curl_fourier(l,1) = (+tensorField_fourier(l,3,i,j,k)*xi1st(2,i,j,k)*geomSize(2)/scaledGeomSize(2) & - -tensorField_fourier(l,2,i,j,k)*xi1st(3,i,j,k)*geomSize(3)/scaledGeomSize(3)) - curl_fourier(l,2) = (+tensorField_fourier(l,1,i,j,k)*xi1st(3,i,j,k)*geomSize(3)/scaledGeomSize(3) & - -tensorField_fourier(l,3,i,j,k)*xi1st(1,i,j,k)*geomSize(1)/scaledGeomSize(1)) - curl_fourier(l,3) = (+tensorField_fourier(l,2,i,j,k)*xi1st(1,i,j,k)*geomSize(1)/scaledGeomSize(1) & - -tensorField_fourier(l,1,i,j,k)*xi1st(2,i,j,k)*geomSize(2)/scaledGeomSize(2)) - enddo - utilities_curlRMS = utilities_curlRMS + & - 2.0_pReal*sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! Has somewhere a conj. complex counterpart. Therefore count it twice. - enddo - do l = 1_pInt, 3_pInt - curl_fourier = (+tensorField_fourier(l,3,1,j,k)*xi1st(2,1,j,k)*geomSize(2)/scaledGeomSize(2) & - -tensorField_fourier(l,2,1,j,k)*xi1st(3,1,j,k)*geomSize(3)/scaledGeomSize(3)) - curl_fourier = (+tensorField_fourier(l,1,1,j,k)*xi1st(3,1,j,k)*geomSize(3)/scaledGeomSize(3) & - -tensorField_fourier(l,3,1,j,k)*xi1st(1,1,j,k)*geomSize(1)/scaledGeomSize(1)) - curl_fourier = (+tensorField_fourier(l,2,1,j,k)*xi1st(1,1,j,k)*geomSize(1)/scaledGeomSize(1) & - -tensorField_fourier(l,1,1,j,k)*xi1st(2,1,j,k)*geomSize(2)/scaledGeomSize(2)) - enddo - utilities_curlRMS = utilities_curlRMS + & - sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! this layer (DC) does not have a conjugate complex counterpart (if grid(1) /= 1) - do l = 1_pInt, 3_pInt - curl_fourier = (+tensorField_fourier(l,3,grid1Red,j,k)*xi1st(2,grid1Red,j,k)*geomSize(2)/scaledGeomSize(2) & - -tensorField_fourier(l,2,grid1Red,j,k)*xi1st(3,grid1Red,j,k)*geomSize(3)/scaledGeomSize(3)) - curl_fourier = (+tensorField_fourier(l,1,grid1Red,j,k)*xi1st(3,grid1Red,j,k)*geomSize(3)/scaledGeomSize(3) & - -tensorField_fourier(l,3,grid1Red,j,k)*xi1st(1,grid1Red,j,k)*geomSize(1)/scaledGeomSize(1)) - curl_fourier = (+tensorField_fourier(l,2,grid1Red,j,k)*xi1st(1,grid1Red,j,k)*geomSize(1)/scaledGeomSize(1) & - -tensorField_fourier(l,1,grid1Red,j,k)*xi1st(2,grid1Red,j,k)*geomSize(2)/scaledGeomSize(2)) - enddo - utilities_curlRMS = utilities_curlRMS + & - sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! this layer (Nyquist) does not have a conjugate complex counterpart (if grid(1) /= 1) - enddo; enddo - - call MPI_Allreduce(MPI_IN_PLACE,utilities_curlRMS,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - utilities_curlRMS = sqrt(utilities_curlRMS) * wgt - if(grid(1) == 1_pInt) utilities_curlRMS = utilities_curlRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 - -end function utilities_curlRMS - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates mask compliance tensor used to adjust F to fullfill stress BC -!-------------------------------------------------------------------------------------------------- -function utilities_maskedCompliance(rot_BC,mask_stress,C) - use prec, only: & - prec_isNaN - use IO, only: & - IO_error - use numerics, only: & - worldrank - use math, only: & - math_Plain3333to99, & - math_plain99to3333, & - math_rotate_forward3333, & - math_rotate_forward33, & - math_invert - - implicit none - real(pReal), dimension(3,3,3,3) :: utilities_maskedCompliance !< masked compliance - real(pReal), intent(in) , dimension(3,3,3,3) :: C !< current average stiffness - real(pReal), intent(in) , dimension(3,3) :: rot_BC !< rotation of load frame - logical, intent(in), dimension(3,3) :: mask_stress !< mask of stress BC - integer(pInt) :: j, k, m, n - logical, dimension(9) :: mask_stressVector - real(pReal), dimension(9,9) :: temp99_Real - integer(pInt) :: size_reduced = 0_pInt - real(pReal), dimension(:,:), allocatable :: & - s_reduced, & !< reduced compliance matrix (depending on number of stress BC) - c_reduced, & !< reduced stiffness (depending on number of stress BC) - sTimesC !< temp variable to check inversion - logical :: errmatinv - character(len=1024):: formatString - - mask_stressVector = reshape(transpose(mask_stress), [9]) - size_reduced = int(count(mask_stressVector), pInt) - if(size_reduced > 0_pInt )then - allocate (c_reduced(size_reduced,size_reduced), source =0.0_pReal) - allocate (s_reduced(size_reduced,size_reduced), source =0.0_pReal) - allocate (sTimesC(size_reduced,size_reduced), source =0.0_pReal) - temp99_Real = math_Plain3333to99(math_rotate_forward3333(C,rot_BC)) - - if(debugGeneral .and. worldrank == 0_pInt) then - write(6,'(/,a)') ' ... updating masked compliance ............................................' - write(6,'(/,a,/,9(9(2x,f12.7,1x)/))',advance='no') ' Stiffness C (load) / GPa =',& - transpose(temp99_Real)/1.e9_pReal - flush(6) - endif - k = 0_pInt ! calculate reduced stiffness - do n = 1_pInt,9_pInt - if(mask_stressVector(n)) then - k = k + 1_pInt - j = 0_pInt - do m = 1_pInt,9_pInt - if(mask_stressVector(m)) then - j = j + 1_pInt - c_reduced(k,j) = temp99_Real(n,m) - endif; enddo; endif; enddo - - call math_invert(size_reduced, c_reduced, s_reduced, errmatinv) ! invert reduced stiffness - if (any(prec_isNaN(s_reduced))) errmatinv = .true. - if(errmatinv) call IO_error(error_ID=400_pInt,ext_msg='utilities_maskedCompliance') - temp99_Real = 0.0_pReal ! fill up compliance with zeros - k = 0_pInt - do n = 1_pInt,9_pInt - if(mask_stressVector(n)) then - k = k + 1_pInt - j = 0_pInt - do m = 1_pInt,9_pInt - if(mask_stressVector(m)) then - j = j + 1_pInt - temp99_Real(n,m) = s_reduced(k,j) - endif; enddo; endif; enddo - -!-------------------------------------------------------------------------------------------------- -! check if inversion was successful - sTimesC = matmul(c_reduced,s_reduced) - do m=1_pInt, size_reduced - do n=1_pInt, size_reduced - if(m==n .and. abs(sTimesC(m,n)) > (1.0_pReal + 10.0e-12_pReal)) errmatinv = .true. ! diagonal elements of S*C should be 1 - if(m/=n .and. abs(sTimesC(m,n)) > (0.0_pReal + 10.0e-12_pReal)) errmatinv = .true. ! off diagonal elements of S*C should be 0 - enddo - enddo - if((debugGeneral .or. errmatinv) .and. (worldrank == 0_pInt)) then ! report - write(formatString, '(I16.16)') size_reduced - formatString = '(/,a,/,'//trim(formatString)//'('//trim(formatString)//'(2x,es9.2,1x)/))' - write(6,trim(formatString),advance='no') ' C * S (load) ', & - transpose(matmul(c_reduced,s_reduced)) - write(6,trim(formatString),advance='no') ' S (load) ', transpose(s_reduced) - endif - if(errmatinv) call IO_error(error_ID=400_pInt,ext_msg='utilities_maskedCompliance') - deallocate(c_reduced) - deallocate(s_reduced) - deallocate(sTimesC) - else - temp99_real = 0.0_pReal - endif - if(debugGeneral .and. worldrank == 0_pInt) & ! report - write(6,'(/,a,/,9(9(2x,f12.7,1x)/),/)',advance='no') ' Masked Compliance (load) * GPa =', & - transpose(temp99_Real*1.e9_pReal) - flush(6) - utilities_maskedCompliance = math_Plain99to3333(temp99_Real) - -end function utilities_maskedCompliance - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate scalar gradient in fourier field -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierScalarGradient() - use mesh, only: & - grid3, & - grid - - implicit none - integer(pInt) :: i, j, k - - vectorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) - forall(k = 1_pInt:grid3, j = 1_pInt:grid(2), i = 1_pInt:grid1Red) & - vectorField_fourier(1:3,i,j,k) = scalarField_fourier(i,j,k)*xi1st(1:3,i,j,k) - -end subroutine utilities_fourierScalarGradient - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate vector divergence in fourier field -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierVectorDivergence() - use mesh, only: & - grid3, & - grid - - implicit none - integer(pInt) :: i, j, k - - scalarField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) - forall(k = 1_pInt:grid3, j = 1_pInt:grid(2), i = 1_pInt:grid1Red) & - scalarField_fourier(i,j,k) = scalarField_fourier(i,j,k) + & - sum(vectorField_fourier(1:3,i,j,k)*conjg(-xi1st(1:3,i,j,k))) - -end subroutine utilities_fourierVectorDivergence - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate vector gradient in fourier field -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierVectorGradient() - use mesh, only: & - grid3, & - grid - - implicit none - integer(pInt) :: i, j, k, m, n - - tensorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red - do m = 1_pInt, 3_pInt; do n = 1_pInt, 3_pInt - tensorField_fourier(m,n,i,j,k) = vectorField_fourier(m,i,j,k)*xi1st(n,i,j,k) - enddo; enddo - enddo; enddo; enddo -end subroutine utilities_fourierVectorGradient - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate tensor divergence in fourier field -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierTensorDivergence() - use mesh, only: & - grid3, & - grid - - implicit none - integer(pInt) :: i, j, k, m, n - - vectorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red - do m = 1_pInt, 3_pInt; do n = 1_pInt, 3_pInt - vectorField_fourier(m,i,j,k) = & - vectorField_fourier(m,i,j,k) + & - tensorField_fourier(m,n,i,j,k)*conjg(-xi1st(n,i,j,k)) - enddo; enddo - enddo; enddo; enddo -end subroutine utilities_fourierTensorDivergence - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates constitutive response -!-------------------------------------------------------------------------------------------------- -subroutine utilities_constitutiveResponse(F_lastInc,F,timeinc, & - P,C_volAvg,C_minmaxAvg,P_av,forwardData,rotation_BC) - use debug, only: & - debug_reset, & - debug_info - use numerics, only: & - worldrank - use math, only: & - math_transpose33, & - math_rotate_forward33, & - math_det33 - use mesh, only: & - grid,& - grid3 - use FEsolving, only: & - restartWrite - use CPFEM2, only: & - CPFEM_general - use homogenization, only: & - materialpoint_F0, & - materialpoint_F, & - materialpoint_P, & - materialpoint_dPdF - - implicit none - real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & - F_lastInc, & !< target deformation gradient - F !< previous deformation gradient - real(pReal), intent(in) :: timeinc !< loading time - logical, intent(in) :: forwardData !< age results - real(pReal), intent(in), dimension(3,3) :: rotation_BC !< rotation of load frame - - real(pReal),intent(out), dimension(3,3,3,3) :: C_volAvg, C_minmaxAvg !< average stiffness - real(pReal),intent(out), dimension(3,3) :: P_av !< average PK stress - real(pReal),intent(out), dimension(3,3,grid(1),grid(2),grid3) :: P !< PK stress - - logical :: & - age - - integer(pInt) :: & - j,k - real(pReal), dimension(3,3,3,3) :: max_dPdF, min_dPdF - real(pReal) :: max_dPdF_norm, min_dPdF_norm, defgradDetMin, defgradDetMax, defgradDet - PetscErrorCode :: ierr - - external :: & - MPI_Reduce, & - MPI_Allreduce - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' ... evaluating constitutive response ......................................' - flush(6) - endif - age = .False. - - if (forwardData) then ! aging results - age = .True. - materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) - endif - if (cutBack) then ! restore saved variables - age = .False. - endif - - materialpoint_F = reshape(F,[3,3,1,product(grid(1:2))*grid3]) - call debug_reset() - -!-------------------------------------------------------------------------------------------------- -! calculate bounds of det(F) and report - if(debugGeneral) then - defgradDetMax = -huge(1.0_pReal) - defgradDetMin = +huge(1.0_pReal) - do j = 1_pInt, product(grid(1:2))*grid3 - defgradDet = math_det33(materialpoint_F(1:3,1:3,1,j)) - defgradDetMax = max(defgradDetMax,defgradDet) - defgradDetMin = min(defgradDetMin,defgradDet) - end do - call MPI_reduce(MPI_IN_PLACE,defgradDetMax,1,MPI_DOUBLE,MPI_MAX,0,PETSC_COMM_WORLD,ierr) - call MPI_reduce(MPI_IN_PLACE,defgradDetMin,1,MPI_DOUBLE,MPI_MIN,0,PETSC_COMM_WORLD,ierr) - if (worldrank == 0_pInt) then - write(6,'(a,1x,es11.4)') ' max determinant of deformation =', defgradDetMax - write(6,'(a,1x,es11.4)') ' min determinant of deformation =', defgradDetMin - flush(6) - endif - endif - - call CPFEM_general(age,timeinc) - - max_dPdF = 0.0_pReal - max_dPdF_norm = 0.0_pReal - min_dPdF = huge(1.0_pReal) - min_dPdF_norm = huge(1.0_pReal) - do k = 1_pInt, product(grid(1:2))*grid3 - if (max_dPdF_norm < sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal)) then - max_dPdF = materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k) - max_dPdF_norm = sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal) - endif - if (min_dPdF_norm > sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal)) then - min_dPdF = materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k) - min_dPdF_norm = sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal) - endif - end do - - call MPI_Allreduce(MPI_IN_PLACE,max_dPdF,81,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) - call MPI_Allreduce(MPI_IN_PLACE,min_dPdF,81,MPI_DOUBLE,MPI_MIN,PETSC_COMM_WORLD,ierr) - - C_minmaxAvg = 0.5_pReal*(max_dPdF + min_dPdF) - C_volAvg = sum(sum(materialpoint_dPdF,dim=6),dim=5) * wgt - - call MPI_Allreduce(MPI_IN_PLACE,C_volAvg,81,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - - call debug_info() - - restartWrite = .false. ! reset restartWrite status - cutBack = .false. ! reset cutBack status - - P = reshape(materialpoint_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 .and. worldrank == 0_pInt) & - write(6,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress (lab) / MPa =',& - math_transpose33(P_av)*1.e-6_pReal - P_av = math_rotate_forward33(P_av,rotation_BC) - if (worldrank == 0_pInt) then - write(6,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress / MPa =',& - math_transpose33(P_av)*1.e-6_pReal - flush(6) - endif - -end subroutine utilities_constitutiveResponse - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates forward rate, either guessing or just add delta/timeinc -!-------------------------------------------------------------------------------------------------- -pure function utilities_calculateRate(avRate,timeinc_old,guess,field_lastInc,field) - use mesh, only: & - grid3, & - grid - - implicit none - real(pReal), intent(in), dimension(3,3) :: avRate !< homogeneous addon - real(pReal), intent(in) :: & - timeinc_old !< timeinc of last step - logical, intent(in) :: & - guess !< guess along former trajectory - real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & - field_lastInc, & !< data of previous step - field !< data of current step - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: & - utilities_calculateRate - - if (guess) then - utilities_calculateRate = (field-field_lastInc) / timeinc_old - else - utilities_calculateRate = spread(spread(spread(avRate,3,grid(1)),4,grid(2)),5,grid3) - endif - -end function utilities_calculateRate - - -!-------------------------------------------------------------------------------------------------- -!> @brief forwards a field with a pointwise given rate, if aim is given, -!> ensures that the average matches the aim -!-------------------------------------------------------------------------------------------------- -function utilities_forwardField(timeinc,field_lastInc,rate,aim) - use mesh, only: & - grid3, & - grid - - implicit none - real(pReal), intent(in) :: & - timeinc !< timeinc of current step - real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & - field_lastInc, & !< initial field - rate !< rate by which to forward - real(pReal), intent(in), optional, dimension(3,3) :: & - aim !< average field value aim - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: & - utilities_forwardField - real(pReal), dimension(3,3) :: fieldDiff !< - aim - PetscErrorCode :: ierr - - external :: & - MPI_Allreduce - - utilities_forwardField = field_lastInc + rate*timeinc - if (present(aim)) then !< correct to match average - fieldDiff = sum(sum(sum(utilities_forwardField,dim=5),dim=4),dim=3)*wgt - call MPI_Allreduce(MPI_IN_PLACE,fieldDiff,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - fieldDiff = fieldDiff - aim - utilities_forwardField = utilities_forwardField - & - spread(spread(spread(fieldDiff,3,grid(1)),4,grid(2)),5,grid3) - endif - -end function utilities_forwardField - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates filter for fourier convolution depending on type given in numerics.config -!-------------------------------------------------------------------------------------------------- -pure function utilities_getFreqDerivative(k_s) - use math, only: & - PI - use mesh, only: & - geomSize, & - grid - - implicit none - integer(pInt), intent(in), dimension(3) :: k_s !< indices of frequency - complex(pReal), dimension(3) :: utilities_getFreqDerivative - - select case (spectral_derivative_ID) - case (DERIVATIVE_CONTINUOUS_ID) - utilities_getFreqDerivative = cmplx(0.0_pReal, 2.0_pReal*PI*real(k_s,pReal)/geomSize,pReal) - - case (DERIVATIVE_CENTRAL_DIFF_ID) - utilities_getFreqDerivative = cmplx(0.0_pReal, sin(2.0_pReal*PI*real(k_s,pReal)/real(grid,pReal)), pReal)/ & - cmplx(2.0_pReal*geomSize/real(grid,pReal), 0.0_pReal, pReal) - - case (DERIVATIVE_FWBW_DIFF_ID) - utilities_getFreqDerivative(1) = & - cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) - 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & - cmplx(4.0_pReal*geomSize(1)/real(grid(1),pReal), 0.0_pReal, pReal) - utilities_getFreqDerivative(2) = & - cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) - 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & - cmplx(4.0_pReal*geomSize(2)/real(grid(2),pReal), 0.0_pReal, pReal) - utilities_getFreqDerivative(3) = & - cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) - 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & - cmplx(4.0_pReal*geomSize(3)/real(grid(3),pReal), 0.0_pReal, pReal) - - end select - -end function utilities_getFreqDerivative - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate coordinates in current configuration for given defgrad field -! using integration in Fourier space. Similar as in mesh.f90, but using data already defined for -! convolution -!-------------------------------------------------------------------------------------------------- -subroutine utilities_updateIPcoords(F) - use math, only: & - math_mul33x3 - use mesh, only: & - grid, & - grid3, & - grid3Offset, & - geomSize, & - mesh_ipCoordinates - implicit none - - real(pReal), dimension(3,3,grid(1),grid(2),grid3), intent(in) :: F - integer(pInt) :: i, j, k, m - real(pReal), dimension(3) :: step, offset_coords - real(pReal), dimension(3,3) :: Favg - PetscErrorCode :: ierr - external & - MPI_Bcast - -!-------------------------------------------------------------------------------------------------- -! integration in Fourier space - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F - call utilities_FFTtensorForward() - call utilities_fourierTensorDivergence() - - do k = 1_pInt, grid3; do j = 1_pInt, grid(2) ;do i = 1_pInt, grid1Red - if (any(abs(xi1st(1:3,i,j,k)) > tiny(0.0_pReal))) & - vectorField_fourier(1:3,i,j,k) = vectorField_fourier(1:3,i,j,k)/ & - sum(conjg(-xi1st(1:3,i,j,k))*xi1st(1:3,i,j,k)) - enddo; enddo; enddo - call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) - -!-------------------------------------------------------------------------------------------------- -! average F - if (grid3Offset == 0_pInt) Favg = real(tensorField_fourier(1:3,1:3,1,1,1),pReal)*wgt - call MPI_Bcast(Favg,9,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) - -!-------------------------------------------------------------------------------------------------- -! add average to fluctuation and put (0,0,0) on (0,0,0) - step = geomSize/real(grid, pReal) - if (grid3Offset == 0_pInt) offset_coords = vectorField_real(1:3,1,1,1) - call MPI_Bcast(offset_coords,3,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) - offset_coords = math_mul33x3(Favg,step/2.0_pReal) - offset_coords - m = 1_pInt - do k = 1_pInt,grid3; do j = 1_pInt,grid(2); do i = 1_pInt,grid(1) - mesh_ipCoordinates(1:3,1,m) = vectorField_real(1:3,i,j,k) & - + offset_coords & - + math_mul33x3(Favg,step*real([i,j,k+grid3Offset]-1_pInt,pReal)) - m = m+1_pInt - enddo; enddo; enddo - -end subroutine utilities_updateIPcoords - - -!-------------------------------------------------------------------------------------------------- -!> @brief cleans up -!-------------------------------------------------------------------------------------------------- -subroutine utilities_destroy() - implicit none - - call fftw_destroy_plan(planTensorForth) - call fftw_destroy_plan(planTensorBack) - call fftw_destroy_plan(planVectorForth) - call fftw_destroy_plan(planVectorBack) - call fftw_destroy_plan(planScalarForth) - call fftw_destroy_plan(planScalarBack) - -end subroutine utilities_destroy - - -end module spectral_utilities diff --git a/code/thermal/CMakeLists.txt b/code/thermal/CMakeLists.txt index b9d3f8ff9..1d06449ef 100644 --- a/code/thermal/CMakeLists.txt +++ b/code/thermal/CMakeLists.txt @@ -8,3 +8,8 @@ set (THERMAL "thermal_isothermal" foreach (p ${THERMAL}) add_library (${p} MODULE "${p}.f90") endforeach (p) + +# set libraries/modules for linking +foreach (p ${THERMAL}) + set (AUX_LIB ${AUX_LIB} ${p}) +endforeach (p) \ No newline at end of file diff --git a/code/thermal_adiabatic.f90 b/code/thermal_adiabatic.f90 deleted file mode 100644 index 7bb8620e7..000000000 --- a/code/thermal_adiabatic.f90 +++ /dev/null @@ -1,422 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for adiabatic temperature evolution -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module thermal_adiabatic - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - thermal_adiabatic_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - thermal_adiabatic_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - thermal_adiabatic_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - thermal_adiabatic_Noutput !< number of outputs per instance of this thermal model - - enum, bind(c) - enumerator :: undefined_ID, & - temperature_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - thermal_adiabatic_outputID !< ID of each post result output - - - public :: & - thermal_adiabatic_init, & - thermal_adiabatic_updateState, & - thermal_adiabatic_getSourceAndItsTangent, & - thermal_adiabatic_getSpecificHeat, & - thermal_adiabatic_getMassDensity, & - thermal_adiabatic_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine thermal_adiabatic_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - thermal_type, & - thermal_typeInstance, & - homogenization_Noutput, & - THERMAL_ADIABATIC_label, & - THERMAL_adiabatic_ID, & - material_homog, & - mappingHomogenization, & - thermalState, & - thermalMapping, & - thermal_initialT, & - temperature, & - temperatureRate, & - material_partHomogenization - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_ADIABATIC_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(thermal_type == THERMAL_adiabatic_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(thermal_adiabatic_sizePostResults(maxNinstance), source=0_pInt) - allocate(thermal_adiabatic_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(thermal_adiabatic_output (maxval(homogenization_Noutput),maxNinstance)) - thermal_adiabatic_output = '' - allocate(thermal_adiabatic_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(thermal_adiabatic_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (thermal_type(section) == THERMAL_adiabatic_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = thermal_typeInstance(section) ! which instance of my thermal is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('temperature') - thermal_adiabatic_Noutput(instance) = thermal_adiabatic_Noutput(instance) + 1_pInt - thermal_adiabatic_outputID(thermal_adiabatic_Noutput(instance),instance) = temperature_ID - thermal_adiabatic_output(thermal_adiabatic_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingFile - - initializeInstances: do section = 1_pInt, size(thermal_type) - if (thermal_type(section) == THERMAL_adiabatic_ID) then - NofMyHomog=count(material_homog==section) - instance = thermal_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,thermal_adiabatic_Noutput(instance) - select case(thermal_adiabatic_outputID(o,instance)) - case(temperature_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - thermal_adiabatic_sizePostResult(o,instance) = mySize - thermal_adiabatic_sizePostResults(instance) = thermal_adiabatic_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 1_pInt - thermalState(section)%sizeState = sizeState - thermalState(section)%sizePostResults = thermal_adiabatic_sizePostResults(instance) - allocate(thermalState(section)%state0 (sizeState,NofMyHomog), source=thermal_initialT(section)) - allocate(thermalState(section)%subState0(sizeState,NofMyHomog), source=thermal_initialT(section)) - allocate(thermalState(section)%state (sizeState,NofMyHomog), source=thermal_initialT(section)) - - nullify(thermalMapping(section)%p) - thermalMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(temperature(section)%p) - temperature(section)%p => thermalState(section)%state(1,:) - deallocate(temperatureRate(section)%p) - allocate (temperatureRate(section)%p(NofMyHomog), source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine thermal_adiabatic_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates adiabatic change in temperature based on local heat generation model -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_updateState(subdt, ip, el) - use numerics, only: & - err_thermal_tolAbs, & - err_thermal_tolRel - use material, only: & - mappingHomogenization, & - thermalState, & - temperature, & - temperatureRate, & - thermalMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - subdt - logical, dimension(2) :: & - thermal_adiabatic_updateState - integer(pInt) :: & - homog, & - offset - real(pReal) :: & - T, Tdot, dTdot_dT - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,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)) & - <= err_thermal_tolAbs & - .or. abs(T - thermalState(homog)%state(1,offset)) & - <= err_thermal_tolRel*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) - use math, only: & - math_Mandel6to33 - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - thermal_typeInstance, & - phase_Nsources, & - phase_source, & - SOURCE_thermal_dissipation_ID, & - SOURCE_thermal_externalheat_ID - use source_thermal_dissipation, only: & - source_thermal_dissipation_getRateAndItsTangent - use source_thermal_externalheat, only: & - source_thermal_externalheat_getRateAndItsTangent - use crystallite, only: & - crystallite_Tstar_v, & - crystallite_Lp - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - T - real(pReal), intent(out) :: & - Tdot, dTdot_dT - real(pReal) :: & - my_Tdot, my_dTdot_dT - integer(pInt) :: & - phase, & - homog, & - offset, & - instance, & - grain, & - source - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - instance = thermal_typeInstance(homog) - - Tdot = 0.0_pReal - dTdot_dT = 0.0_pReal - do grain = 1, homogenization_Ngrains(homog) - phase = phaseAt(grain,ip,el) - do source = 1, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_thermal_dissipation_ID) - call source_thermal_dissipation_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & - crystallite_Tstar_v(1:6,grain,ip,el), & - crystallite_Lp(1:3,1:3,grain,ip,el), & - grain, ip, el) - - case (SOURCE_thermal_externalheat_ID) - call source_thermal_externalheat_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & - grain, ip, el) - - case default - my_Tdot = 0.0_pReal - my_dTdot_dT = 0.0_pReal - end select - Tdot = Tdot + my_Tdot - dTdot_dT = dTdot_dT + my_dTdot_dT - enddo - enddo - - Tdot = Tdot/homogenization_Ngrains(homog) - dTdot_dT = dTdot_dT/homogenization_Ngrains(homog) - -end subroutine thermal_adiabatic_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized specific heat capacity -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_getSpecificHeat(ip,el) - use lattice, only: & - lattice_specificHeat - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - thermal_adiabatic_getSpecificHeat - integer(pInt) :: & - homog, grain - - thermal_adiabatic_getSpecificHeat = 0.0_pReal - - homog = mappingHomogenization(2,ip,el) - - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - thermal_adiabatic_getSpecificHeat = thermal_adiabatic_getSpecificHeat + & - lattice_specificHeat(material_phase(grain,ip,el)) - enddo - - thermal_adiabatic_getSpecificHeat = & - thermal_adiabatic_getSpecificHeat/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function thermal_adiabatic_getSpecificHeat - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized mass density -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_getMassDensity(ip,el) - use lattice, only: & - lattice_massDensity - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - thermal_adiabatic_getMassDensity - integer(pInt) :: & - homog, grain - - thermal_adiabatic_getMassDensity = 0.0_pReal - - homog = mappingHomogenization(2,ip,el) - - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - thermal_adiabatic_getMassDensity = thermal_adiabatic_getMassDensity + & - lattice_massDensity(material_phase(grain,ip,el)) - enddo - - thermal_adiabatic_getMassDensity = & - thermal_adiabatic_getMassDensity/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function thermal_adiabatic_getMassDensity - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of thermal results -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_postResults(ip,el) - use material, only: & - mappingHomogenization, & - thermal_typeInstance, & - thermalMapping, & - temperature - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(thermal_adiabatic_sizePostResults(thermal_typeInstance(mappingHomogenization(2,ip,el)))) :: & - thermal_adiabatic_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = thermalMapping(homog)%p(ip,el) - instance = thermal_typeInstance(homog) - - c = 0_pInt - thermal_adiabatic_postResults = 0.0_pReal - - do o = 1_pInt,thermal_adiabatic_Noutput(instance) - select case(thermal_adiabatic_outputID(o,instance)) - - case (temperature_ID) - thermal_adiabatic_postResults(c+1_pInt) = temperature(homog)%p(offset) - c = c + 1 - end select - enddo -end function thermal_adiabatic_postResults - -end module thermal_adiabatic diff --git a/code/thermal_conduction.f90 b/code/thermal_conduction.f90 deleted file mode 100644 index 2f9b766eb..000000000 --- a/code/thermal_conduction.f90 +++ /dev/null @@ -1,444 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for temperature evolution from heat conduction -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module thermal_conduction - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - thermal_conduction_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - thermal_conduction_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - thermal_conduction_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - thermal_conduction_Noutput !< number of outputs per instance of this damage - - enum, bind(c) - enumerator :: undefined_ID, & - temperature_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - thermal_conduction_outputID !< ID of each post result output - - - public :: & - thermal_conduction_init, & - thermal_conduction_getSourceAndItsTangent, & - thermal_conduction_getConductivity33, & - thermal_conduction_getSpecificHeat, & - thermal_conduction_getMassDensity, & - thermal_conduction_putTemperatureAndItsRate, & - thermal_conduction_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine thermal_conduction_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - thermal_type, & - thermal_typeInstance, & - homogenization_Noutput, & - THERMAL_conduction_label, & - THERMAL_conduction_ID, & - material_homog, & - mappingHomogenization, & - thermalState, & - thermalMapping, & - thermal_initialT, & - temperature, & - temperatureRate, & - material_partHomogenization - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_CONDUCTION_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(thermal_type == THERMAL_conduction_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(thermal_conduction_sizePostResults(maxNinstance), source=0_pInt) - allocate(thermal_conduction_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(thermal_conduction_output (maxval(homogenization_Noutput),maxNinstance)) - thermal_conduction_output = '' - allocate(thermal_conduction_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(thermal_conduction_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (thermal_type(section) == THERMAL_conduction_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = thermal_typeInstance(section) ! which instance of my thermal is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('temperature') - thermal_conduction_Noutput(instance) = thermal_conduction_Noutput(instance) + 1_pInt - thermal_conduction_outputID(thermal_conduction_Noutput(instance),instance) = temperature_ID - thermal_conduction_output(thermal_conduction_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingFile - - initializeInstances: do section = 1_pInt, size(thermal_type) - if (thermal_type(section) == THERMAL_conduction_ID) then - NofMyHomog=count(material_homog==section) - instance = thermal_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,thermal_conduction_Noutput(instance) - select case(thermal_conduction_outputID(o,instance)) - case(temperature_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - thermal_conduction_sizePostResult(o,instance) = mySize - thermal_conduction_sizePostResults(instance) = thermal_conduction_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 0_pInt - thermalState(section)%sizeState = sizeState - thermalState(section)%sizePostResults = thermal_conduction_sizePostResults(instance) - allocate(thermalState(section)%state0 (sizeState,NofMyHomog)) - allocate(thermalState(section)%subState0(sizeState,NofMyHomog)) - allocate(thermalState(section)%state (sizeState,NofMyHomog)) - - nullify(thermalMapping(section)%p) - thermalMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(temperature (section)%p) - allocate (temperature (section)%p(NofMyHomog), source=thermal_initialT(section)) - deallocate(temperatureRate(section)%p) - allocate (temperatureRate(section)%p(NofMyHomog), source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine thermal_conduction_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns heat generation rate -!-------------------------------------------------------------------------------------------------- -subroutine thermal_conduction_getSourceAndItsTangent(Tdot, dTdot_dT, T, ip, el) - use math, only: & - math_Mandel6to33 - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - thermal_typeInstance, & - phase_Nsources, & - phase_source, & - SOURCE_thermal_dissipation_ID, & - SOURCE_thermal_externalheat_ID - use source_thermal_dissipation, only: & - source_thermal_dissipation_getRateAndItsTangent - use source_thermal_externalheat, only: & - source_thermal_externalheat_getRateAndItsTangent - use crystallite, only: & - crystallite_Tstar_v, & - crystallite_Lp - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - T - real(pReal), intent(out) :: & - Tdot, dTdot_dT - real(pReal) :: & - my_Tdot, my_dTdot_dT - integer(pInt) :: & - phase, & - homog, & - offset, & - instance, & - grain, & - source - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - instance = thermal_typeInstance(homog) - - Tdot = 0.0_pReal - dTdot_dT = 0.0_pReal - do grain = 1, homogenization_Ngrains(homog) - phase = phaseAt(grain,ip,el) - do source = 1, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_thermal_dissipation_ID) - call source_thermal_dissipation_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & - crystallite_Tstar_v(1:6,grain,ip,el), & - crystallite_Lp(1:3,1:3,grain,ip,el), & - grain, ip, el) - - case (SOURCE_thermal_externalheat_ID) - call source_thermal_externalheat_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & - grain, ip, el) - - case default - my_Tdot = 0.0_pReal - my_dTdot_dT = 0.0_pReal - - end select - Tdot = Tdot + my_Tdot - dTdot_dT = dTdot_dT + my_dTdot_dT - enddo - enddo - - Tdot = Tdot/homogenization_Ngrains(homog) - dTdot_dT = dTdot_dT/homogenization_Ngrains(homog) - -end subroutine thermal_conduction_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized thermal conductivity in reference configuration -!-------------------------------------------------------------------------------------------------- -function thermal_conduction_getConductivity33(ip,el) - use lattice, only: & - lattice_thermalConductivity33 - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - thermal_conduction_getConductivity33 - integer(pInt) :: & - homog, & - grain - - homog = mappingHomogenization(2,ip,el) - - thermal_conduction_getConductivity33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - thermal_conduction_getConductivity33 = thermal_conduction_getConductivity33 + & - crystallite_push33ToRef(grain,ip,el,lattice_thermalConductivity33(:,:,material_phase(grain,ip,el))) - enddo - - thermal_conduction_getConductivity33 = & - thermal_conduction_getConductivity33/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function thermal_conduction_getConductivity33 - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized specific heat capacity -!-------------------------------------------------------------------------------------------------- -function thermal_conduction_getSpecificHeat(ip,el) - use lattice, only: & - lattice_specificHeat - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - thermal_conduction_getSpecificHeat - integer(pInt) :: & - homog, grain - - thermal_conduction_getSpecificHeat = 0.0_pReal - - homog = mappingHomogenization(2,ip,el) - - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - thermal_conduction_getSpecificHeat = thermal_conduction_getSpecificHeat + & - lattice_specificHeat(material_phase(grain,ip,el)) - enddo - - thermal_conduction_getSpecificHeat = & - thermal_conduction_getSpecificHeat/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function thermal_conduction_getSpecificHeat - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized mass density -!-------------------------------------------------------------------------------------------------- -function thermal_conduction_getMassDensity(ip,el) - use lattice, only: & - lattice_massDensity - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - thermal_conduction_getMassDensity - integer(pInt) :: & - homog, grain - - thermal_conduction_getMassDensity = 0.0_pReal - - homog = mappingHomogenization(2,ip,el) - - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - thermal_conduction_getMassDensity = thermal_conduction_getMassDensity + & - lattice_massDensity(material_phase(grain,ip,el)) - enddo - - thermal_conduction_getMassDensity = & - thermal_conduction_getMassDensity/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function thermal_conduction_getMassDensity - -!-------------------------------------------------------------------------------------------------- -!> @brief updates thermal state with solution from heat conduction PDE -!-------------------------------------------------------------------------------------------------- -subroutine thermal_conduction_putTemperatureAndItsRate(T,Tdot,ip,el) - use material, only: & - mappingHomogenization, & - temperature, & - temperatureRate, & - thermalMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - T, & - Tdot - integer(pInt) :: & - homog, & - offset - - homog = mappingHomogenization(2,ip,el) - offset = thermalMapping(homog)%p(ip,el) - temperature (homog)%p(offset) = T - temperatureRate(homog)%p(offset) = Tdot - -end subroutine thermal_conduction_putTemperatureAndItsRate - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of thermal results -!-------------------------------------------------------------------------------------------------- -function thermal_conduction_postResults(ip,el) - use material, only: & - mappingHomogenization, & - thermal_typeInstance, & - temperature, & - thermalMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(thermal_conduction_sizePostResults(thermal_typeInstance(mappingHomogenization(2,ip,el)))) :: & - thermal_conduction_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = thermalMapping(homog)%p(ip,el) - instance = thermal_typeInstance(homog) - - c = 0_pInt - thermal_conduction_postResults = 0.0_pReal - - do o = 1_pInt,thermal_conduction_Noutput(instance) - select case(thermal_conduction_outputID(o,instance)) - - case (temperature_ID) - thermal_conduction_postResults(c+1_pInt) = temperature(homog)%p(offset) - c = c + 1 - end select - enddo -end function thermal_conduction_postResults - -end module thermal_conduction diff --git a/code/thermal_isothermal.f90 b/code/thermal_isothermal.f90 deleted file mode 100644 index 8c9d3a782..000000000 --- a/code/thermal_isothermal.f90 +++ /dev/null @@ -1,65 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for isothermal temperature field -!-------------------------------------------------------------------------------------------------- -module thermal_isothermal - - implicit none - private - - public :: & - thermal_isothermal_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine thermal_isothermal_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog, & - sizeState - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_isothermal_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (thermal_type(homog) == THERMAL_isothermal_ID) then - NofMyHomog = count(material_homog == homog) - sizeState = 0_pInt - thermalState(homog)%sizeState = sizeState - thermalState(homog)%sizePostResults = sizeState - allocate(thermalState(homog)%state0 (sizeState,NofMyHomog), source=0.0_pReal) - allocate(thermalState(homog)%subState0(sizeState,NofMyHomog), source=0.0_pReal) - allocate(thermalState(homog)%state (sizeState,NofMyHomog), source=0.0_pReal) - - deallocate(temperature (homog)%p) - allocate (temperature (homog)%p(1), source=thermal_initialT(homog)) - deallocate(temperatureRate(homog)%p) - allocate (temperatureRate(homog)%p(1), source=0.0_pReal) - - endif myhomog - enddo initializeInstances - - -end subroutine thermal_isothermal_init - -end module thermal_isothermal diff --git a/code/vacancyflux/CMakeLists.txt b/code/vacancyflux/CMakeLists.txt index 4a4c4f31c..43e2a75fe 100644 --- a/code/vacancyflux/CMakeLists.txt +++ b/code/vacancyflux/CMakeLists.txt @@ -8,3 +8,8 @@ set (VACANCYFLUX "vacancyflux_isoconc" foreach (p ${VACANCYFLUX}) add_library (${p} MODULE "${p}.f90") endforeach (p) + +# set libraries/modules for linking +foreach (p ${VACANCYFLUX}) + set (AUX_LIB ${AUX_LIB} ${p}) +endforeach (p) \ No newline at end of file diff --git a/code/vacancyflux_cahnhilliard.f90 b/code/vacancyflux_cahnhilliard.f90 deleted file mode 100644 index 16a380ffc..000000000 --- a/code/vacancyflux_cahnhilliard.f90 +++ /dev/null @@ -1,606 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for conservative transport of vacancy concentration field -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module vacancyflux_cahnhilliard - use prec, only: & - pReal, & - pInt, & - p_vec - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - vacancyflux_cahnhilliard_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - vacancyflux_cahnhilliard_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - vacancyflux_cahnhilliard_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - vacancyflux_cahnhilliard_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - vacancyflux_cahnhilliard_flucAmplitude - - type(p_vec), dimension(:), allocatable, private :: & - vacancyflux_cahnhilliard_thermalFluc - - real(pReal), parameter, private :: & - kB = 1.3806488e-23_pReal !< Boltzmann constant in J/Kelvin - - enum, bind(c) - enumerator :: undefined_ID, & - vacancyConc_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - vacancyflux_cahnhilliard_outputID !< ID of each post result output - - - public :: & - vacancyflux_cahnhilliard_init, & - vacancyflux_cahnhilliard_getSourceAndItsTangent, & - vacancyflux_cahnhilliard_getMobility33, & - vacancyflux_cahnhilliard_getDiffusion33, & - vacancyflux_cahnhilliard_getChemPotAndItsTangent, & - vacancyflux_cahnhilliard_putVacancyConcAndItsRate, & - vacancyflux_cahnhilliard_postResults - private :: & - vacancyflux_cahnhilliard_getFormationEnergy, & - vacancyflux_cahnhilliard_getEntropicCoeff, & - vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_cahnhilliard_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - vacancyflux_type, & - vacancyflux_typeInstance, & - homogenization_Noutput, & - VACANCYFLUX_cahnhilliard_label, & - VACANCYFLUX_cahnhilliard_ID, & - material_homog, & - mappingHomogenization, & - vacancyfluxState, & - vacancyfluxMapping, & - vacancyConc, & - vacancyConcRate, & - vacancyflux_initialCv, & - material_partHomogenization, & - material_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o,offset - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_cahnhilliard_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(vacancyflux_type == VACANCYFLUX_cahnhilliard_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(vacancyflux_cahnhilliard_sizePostResults(maxNinstance), source=0_pInt) - allocate(vacancyflux_cahnhilliard_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(vacancyflux_cahnhilliard_output (maxval(homogenization_Noutput),maxNinstance)) - vacancyflux_cahnhilliard_output = '' - allocate(vacancyflux_cahnhilliard_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(vacancyflux_cahnhilliard_Noutput (maxNinstance), source=0_pInt) - - allocate(vacancyflux_cahnhilliard_flucAmplitude (maxNinstance)) - allocate(vacancyflux_cahnhilliard_thermalFluc (maxNinstance)) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (vacancyflux_type(section) == VACANCYFLUX_cahnhilliard_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = vacancyflux_typeInstance(section) ! which instance of my vacancyflux is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('vacancyconc') - vacancyflux_cahnhilliard_Noutput(instance) = vacancyflux_cahnhilliard_Noutput(instance) + 1_pInt - vacancyflux_cahnhilliard_outputID(vacancyflux_cahnhilliard_Noutput(instance),instance) = vacancyConc_ID - vacancyflux_cahnhilliard_output(vacancyflux_cahnhilliard_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('vacancyflux_flucamplitude') - vacancyflux_cahnhilliard_flucAmplitude(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingHomog - - initializeInstances: do section = 1_pInt, size(vacancyflux_type) - if (vacancyflux_type(section) == VACANCYFLUX_cahnhilliard_ID) then - NofMyHomog=count(material_homog==section) - instance = vacancyflux_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,vacancyflux_cahnhilliard_Noutput(instance) - select case(vacancyflux_cahnhilliard_outputID(o,instance)) - case(vacancyConc_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - vacancyflux_cahnhilliard_sizePostResult(o,instance) = mySize - vacancyflux_cahnhilliard_sizePostResults(instance) = vacancyflux_cahnhilliard_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 0_pInt - vacancyfluxState(section)%sizeState = sizeState - vacancyfluxState(section)%sizePostResults = vacancyflux_cahnhilliard_sizePostResults(instance) - allocate(vacancyfluxState(section)%state0 (sizeState,NofMyHomog)) - allocate(vacancyfluxState(section)%subState0(sizeState,NofMyHomog)) - allocate(vacancyfluxState(section)%state (sizeState,NofMyHomog)) - - allocate(vacancyflux_cahnhilliard_thermalFluc(instance)%p(NofMyHomog)) - do offset = 1_pInt, NofMyHomog - call random_number(vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset)) - vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset) = & - 1.0_pReal - & - vacancyflux_cahnhilliard_flucAmplitude(instance)* & - (vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset) - 0.5_pReal) - enddo - - nullify(vacancyfluxMapping(section)%p) - vacancyfluxMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(vacancyConc (section)%p) - allocate (vacancyConc (section)%p(NofMyHomog), source=vacancyflux_initialCv(section)) - deallocate(vacancyConcRate(section)%p) - allocate (vacancyConcRate(section)%p(NofMyHomog), source=0.0_pReal) - - endif - - enddo initializeInstances - -end subroutine vacancyflux_cahnhilliard_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates homogenized vacancy driving forces -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_cahnhilliard_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - phase_source, & - phase_Nsources, & - SOURCE_vacancy_phenoplasticity_ID, & - SOURCE_vacancy_irradiation_ID, & - SOURCE_vacancy_thermalfluc_ID - use source_vacancy_phenoplasticity, only: & - source_vacancy_phenoplasticity_getRateAndItsTangent - use source_vacancy_irradiation, only: & - source_vacancy_irradiation_getRateAndItsTangent - use source_vacancy_thermalfluc, only: & - source_vacancy_thermalfluc_getRateAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Cv - integer(pInt) :: & - phase, & - grain, & - source - real(pReal) :: & - CvDot, dCvDot_dCv, localCvDot, dLocalCvDot_dCv - - CvDot = 0.0_pReal - dCvDot_dCv = 0.0_pReal - do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) - phase = phaseAt(grain,ip,el) - do source = 1_pInt, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_vacancy_phenoplasticity_ID) - call source_vacancy_phenoplasticity_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) - - case (SOURCE_vacancy_irradiation_ID) - call source_vacancy_irradiation_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) - - case (SOURCE_vacancy_thermalfluc_ID) - call source_vacancy_thermalfluc_getRateAndItsTangent(localCvDot, dLocalCvDot_dCv, grain, ip, el) - - end select - CvDot = CvDot + localCvDot - dCvDot_dCv = dCvDot_dCv + dLocalCvDot_dCv - enddo - enddo - - CvDot = CvDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - dCvDot_dCv = dCvDot_dCv/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - -end subroutine vacancyflux_cahnhilliard_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized vacancy mobility tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function vacancyflux_cahnhilliard_getMobility33(ip,el) - use lattice, only: & - lattice_vacancyfluxMobility33 - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - vacancyflux_cahnhilliard_getMobility33 - integer(pInt) :: & - grain - - vacancyflux_cahnhilliard_getMobility33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - vacancyflux_cahnhilliard_getMobility33 = vacancyflux_cahnhilliard_getMobility33 + & - crystallite_push33ToRef(grain,ip,el,lattice_vacancyfluxMobility33(:,:,material_phase(grain,ip,el))) - enddo - - vacancyflux_cahnhilliard_getMobility33 = & - vacancyflux_cahnhilliard_getMobility33/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function vacancyflux_cahnhilliard_getMobility33 - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized vacancy diffusion tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function vacancyflux_cahnhilliard_getDiffusion33(ip,el) - use lattice, only: & - lattice_vacancyfluxDiffusion33 - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - vacancyflux_cahnhilliard_getDiffusion33 - integer(pInt) :: & - grain - - vacancyflux_cahnhilliard_getDiffusion33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - vacancyflux_cahnhilliard_getDiffusion33 = vacancyflux_cahnhilliard_getDiffusion33 + & - crystallite_push33ToRef(grain,ip,el,lattice_vacancyfluxDiffusion33(:,:,material_phase(grain,ip,el))) - enddo - - vacancyflux_cahnhilliard_getDiffusion33 = & - vacancyflux_cahnhilliard_getDiffusion33/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function vacancyflux_cahnhilliard_getDiffusion33 - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized vacancy formation energy -!-------------------------------------------------------------------------------------------------- -real(pReal) function vacancyflux_cahnhilliard_getFormationEnergy(ip,el) - use lattice, only: & - lattice_vacancyFormationEnergy, & - lattice_vacancyVol, & - lattice_vacancySurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - integer(pInt) :: & - grain - - vacancyflux_cahnhilliard_getFormationEnergy = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - vacancyflux_cahnhilliard_getFormationEnergy = vacancyflux_cahnhilliard_getFormationEnergy + & - lattice_vacancyFormationEnergy(material_phase(grain,ip,el))/ & - lattice_vacancyVol(material_phase(grain,ip,el))/ & - lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) - enddo - - vacancyflux_cahnhilliard_getFormationEnergy = & - vacancyflux_cahnhilliard_getFormationEnergy/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function vacancyflux_cahnhilliard_getFormationEnergy - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized vacancy entropy coefficient -!-------------------------------------------------------------------------------------------------- -real(pReal) function vacancyflux_cahnhilliard_getEntropicCoeff(ip,el) - use lattice, only: & - lattice_vacancyVol, & - lattice_vacancySurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_homog, & - material_phase, & - temperature, & - thermalMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - integer(pInt) :: & - grain - - vacancyflux_cahnhilliard_getEntropicCoeff = 0.0_pReal - do grain = 1, homogenization_Ngrains(material_homog(ip,el)) - vacancyflux_cahnhilliard_getEntropicCoeff = vacancyflux_cahnhilliard_getEntropicCoeff + & - kB/ & - lattice_vacancyVol(material_phase(grain,ip,el))/ & - lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) - enddo - - vacancyflux_cahnhilliard_getEntropicCoeff = & - vacancyflux_cahnhilliard_getEntropicCoeff* & - temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))/ & - homogenization_Ngrains(material_homog(ip,el)) - -end function vacancyflux_cahnhilliard_getEntropicCoeff - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized kinematic contribution to chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCv, Cv, ip, el) - use lattice, only: & - lattice_vacancySurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_homog, & - phase_kinematics, & - phase_Nkinematics, & - material_phase, & - KINEMATICS_vacancy_strain_ID - use crystallite, only: & - crystallite_Tstar_v, & - crystallite_Fi0, & - crystallite_Fi - use kinematics_vacancy_strain, only: & - kinematics_vacancy_strain_ChemPotAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Cv - real(pReal), intent(out) :: & - KPot, dKPot_dCv - real(pReal) :: & - my_KPot, my_dKPot_dCv - integer(pInt) :: & - grain, kinematics - - KPot = 0.0_pReal - dKPot_dCv = 0.0_pReal - do grain = 1_pInt,homogenization_Ngrains(material_homog(ip,el)) - do kinematics = 1_pInt, phase_Nkinematics(material_phase(grain,ip,el)) - select case (phase_kinematics(kinematics,material_phase(grain,ip,el))) - case (KINEMATICS_vacancy_strain_ID) - call kinematics_vacancy_strain_ChemPotAndItsTangent(my_KPot, my_dKPot_dCv, & - crystallite_Tstar_v(1:6,grain,ip,el), & - crystallite_Fi0(1:3,1:3,grain,ip,el), & - crystallite_Fi (1:3,1:3,grain,ip,el), & - grain,ip, el) - - case default - my_KPot = 0.0_pReal - my_dKPot_dCv = 0.0_pReal - - end select - KPot = KPot + my_KPot/lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) - dKPot_dCv = dKPot_dCv + my_dKPot_dCv/lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) - enddo - enddo - - KPot = KPot/homogenization_Ngrains(material_homog(ip,el)) - dKPot_dCv = dKPot_dCv/homogenization_Ngrains(material_homog(ip,el)) - -end subroutine vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized chemical potential and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_cahnhilliard_getChemPotAndItsTangent(ChemPot,dChemPot_dCv,Cv,ip,el) - use numerics, only: & - vacancyBoundPenalty, & - vacancyPolyOrder - use material, only: & - mappingHomogenization, & - vacancyflux_typeInstance, & - porosity, & - porosityMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Cv - real(pReal), intent(out) :: & - ChemPot, & - dChemPot_dCv - real(pReal) :: & - VoidPhaseFrac, kBT, KPot, dKPot_dCv - integer(pInt) :: & - homog, o - - homog = mappingHomogenization(2,ip,el) - VoidPhaseFrac = porosity(homog)%p(porosityMapping(homog)%p(ip,el)) - kBT = vacancyflux_cahnhilliard_getEntropicCoeff(ip,el) - - ChemPot = vacancyflux_cahnhilliard_getFormationEnergy(ip,el) - dChemPot_dCv = 0.0_pReal - do o = 1_pInt, vacancyPolyOrder - ChemPot = ChemPot + kBT*((2.0_pReal*Cv - 1.0_pReal)**real(2_pInt*o-1_pInt,pReal))/ & - real(2_pInt*o-1_pInt,pReal) - dChemPot_dCv = dChemPot_dCv + 2.0_pReal*kBT*(2.0_pReal*Cv - 1.0_pReal)**real(2_pInt*o-2_pInt,pReal) - enddo - - ChemPot = VoidPhaseFrac*VoidPhaseFrac*ChemPot & - - 2.0_pReal*(1.0_pReal - Cv)*(1.0_pReal - VoidPhaseFrac)*(1.0_pReal - VoidPhaseFrac) - - dChemPot_dCv = VoidPhaseFrac*VoidPhaseFrac*dChemPot_dCv & - + 2.0_pReal*(1.0_pReal - VoidPhaseFrac)*(1.0_pReal - VoidPhaseFrac) - - call vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCv, Cv, ip, el) - ChemPot = ChemPot + KPot - dChemPot_dCv = dChemPot_dCv + dKPot_dCv - - if (Cv < 0.0_pReal) then - ChemPot = ChemPot - 3.0_pReal*vacancyBoundPenalty*Cv*Cv - dChemPot_dCv = dChemPot_dCv - 6.0_pReal*vacancyBoundPenalty*Cv - elseif (Cv > 1.0_pReal) then - ChemPot = ChemPot + 3.0_pReal*vacancyBoundPenalty*(1.0_pReal - Cv)*(1.0_pReal - Cv) - dChemPot_dCv = dChemPot_dCv - 6.0_pReal*vacancyBoundPenalty*(1.0_pReal - Cv) - endif - - ChemPot = ChemPot* & - vacancyflux_cahnhilliard_thermalFluc(vacancyflux_typeInstance(homog))%p(mappingHomogenization(1,ip,el)) - dChemPot_dCv = dChemPot_dCv* & - vacancyflux_cahnhilliard_thermalFluc(vacancyflux_typeInstance(homog))%p(mappingHomogenization(1,ip,el)) - -end subroutine vacancyflux_cahnhilliard_getChemPotAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief updated vacancy concentration and its rate with solution from transport PDE -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_cahnhilliard_putVacancyConcAndItsRate(Cv,Cvdot,ip,el) - use material, only: & - mappingHomogenization, & - vacancyConc, & - vacancyConcRate, & - vacancyfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Cv, & - Cvdot - integer(pInt) :: & - homog, & - offset - - homog = mappingHomogenization(2,ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - vacancyConc (homog)%p(offset) = Cv - vacancyConcRate(homog)%p(offset) = Cvdot - -end subroutine vacancyflux_cahnhilliard_putVacancyConcAndItsRate - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of vacancy transport results -!-------------------------------------------------------------------------------------------------- -function vacancyflux_cahnhilliard_postResults(ip,el) - use material, only: & - mappingHomogenization, & - vacancyflux_typeInstance, & - vacancyConc, & - vacancyfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(vacancyflux_cahnhilliard_sizePostResults(vacancyflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & - vacancyflux_cahnhilliard_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - instance = vacancyflux_typeInstance(homog) - - c = 0_pInt - vacancyflux_cahnhilliard_postResults = 0.0_pReal - - do o = 1_pInt,vacancyflux_cahnhilliard_Noutput(instance) - select case(vacancyflux_cahnhilliard_outputID(o,instance)) - - case (vacancyConc_ID) - vacancyflux_cahnhilliard_postResults(c+1_pInt) = vacancyConc(homog)%p(offset) - c = c + 1 - end select - enddo -end function vacancyflux_cahnhilliard_postResults - -end module vacancyflux_cahnhilliard diff --git a/code/vacancyflux_isochempot.f90 b/code/vacancyflux_isochempot.f90 deleted file mode 100644 index 35db8d159..000000000 --- a/code/vacancyflux_isochempot.f90 +++ /dev/null @@ -1,329 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for locally evolving vacancy concentration -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module vacancyflux_isochempot - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - vacancyflux_isochempot_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - vacancyflux_isochempot_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - vacancyflux_isochempot_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - vacancyflux_isochempot_Noutput !< number of outputs per instance of this damage - - enum, bind(c) - enumerator :: undefined_ID, & - vacancyconc_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - vacancyflux_isochempot_outputID !< ID of each post result output - - - public :: & - vacancyflux_isochempot_init, & - vacancyflux_isochempot_updateState, & - vacancyflux_isochempot_getSourceAndItsTangent, & - vacancyflux_isochempot_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_isochempot_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - vacancyflux_type, & - vacancyflux_typeInstance, & - homogenization_Noutput, & - VACANCYFLUX_isochempot_label, & - VACANCYFLUX_isochempot_ID, & - material_homog, & - mappingHomogenization, & - vacancyfluxState, & - vacancyfluxMapping, & - vacancyConc, & - vacancyConcRate, & - vacancyflux_initialCv, & - material_partHomogenization - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_isochempot_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(vacancyflux_type == VACANCYFLUX_isochempot_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(vacancyflux_isochempot_sizePostResults(maxNinstance), source=0_pInt) - allocate(vacancyflux_isochempot_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(vacancyflux_isochempot_output (maxval(homogenization_Noutput),maxNinstance)) - vacancyflux_isochempot_output = '' - allocate(vacancyflux_isochempot_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(vacancyflux_isochempot_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (vacancyflux_type(section) == VACANCYFLUX_isochempot_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = vacancyflux_typeInstance(section) ! which instance of my vacancyflux is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('vacancyconc') - vacancyflux_isochempot_Noutput(instance) = vacancyflux_isochempot_Noutput(instance) + 1_pInt - vacancyflux_isochempot_outputID(vacancyflux_isochempot_Noutput(instance),instance) = vacancyconc_ID - vacancyflux_isochempot_output(vacancyflux_isochempot_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingFile - - initializeInstances: do section = 1_pInt, size(vacancyflux_type) - if (vacancyflux_type(section) == VACANCYFLUX_isochempot_ID) then - NofMyHomog=count(material_homog==section) - instance = vacancyflux_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,vacancyflux_isochempot_Noutput(instance) - select case(vacancyflux_isochempot_outputID(o,instance)) - case(vacancyconc_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - vacancyflux_isochempot_sizePostResult(o,instance) = mySize - vacancyflux_isochempot_sizePostResults(instance) = vacancyflux_isochempot_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 1_pInt - vacancyfluxState(section)%sizeState = sizeState - vacancyfluxState(section)%sizePostResults = vacancyflux_isochempot_sizePostResults(instance) - allocate(vacancyfluxState(section)%state0 (sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) - allocate(vacancyfluxState(section)%subState0(sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) - allocate(vacancyfluxState(section)%state (sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) - - nullify(vacancyfluxMapping(section)%p) - vacancyfluxMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(vacancyConc(section)%p) - vacancyConc(section)%p => vacancyfluxState(section)%state(1,:) - deallocate(vacancyConcRate(section)%p) - allocate(vacancyConcRate(section)%p(NofMyHomog), source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine vacancyflux_isochempot_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates change in vacancy concentration based on local vacancy generation model -!-------------------------------------------------------------------------------------------------- -function vacancyflux_isochempot_updateState(subdt, ip, el) - use numerics, only: & - err_vacancyflux_tolAbs, & - err_vacancyflux_tolRel - use material, only: & - mappingHomogenization, & - vacancyflux_typeInstance, & - vacancyfluxState, & - vacancyConc, & - vacancyConcRate, & - vacancyfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - subdt - logical, dimension(2) :: & - vacancyflux_isochempot_updateState - integer(pInt) :: & - homog, & - offset, & - instance - real(pReal) :: & - Cv, Cvdot, dCvDot_dCv - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - instance = vacancyflux_typeInstance(homog) - - Cv = vacancyfluxState(homog)%subState0(1,offset) - call vacancyflux_isochempot_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) - Cv = Cv + subdt*Cvdot - - vacancyflux_isochempot_updateState = [ abs(Cv - vacancyfluxState(homog)%state(1,offset)) & - <= err_vacancyflux_tolAbs & - .or. abs(Cv - vacancyfluxState(homog)%state(1,offset)) & - <= err_vacancyflux_tolRel*abs(vacancyfluxState(homog)%state(1,offset)), & - .true.] - - vacancyConc (homog)%p(vacancyfluxMapping(homog)%p(ip,el)) = Cv - vacancyConcRate(homog)%p(vacancyfluxMapping(homog)%p(ip,el)) = & - (vacancyfluxState(homog)%state(1,offset) - vacancyfluxState(homog)%subState0(1,offset))/(subdt+tiny(0.0_pReal)) - -end function vacancyflux_isochempot_updateState - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates homogenized vacancy driving forces -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_isochempot_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - phase_source, & - phase_Nsources, & - SOURCE_vacancy_phenoplasticity_ID, & - SOURCE_vacancy_irradiation_ID, & - SOURCE_vacancy_thermalfluc_ID - use source_vacancy_phenoplasticity, only: & - source_vacancy_phenoplasticity_getRateAndItsTangent - use source_vacancy_irradiation, only: & - source_vacancy_irradiation_getRateAndItsTangent - use source_vacancy_thermalfluc, only: & - source_vacancy_thermalfluc_getRateAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Cv - integer(pInt) :: & - phase, & - grain, & - source - real(pReal) :: & - CvDot, dCvDot_dCv, localCvDot, dLocalCvDot_dCv - - CvDot = 0.0_pReal - dCvDot_dCv = 0.0_pReal - do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) - phase = phaseAt(grain,ip,el) - do source = 1_pInt, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_vacancy_phenoplasticity_ID) - call source_vacancy_phenoplasticity_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) - - case (SOURCE_vacancy_irradiation_ID) - call source_vacancy_irradiation_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) - - case (SOURCE_vacancy_thermalfluc_ID) - call source_vacancy_thermalfluc_getRateAndItsTangent(localCvDot, dLocalCvDot_dCv, grain, ip, el) - - end select - CvDot = CvDot + localCvDot - dCvDot_dCv = dCvDot_dCv + dLocalCvDot_dCv - enddo - enddo - - CvDot = CvDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - dCvDot_dCv = dCvDot_dCv/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - -end subroutine vacancyflux_isochempot_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of vacancy transport results -!-------------------------------------------------------------------------------------------------- -function vacancyflux_isochempot_postResults(ip,el) - use material, only: & - mappingHomogenization, & - vacancyflux_typeInstance, & - vacancyConc, & - vacancyfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(vacancyflux_isochempot_sizePostResults(vacancyflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & - vacancyflux_isochempot_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - instance = vacancyflux_typeInstance(homog) - - c = 0_pInt - vacancyflux_isochempot_postResults = 0.0_pReal - - do o = 1_pInt,vacancyflux_isochempot_Noutput(instance) - select case(vacancyflux_isochempot_outputID(o,instance)) - - case (vacancyconc_ID) - vacancyflux_isochempot_postResults(c+1_pInt) = vacancyConc(homog)%p(offset) - c = c + 1 - end select - enddo -end function vacancyflux_isochempot_postResults - -end module vacancyflux_isochempot diff --git a/code/vacancyflux_isoconc.f90 b/code/vacancyflux_isoconc.f90 deleted file mode 100644 index 63cfb1b62..000000000 --- a/code/vacancyflux_isoconc.f90 +++ /dev/null @@ -1,63 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for constant vacancy concentration -!-------------------------------------------------------------------------------------------------- -module vacancyflux_isoconc - - implicit none - private - - public :: & - vacancyflux_isoconc_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_isoconc_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_isoconc_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (vacancyflux_type(homog) == VACANCYFLUX_isoconc_ID) then - NofMyHomog = count(material_homog == homog) - vacancyfluxState(homog)%sizeState = 0_pInt - vacancyfluxState(homog)%sizePostResults = 0_pInt - allocate(vacancyfluxState(homog)%state0 (0_pInt,NofMyHomog)) - allocate(vacancyfluxState(homog)%subState0(0_pInt,NofMyHomog)) - allocate(vacancyfluxState(homog)%state (0_pInt,NofMyHomog)) - - deallocate(vacancyConc (homog)%p) - allocate (vacancyConc (homog)%p(1), source=vacancyflux_initialCv(homog)) - deallocate(vacancyConcRate(homog)%p) - allocate (vacancyConcRate(homog)%p(1), source=0.0_pReal) - - endif myhomog - enddo initializeInstances - - -end subroutine vacancyflux_isoconc_init - -end module vacancyflux_isoconc From 409f98514baa95f80d91f0ebffcbcd0294b36a56 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Thu, 25 Feb 2016 14:30:12 -0500 Subject: [PATCH 007/183] updating structure of the CMake build system --- build_spectral.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 build_spectral.sh diff --git a/build_spectral.sh b/build_spectral.sh new file mode 100755 index 000000000..1f8f8473f --- /dev/null +++ b/build_spectral.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +cat README +echo "Building spectral solver with ${FC}" + +# prepare building directory +if [ ! -d build_spectral ] ; then + mkdir build_spectral +fi +cd build_spectral + +# start building +cmake -D PETSC_DIR=${PETSC_DIR} \ + -D HDF5=${HDF5} \ + .. + +# instruction for compiling +echo "Please go into build_spectral directory and use make" +echo "to build DAMASK_spectal.exe" \ No newline at end of file From 400076b742100758ddc0e6c1777edfde7eb0ee33 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Thu, 25 Feb 2016 15:40:10 -0500 Subject: [PATCH 008/183] cumulative modification to CMake build system --- build_FEM.sh | 0 build_marc.sh | 0 build_spectral.sh | 25 ++++++++++++++++++++----- 3 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 build_FEM.sh create mode 100644 build_marc.sh diff --git a/build_FEM.sh b/build_FEM.sh new file mode 100644 index 000000000..e69de29bb diff --git a/build_marc.sh b/build_marc.sh new file mode 100644 index 000000000..e69de29bb diff --git a/build_spectral.sh b/build_spectral.sh index 1f8f8473f..b21e633eb 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -2,16 +2,31 @@ cat README echo "Building spectral solver with ${FC}" +DAMASKVERSION :=$(shell cat ../VERSION) # prepare building directory -if [ ! -d build_spectral ] ; then - mkdir build_spectral +if [ -d build_spectral ] ; then + rm -rf build_spectral fi +mkdir build_spectral cd build_spectral -# start building -cmake -D PETSC_DIR=${PETSC_DIR} \ - -D HDF5=${HDF5} \ +## +# CMake call +# PETSC_DIR | PETSC directory +# HDF5_DIR | HDF5 library (same compiler for DAMASK) +# DAMASK_ROOT | DAMASK source location +# DAMASK_V | DAMASK current revision +# CMAKE_BUILD_TYPE | Default set to release (no debugging output) +# OPENMP | "ON" will turn on OPENMP support +# OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] +cmake -D PETSC_DIR=${PETSC_DIR} \ + -D HDF5_DIR=${HDF5_DIR} \ + -D DAMASK_ROOT=.. \ + -D DAMASK_V=${DAMASKVERSION} \ + -D CMAKE_BUILD_TYPE=RELEASE \ + -D OPENMP=ON \ + -D OPTIMIZATION=DEFENSIVE \ .. # instruction for compiling From b5c630141def6f78be32779fe98124ca61de55bf Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Thu, 25 Feb 2016 16:33:21 -0500 Subject: [PATCH 009/183] converting compiler flag settings to CMake --- CMakeLists.txt | 348 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 302 insertions(+), 46 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b9eba77b..d2fa52e9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,66 +1,322 @@ -# INITIAL ATTEMPT OF USING CMAKE TO BUILD THE SPECTRAL SOLVER -# CMAKE SHOULD BE ABLE TO TAKE CARE OF THE DEPENDENCE BY ITSELF. -# +######################################################################################## +# CMAKE for build the Material subroutine for BVP solution +######################################################################################## +# OPTIONS = standard (alternative): meaning +#------------------------------------------------------------- +# F90 = ifort (gfortran): compiler type, choose Intel or GNU +# COMPILERNAME = name of the compiler executable (if not the same as the ype), e.g. using mpich-g90 instead of ifort +# PORTABLE = TRUE (FALSE): decision, if executable is optimized for the machine on which it was built. +# OPTIMIZATION = DEFENSIVE (OFF,AGGRESSIVE,ULTRA): Optimization mode: O2, O0, O3 + further options for most files, O3 + further options for all files +# OPENMP = TRUE (FALSE): OpenMP multiprocessor support +# PREFIX = arbitrary prefix (before compilername) +# OPTION = arbitrary option (just before file to compile) +# SUFFIX = arbitrary suffix (after file to compile) +# STANDARD_CHECK = checking for Fortran 2008, compiler dependend +######################################################################################## cmake_minimum_required (VERSION 3.1.0) -project (DAMASKSpectral Fortran) - - -# make sure that the default is a RELEASE -if (NOT CMAKE_BUILD_TYPE) - set (CMAKE_BUILD_TYPE RELEASE CACHE STRING - "Choose the type of build, options are: None Debug Release." - FORCE) -endif (NOT CMAKE_BUILD_TYPE) - +project (DAMASK Fortran) # The version number. -set (DAMASKSpectral_VERSION_MAJOR 1) -set (DAMASKSpectral_VERSION_MINOR 0) +set (DAMASK_VERSION_MAJOR 1) +set (DAMASK_VERSION_MINOR ${DAMASK_V}) -# Set up build directory -set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/build) -set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) -set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +## +# find_package() might not work on customized system. +# it is recommended for the user to specify the location +# of PETSc and HDF5 library +if (defined PETSC_DIR) + set (PETSC ${PETSC_DIR}) +else (defined PETSC_DIR) + find_package(PETSC) +endif (defined PETSC_DIR) +if (defined HDF5_DIR) + set (HDF5 ${HDF5_DIR}) +else (defined HDF5_DIR) + find_package(HDF5) +endif (defined HDF5_DIR) -# setup modules -find_package(petsc) -find_package(hdf5) +## +# set system include directories +include_directories( + ${PETSC}/lib/petsc/conf/variables + ${PETSC}/lib/petsc/conf/rules + ../lib + ${HDF5}/include + ) -# FFLAGS depend on the compiler -# need extra time to work on these +## +# set compile and debug flags +if (OPENMP MATCHES 'ON') + set (OPENMP_FLAG_ifort "-openmp -openmp-report0 -parallel") + set (OPENMP_FLAG_gfortran "-fopenmp") +else (OPENMP MATCHES 'ON') + message("No openmp support specified") + set (OPENMP_FLAG_ifort "") + set (OPENMP_FLAG_gfortran "") +endif (OPENMP MATCHES 'ON') + +if (OPTIMIZATION MATCHES "OFF") + set (OPTIMIZATION_ifort "-O0 -no-ip") + set (OPTIMIZATION_gfortran "-O0") +elseif (OPTIMIZATION MATCHES "DEFENSIVE") + set (OPTIMIZATION_ifort "-O2") + set (OPTIMIZATION_gfortran "-O2") +elseif (OPTIMIZATION MATCHES "AGGRESSIVE") + set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost") #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" + set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") +elseif (OPTIMIZATION MATCHES "ULTRA") + set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost") #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" + set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") +else (OPTIMIZATION MATCHES "OFF") + set (OPTIMIZATION_ifort "-O2") + set (OPTIMIZATION_gfortran "-O2") +endif (OPTIMIZATION MATCHES "OFF") + +set (STANDARD_CHECK_ifort "-stand f08 -standard-semantics") +set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) + +################################################################################################### +# COMPILE SWITCHES +# -shared-intel: Link against shared Intel libraries instead of static ones +# -fpp: preprocessor +# -ftz: flush unterflow to zero, automatically set if O<0,1,2,3> >0 +# -assume byterecl record length is given in bytes (also set by -standard-semantics) +# fpe_summary print list of floating point exceptions occured during execution +# -fimplicit-none: assume "implicit-none" even if not present in source +# -diag-disable: disables warnings, where +# warning ID 5268: the text exceeds right hand column allowed on the line (we have only comments there) +# -warn: enables warnings, where +# declarations: any undeclared names (alternative name: -implicitnone) +# general: warning messages and informational messages are issued by the compiler +# usage: questionable programming practices +# interfaces: checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks +# ignore_loc: %LOC is stripped from an actual argument +# alignments: data that is not naturally aligned +# unused: declared variables that are never used +# stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) +# +################################################################################################### +# MORE OPTIONS FOR DEBUGGING DURING COMPILATION +# -warn: enables warnings, where +# truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) +# uncalled: Determines whether warnings occur when a statement function is never called +# all: +# -name as_is: case sensitive Fortran! +################################################################################################### +set (COMPILE_OPTIONS_ifort "-DDAMASKVERSION=${DAMASK_V}" + "-fpp" + "-ftz" + "-assume byterecl,fpe_summary" + "-diag-disable 5268" + "-warn declarations" + "-warn general" + "-warn usage" + "-warn interfaces" + "-warn ignore_loc" + "-warn alignments" + "-warn unused" + ) + +################################################################################################### +# COMPILE SWITCHES FOR RUNTIME DEBUGGING +# -g: Generate symbolic debugging information in the object file +# -traceback: Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. +# -gen-interfaces: Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ +# -fp-stack-check: Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. +# -ftrapuv Trap uninitalized variables +# -check: checks at runtime, where +# bounds: check if an array index is too small (<1) or too large! +# format: Checking for the data type of an item being formatted for output. +# output_conversion: Checking for the fit of data items within a designated format descriptor field. +# pointers: Checking for certain disassociated or uninitialized pointers or unallocated allocatable objects. +# uninit: Checking for uninitialized variables. +# -fpe-all0 capture all floating-point exceptions, sets -ftz automatically +# -warn: enables warnings, where +# errors: warnings are changed to errors +# stderrors: warnings about Fortran standard violations are changed to errors +# information on http://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors/ +################################################################################################### +# MORE OPTIONS FOR RUNTIME DEBUGGING +# -heap-arrays: should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits +# -check: checks at runtime, where +# arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) +# stack: +################################################################################################### +set (DEBUG_OPTIONS_ifort "-g" + "-traceback" + "-gen-interfaces" + "-fp-stack-check" + "-fp-model strict" + "-check bounds,format,output_conversion,pointers,uninit" + "-ftrapuv" + "-fpe-all0" + "-warn errors" + "-warn stderrors" + "-debug-parameters all" + ) + +set (LINK_OPTIONS_ifort "-shared-intel") + +################################################################################################### +# COMPILE SWITCHES +# -shared +# -Wl,-undefined,dynamic_lookup:ensure to link against dynamic libraries +# -xf95-cpp-input: preprocessor +# -ffree-line-length-132: restrict line length to the standard 132 characters +# -ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) +# -fimplicit-none: assume "implicit-none" even if not present in source +# -fmodule-private: assume "private" even if not present in source +# -Wcharacter-truncation: warn if character expressions (strings) are truncated +# -Wunderflow: produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation +# -Wsuggest-attribute=pure: +# -Wsuggest-attribute=noreturn: +# -Wconversion-extra +# -Wimplicit-procedure +# -Wall: sets the following Fortran options: +# -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. +# -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line +# -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime +# -Wconversion: warn about implicit conversions between different type +# -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. +# -Wc-binding-type: +# -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error +# -Wno-tabs: do not allow tabs in source +# -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic +# -Wline-truncation: +# -Wtarget-lifetime: +# -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter +# -Wunused: a number of unused-xxx warnings +# these are general (non -Fortran options) implied by -Wall +# -Waddress +# -Warray-bounds (only with -O2) +# -Wc++11-compat +# -Wchar-subscripts +# -Wcomment +# -Wformat +# -Wmaybe-uninitialized +# -Wnonnull +# -Wparentheses +# -Wpointer-sign +# -Wreorder +# -Wreturn-type +# -Wsequence-point +# -Wstrict-aliasing +# -Wstrict-overflow=1 +# -Wswitch +# -Wtrigraphs +# -Wuninitialized +# -Wunknown-pragmas +# -Wunused-function +# -Wunused-label +# -Wunused-value +# -Wunused-variable +# -Wvolatile-register-var +# -Wextra: sets the following Fortran options: +# -Wunuses-parameter: +# -Wcompare-reals: +# these are general (non -Fortran options) implied by -Wextra +# -Wclobbered +# -Wempty-body +# -Wignored-qualifiers +# -Wmissing-field-initializers +# -Woverride-init +# -Wsign-compare +# -Wtype-limits +# -Wuninitialized +# -Wunused-but-set-parameter (only with -Wunused or -Wall) +# -Wno-globals +# -ffpe-summary=all only for newer gfortran +################################################################################################### +# MORE OPTIONS FOR DEBUGGING DURING COMPILATION +# -Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): +# -Wimplicit-interface: no interfaces for lapack routines +# -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. +# -Wstrict-overflow: +################################################################################################### +set (COMPILE_OPTIONS_gfortran "-DDAMASKVERSION=${DAMASKVERSION}" + "-xf95-cpp-input" + "-ffree-line-length-132" + "-fimplicit-none" + "-fmodule-private" + "-Wall" + "-Wextra" + "-Wcharacter-truncation" + "-Wunderflow" + "-Wsuggest-attribute=pure" + "-Wsuggest-attribute=noreturn" + "-Wconversion-extra" + "-Wimplicit-procedure" + "-Wno-unused-parameter" + ) + +################################################################################################### +# COMPILE SWITCHES FOR RUNTIME DEBUGGING +# -ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) +# zero,\ +# overflow +# -fcheck=all: sets the following Fortran options: +# array-temps +# bounds +# do +# mem +# pointer +# recursion +################################################################################################### +# MORE OPTIONS FOR RUNTIME DEBUGGING +# -ffpe-trap=precision,\ +# denormal, \ +# underflow +################################################################################################### +set (DEBUG_OPTIONS_gfortran "-g" + "-fbacktrace" + "-fdump-core" + "-fcheck=all" + "-ffpe-trap=invalid,zero,overflow" + ) + +set (LINK_OPTIONS_gfortran "-Wl,-undefined,dynamic_lookup") + +# set FLAGS get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) -if (Fortran_COMPILER_NAME MATCHES "gfortran.*") - # gfortran - set (CMAKE_Fortran_FLAGS_RELEASE "-funroll-all-loops -fno-f2c -O3") - set (CMAKE_Fortran_FLAGS_DEBUG "-fno-f2c -O0 -g") -elseif (Fortran_COMPILER_NAME MATCHES "ifort.*") - # ifort (untested) - set (CMAKE_Fortran_FLAGS_RELEASE "-f77rtl -O3") - set (CMAKE_Fortran_FLAGS_DEBUG "-f77rtl -O0 -g") +if (Fortran_COMPILER_NAME MATCHES "ifort.*") + # for RELEASE + set (CMAKE_Fortran_FLAGS_RELEASE ${COMPILE_OPTIONS_ifort}) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE ${LINK_OPTIONS_ifort} + ${OPTIMIZATION_ifort} ) + # for DEBUG + set (CMAKE_Fortran_FLAGS_DEBUG ${COMPILE_OPTIONS_ifort} + ${DEBUG_OPTIONS_ifort} ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG ${LINK_OPTIONS_ifort} + ${DEBUG_OPTIONS_ifort} ) + # +elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") + # for RELEASE + set (CMAKE_Fortran_FLAGS_RELEASE ${COMPILE_OPTIONS_gfortran}) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE ${LINK_OPTIONS_gfortran} + ${OPTIMIZATION_gfortran} ) + # for DEBUG + set (CMAKE_Fortran_FLAGS_DEBUG ${COMPILE_OPTIONS_gfortran} + ${DEBUG_OPTIONS_gfortran} ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG ${LINK_OPTIONS_gfortran} + ${DEBUG_OPTIONS_gfortran} ) + # elseif (Fortran_COMPILER_NAME MATCHES "g77") - # g77 - set (CMAKE_Fortran_FLAGS_RELEASE "-funroll-all-loops -fno-f2c -O3 -m32") - set (CMAKE_Fortran_FLAGS_DEBUG "-fno-f2c -O0 -g -m32") -else (Fortran_COMPILER_NAME MATCHES "gfortran.*") - message ("CMAKE_Fortran_COMPILER full path: " ${CMAKE_Fortran_COMPILER}) - message ("Fortran compiler: " ${Fortran_COMPILER_NAME}) - message ("No optimized Fortran compiler flags are known, we just try -O2...") - set (CMAKE_Fortran_FLAGS_RELEASE "-O2") - set (CMAKE_Fortran_FLAGS_DEBUG "-O0 -g") -endif (Fortran_COMPILER_NAME MATCHES "gfortran.*") - + message (FATAL_ERROR "Fortran 77 is not supported.") +else (Fortran_COMPILER_NAME MATCHES "ifort.*") + message (FATAL_ERROR "Require Fortran90 from GNU or Intel.") +endif (Fortran_COMPILER_NAME MATCHES "ifort.*") +## # ADD CODE(SOURCE) DIRECTORY add_subdirectory(code) - +## # ADD TESTING CASES add_test (SmokeTestRun DAMASK_spectral.exe -g test/test1.geom -l test/test.load) - # Enable Dashboard scripting # include (CTest) -# set (CTEST_PROJECT_NAME "DAMASK") +# set (CTEST_PROJECT_NAME "DAMASK") \ No newline at end of file From a8f0624849c2e7023b3a51770b64a103d5e1895f Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Thu, 25 Feb 2016 16:40:26 -0500 Subject: [PATCH 010/183] initial translation is done for spectral solver --- build_spectral.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build_spectral.sh b/build_spectral.sh index b21e633eb..7a4239f86 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -2,7 +2,7 @@ cat README echo "Building spectral solver with ${FC}" -DAMASKVERSION :=$(shell cat ../VERSION) +DAMASKVERSION :=$(sh cat ../VERSION) # prepare building directory if [ -d build_spectral ] ; then @@ -15,14 +15,12 @@ cd build_spectral # CMake call # PETSC_DIR | PETSC directory # HDF5_DIR | HDF5 library (same compiler for DAMASK) -# DAMASK_ROOT | DAMASK source location # DAMASK_V | DAMASK current revision # CMAKE_BUILD_TYPE | Default set to release (no debugging output) # OPENMP | "ON" will turn on OPENMP support # OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] cmake -D PETSC_DIR=${PETSC_DIR} \ -D HDF5_DIR=${HDF5_DIR} \ - -D DAMASK_ROOT=.. \ -D DAMASK_V=${DAMASKVERSION} \ -D CMAKE_BUILD_TYPE=RELEASE \ -D OPENMP=ON \ From a0e98c328c190fa07ecaf3051edc42dc1013500b Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Fri, 26 Feb 2016 11:08:25 -0500 Subject: [PATCH 011/183] set different compiling flags for FEM and SPECTRAL --- CMakeLists.txt | 219 ++++++++++++++++------------- build_spectral.sh | 21 ++- code/CMakeLists.txt | 25 +++- code/damage/CMakeLists.txt | 4 +- code/homogenization/CMakeLists.txt | 4 +- code/hydrogenflux/CMakeLists.txt | 4 +- code/kinematics/CMakeLists.txt | 4 +- code/plastic/CMakeLists.txt | 4 +- code/porosity/CMakeLists.txt | 4 +- code/source/CMakeLists.txt | 4 +- code/spectral/CMakeLists.txt | 4 +- code/thermal/CMakeLists.txt | 4 +- code/vacancyflux/CMakeLists.txt | 4 +- 13 files changed, 180 insertions(+), 125 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2fa52e9a..a9e672c00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,58 +20,68 @@ project (DAMASK Fortran) set (DAMASK_VERSION_MAJOR 1) set (DAMASK_VERSION_MINOR ${DAMASK_V}) -## -# find_package() might not work on customized system. -# it is recommended for the user to specify the location -# of PETSc and HDF5 library -if (defined PETSC_DIR) - set (PETSC ${PETSC_DIR}) -else (defined PETSC_DIR) - find_package(PETSC) -endif (defined PETSC_DIR) +# PETSC and HDF5 is required +if (NOT DEFINED PETSC_DIR) + message (FATAL_ERROR "PETSC_DIR is not found!") +endif (NOT DEFINED PETSC_DIR) +if (NOT DEFINED HDF5_DIR) + message (FATAL_ERROR "HDF5_DIR is not found!" ) +endif (NOT DEFINED HDF5_DIR) + +# OUTPUT TYPE +set (SPECTRAL OFF) +set (FEM OFF) +set (MARC OFF) +set (ABAQUS OFF) +if (DAMASK_DRIVER STREQUAL "SPECTRAL") + set (SPECTRAL ON ) +elseif (DAMASK_DRIVER STREQUAL "FEM") + set (FEM ON ) +elseif (DAMASK_DRIVER STREQUAL "MARC") + set (MARC ON ) +elseif (DAMASK_DRIVER STREQUAL "ABAQUS") + set (ABAQUS ON ) +else (DAMASK_DRIVER STREQUAL "SPECTRAL") + message (FATAL_ERROR "Unknown output, check build script!") +endif (DAMASK_DRIVER STREQUAL "SPECTRAL") -if (defined HDF5_DIR) - set (HDF5 ${HDF5_DIR}) -else (defined HDF5_DIR) - find_package(HDF5) -endif (defined HDF5_DIR) -## # set system include directories include_directories( - ${PETSC}/lib/petsc/conf/variables - ${PETSC}/lib/petsc/conf/rules + ${PETSC_DIR}/lib/petsc/conf/variables + ${PETSC_DIR}/lib/petsc/conf/rules ../lib - ${HDF5}/include + ${HDF5_DIR}/include ) +link_directories(${HDF5_DIR}/lib) ## # set compile and debug flags -if (OPENMP MATCHES 'ON') +if (OPENMP) set (OPENMP_FLAG_ifort "-openmp -openmp-report0 -parallel") set (OPENMP_FLAG_gfortran "-fopenmp") -else (OPENMP MATCHES 'ON') +else (OPENMP) message("No openmp support specified") set (OPENMP_FLAG_ifort "") set (OPENMP_FLAG_gfortran "") -endif (OPENMP MATCHES 'ON') +endif (OPENMP) -if (OPTIMIZATION MATCHES "OFF") +if (OPTIMIZATION STREQUAL "OFF") set (OPTIMIZATION_ifort "-O0 -no-ip") - set (OPTIMIZATION_gfortran "-O0") -elseif (OPTIMIZATION MATCHES "DEFENSIVE") + set (OPTIMIZATION_gfortran "-O0" ) +elseif (OPTIMIZATION STREQUAL "DEFENSIVE") set (OPTIMIZATION_ifort "-O2") set (OPTIMIZATION_gfortran "-O2") -elseif (OPTIMIZATION MATCHES "AGGRESSIVE") - set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost") #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" +elseif (OPTIMIZATION STREQUAL "AGGRESSIVE") + set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") -elseif (OPTIMIZATION MATCHES "ULTRA") - set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost") #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" +elseif (OPTIMIZATION STREQUAL "ULTRA") + set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") -else (OPTIMIZATION MATCHES "OFF") +else (OPTIMIZATION STREQUAL "OFF") set (OPTIMIZATION_ifort "-O2") set (OPTIMIZATION_gfortran "-O2") -endif (OPTIMIZATION MATCHES "OFF") +endif (OPTIMIZATION STREQUAL "OFF") set (STANDARD_CHECK_ifort "-stand f08 -standard-semantics") set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) @@ -104,19 +114,18 @@ set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) # all: # -name as_is: case sensitive Fortran! ################################################################################################### -set (COMPILE_OPTIONS_ifort "-DDAMASKVERSION=${DAMASK_V}" - "-fpp" - "-ftz" - "-assume byterecl,fpe_summary" - "-diag-disable 5268" - "-warn declarations" - "-warn general" - "-warn usage" - "-warn interfaces" - "-warn ignore_loc" - "-warn alignments" - "-warn unused" - ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -DDAMASKVERSION=${DAMASK_V}" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -fpp" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -ftz" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -assume byterecl,fpe_summary" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -diag-disable 5268" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn declarations" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn general" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn usage" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn interfaces" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn ignore_loc" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn alignments" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn unused" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING @@ -143,18 +152,17 @@ set (COMPILE_OPTIONS_ifort "-DDAMASKVERSION=${DAMASK_V}" # arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) # stack: ################################################################################################### -set (DEBUG_OPTIONS_ifort "-g" - "-traceback" - "-gen-interfaces" - "-fp-stack-check" - "-fp-model strict" - "-check bounds,format,output_conversion,pointers,uninit" - "-ftrapuv" - "-fpe-all0" - "-warn errors" - "-warn stderrors" - "-debug-parameters all" - ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -g" ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -traceback" ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -gen-interfaces" ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -fp-stack-check" ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -fp-model strict" ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -check bounds,format,output_conversion,pointers,uninit" ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -ftrapuv" ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -fpe-all0" ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -warn errors" ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -warn stderrors" ) +set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -debug-parameters all" ) set (LINK_OPTIONS_ifort "-shared-intel") @@ -163,7 +171,7 @@ set (LINK_OPTIONS_ifort "-shared-intel") # -shared # -Wl,-undefined,dynamic_lookup:ensure to link against dynamic libraries # -xf95-cpp-input: preprocessor -# -ffree-line-length-132: restrict line length to the standard 132 characters +# -ffree-line-length-132: restrict line length to the standard 240 characters (lattice.f90 require larger) # -ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) # -fimplicit-none: assume "implicit-none" even if not present in source # -fmodule-private: assume "private" even if not present in source @@ -234,21 +242,20 @@ set (LINK_OPTIONS_ifort "-shared-intel") # -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. # -Wstrict-overflow: ################################################################################################### -set (COMPILE_OPTIONS_gfortran "-DDAMASKVERSION=${DAMASKVERSION}" - "-xf95-cpp-input" - "-ffree-line-length-132" - "-fimplicit-none" - "-fmodule-private" - "-Wall" - "-Wextra" - "-Wcharacter-truncation" - "-Wunderflow" - "-Wsuggest-attribute=pure" - "-Wsuggest-attribute=noreturn" - "-Wconversion-extra" - "-Wimplicit-procedure" - "-Wno-unused-parameter" - ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -DDAMASKVERSION=${DAMASKVERSION}") +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -xf95-cpp-input" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -ffree-line-length-240" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fimplicit-none" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fmodule-private" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wall" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wextra" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wcharacter-truncation" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wunderflow" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wsuggest-attribute=pure" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wsuggest-attribute=noreturn" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wconversion-extra" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wimplicit-procedure" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wno-unused-parameter" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING @@ -268,39 +275,48 @@ set (COMPILE_OPTIONS_gfortran "-DDAMASKVERSION=${DAMASKVERSION}" # denormal, \ # underflow ################################################################################################### -set (DEBUG_OPTIONS_gfortran "-g" - "-fbacktrace" - "-fdump-core" - "-fcheck=all" - "-ffpe-trap=invalid,zero,overflow" - ) +set (DEBUG_OPTIONS_gfortran "${DEBUG_OPTIONS_gfortran} -g" ) +set (DEBUG_OPTIONS_gfortran "${DEBUG_OPTIONS_gfortran} -fbacktrace" ) +set (DEBUG_OPTIONS_gfortran "${DEBUG_OPTIONS_gfortran} -fdump-core" ) +set (DEBUG_OPTIONS_gfortran "${DEBUG_OPTIONS_gfortran} -fcheck=all" ) +set (DEBUG_OPTIONS_gfortran "${DEBUG_OPTIONS_gfortran} -ffpe-trap=invalid,zero,overflow") set (LINK_OPTIONS_gfortran "-Wl,-undefined,dynamic_lookup") +################################################################################################### +#-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) +#-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) +################################################################################################### +set (PRECISION_ifort "-real-size 64 -integer-size 32 -DFLOAT=8 -DINT=4") + +################################################################################################### +#-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set +#-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used +#-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) +################################################################################################### +set (PRECISION_gfortran "-fdefault-real-8 -fdefault-double-8 -DFLOAT=8 -DINT=4") + # set FLAGS get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) if (Fortran_COMPILER_NAME MATCHES "ifort.*") + # need the PETSC wrapped version of ifort + set (CMAKE_Fortran_COMPILER "${PETSC_DIR}/bin/mpifort") # for RELEASE - set (CMAKE_Fortran_FLAGS_RELEASE ${COMPILE_OPTIONS_ifort}) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE ${LINK_OPTIONS_ifort} - ${OPTIMIZATION_ifort} ) + set (CMAKE_Fortran_FLAGS_RELEASE "${COMPILE_OPTIONS_ifort}") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_ifort}") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}") # for DEBUG - set (CMAKE_Fortran_FLAGS_DEBUG ${COMPILE_OPTIONS_ifort} - ${DEBUG_OPTIONS_ifort} ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG ${LINK_OPTIONS_ifort} - ${DEBUG_OPTIONS_ifort} ) - # + set (CMAKE_Fortran_FLAGS_DEBUG "${COMPILE_OPTIONS_ifort} ${DEBUG_OPTIONS_ifort}") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${LINK_OPTIONS_ifort} ${DEBUG_OPTIONS_ifort}") elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") + set (CMAKE_Fortran_COMPILER "${PETSC_DIR}/bin/mpif90") # for RELEASE - set (CMAKE_Fortran_FLAGS_RELEASE ${COMPILE_OPTIONS_gfortran}) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE ${LINK_OPTIONS_gfortran} - ${OPTIMIZATION_gfortran} ) + set (CMAKE_Fortran_FLAGS_RELEASE "${COMPILE_OPTIONS_gfortran}") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${LINK_OPTIONS_gfortran} ${OPTIMIZATION_gfortran}") # for DEBUG - set (CMAKE_Fortran_FLAGS_DEBUG ${COMPILE_OPTIONS_gfortran} - ${DEBUG_OPTIONS_gfortran} ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG ${LINK_OPTIONS_gfortran} - ${DEBUG_OPTIONS_gfortran} ) + set (CMAKE_Fortran_FLAGS_DEBUG "${COMPILE_OPTIONS_gfortran} ${DEBUG_OPTIONS_gfortran}") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${LINK_OPTIONS_gfortran} ${DEBUG_OPTIONS_gfortran}") # elseif (Fortran_COMPILER_NAME MATCHES "g77") message (FATAL_ERROR "Fortran 77 is not supported.") @@ -308,14 +324,27 @@ else (Fortran_COMPILER_NAME MATCHES "ifort.*") message (FATAL_ERROR "Require Fortran90 from GNU or Intel.") endif (Fortran_COMPILER_NAME MATCHES "ifort.*") +# additional flag for SPECTRAL solver +if (SPECTRAL) + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DSpectral") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DSpectral") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${LINK_OPTIONS_ifort} -DSpectral") +endif (SPECTRAL) +# additional flags for FEM solver +if (FEM) + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DFEM") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DFEM") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${LINK_OPTIONS_ifort} -DFEM") +endif (FEM) + ## -# ADD CODE(SOURCE) DIRECTORY +# ADD CODE DIRECTORY add_subdirectory(code) ## # ADD TESTING CASES -add_test (SmokeTestRun - DAMASK_spectral.exe -g test/test1.geom -l test/test.load) +# add_test (SmokeTestRun +# DAMASK_spectral.exe -g test/test1.geom -l test/test.load) # Enable Dashboard scripting # include (CTest) diff --git a/build_spectral.sh b/build_spectral.sh index 7a4239f86..36b60a771 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -1,10 +1,20 @@ #!/bin/bash cat README +echo echo "Building spectral solver with ${FC}" -DAMASKVERSION :=$(sh cat ../VERSION) +DAMASKVERSION=$(cat VERSION) # prepare building directory +# structure: +# BUILD_DIR +# |-BUILD_SPECTRAL +# |-BUILD_FEM +# |-BUILD_MARC +if [ ! -d build ]; then + mkdir build +fi +cd build if [ -d build_spectral ] ; then rm -rf build_spectral fi @@ -17,16 +27,17 @@ cd build_spectral # HDF5_DIR | HDF5 library (same compiler for DAMASK) # DAMASK_V | DAMASK current revision # CMAKE_BUILD_TYPE | Default set to release (no debugging output) -# OPENMP | "ON" will turn on OPENMP support +# OPENMP | [ON/OFF] # OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] +# DAMASK_DRIVER | [SPECTRAL, FEM, MARC] cmake -D PETSC_DIR=${PETSC_DIR} \ -D HDF5_DIR=${HDF5_DIR} \ -D DAMASK_V=${DAMASKVERSION} \ -D CMAKE_BUILD_TYPE=RELEASE \ -D OPENMP=ON \ -D OPTIMIZATION=DEFENSIVE \ - .. + -D DAMASK_DRIVER=SPECTRAL \ + ../.. # instruction for compiling -echo "Please go into build_spectral directory and use make" -echo "to build DAMASK_spectal.exe" \ No newline at end of file +echo "Please go into the directory above and use make to build DAMASK_spectal.exe" \ No newline at end of file diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 9c9688490..544118af7 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,4 +1,19 @@ + +include_directories(${PROJECT_SRC_DIR}/code) +include_directories(${PROJECT_SRC_DIR}/code/damage) +include_directories(${PROJECT_SRC_DIR}/code/homogenization) +include_directories(${PROJECT_SRC_DIR}/code/hydrogenflux) +include_directories(${PROJECT_SRC_DIR}/code/kinematics) +include_directories(${PROJECT_SRC_DIR}/code/plastic) +include_directories(${PROJECT_SRC_DIR}/code/porosity) +include_directories(${PROJECT_SRC_DIR}/code/source) +include_directories(${PROJECT_SRC_DIR}/code/spectral) +include_directories(${PROJECT_SRC_DIR}/code/thermal) +include_directories(${PROJECT_SRC_DIR}/code/vacancyflux) + # group sources for base modules +# the FEM modules would require special attention +# will take care of it later. set (SRC "CPFEM" "CPFEM2" "core_quit" @@ -6,7 +21,7 @@ set (SRC "CPFEM" "compilation_info" "constitutive" "crystallite" - "damask_hdf5.f90" + "damask_hdf5" "debug" "FEsolving" "IO" @@ -22,12 +37,12 @@ set (SRC "CPFEM" # compiler base modules foreach (p ${SRC}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries/modules for linking foreach (p ${SRC}) - set (AUX_LIB ${AUX_LIB} ${p}) + set (DAMASK_LIB ${DAMASK_LIB} ${p}) endforeach (p) # compile each sub moudel @@ -37,11 +52,11 @@ add_subdirectory(hydrogenflux) add_subdirectory(kinematics) add_subdirectory(plastic) add_subdirectory(porosity) -add_subdirectory(sources) +add_subdirectory(source) add_subdirectory(spectral) add_subdirectory(thermal) add_subdirectory(vacancyflux) # compile spectral solver add_executable(DAMASKSpectral.exe DAMASK_spectral.f90) -target_link_libraries (DAMASKSpectral.exe ${AUX_LIB}) \ No newline at end of file +target_link_libraries (DAMASKSpectral.exe ${DAMASK_LIB}) \ No newline at end of file diff --git a/code/damage/CMakeLists.txt b/code/damage/CMakeLists.txt index ef6c768bd..25d3e7e37 100644 --- a/code/damage/CMakeLists.txt +++ b/code/damage/CMakeLists.txt @@ -6,10 +6,10 @@ set (DAMAGE "damage_none" # compile damage module foreach (p ${DAMAGE}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries for linking foreach (p ${DAMAGE}) - set (AUX_LIB ${AUX_LIB} ${P}) + set (DAMASK_LIB ${DAMASK_LIB} ${P}) endforeach (p) \ No newline at end of file diff --git a/code/homogenization/CMakeLists.txt b/code/homogenization/CMakeLists.txt index 584f1f89a..a10de9aaa 100644 --- a/code/homogenization/CMakeLists.txt +++ b/code/homogenization/CMakeLists.txt @@ -7,10 +7,10 @@ set (HOMOGENIZATION "homogenization" # compile modules foreach (p ${HOMOGENIZATION}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries/modules for linking foreach (p ${HOMOGENIZATION}) - set (AUX_LIB ${AUX_LIB} ${p}) + set (DAMASK_LIB ${DAMASK_LIB} ${p}) endforeach (p) \ No newline at end of file diff --git a/code/hydrogenflux/CMakeLists.txt b/code/hydrogenflux/CMakeLists.txt index 4f133e0f6..33fa04574 100644 --- a/code/hydrogenflux/CMakeLists.txt +++ b/code/hydrogenflux/CMakeLists.txt @@ -5,10 +5,10 @@ set (HYDROGENFLUX "hydrogenflux_isoconc" # compile hydrogenflux modules foreach (p ${HYDROGENFLUX}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries/modules for linking foreach (p ${HYDROGENFLUX}) - set (AUX_LIB ${AUX_LIB} ${p}) + set (DAMASK_LIB ${DAMASK_LIB} ${p}) endforeach (p) \ No newline at end of file diff --git a/code/kinematics/CMakeLists.txt b/code/kinematics/CMakeLists.txt index f387c5d31..c6eb341d0 100644 --- a/code/kinematics/CMakeLists.txt +++ b/code/kinematics/CMakeLists.txt @@ -8,10 +8,10 @@ set (KINEMATICS "kinematics_cleavage_opening" # compile kinamtic modules foreach (p ${KINEMATICS}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries/modules for linking foreach (p ${KINEMATICS}) - set (AUX_LIB ${AUX_LIB} ${p}) + set (DAMASK_LIB ${DAMASK_LIB} ${p}) endforeach (p) \ No newline at end of file diff --git a/code/plastic/CMakeLists.txt b/code/plastic/CMakeLists.txt index 3b6593c07..be40539d3 100644 --- a/code/plastic/CMakeLists.txt +++ b/code/plastic/CMakeLists.txt @@ -12,10 +12,10 @@ set (PLASTIC "plastic_dislotwin" # compile module foreach (p ${PLASTIC}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries/modules for linking foreach (p ${PLASTIC}) - set (AUX_LIB ${AUX_LIB} ${p}) + set (DAMASK_LIB ${DAMASK_LIB} ${p}) endforeach (p) \ No newline at end of file diff --git a/code/porosity/CMakeLists.txt b/code/porosity/CMakeLists.txt index 3e62f4096..0e30067e8 100644 --- a/code/porosity/CMakeLists.txt +++ b/code/porosity/CMakeLists.txt @@ -5,10 +5,10 @@ set (POROSITY "porosity_none" # compile porosity modules foreach (p ${POROSITY}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries/modules for linking foreach (p ${POROSITY}) - set (AUX_LIB ${AUX_LIB} ${p}) + set (DAMASK_LIB ${DAMASK_LIB} ${p}) endforeach (p) \ No newline at end of file diff --git a/code/source/CMakeLists.txt b/code/source/CMakeLists.txt index 398bce557..780a8ffac 100644 --- a/code/source/CMakeLists.txt +++ b/code/source/CMakeLists.txt @@ -12,10 +12,10 @@ set (SOURCE "source_thermal_dissipation" # compile modules for source foreach (p ${SOURCE}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries/modules for linking foreach (p ${SOURCE}) - set (AUX_LIB ${AUX_LIB} ${p}) + set (DAMASK_LIB ${DAMASK_LIB} ${p}) endforeach (p) \ No newline at end of file diff --git a/code/spectral/CMakeLists.txt b/code/spectral/CMakeLists.txt index 659709917..1e16c00c5 100644 --- a/code/spectral/CMakeLists.txt +++ b/code/spectral/CMakeLists.txt @@ -10,10 +10,10 @@ set (SPECTRAL "spectral_damage" # compile spectral solver driver module foreach (p ${SPECTRAL}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries/modules for linking foreach (p ${SPECTRAL}) - set (AUX_LIB ${AUX_LIB} ${p}) + set (DAMASK_LIB ${DAMASK_LIB} ${p}) endforeach (p) \ No newline at end of file diff --git a/code/thermal/CMakeLists.txt b/code/thermal/CMakeLists.txt index 1d06449ef..8f34d0815 100644 --- a/code/thermal/CMakeLists.txt +++ b/code/thermal/CMakeLists.txt @@ -6,10 +6,10 @@ set (THERMAL "thermal_isothermal" # compiler theraml module foreach (p ${THERMAL}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries/modules for linking foreach (p ${THERMAL}) - set (AUX_LIB ${AUX_LIB} ${p}) + set (DAMASK_LIB ${DAMASK_LIB} ${p}) endforeach (p) \ No newline at end of file diff --git a/code/vacancyflux/CMakeLists.txt b/code/vacancyflux/CMakeLists.txt index 43e2a75fe..7163f38d7 100644 --- a/code/vacancyflux/CMakeLists.txt +++ b/code/vacancyflux/CMakeLists.txt @@ -6,10 +6,10 @@ set (VACANCYFLUX "vacancyflux_isoconc" # compiler as module foreach (p ${VACANCYFLUX}) - add_library (${p} MODULE "${p}.f90") + add_library (${p} "${p}.f90") endforeach (p) # set libraries/modules for linking foreach (p ${VACANCYFLUX}) - set (AUX_LIB ${AUX_LIB} ${p}) + set (DAMASK_LIB ${DAMASK_LIB} ${p}) endforeach (p) \ No newline at end of file From 3a6d5311e3ead75f407fa1150b90a8ce79ee121c Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Fri, 26 Feb 2016 12:30:57 -0500 Subject: [PATCH 012/183] auto dependency detection is not working, revert to manual --- CMakeLists.txt | 7 + code/CMakeLists.txt | 42 +- code/Makefile_bk | 699 --------------------------- code/spectral/CMakeLists.txt | 1 - code/spectral/spectral_interface.f90 | 568 ---------------------- 5 files changed, 32 insertions(+), 1285 deletions(-) delete mode 100644 code/Makefile_bk delete mode 100644 code/spectral/spectral_interface.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index a9e672c00..9b14c6efc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -337,6 +337,13 @@ if (FEM) set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${LINK_OPTIONS_ifort} -DFEM") endif (FEM) +# set default project compiler flags +# NOTE: some file requires different flags for compiling, DAMASK_$FLAGS +# are essentially the swap for this purpose +set (DAMASK_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" ) +set (DAMASK_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set (DAMASK_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" ) + ## # ADD CODE DIRECTORY add_subdirectory(code) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 544118af7..71d373157 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,15 +1,28 @@ +# The dependency detection for Fortran is not working in CMake +# Have to define them explicitly +add_library(DAMASK_prec "prec.f90") -include_directories(${PROJECT_SRC_DIR}/code) -include_directories(${PROJECT_SRC_DIR}/code/damage) -include_directories(${PROJECT_SRC_DIR}/code/homogenization) -include_directories(${PROJECT_SRC_DIR}/code/hydrogenflux) -include_directories(${PROJECT_SRC_DIR}/code/kinematics) -include_directories(${PROJECT_SRC_DIR}/code/plastic) -include_directories(${PROJECT_SRC_DIR}/code/porosity) -include_directories(${PROJECT_SRC_DIR}/code/source) -include_directories(${PROJECT_SRC_DIR}/code/spectral) -include_directories(${PROJECT_SRC_DIR}/code/thermal) -include_directories(${PROJECT_SRC_DIR}/code/vacancyflux) +################################################################################################### + +################################################################################################### +if (SPECTRAL) + add_library(DAMASK_interface "spectral_interface.f90") + target_link_libraries(DAMASK_interface DAMASK_prec) +endif(SPECTRAL) + +add_library(DAMASK_IO "IO.f90") +target_link_libraries(DAMASK_IO DAMASK_interface) + +add_library(DAMASK_LIBS "libs.f90") +target_link_libraries(DAMASK_LIBS DAMASK_IO) + +add_library(DAMASK_NUMERICS "numerics.f90") +target_link_libraries(DAMASK_NUMERICS DAMASK_LIBS) + +add_library(DAMASK_DEBUG "debug.f90") +target_link_libraries(DAMASK_DEBUG DAMASK_NUMERICS) + +add_library(DAMASK_BASICS ALIAS DAMASK_DEBUG) # group sources for base modules # the FEM modules would require special attention @@ -22,22 +35,17 @@ set (SRC "CPFEM" "constitutive" "crystallite" "damask_hdf5" - "debug" - "FEsolving" - "IO" "lattice" - "libs" "material" "math" "mesh" - "numerics" - "prec" "quit__genmod" ) # compiler base modules foreach (p ${SRC}) add_library (${p} "${p}.f90") + target_link_libraries(${p} DAMASK_BASICS) endforeach (p) # set libraries/modules for linking diff --git a/code/Makefile_bk b/code/Makefile_bk deleted file mode 100644 index a18cbebac..000000000 --- a/code/Makefile_bk +++ /dev/null @@ -1,699 +0,0 @@ -SHELL = /bin/sh -######################################################################################## -# Makefile to compile the Material subroutine for BVP solution using spectral method -######################################################################################## -# Be sure to remove all files compiled with different options by using "make clean" -######################################################################################## -# OPTIONS = standard (alternative): meaning -#------------------------------------------------------------- -# F90 = ifort (gfortran): compiler type, choose Intel or GNU -# COMPILERNAME = name of the compiler executable (if not the same as the ype), e.g. using mpich-g90 instead of ifort -# PORTABLE = TRUE (FALSE): decision, if executable is optimized for the machine on which it was built. -# OPTIMIZATION = DEFENSIVE (OFF,AGGRESSIVE,ULTRA): Optimization mode: O2, O0, O3 + further options for most files, O3 + further options for all files -# OPENMP = TRUE (FALSE): OpenMP multiprocessor support -# PREFIX = arbitrary prefix (before compilername) -# OPTION = arbitrary option (just before file to compile) -# SUFFIX = arbitrary suffix (after file to compile) -# STANDARD_CHECK = checking for Fortran 2008, compiler dependend -######################################################################################## -# including PETSc files. PETSC_ARCH is loaded from these files. -DAMASKVERSION :=$(shell cat ../VERSION) - -include ${PETSC_DIR}/lib/petsc/conf/variables -include ${PETSC_DIR}/lib/petsc/conf/rules - -INCLUDE_DIRS := $(PETSC_FC_INCLUDES) -DPETSc -I../lib -LIBRARIES := $(PETSC_WITH_EXTERNAL_LIB) -COMPILERNAME ?= $(FC) -LINKERNAME ?= $(FLINKER) - -# -# setting up for HDF5 support (hard link for now) -# 1. Location of HDF5 binaries (with include/ and lib/ underneath) -HDF5 = /mnt/research/CMM/opt/hdf5 -# 2. Location of External Libraries (missing in the 1.8.12 version) -LIBZ = /mnt/research/CMM/opt/hdf5/lib/libz.a -LIBSZ = /mnt/research/CMM/opt/hdf5/lib/libsz.a -# 3. Set libraries for HDF5 (LIBS: shared lib, LIBZ: external lib) -HDFLIBS = -I$(HDF5)/include -L$(HDF5)/lib -HDFLIBZ = -L$(LIBZ) -L$(LIBSZ) - -# MPI compiler wrappers will tell if they are pointing to ifort or gfortran -COMPILEROUT :=$(shell $(FC) -show) -# search in FC or COMPILEROUT for gfortran/ifort if not defined -ifeq ($(strip $(F90)),) - F90 :=$(findstring gfortran,$(FC) $(COMPILEROUT)) -endif -ifeq ($(strip $(F90)),) - F90 :=$(findstring ifort,$(FC) $(COMPILEROUT)) -endif - -OPENMP ?= ON -OPTIMIZATION ?= DEFENSIVE - -ifeq "$(OPTIMIZATION)" "OFF" -OPTI := OFF -MAXOPTI := OFF -endif -ifeq "$(OPTIMIZATION)" "DEFENSIVE" -OPTI := DEFENSIVE -MAXOPTI := DEFENSIVE -endif -ifeq "$(OPTIMIZATION)" "AGGRESSIVE" -OPTI := AGGRESSIVE -MAXOPTI := DEFENSIVE -endif -ifeq "$(OPTIMIZATION)" "ULTRA" -OPTI := AGGRESSIVE -MAXOPTI := AGGRESSIVE -endif - -ifndef OPTI -OPTI := DEFENSIVE -MAXOPTI := DEFENSIVE -endif - -# settings for shared memory multicore support -ifeq "$(OPENMP)" "ON" -OPENMP_FLAG_ifort =-openmp -openmp-report0 -parallel -OPENMP_FLAG_gfortran =-fopenmp -endif - -ifdef STANDARD_CHECK -STANDARD_CHECK_ifort =$(STANDARD_CHECK) -STANDARD_CHECK_gfortran =$(STANDARD_CHECK) -endif - -STANDARD_CHECK_ifort ?=-stand f08 -standard-semantics -STANDARD_CHECK_gfortran ?=-std=f2008ts -pedantic-errors - -#-pedantic: more strict on standard, enables some warnings -# -pedantic-errors: like pedantic, but errors instead of warnings -OPTIMIZATION_OFF_ifort :=-O0 -no-ip -OPTIMIZATION_OFF_gfortran :=-O0 -OPTIMIZATION_DEFENSIVE_ifort :=-O2 -OPTIMIZATION_DEFENSIVE_gfortran :=-O2 -OPTIMIZATION_AGGRESSIVE_ifort :=-ipo -O3 -no-prec-div -fp-model fast=2 -xHost #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost -OPTIMIZATION_AGGRESSIVE_gfortran :=-O3 -ffast-math -funroll-loops -ftree-vectorize - - -LINK_OPTIONS_ifort :=-shared-intel -COMPILE_OPTIONS_ifort :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ - -fpp\ - -ftz\ - -assume byterecl,fpe_summary\ - -diag-disable 5268\ - -warn declarations\ - -warn general\ - -warn usage\ - -warn interfaces\ - -warn ignore_loc\ - -warn alignments\ - -warn unused - -################################################################################################### -#COMPILE SWITCHES -#-shared-intel: Link against shared Intel libraries instead of static ones -#-fpp: preprocessor -#-ftz: flush unterflow to zero, automatically set if O<0,1,2,3> >0 -#-assume byterecl record length is given in bytes (also set by -standard-semantics) -# fpe_summary print list of floating point exceptions occured during execution -#-fimplicit-none: assume "implicit-none" even if not present in source -#-diag-disable: disables warnings, where -# warning ID 5268: the text exceeds right hand column allowed on the line (we have only comments there) -#-warn: enables warnings, where -# declarations: any undeclared names (alternative name: -implicitnone) -# general: warning messages and informational messages are issued by the compiler -# usage: questionable programming practices -# interfaces: checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks -# ignore_loc: %LOC is stripped from an actual argument -# alignments: data that is not naturally aligned -# unused: declared variables that are never used -# stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) -# -################################################################################################### -#MORE OPTIONS FOR DEBUGGING DURING COMPILATION -#-warn: enables warnings, where -# truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) -# uncalled: Determines whether warnings occur when a statement function is never called -# all: -# -name as_is: case sensitive Fortran! - -DEBUG_OPTIONS_ifort :=-g\ - -traceback\ - -gen-interfaces\ - -fp-stack-check\ - -fp-model strict\ - -check bounds,format,output_conversion,pointers,uninit\ - -ftrapuv\ - -fpe-all0\ - -warn errors\ - -warn stderrors\ - -debug-parameters all - -################################################################################################### -#COMPILE SWITCHES FOR RUNTIME DEBUGGING -#-g: Generate symbolic debugging information in the object file -#-traceback: Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. -#-gen-interfaces: Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ -#-fp-stack-check: Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. -#-ftrapuv Trap uninitalized variables -#-check: checks at runtime, where -# bounds: check if an array index is too small (<1) or too large! -# format: Checking for the data type of an item being formatted for output. -# output_conversion: Checking for the fit of data items within a designated format descriptor field. -# pointers: Checking for certain disassociated or uninitialized pointers or unallocated allocatable objects. -# uninit: Checking for uninitialized variables. -#-fpe-all0 capture all floating-point exceptions, sets -ftz automatically -#-warn: enables warnings, where -# errors: warnings are changed to errors -# stderrors: warnings about Fortran standard violations are changed to errors -# information on http://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors/ -################################################################################################### -#MORE OPTIONS FOR RUNTIME DEBUGGING -#-heap-arrays: should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits -#-check: checks at runtime, where -# arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) -# stack: -LINK_OPTIONS_gfortran :=-Wl,-undefined,dynamic_lookup -COMPILE_OPTIONS_gfortran :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ - -xf95-cpp-input\ - -ffree-line-length-132\ - -fimplicit-none\ - -fmodule-private\ - -Wall\ - -Wextra\ - -Wcharacter-truncation\ - -Wunderflow\ - -Wsuggest-attribute=pure\ - -Wsuggest-attribute=noreturn\ - -Wconversion-extra\ - -Wimplicit-procedure\ - -Wno-unused-parameter -#-ffpe-summary=all only for newer gfortran -################################################################################################### -#COMPILE SWITCHES -#-shared -#-Wl,-undefined,dynamic_lookup:ensure to link against dynamic libraries -#-xf95-cpp-input: preprocessor -#-ffree-line-length-132: restrict line length to the standard 132 characters -#-ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) -#-fimplicit-none: assume "implicit-none" even if not present in source -#-fmodule-private: assume "private" even if not present in source -#-Wcharacter-truncation: warn if character expressions (strings) are truncated -#-Wunderflow: produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation -#-Wsuggest-attribute=pure: -#-Wsuggest-attribute=noreturn: -#-Wconversion-extra -#-Wimplicit-procedure -#-Wall: sets the following Fortran options: -# -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. -# -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line -# -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime -# -Wconversion: warn about implicit conversions between different type -# -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. -# -Wc-binding-type: -# -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error -# -Wno-tabs: do not allow tabs in source -# -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic -# -Wline-truncation: -# -Wtarget-lifetime: -# -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter -# -Wunused: a number of unused-xxx warnings -# these are general (non -Fortran options) implied by -Wall -# -Waddress -# -Warray-bounds (only with -O2) -# -Wc++11-compat -# -Wchar-subscripts -# -Wcomment -# -Wformat -# -Wmaybe-uninitialized -# -Wnonnull -# -Wparentheses -# -Wpointer-sign -# -Wreorder -# -Wreturn-type -# -Wsequence-point -# -Wstrict-aliasing -# -Wstrict-overflow=1 -# -Wswitch -# -Wtrigraphs -# -Wuninitialized -# -Wunknown-pragmas -# -Wunused-function -# -Wunused-label -# -Wunused-value -# -Wunused-variable -# -Wvolatile-register-var -#-Wextra: sets the following Fortran options: -# -Wunuses-parameter: -# -Wcompare-reals: -# these are general (non -Fortran options) implied by -Wextra -# -Wclobbered -# -Wempty-body -# -Wignored-qualifiers -# -Wmissing-field-initializers -# -Woverride-init -# -Wsign-compare -# -Wtype-limits -# -Wuninitialized -# -Wunused-but-set-parameter (only with -Wunused or -Wall) -# -Wno-globals - -################################################################################################### -#MORE OPTIONS FOR DEBUGGING DURING COMPILATION -#-Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): -#-Wimplicit-interface: no interfaces for lapack routines -#-Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. -#-Wstrict-overflow: - -DEBUG_OPTIONS_gfortran :=-g\ - -fbacktrace\ - -fdump-core\ - -fcheck=all\ - -ffpe-trap=invalid,zero,overflow - -################################################################################################### -#COMPILE SWITCHES FOR RUNTIME DEBUGGING -#-ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) -# zero,\ -# overflow -#-fcheck=all: sets the following Fortran options: -#array-temps -#bounds -#do -#mem -#pointer -#recursion -################################################################################################### -#MORE OPTIONS FOR RUNTIME DEBUGGING -#-ffpe-trap=precision,\ -# denormal, \ -# underflow - -ifeq "$(DEBUG)" "ON" -COMPILE_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) -LINK_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) -endif -LINK_OPTIONS_$(F90) += $(OPTIMIZATION_$(MAXOPTI)_$(F90)) - -PRECISION_ifort :=-real-size 64 -integer-size 32 -DFLOAT=8 -DINT=4 -#-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) -#-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) -PRECISION_gfortran :=-fdefault-real-8 -fdefault-double-8 -DFLOAT=8 -DINT=4 -#-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set -#-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used -#-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) - -################################################################################################### -COMPILE =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(OPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) -COMPILE_MAXOPTI =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) -################################################################################################### -SOURCE_FILES = \ - source_thermal_dissipation.o source_thermal_externalheat.o \ - source_damage_isoBrittle.o source_damage_isoDuctile.o source_damage_anisoBrittle.o source_damage_anisoDuctile.o \ - source_vacancy_phenoplasticity.o source_vacancy_irradiation.o source_vacancy_thermalfluc.o - -KINEMATICS_FILES = \ - kinematics_cleavage_opening.o kinematics_slipplane_opening.o \ - kinematics_thermal_expansion.o \ - kinematics_vacancy_strain.o kinematics_hydrogen_strain.o - -PLASTIC_FILES = \ - plastic_dislotwin.o plastic_disloUCLA.o plastic_isotropic.o plastic_j2.o \ - plastic_phenopowerlaw.o plastic_titanmod.o plastic_nonlocal.o plastic_none.o \ - plastic_phenoplus.o - -THERMAL_FILES = \ - thermal_isothermal.o thermal_adiabatic.o thermal_conduction.o - -DAMAGE_FILES = \ - damage_none.o damage_local.o damage_nonlocal.o - -VACANCYFLUX_FILES = \ - vacancyflux_isoconc.o vacancyflux_isochempot.o vacancyflux_cahnhilliard.o - -POROSITY_FILES = \ - porosity_none.o porosity_phasefield.o - -HYDROGENFLUX_FILES = \ - hydrogenflux_isoconc.o hydrogenflux_cahnhilliard.o - -HOMOGENIZATION_FILES = \ - homogenization_RGC.o homogenization_isostrain.o homogenization_none.o - -##################### -# Spectral Solver -##################### -DAMASK_spectral.exe: IGNORE := \# -DAMASK_spectral.exe: COMPILE += -DSpectral -DAMASK_spectral.exe: COMPILE_MAXOPTI += -DSpectral -DAMASK_spectral.exe: MESHNAME := mesh.f90 -DAMASK_spectral.exe: INTERFACENAME := spectral_interface.f90 - -DAMASK_spectral.o: IGNORE := \# -DAMASK_spectral.o: COMPILE += -DSpectral -DAMASK_spectral.o: COMPILE_MAXOPTI += -DSpectral -DAMASK_spectral.o: MESHNAME := mesh.f90 -DAMASK_spectral.o: INTERFACENAME := spectral_interface.f90 - - -SPECTRAL_SOLVER_FILES = spectral_mech_AL.o spectral_mech_Basic.o spectral_mech_Polarisation.o \ - spectral_thermal.o spectral_damage.o - -SPECTRAL_FILES = prec.o DAMASK_interface.o IO.o libs.o numerics.o debug.o math.o damask_hdf5.o \ - FEsolving.o mesh.o material.o lattice.o \ - $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ - crystallite.o \ - $(THERMAL_FILES) $(DAMAGE_FILES) $(VACANCYFLUX_FILES) $(HYDROGENFLUX_FILES) $(POROSITY_FILES) \ - $(HOMOGENIZATION_FILES) homogenization.o \ - CPFEM2.o \ - spectral_utilities.o \ - $(SPECTRAL_SOLVER_FILES) - -DAMASK_spectral.exe: DAMASK_spectral.o \ - $(SPECTRAL_FILES) - $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ - -o DAMASK_spectral.exe DAMASK_spectral.o \ - $(SPECTRAL_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) - - -DAMASK_spectral.o: DAMASK_spectral.f90 \ - $(SPECTRAL_SOLVER_FILES) - $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c DAMASK_spectral.f90 $(SUFFIX) - -spectral_mech_AL.o: spectral_mech_AL.f90 \ - spectral_utilities.o - -spectral_mech_Polarisation.o: spectral_mech_Polarisation.f90 \ - spectral_utilities.o - -spectral_mech_Basic.o: spectral_mech_Basic.f90 \ - spectral_utilities.o - -spectral_thermal.o: spectral_thermal.f90 \ - spectral_utilities.o - -spectral_damage.o: spectral_damage.f90 \ - spectral_utilities.o - -spectral_utilities.o: spectral_utilities.f90 \ - CPFEM2.o - -##################### -# FEM Solver -##################### -VPATH := ../private/FEM/code -DAMASK_FEM.exe: COMPILE += -DFEM -DAMASK_FEM.exe: COMPILE_MAXOPTI += -DFEM -DAMASK_FEM.exe: MESHNAME := ../private/FEM/code/meshFEM.f90 -DAMASK_FEM.exe: INTERFACENAME := ../private/FEM/code/DAMASK_FEM_interface.f90 -DAMASK_FEM.exe: INCLUDE_DIRS += -I./ - -FEM_SOLVER_FILES = FEM_mech.o FEM_thermal.o FEM_damage.o FEM_vacancyflux.o FEM_porosity.o FEM_hydrogenflux.o - -FEM_FILES = prec.o DAMASK_interface.o FEZoo.o IO.o libs.o numerics.o debug.o math.o \ - FEsolving.o mesh.o material.o lattice.o \ - $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ - crystallite.o \ - $(THERMAL_FILES) $(DAMAGE_FILES) $(VACANCYFLUX_FILES) $(HYDROGENFLUX_FILES) $(POROSITY_FILES) \ - $(HOMOGENIZATION_FILES) homogenization.o \ - CPFEM.o \ - FEM_utilities.o $(FEM_SOLVER_FILES) - -DAMASK_FEM.exe: DAMASK_FEM_driver.o - $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ - -o DAMASK_FEM.exe DAMASK_FEM_driver.o \ - $(FEM_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) - -DAMASK_FEM_driver.o: DAMASK_FEM_driver.f90 $(FEM_SOLVER_FILES) - $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c ../private/FEM/code/DAMASK_FEM_driver.f90 $(SUFFIX) - -FEM_mech.o: FEM_mech.f90 \ - FEM_utilities.o - -FEM_thermal.o: FEM_thermal.f90 \ - FEM_utilities.o - -FEM_damage.o: FEM_damage.f90 \ - FEM_utilities.o - -FEM_vacancyflux.o: FEM_vacancyflux.f90 \ - FEM_utilities.o - -FEM_porosity.o: FEM_porosity.f90 \ - FEM_utilities.o - -FEM_hydrogenflux.o: FEM_hydrogenflux.f90 \ - FEM_utilities.o - -FEM_utilities.o: FEM_utilities.f90 \ - CPFEM.o - -FEZoo.o: $(wildcard FEZoo.f90) \ - IO.o - $(IGNORE) $(PREFIX) $(COMPILERNAME) $(COMPILE) -c ../private/FEM/code/FEZoo.f90 $(SUFFIX) - touch FEZoo.o - -CPFEM.o: CPFEM.f90 \ - homogenization.o - -CPFEM2.o: CPFEM2.f90 \ - homogenization.o - -homogenization.o: homogenization.f90 \ - $(THERMAL_FILES) \ - $(DAMAGE_FILES) \ - $(VACANCYFLUX_FILES) \ - $(POROSITY_FILES) \ - $(HYDROGENFLUX_FILES) \ - $(HOMOGENIZATION_FILES) - -thermal_isothermal.o: thermal_isothermal.f90 \ - crystallite.o - -thermal_adiabatic.o: thermal_adiabatic.f90 \ - crystallite.o - -thermal_conduction.o: thermal_conduction.f90 \ - crystallite.o - -damage_none.o: damage_none.f90 \ - crystallite.o - -damage_local.o: damage_local.f90 \ - crystallite.o - -damage_nonlocal.o: damage_nonlocal.f90 \ - crystallite.o - -thermal_conduction.o: thermal_conduction.f90 \ - crystallite.o - -vacancyflux_isoconc.o: vacancyflux_isoconc.f90 \ - crystallite.o - -vacancyflux_isochempot.o: vacancyflux_isochempot.f90 \ - crystallite.o - -vacancyflux_cahnhilliard.o: vacancyflux_cahnhilliard.f90 \ - crystallite.o - -porosity_none.o: porosity_none.f90 \ - crystallite.o - -porosity_phasefield.o: porosity_phasefield.f90 \ - crystallite.o - -hydrogenflux_isoconc.o: hydrogenflux_isoconc.f90 \ - crystallite.o - -hydrogenflux_cahnhilliard.o: hydrogenflux_cahnhilliard.f90 \ - crystallite.o - -homogenization_RGC.o: homogenization_RGC.f90 \ - crystallite.o - -homogenization_isostrain.o: homogenization_isostrain.f90 \ - crystallite.o - -homogenization_none.o: homogenization_none.f90 \ - crystallite.o - -crystallite.o: crystallite.f90 \ - constitutive.o - -constitutive.o: constitutive.f90 \ - $(SOURCE_FILES) \ - $(KINEMATICS_FILES) \ - $(PLASTIC_FILES) - -source_thermal_dissipation.o: source_thermal_dissipation.f90 \ - lattice.o - -source_thermal_externalheat.o: source_thermal_externalheat.f90 \ - lattice.o - -source_damage_isoBrittle.o: source_damage_isoBrittle.f90 \ - lattice.o - -source_damage_isoDuctile.o: source_damage_isoDuctile.f90 \ - lattice.o - -source_damage_anisoBrittle.o: source_damage_anisoBrittle.f90 \ - lattice.o - -source_damage_anisoDuctile.o: source_damage_anisoDuctile.f90 \ - lattice.o - -source_vacancy_phenoplasticity.o: source_vacancy_phenoplasticity.f90 \ - lattice.o - -source_vacancy_irradiation.o: source_vacancy_irradiation.f90 \ - lattice.o - -source_vacancy_thermalfluc.o: source_vacancy_thermalfluc.f90 \ - lattice.o - -kinematics_cleavage_opening.o: kinematics_cleavage_opening.f90 \ - lattice.o - -kinematics_slipplane_opening.o: kinematics_slipplane_opening.f90 \ - lattice.o - -kinematics_thermal_expansion.o: kinematics_thermal_expansion.f90 \ - lattice.o - -kinematics_vacancy_strain.o: kinematics_vacancy_strain.f90 \ - lattice.o - -kinematics_hydrogen_strain.o: kinematics_hydrogen_strain.f90 \ - lattice.o - -plastic_nonlocal.o: plastic_nonlocal.f90 \ - lattice.o - -plastic_titanmod.o: plastic_titanmod.f90 \ - lattice.o - -plastic_disloUCLA.o: plastic_disloUCLA.f90 \ - lattice.o - -plastic_dislotwin.o: plastic_dislotwin.f90 \ - lattice.o - -plastic_phenopowerlaw.o: plastic_phenopowerlaw.f90 \ - lattice.o - -plastic_phenoplus.o: plastic_phenoplus.f90 \ - lattice.o - -plastic_isotropic.o: plastic_isotropic.f90 \ - lattice.o - -plastic_j2.o: plastic_j2.f90 \ - lattice.o - -plastic_none.o: plastic_none.f90 \ - lattice.o -ifeq "$(F90)" "gfortran" -lattice.o: lattice.f90 \ - material.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -ffree-line-length-240 -c lattice.f90 $(SUFFIX) -# long lines for interaction matrix -else -lattice.o: lattice.f90 \ - material.o -endif - -material.o: material.f90 \ - mesh.o - -mesh.o: mesh.f90 \ - $(wildcard meshFEM.f90) \ - FEsolving.o \ - math.o \ - FEZoo.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(MESHNAME) -o mesh.o $(SUFFIX) - -FEsolving.o: FEsolving.f90 \ - debug.o - -math.o: math.f90 \ - debug.o - -debug.o: debug.f90 \ - numerics.o - -numerics.o: numerics.f90 \ - libs.o - -libs.o: libs.f90 \ - IO.o - -IO.o: IO.f90 \ - DAMASK_interface.o - -ifeq "$(F90)" "gfortran" -DAMASK_interface.o: spectral_interface.f90 \ - $(wildcard DAMASK_FEM_interface.f90) \ - prec.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -fall-intrinsics -o DAMASK_interface.o $(SUFFIX) -#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored -# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external -# --> allows the use of 'getcwd' -prec.o: prec.f90 - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 -fno-range-check -fall-intrinsics -fno-fast-math $(SUFFIX) -# fno-range-check: Disable range checking on results of simplification of constant expressions during compilation -# --> allows the definition of DAMASK_NaN -#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored -# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external -# --> allows the use of 'isnan' -#-fno-fast-math: -# --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) -else -DAMASK_interface.o: spectral_interface.f90 \ - $(wildcard DAMASK_FEM_interface.f90) \ - prec.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -diag-remark 7410 -stand none -warn nostderrors -o DAMASK_interface.o $(SUFFIX) -# -diag-disable 7410 should disable warning about directory statement in inquire function, but does not work. hence the other 2 statements -prec.o: prec.f90 - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 $(SUFFIX) - -damask_hdf5.o: damask_hdf5.f90 \ - prec.o \ - IO.o - $(PREFIX) $(COMPILERNAME) $(HDFLIBS) $(HDFLIBZ) -c damask_hdf5.f90 $(SUFFIX) -lm -endif - -%.o : %.f90 - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $< $(SUFFIX) - -.PHONY: tidy -tidy: - @rm -rf *.o - @rm -rf *.mod - @rm -rf *.inst.f90 # for instrumentation - @rm -rf *.pomp.f90 # for instrumentation - @rm -rf *.pp.f90 # for instrumentation - @rm -rf *.pdb # for instrumnentation - @rm -rf *.opari.inc # for instrumnentation - -.PHONY: cleanDAMASK -cleanDAMASK: - @rm -rf *.exe - @rm -rf *.marc - @rm -rf *.o - @rm -rf *.mod - @rm -rf *.inst.f90 # for instrumentation - @rm -rf *.pomp.f90 # for instrumentation - @rm -rf *.pp.f90 # for instrumentation - @rm -rf *.pdb # for instrumentation - @rm -rf *.opari.inc # for instrumentation - -.PHONY: help -help: - F90="$(F90)" - COMPILERNAME="$(COMPILERNAME)" - COMPILEROUT="$(COMPILEROUT)" - diff --git a/code/spectral/CMakeLists.txt b/code/spectral/CMakeLists.txt index 1e16c00c5..136d1ad88 100644 --- a/code/spectral/CMakeLists.txt +++ b/code/spectral/CMakeLists.txt @@ -1,6 +1,5 @@ # group source for sepctral solver driver set (SPECTRAL "spectral_damage" - "spectral_interface" "spectral_mech_AL" "spectral_mech_Basic" "spectral_mech_Polarisation" diff --git a/code/spectral/spectral_interface.f90 b/code/spectral/spectral_interface.f90 deleted file mode 100644 index b24c5f747..000000000 --- a/code/spectral/spectral_interface.f90 +++ /dev/null @@ -1,568 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Interfacing between the spectral solver and the material subroutines provided -!! by DAMASK -!> @details Interfacing between the spectral solver and the material subroutines provided -!> by DAMASK. Interpretating the command line arguments or, in case of called from f2py, -!> the arguments parsed to the init routine to get load case, geometry file, working -!> directory, etc. -!-------------------------------------------------------------------------------------------------- -module DAMASK_interface - use prec, only: & - pInt - - implicit none - private -#ifdef PETSc -#include -#endif - logical, public, protected :: appendToOutFile = .false. !< Append to existing spectralOut file (in case of restart, not in case of regridding) - integer(pInt), public, protected :: spectralRestartInc = 1_pInt !< Increment at which calculation starts - character(len=1024), public, protected :: & - geometryFile = '', & !< parameter given for geometry file - loadCaseFile = '' !< parameter given for load case file - character(len=1024), private :: workingDirectory !< accessed by getSolverWorkingDirectoryName for compatibility reasons - - public :: & - getSolverWorkingDirectoryName, & - getSolverJobName, & - DAMASK_interface_init - private :: & - storeWorkingDirectory, & - getGeometryFile, & - getLoadCaseFile, & - rectifyPath, & - makeRelativePath, & - getPathSep, & - IIO_stringValue, & - IIO_intValue, & - IIO_lc, & - IIO_stringPos - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief initializes the solver by interpreting the command line arguments. Also writes -!! information on computation to screen -!-------------------------------------------------------------------------------------------------- -subroutine DAMASK_interface_init(loadCaseParameterIn,geometryParameterIn) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - - implicit none - character(len=1024), optional, intent(in) :: & - loadCaseParameterIn, & !< if using the f2py variant, the -l argument of DAMASK_spectral.exe - geometryParameterIn !< if using the f2py variant, the -g argument of DAMASK_spectral.exe - character(len=1024) :: & - commandLine, & !< command line call as string - loadCaseArg ='', & !< -l argument given to DAMASK_spectral.exe - geometryArg ='', & !< -g argument given to DAMASK_spectral.exe - workingDirArg ='', & !< -w argument given to DAMASK_spectral.exe - hostName, & !< name of machine on which DAMASK_spectral.exe is execute (might require export HOSTNAME) - userName, & !< name of user calling DAMASK_spectral.exe - tag - integer :: & - i, & - worldrank = 0 - integer, allocatable, dimension(:) :: & - chunkPos - integer, dimension(8) :: & - dateAndTime ! type default integer -#ifdef PETSc - PetscErrorCode :: ierr -#endif - external :: & - quit,& - MPI_Comm_rank,& - PETScInitialize, & - MPI_abort - -!-------------------------------------------------------------------------------------------------- -! PETSc Init -#ifdef PETSc - call PetscInitialize(PETSC_NULL_CHARACTER,ierr) ! according to PETSc manual, that should be the first line in the code - CHKERRQ(ierr) ! this is a macro definition, it is case sensitive - - open(6, encoding='UTF-8') ! modern fortran compilers (gfortran >4.4, ifort >11 support it) - call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) -#endif - mainProcess: if (worldrank == 0) then - call date_and_time(values = dateAndTime) - write(6,'(/,a)') ' <<<+- DAMASK_spectral -+>>>' - write(6,'(/,a)') ' Version: '//DAMASKVERSION - write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& - dateAndTime(2),'/',& - dateAndTime(1) - write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& - dateAndTime(6),':',& - dateAndTime(7) - write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' -#include "compilation_info.f90" - endif mainProcess - - if ( present(loadcaseParameterIn) .and. present(geometryParameterIn)) then ! both mandatory parameters given in function call - geometryArg = geometryParameterIn - loadcaseArg = loadcaseParameterIn - commandLine = 'n/a' - else if ( .not.( present(loadcaseParameterIn) .and. present(geometryParameterIn))) then ! none parameters given in function call, trying to get them from command line - call get_command(commandLine) - chunkPos = IIO_stringPos(commandLine) - do i = 1, chunkPos(1) - tag = IIO_lc(IIO_stringValue(commandLine,chunkPos,i)) ! extract key - select case(tag) - case ('-h','--help') - mainProcess2: if (worldrank == 0) then - write(6,'(a)') ' #######################################################################' - write(6,'(a)') ' DAMASK_spectral:' - write(6,'(a)') ' The spectral method boundary value problem solver for' - write(6,'(a)') ' the Düsseldorf Advanced Material Simulation Kit' - write(6,'(a,/)')' #######################################################################' - write(6,'(a,/)')' Valid command line switches:' - write(6,'(a)') ' --geom (-g, --geometry)' - write(6,'(a)') ' --load (-l, --loadcase)' - write(6,'(a)') ' --workingdir (-w, --wd, --workingdirectory, -d, --directory)' - write(6,'(a)') ' --restart (-r, --rs)' - write(6,'(a)') ' --regrid (--rg)' - write(6,'(a)') ' --help (-h)' - write(6,'(/,a)')' -----------------------------------------------------------------------' - write(6,'(a)') ' Mandatory arguments:' - write(6,'(/,a)')' --geom PathToGeomFile/NameOfGeom.geom' - write(6,'(a)') ' Specifies the location of the geometry definition file,' - write(6,'(a)') ' if no extension is given, .geom will be appended.' - write(6,'(a)') ' "PathToGeomFile" will be the working directory if not specified' - write(6,'(a)') ' via --workingdir.' - write(6,'(a)') ' Make sure the file "material.config" exists in the working' - write(6,'(a)') ' directory.' - write(6,'(a)') ' For further configuration place "numerics.config"' - write(6,'(a)')' and "numerics.config" in that directory.' - write(6,'(/,a)')' --load PathToLoadFile/NameOfLoadFile.load' - write(6,'(a)') ' Specifies the location of the load case definition file,' - write(6,'(a)') ' if no extension is given, .load will be appended.' - write(6,'(/,a)')' -----------------------------------------------------------------------' - write(6,'(a)') ' Optional arguments:' - write(6,'(/,a)')' --workingdirectory PathToWorkingDirectory' - write(6,'(a)') ' Specifies the working directory and overwrites the default' - write(6,'(a)') ' "PathToGeomFile".' - write(6,'(a)') ' Make sure the file "material.config" exists in the working' - write(6,'(a)') ' directory.' - write(6,'(a)') ' For further configuration place "numerics.config"' - write(6,'(a)')' and "numerics.config" in that directory.' - write(6,'(/,a)')' --restart XX' - write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' - write(6,'(a)') ' calculate total increment No. XX.' - write(6,'(a)') ' Appends to existing results file ' - write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' - write(6,'(a)') ' Works only if the restart information for total increment' - write(6,'(a)') ' No. XX-1 is available in the working directory.' - write(6,'(/,a)')' --regrid XX' - write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' - write(6,'(a)') ' calculate total increment No. XX.' - write(6,'(a)') ' Attention: Overwrites existing results file ' - write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' - write(6,'(a)') ' Works only if the restart information for total increment' - write(6,'(a)') ' No. XX-1 is available in the working directory.' - write(6,'(/,a)')' -----------------------------------------------------------------------' - write(6,'(a)') ' Help:' - write(6,'(/,a)')' --help' - write(6,'(a,/)')' Prints this message and exits' - call quit(0_pInt) ! normal Termination - endif mainProcess2 - case ('-l', '--load', '--loadcase') - loadcaseArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) - case ('-g', '--geom', '--geometry') - geometryArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) - case ('-w', '-d', '--wd', '--directory', '--workingdir', '--workingdirectory') - workingDirArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) - case ('-r', '--rs', '--restart') - spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) - appendToOutFile = .true. - case ('--rg', '--regrid') - spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) - appendToOutFile = .false. - end select - enddo - endif - - if (len(trim(loadcaseArg)) == 0 .or. len(trim(geometryArg)) == 0) then - write(6,'(a)') ' Please specify geometry AND load case (-h for help)' - call quit(1_pInt) - endif - - workingDirectory = storeWorkingDirectory(trim(workingDirArg),trim(geometryArg)) - geometryFile = getGeometryFile(geometryArg) - loadCaseFile = getLoadCaseFile(loadCaseArg) - - call get_environment_variable('HOSTNAME',hostName) - call get_environment_variable('USER',userName) - mainProcess3: if (worldrank == 0) then - write(6,'(a,a)') ' Host name: ', trim(hostName) - write(6,'(a,a)') ' User name: ', trim(userName) - write(6,'(a,a)') ' Path separator: ', getPathSep() - write(6,'(a,a)') ' Command line call: ', trim(commandLine) - if (len(trim(workingDirArg))>0) & - write(6,'(a,a)') ' Working dir argument: ', trim(workingDirArg) - write(6,'(a,a)') ' Geometry argument: ', trim(geometryArg) - write(6,'(a,a)') ' Loadcase argument: ', trim(loadcaseArg) - write(6,'(a,a)') ' Working directory: ', trim(getSolverWorkingDirectoryName()) - write(6,'(a,a)') ' Geometry file: ', trim(geometryFile) - write(6,'(a,a)') ' Loadcase file: ', trim(loadCaseFile) - write(6,'(a,a)') ' Solver job name: ', trim(getSolverJobName()) - if (SpectralRestartInc > 1_pInt) & - write(6,'(a,i6.6)') ' Restart at increment: ', spectralRestartInc - write(6,'(a,l1,/)') ' Append to result file: ', appendToOutFile - endif mainProcess3 - -end subroutine DAMASK_interface_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief extract working directory from given argument or from location of geometry file, -!! possibly converting relative arguments to absolut path -!> @todo change working directory with call chdir(storeWorkingDirectory)? -!-------------------------------------------------------------------------------------------------- -character(len=1024) function storeWorkingDirectory(workingDirectoryArg,geometryArg) -#ifdef __INTEL_COMPILER - use IFPORT -#endif - - implicit none - character(len=*), intent(in) :: workingDirectoryArg !< working directory argument - character(len=*), intent(in) :: geometryArg !< geometry argument - character(len=1024) :: cwd - character :: pathSep - logical :: dirExists - external :: quit - integer :: error - - pathSep = getPathSep() - if (len(workingDirectoryArg)>0) then ! got working directory as input - if (workingDirectoryArg(1:1) == pathSep) then ! absolute path given as command line argument - storeWorkingDirectory = workingDirectoryArg - else - error = getcwd(cwd) ! relative path given as command line argument - storeWorkingDirectory = trim(cwd)//pathSep//workingDirectoryArg - endif - if (storeWorkingDirectory(len(trim(storeWorkingDirectory)):len(trim(storeWorkingDirectory))) & ! if path seperator is not given, append it - /= pathSep) storeWorkingDirectory = trim(storeWorkingDirectory)//pathSep -#ifdef __INTEL_COMPILER - inquire(directory = trim(storeWorkingDirectory)//'.', exist=dirExists) -#else - inquire(file = trim(storeWorkingDirectory), exist=dirExists) -#endif - if(.not. dirExists) then ! check if the directory exists - write(6,'(a20,a,a16)') ' working directory "',trim(storeWorkingDirectory),'" does not exist' - call quit(1_pInt) - endif - else ! using path to geometry file as working dir - if (geometryArg(1:1) == pathSep) then ! absolute path given as command line argument - storeWorkingDirectory = geometryArg(1:scan(geometryArg,pathSep,back=.true.)) - else - error = getcwd(cwd) ! relative path given as command line argument - storeWorkingDirectory = trim(cwd)//pathSep//& - geometryArg(1:scan(geometryArg,pathSep,back=.true.)) - endif - endif - storeWorkingDirectory = rectifyPath(storeWorkingDirectory) - -end function storeWorkingDirectory - - -!-------------------------------------------------------------------------------------------------- -!> @brief simply returns the private string workingDir -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getSolverWorkingDirectoryName() - - implicit none - getSolverWorkingDirectoryName = workingDirectory - -end function getSolverWorkingDirectoryName - - -!-------------------------------------------------------------------------------------------------- -!> @brief solver job name (no extension) as combination of geometry and load case name -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getSolverJobName() - - implicit none - integer :: posExt,posSep - character :: pathSep - character(len=1024) :: tempString - - pathSep = getPathSep() - - tempString = geometryFile - posExt = scan(tempString,'.',back=.true.) - posSep = scan(tempString,pathSep,back=.true.) - - getSolverJobName = tempString(posSep+1:posExt-1) - - tempString = loadCaseFile - posExt = scan(tempString,'.',back=.true.) - posSep = scan(tempString,pathSep,back=.true.) - - getSolverJobName = trim(getSolverJobName)//'_'//tempString(posSep+1:posExt-1) - -end function getSolverJobName - - -!-------------------------------------------------------------------------------------------------- -!> @brief basename of geometry file with extension from command line arguments -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getGeometryFile(geometryParameter) -#ifdef __INTEL_COMPILER - use IFPORT -#endif - - implicit none - character(len=1024), intent(in) :: & - geometryParameter - character(len=1024) :: & - cwd - integer :: posExt, posSep - character :: pathSep - integer :: error - - getGeometryFile = geometryParameter - pathSep = getPathSep() - posExt = scan(getGeometryFile,'.',back=.true.) - posSep = scan(getGeometryFile,pathSep,back=.true.) - - if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') ! no extension present - if (scan(getGeometryFile,pathSep) /= 1) then ! relative path given as command line argument - error = getcwd(cwd) - getGeometryFile = rectifyPath(trim(cwd)//pathSep//getGeometryFile) - else - getGeometryFile = rectifyPath(getGeometryFile) - endif - - getGeometryFile = makeRelativePath(getSolverWorkingDirectoryName(), getGeometryFile) - -end function getGeometryFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief relative path of loadcase from command line arguments -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getLoadCaseFile(loadCaseParameter) -#ifdef __INTEL_COMPILER - use IFPORT -#endif - - implicit none - character(len=1024), intent(in) :: & - loadCaseParameter - character(len=1024) :: & - cwd - integer :: posExt, posSep, error - character :: pathSep - - getLoadCaseFile = loadcaseParameter - pathSep = getPathSep() - posExt = scan(getLoadCaseFile,'.',back=.true.) - posSep = scan(getLoadCaseFile,pathSep,back=.true.) - - if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') ! no extension present - if (scan(getLoadCaseFile,pathSep) /= 1) then ! relative path given as command line argument - error = getcwd(cwd) - getLoadCaseFile = rectifyPath(trim(cwd)//pathSep//getLoadCaseFile) - else - getLoadCaseFile = rectifyPath(getLoadCaseFile) - endif - - getLoadCaseFile = makeRelativePath(getSolverWorkingDirectoryName(), getLoadCaseFile) - -end function getLoadCaseFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief remove ../ and /./ from path -!-------------------------------------------------------------------------------------------------- -function rectifyPath(path) - - implicit none - character(len=*) :: path - character(len=len_trim(path)) :: rectifyPath - character :: pathSep - integer :: i,j,k,l ! no pInt - - pathSep = getPathSep() - -!-------------------------------------------------------------------------------------------------- -! remove /./ from path - l = len_trim(path) - rectifyPath = path - do i = l,3,-1 - if (rectifyPath(i-2:i) == pathSep//'.'//pathSep) & - rectifyPath(i-1:l) = rectifyPath(i+1:l)//' ' - enddo - -!-------------------------------------------------------------------------------------------------- -! remove ../ and corresponding directory from rectifyPath - l = len_trim(rectifyPath) - i = index(rectifyPath(i:l),'..'//pathSep) - j = 0 - do while (i > j) - j = scan(rectifyPath(1:i-2),pathSep,back=.true.) - rectifyPath(j+1:l) = rectifyPath(i+3:l)//repeat(' ',2+i-j) - if (rectifyPath(j+1:j+1) == pathSep) then !search for '//' that appear in case of XXX/../../XXX - k = len_trim(rectifyPath) - rectifyPath(j+1:k-1) = rectifyPath(j+2:k) - rectifyPath(k:k) = ' ' - endif - i = j+index(rectifyPath(j+1:l),'..'//pathSep) - enddo - if(len_trim(rectifyPath) == 0) rectifyPath = pathSep - -end function rectifyPath - - -!-------------------------------------------------------------------------------------------------- -!> @brief relative path from absolute a to absolute b -!-------------------------------------------------------------------------------------------------- -character(len=1024) function makeRelativePath(a,b) - - implicit none - character (len=*) :: a,b - character :: pathSep - integer :: i,posLastCommonSlash,remainingSlashes !no pInt - - pathSep = getPathSep() - posLastCommonSlash = 0 - remainingSlashes = 0 - - do i = 1, min(1024,len_trim(a),len_trim(b)) - if (a(i:i) /= b(i:i)) exit - if (a(i:i) == pathSep) posLastCommonSlash = i - enddo - do i = posLastCommonSlash+1,len_trim(a) - if (a(i:i) == pathSep) remainingSlashes = remainingSlashes + 1 - enddo - makeRelativePath = repeat('..'//pathSep,remainingSlashes)//b(posLastCommonSlash+1:len_trim(b)) - -end function makeRelativePath - - -!-------------------------------------------------------------------------------------------------- -!> @brief counting / and \ in $PATH System variable the character occuring more often is assumed -! to be the path separator -!-------------------------------------------------------------------------------------------------- -character function getPathSep() - - implicit none - character(len=2048) :: & - path - integer(pInt) :: & - backslash = 0_pInt, & - slash = 0_pInt - integer :: i - - call get_environment_variable('PATH',path) - do i=1, len(trim(path)) - if (path(i:i)=='/') slash = slash + 1_pInt - if (path(i:i)=='\') backslash = backslash + 1_pInt - enddo - - if (backslash>slash) then - getPathSep = '\' - else - getPathSep = '/' - endif - -end function getPathSep - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_stringValue for documentation -!-------------------------------------------------------------------------------------------------- -pure function IIO_stringValue(string,chunkPos,myChunk) - - implicit none - integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - character(len=1+chunkPos(myChunk*2+1)-chunkPos(myChunk*2)) :: IIO_stringValue - character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - - - valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then - IIO_stringValue = '' - else valuePresent - IIO_stringValue = string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) - endif valuePresent - -end function IIO_stringValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_intValue for documentation -!-------------------------------------------------------------------------------------------------- -integer(pInt) pure function IIO_intValue(string,chunkPos,myChunk) - - implicit none - character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - integer(pInt), intent(in) :: myChunk !< position number of desired sub string - integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string - - - valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then - IIO_intValue = 0_pInt - else valuePresent - read(UNIT=string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)),ERR=100,FMT=*) IIO_intValue - endif valuePresent - return -100 IIO_intValue = huge(1_pInt) - -end function IIO_intValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_lc for documentation -!-------------------------------------------------------------------------------------------------- -pure function IIO_lc(string) - - implicit none - character(len=*), intent(in) :: string !< string to convert - character(len=len(string)) :: IIO_lc - - character(26), parameter :: LOWER = 'abcdefghijklmnopqrstuvwxyz' - character(26), parameter :: UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - - integer :: i,n ! no pInt (len returns default integer) - - IIO_lc = string - do i=1,len(string) - n = index(UPPER,IIO_lc(i:i)) - if (n/=0) IIO_lc(i:i) = LOWER(n:n) - enddo - -end function IIO_lc - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_stringPos for documentation -!-------------------------------------------------------------------------------------------------- -pure function IIO_stringPos(string) - - implicit none - integer(pInt), dimension(:), allocatable :: IIO_stringPos - character(len=*), intent(in) :: string !< string in which chunks are searched for - - character(len=*), parameter :: SEP=achar(44)//achar(32)//achar(9)//achar(10)//achar(13) ! comma and whitespaces - integer :: left, right ! no pInt (verify and scan return default integer) - - allocate(IIO_stringPos(1), source=0_pInt) - right = 0 - - do while (verify(string(right+1:),SEP)>0) - left = right + verify(string(right+1:),SEP) - right = left + scan(string(left:),SEP) - 2 - if ( string(left:left) == '#' ) exit - IIO_stringPos = [IIO_stringPos,int(left, pInt), int(right, pInt)] - IIO_stringPos(1) = IIO_stringPos(1)+1_pInt - enddo - -end function IIO_stringPos - - -end module From 13d608fbb60ee0507c00a2b5d4c7402146c9d8a1 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Fri, 26 Feb 2016 12:31:53 -0500 Subject: [PATCH 013/183] put interface module back at base level --- code/spectral_interface.f90 | 568 ++++++++++++++++++++++++++++++++++++ 1 file changed, 568 insertions(+) create mode 100644 code/spectral_interface.f90 diff --git a/code/spectral_interface.f90 b/code/spectral_interface.f90 new file mode 100644 index 000000000..b24c5f747 --- /dev/null +++ b/code/spectral_interface.f90 @@ -0,0 +1,568 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Interfacing between the spectral solver and the material subroutines provided +!! by DAMASK +!> @details Interfacing between the spectral solver and the material subroutines provided +!> by DAMASK. Interpretating the command line arguments or, in case of called from f2py, +!> the arguments parsed to the init routine to get load case, geometry file, working +!> directory, etc. +!-------------------------------------------------------------------------------------------------- +module DAMASK_interface + use prec, only: & + pInt + + implicit none + private +#ifdef PETSc +#include +#endif + logical, public, protected :: appendToOutFile = .false. !< Append to existing spectralOut file (in case of restart, not in case of regridding) + integer(pInt), public, protected :: spectralRestartInc = 1_pInt !< Increment at which calculation starts + character(len=1024), public, protected :: & + geometryFile = '', & !< parameter given for geometry file + loadCaseFile = '' !< parameter given for load case file + character(len=1024), private :: workingDirectory !< accessed by getSolverWorkingDirectoryName for compatibility reasons + + public :: & + getSolverWorkingDirectoryName, & + getSolverJobName, & + DAMASK_interface_init + private :: & + storeWorkingDirectory, & + getGeometryFile, & + getLoadCaseFile, & + rectifyPath, & + makeRelativePath, & + getPathSep, & + IIO_stringValue, & + IIO_intValue, & + IIO_lc, & + IIO_stringPos + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief initializes the solver by interpreting the command line arguments. Also writes +!! information on computation to screen +!-------------------------------------------------------------------------------------------------- +subroutine DAMASK_interface_init(loadCaseParameterIn,geometryParameterIn) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + + implicit none + character(len=1024), optional, intent(in) :: & + loadCaseParameterIn, & !< if using the f2py variant, the -l argument of DAMASK_spectral.exe + geometryParameterIn !< if using the f2py variant, the -g argument of DAMASK_spectral.exe + character(len=1024) :: & + commandLine, & !< command line call as string + loadCaseArg ='', & !< -l argument given to DAMASK_spectral.exe + geometryArg ='', & !< -g argument given to DAMASK_spectral.exe + workingDirArg ='', & !< -w argument given to DAMASK_spectral.exe + hostName, & !< name of machine on which DAMASK_spectral.exe is execute (might require export HOSTNAME) + userName, & !< name of user calling DAMASK_spectral.exe + tag + integer :: & + i, & + worldrank = 0 + integer, allocatable, dimension(:) :: & + chunkPos + integer, dimension(8) :: & + dateAndTime ! type default integer +#ifdef PETSc + PetscErrorCode :: ierr +#endif + external :: & + quit,& + MPI_Comm_rank,& + PETScInitialize, & + MPI_abort + +!-------------------------------------------------------------------------------------------------- +! PETSc Init +#ifdef PETSc + call PetscInitialize(PETSC_NULL_CHARACTER,ierr) ! according to PETSc manual, that should be the first line in the code + CHKERRQ(ierr) ! this is a macro definition, it is case sensitive + + open(6, encoding='UTF-8') ! modern fortran compilers (gfortran >4.4, ifort >11 support it) + call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) +#endif + mainProcess: if (worldrank == 0) then + call date_and_time(values = dateAndTime) + write(6,'(/,a)') ' <<<+- DAMASK_spectral -+>>>' + write(6,'(/,a)') ' Version: '//DAMASKVERSION + write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& + dateAndTime(2),'/',& + dateAndTime(1) + write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& + dateAndTime(6),':',& + dateAndTime(7) + write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' +#include "compilation_info.f90" + endif mainProcess + + if ( present(loadcaseParameterIn) .and. present(geometryParameterIn)) then ! both mandatory parameters given in function call + geometryArg = geometryParameterIn + loadcaseArg = loadcaseParameterIn + commandLine = 'n/a' + else if ( .not.( present(loadcaseParameterIn) .and. present(geometryParameterIn))) then ! none parameters given in function call, trying to get them from command line + call get_command(commandLine) + chunkPos = IIO_stringPos(commandLine) + do i = 1, chunkPos(1) + tag = IIO_lc(IIO_stringValue(commandLine,chunkPos,i)) ! extract key + select case(tag) + case ('-h','--help') + mainProcess2: if (worldrank == 0) then + write(6,'(a)') ' #######################################################################' + write(6,'(a)') ' DAMASK_spectral:' + write(6,'(a)') ' The spectral method boundary value problem solver for' + write(6,'(a)') ' the Düsseldorf Advanced Material Simulation Kit' + write(6,'(a,/)')' #######################################################################' + write(6,'(a,/)')' Valid command line switches:' + write(6,'(a)') ' --geom (-g, --geometry)' + write(6,'(a)') ' --load (-l, --loadcase)' + write(6,'(a)') ' --workingdir (-w, --wd, --workingdirectory, -d, --directory)' + write(6,'(a)') ' --restart (-r, --rs)' + write(6,'(a)') ' --regrid (--rg)' + write(6,'(a)') ' --help (-h)' + write(6,'(/,a)')' -----------------------------------------------------------------------' + write(6,'(a)') ' Mandatory arguments:' + write(6,'(/,a)')' --geom PathToGeomFile/NameOfGeom.geom' + write(6,'(a)') ' Specifies the location of the geometry definition file,' + write(6,'(a)') ' if no extension is given, .geom will be appended.' + write(6,'(a)') ' "PathToGeomFile" will be the working directory if not specified' + write(6,'(a)') ' via --workingdir.' + write(6,'(a)') ' Make sure the file "material.config" exists in the working' + write(6,'(a)') ' directory.' + write(6,'(a)') ' For further configuration place "numerics.config"' + write(6,'(a)')' and "numerics.config" in that directory.' + write(6,'(/,a)')' --load PathToLoadFile/NameOfLoadFile.load' + write(6,'(a)') ' Specifies the location of the load case definition file,' + write(6,'(a)') ' if no extension is given, .load will be appended.' + write(6,'(/,a)')' -----------------------------------------------------------------------' + write(6,'(a)') ' Optional arguments:' + write(6,'(/,a)')' --workingdirectory PathToWorkingDirectory' + write(6,'(a)') ' Specifies the working directory and overwrites the default' + write(6,'(a)') ' "PathToGeomFile".' + write(6,'(a)') ' Make sure the file "material.config" exists in the working' + write(6,'(a)') ' directory.' + write(6,'(a)') ' For further configuration place "numerics.config"' + write(6,'(a)')' and "numerics.config" in that directory.' + write(6,'(/,a)')' --restart XX' + write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' + write(6,'(a)') ' calculate total increment No. XX.' + write(6,'(a)') ' Appends to existing results file ' + write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' + write(6,'(a)') ' Works only if the restart information for total increment' + write(6,'(a)') ' No. XX-1 is available in the working directory.' + write(6,'(/,a)')' --regrid XX' + write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' + write(6,'(a)') ' calculate total increment No. XX.' + write(6,'(a)') ' Attention: Overwrites existing results file ' + write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' + write(6,'(a)') ' Works only if the restart information for total increment' + write(6,'(a)') ' No. XX-1 is available in the working directory.' + write(6,'(/,a)')' -----------------------------------------------------------------------' + write(6,'(a)') ' Help:' + write(6,'(/,a)')' --help' + write(6,'(a,/)')' Prints this message and exits' + call quit(0_pInt) ! normal Termination + endif mainProcess2 + case ('-l', '--load', '--loadcase') + loadcaseArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + case ('-g', '--geom', '--geometry') + geometryArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + case ('-w', '-d', '--wd', '--directory', '--workingdir', '--workingdirectory') + workingDirArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + case ('-r', '--rs', '--restart') + spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) + appendToOutFile = .true. + case ('--rg', '--regrid') + spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) + appendToOutFile = .false. + end select + enddo + endif + + if (len(trim(loadcaseArg)) == 0 .or. len(trim(geometryArg)) == 0) then + write(6,'(a)') ' Please specify geometry AND load case (-h for help)' + call quit(1_pInt) + endif + + workingDirectory = storeWorkingDirectory(trim(workingDirArg),trim(geometryArg)) + geometryFile = getGeometryFile(geometryArg) + loadCaseFile = getLoadCaseFile(loadCaseArg) + + call get_environment_variable('HOSTNAME',hostName) + call get_environment_variable('USER',userName) + mainProcess3: if (worldrank == 0) then + write(6,'(a,a)') ' Host name: ', trim(hostName) + write(6,'(a,a)') ' User name: ', trim(userName) + write(6,'(a,a)') ' Path separator: ', getPathSep() + write(6,'(a,a)') ' Command line call: ', trim(commandLine) + if (len(trim(workingDirArg))>0) & + write(6,'(a,a)') ' Working dir argument: ', trim(workingDirArg) + write(6,'(a,a)') ' Geometry argument: ', trim(geometryArg) + write(6,'(a,a)') ' Loadcase argument: ', trim(loadcaseArg) + write(6,'(a,a)') ' Working directory: ', trim(getSolverWorkingDirectoryName()) + write(6,'(a,a)') ' Geometry file: ', trim(geometryFile) + write(6,'(a,a)') ' Loadcase file: ', trim(loadCaseFile) + write(6,'(a,a)') ' Solver job name: ', trim(getSolverJobName()) + if (SpectralRestartInc > 1_pInt) & + write(6,'(a,i6.6)') ' Restart at increment: ', spectralRestartInc + write(6,'(a,l1,/)') ' Append to result file: ', appendToOutFile + endif mainProcess3 + +end subroutine DAMASK_interface_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief extract working directory from given argument or from location of geometry file, +!! possibly converting relative arguments to absolut path +!> @todo change working directory with call chdir(storeWorkingDirectory)? +!-------------------------------------------------------------------------------------------------- +character(len=1024) function storeWorkingDirectory(workingDirectoryArg,geometryArg) +#ifdef __INTEL_COMPILER + use IFPORT +#endif + + implicit none + character(len=*), intent(in) :: workingDirectoryArg !< working directory argument + character(len=*), intent(in) :: geometryArg !< geometry argument + character(len=1024) :: cwd + character :: pathSep + logical :: dirExists + external :: quit + integer :: error + + pathSep = getPathSep() + if (len(workingDirectoryArg)>0) then ! got working directory as input + if (workingDirectoryArg(1:1) == pathSep) then ! absolute path given as command line argument + storeWorkingDirectory = workingDirectoryArg + else + error = getcwd(cwd) ! relative path given as command line argument + storeWorkingDirectory = trim(cwd)//pathSep//workingDirectoryArg + endif + if (storeWorkingDirectory(len(trim(storeWorkingDirectory)):len(trim(storeWorkingDirectory))) & ! if path seperator is not given, append it + /= pathSep) storeWorkingDirectory = trim(storeWorkingDirectory)//pathSep +#ifdef __INTEL_COMPILER + inquire(directory = trim(storeWorkingDirectory)//'.', exist=dirExists) +#else + inquire(file = trim(storeWorkingDirectory), exist=dirExists) +#endif + if(.not. dirExists) then ! check if the directory exists + write(6,'(a20,a,a16)') ' working directory "',trim(storeWorkingDirectory),'" does not exist' + call quit(1_pInt) + endif + else ! using path to geometry file as working dir + if (geometryArg(1:1) == pathSep) then ! absolute path given as command line argument + storeWorkingDirectory = geometryArg(1:scan(geometryArg,pathSep,back=.true.)) + else + error = getcwd(cwd) ! relative path given as command line argument + storeWorkingDirectory = trim(cwd)//pathSep//& + geometryArg(1:scan(geometryArg,pathSep,back=.true.)) + endif + endif + storeWorkingDirectory = rectifyPath(storeWorkingDirectory) + +end function storeWorkingDirectory + + +!-------------------------------------------------------------------------------------------------- +!> @brief simply returns the private string workingDir +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getSolverWorkingDirectoryName() + + implicit none + getSolverWorkingDirectoryName = workingDirectory + +end function getSolverWorkingDirectoryName + + +!-------------------------------------------------------------------------------------------------- +!> @brief solver job name (no extension) as combination of geometry and load case name +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getSolverJobName() + + implicit none + integer :: posExt,posSep + character :: pathSep + character(len=1024) :: tempString + + pathSep = getPathSep() + + tempString = geometryFile + posExt = scan(tempString,'.',back=.true.) + posSep = scan(tempString,pathSep,back=.true.) + + getSolverJobName = tempString(posSep+1:posExt-1) + + tempString = loadCaseFile + posExt = scan(tempString,'.',back=.true.) + posSep = scan(tempString,pathSep,back=.true.) + + getSolverJobName = trim(getSolverJobName)//'_'//tempString(posSep+1:posExt-1) + +end function getSolverJobName + + +!-------------------------------------------------------------------------------------------------- +!> @brief basename of geometry file with extension from command line arguments +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getGeometryFile(geometryParameter) +#ifdef __INTEL_COMPILER + use IFPORT +#endif + + implicit none + character(len=1024), intent(in) :: & + geometryParameter + character(len=1024) :: & + cwd + integer :: posExt, posSep + character :: pathSep + integer :: error + + getGeometryFile = geometryParameter + pathSep = getPathSep() + posExt = scan(getGeometryFile,'.',back=.true.) + posSep = scan(getGeometryFile,pathSep,back=.true.) + + if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') ! no extension present + if (scan(getGeometryFile,pathSep) /= 1) then ! relative path given as command line argument + error = getcwd(cwd) + getGeometryFile = rectifyPath(trim(cwd)//pathSep//getGeometryFile) + else + getGeometryFile = rectifyPath(getGeometryFile) + endif + + getGeometryFile = makeRelativePath(getSolverWorkingDirectoryName(), getGeometryFile) + +end function getGeometryFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief relative path of loadcase from command line arguments +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getLoadCaseFile(loadCaseParameter) +#ifdef __INTEL_COMPILER + use IFPORT +#endif + + implicit none + character(len=1024), intent(in) :: & + loadCaseParameter + character(len=1024) :: & + cwd + integer :: posExt, posSep, error + character :: pathSep + + getLoadCaseFile = loadcaseParameter + pathSep = getPathSep() + posExt = scan(getLoadCaseFile,'.',back=.true.) + posSep = scan(getLoadCaseFile,pathSep,back=.true.) + + if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') ! no extension present + if (scan(getLoadCaseFile,pathSep) /= 1) then ! relative path given as command line argument + error = getcwd(cwd) + getLoadCaseFile = rectifyPath(trim(cwd)//pathSep//getLoadCaseFile) + else + getLoadCaseFile = rectifyPath(getLoadCaseFile) + endif + + getLoadCaseFile = makeRelativePath(getSolverWorkingDirectoryName(), getLoadCaseFile) + +end function getLoadCaseFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief remove ../ and /./ from path +!-------------------------------------------------------------------------------------------------- +function rectifyPath(path) + + implicit none + character(len=*) :: path + character(len=len_trim(path)) :: rectifyPath + character :: pathSep + integer :: i,j,k,l ! no pInt + + pathSep = getPathSep() + +!-------------------------------------------------------------------------------------------------- +! remove /./ from path + l = len_trim(path) + rectifyPath = path + do i = l,3,-1 + if (rectifyPath(i-2:i) == pathSep//'.'//pathSep) & + rectifyPath(i-1:l) = rectifyPath(i+1:l)//' ' + enddo + +!-------------------------------------------------------------------------------------------------- +! remove ../ and corresponding directory from rectifyPath + l = len_trim(rectifyPath) + i = index(rectifyPath(i:l),'..'//pathSep) + j = 0 + do while (i > j) + j = scan(rectifyPath(1:i-2),pathSep,back=.true.) + rectifyPath(j+1:l) = rectifyPath(i+3:l)//repeat(' ',2+i-j) + if (rectifyPath(j+1:j+1) == pathSep) then !search for '//' that appear in case of XXX/../../XXX + k = len_trim(rectifyPath) + rectifyPath(j+1:k-1) = rectifyPath(j+2:k) + rectifyPath(k:k) = ' ' + endif + i = j+index(rectifyPath(j+1:l),'..'//pathSep) + enddo + if(len_trim(rectifyPath) == 0) rectifyPath = pathSep + +end function rectifyPath + + +!-------------------------------------------------------------------------------------------------- +!> @brief relative path from absolute a to absolute b +!-------------------------------------------------------------------------------------------------- +character(len=1024) function makeRelativePath(a,b) + + implicit none + character (len=*) :: a,b + character :: pathSep + integer :: i,posLastCommonSlash,remainingSlashes !no pInt + + pathSep = getPathSep() + posLastCommonSlash = 0 + remainingSlashes = 0 + + do i = 1, min(1024,len_trim(a),len_trim(b)) + if (a(i:i) /= b(i:i)) exit + if (a(i:i) == pathSep) posLastCommonSlash = i + enddo + do i = posLastCommonSlash+1,len_trim(a) + if (a(i:i) == pathSep) remainingSlashes = remainingSlashes + 1 + enddo + makeRelativePath = repeat('..'//pathSep,remainingSlashes)//b(posLastCommonSlash+1:len_trim(b)) + +end function makeRelativePath + + +!-------------------------------------------------------------------------------------------------- +!> @brief counting / and \ in $PATH System variable the character occuring more often is assumed +! to be the path separator +!-------------------------------------------------------------------------------------------------- +character function getPathSep() + + implicit none + character(len=2048) :: & + path + integer(pInt) :: & + backslash = 0_pInt, & + slash = 0_pInt + integer :: i + + call get_environment_variable('PATH',path) + do i=1, len(trim(path)) + if (path(i:i)=='/') slash = slash + 1_pInt + if (path(i:i)=='\') backslash = backslash + 1_pInt + enddo + + if (backslash>slash) then + getPathSep = '\' + else + getPathSep = '/' + endif + +end function getPathSep + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_stringValue for documentation +!-------------------------------------------------------------------------------------------------- +pure function IIO_stringValue(string,chunkPos,myChunk) + + implicit none + integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + character(len=1+chunkPos(myChunk*2+1)-chunkPos(myChunk*2)) :: IIO_stringValue + character(len=*), intent(in) :: string !< raw input with known start and end of each chunk + + + valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then + IIO_stringValue = '' + else valuePresent + IIO_stringValue = string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) + endif valuePresent + +end function IIO_stringValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_intValue for documentation +!-------------------------------------------------------------------------------------------------- +integer(pInt) pure function IIO_intValue(string,chunkPos,myChunk) + + implicit none + character(len=*), intent(in) :: string !< raw input with known start and end of each chunk + integer(pInt), intent(in) :: myChunk !< position number of desired sub string + integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string + + + valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then + IIO_intValue = 0_pInt + else valuePresent + read(UNIT=string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)),ERR=100,FMT=*) IIO_intValue + endif valuePresent + return +100 IIO_intValue = huge(1_pInt) + +end function IIO_intValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_lc for documentation +!-------------------------------------------------------------------------------------------------- +pure function IIO_lc(string) + + implicit none + character(len=*), intent(in) :: string !< string to convert + character(len=len(string)) :: IIO_lc + + character(26), parameter :: LOWER = 'abcdefghijklmnopqrstuvwxyz' + character(26), parameter :: UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + + integer :: i,n ! no pInt (len returns default integer) + + IIO_lc = string + do i=1,len(string) + n = index(UPPER,IIO_lc(i:i)) + if (n/=0) IIO_lc(i:i) = LOWER(n:n) + enddo + +end function IIO_lc + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_stringPos for documentation +!-------------------------------------------------------------------------------------------------- +pure function IIO_stringPos(string) + + implicit none + integer(pInt), dimension(:), allocatable :: IIO_stringPos + character(len=*), intent(in) :: string !< string in which chunks are searched for + + character(len=*), parameter :: SEP=achar(44)//achar(32)//achar(9)//achar(10)//achar(13) ! comma and whitespaces + integer :: left, right ! no pInt (verify and scan return default integer) + + allocate(IIO_stringPos(1), source=0_pInt) + right = 0 + + do while (verify(string(right+1:),SEP)>0) + left = right + verify(string(right+1:),SEP) + right = left + scan(string(left:),SEP) - 2 + if ( string(left:left) == '#' ) exit + IIO_stringPos = [IIO_stringPos,int(left, pInt), int(right, pInt)] + IIO_stringPos(1) = IIO_stringPos(1)+1_pInt + enddo + +end function IIO_stringPos + + +end module From 018668f4749c0d0459688c8974e8a20165409d41 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Fri, 26 Feb 2016 17:21:10 -0500 Subject: [PATCH 014/183] finally get prec.f90 to compile, now damask_interface --- CMakeLists.txt | 113 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b14c6efc..b461f7d40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ # SUFFIX = arbitrary suffix (after file to compile) # STANDARD_CHECK = checking for Fortran 2008, compiler dependend ######################################################################################## -cmake_minimum_required (VERSION 3.1.0) +cmake_minimum_required (VERSION 3.1.0 FATAL_ERROR) project (DAMASK Fortran) # The version number. @@ -28,6 +28,38 @@ if (NOT DEFINED HDF5_DIR) message (FATAL_ERROR "HDF5_DIR is not found!" ) endif (NOT DEFINED HDF5_DIR) +# Work around to probe PETSc configuration +# set (petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules") +# set (petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") + +# set (petsc_config_makefile "${DAMASK_SOURCE_DIR}/Makefile.petsc") +# file (WRITE "${petsc_config_makefile}" +# "## This file was autogenerated by FindPETSc.cmake +# # PETSC_DIR = ${PETSC_DIR} +# # PETSC_ARCH = ${PETSC_ARCH} +# include ${petsc_conf_rules} +# include ${petsc_conf_variables} +# show : +# \t-@echo -n \${\${VARIABLE}} +# " ) + +# macro (PETSC_GET_VARIABLE name var) +# set (${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) +# execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} show VARIABLE=${name} +# OUTPUT_VARIABLE ${var} +# RESULT_VARIABLE petsc_return) +# endmacro (PETSC_GET_VARIABLE) + +# petsc_get_variable (PETSC_LIB_DIR petsc_lib_dir) +# petsc_get_variable (PETSC_EXTERNAL_LIB_BASIC petsc_libs_external) +# petsc_get_variable (PETSC_CCPPFLAGS petsc_cpp_line) +# petsc_get_variable (PETSC_INCLUDE petsc_include) +# petsc_get_variable (PCC petsc_cc) +# petsc_get_variable (PCC_FLAGS petsc_cc_flags) +# petsc_get_variable (MPIEXEC petsc_mpiexec) +# # We are done with the temporary Makefile, calling PETSC_GET_VARIABLE after this point is invalid! +# file (REMOVE ${petsc_config_makefile}) + # OUTPUT TYPE set (SPECTRAL OFF) set (FEM OFF) @@ -47,10 +79,8 @@ endif (DAMASK_DRIVER STREQUAL "SPECTRAL") # set system include directories -include_directories( - ${PETSC_DIR}/lib/petsc/conf/variables - ${PETSC_DIR}/lib/petsc/conf/rules - ../lib +include_directories(${PETSC_DIR}/include + lib ${HDF5_DIR}/include ) link_directories(${HDF5_DIR}/lib) @@ -114,18 +144,18 @@ set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) # all: # -name as_is: case sensitive Fortran! ################################################################################################### -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -DDAMASKVERSION=${DAMASK_V}" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -fpp" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -ftz" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -assume byterecl,fpe_summary" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -diag-disable 5268" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn declarations" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn general" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn usage" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn interfaces" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn ignore_loc" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn alignments" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn unused" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -DDAMASKVERSION=\"${DAMASK_V}\"" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -fpp" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -ftz" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -assume byterecl,fpe_summary" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -diag-disable 5268" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn declarations" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn general" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn usage" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn interfaces" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn ignore_loc" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn alignments" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn unused" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING @@ -301,22 +331,41 @@ get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) if (Fortran_COMPILER_NAME MATCHES "ifort.*") # need the PETSC wrapped version of ifort - set (CMAKE_Fortran_COMPILER "${PETSC_DIR}/bin/mpifort") + set (CMAKE_Fortran_COMPILER "${PETSC_DIR}/bin/mpif90") # for RELEASE - set (CMAKE_Fortran_FLAGS_RELEASE "${COMPILE_OPTIONS_ifort}") + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}" ) + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPTIMIZATION_ifort}" ) + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_OPTIONS_ifort}") + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_ifort}") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}") # for DEBUG - set (CMAKE_Fortran_FLAGS_DEBUG "${COMPILE_OPTIONS_ifort} ${DEBUG_OPTIONS_ifort}") - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${LINK_OPTIONS_ifort} ${DEBUG_OPTIONS_ifort}") + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${COMPILE_OPTIONS_ifort}") + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${PRECISION_ifort}" ) + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}" ) + + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINK_OPTIONS_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}") elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") set (CMAKE_Fortran_COMPILER "${PETSC_DIR}/bin/mpif90") # for RELEASE - set (CMAKE_Fortran_FLAGS_RELEASE "${COMPILE_OPTIONS_gfortran}") - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${LINK_OPTIONS_gfortran} ${OPTIMIZATION_gfortran}") + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_gfortran}" ) + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_gfortran}" ) + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPTIMIZATION_gfortran}" ) + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_OPTIONS_gfortran}") + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_gfortran}" ) + + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_gfortran}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}" ) # for DEBUG - set (CMAKE_Fortran_FLAGS_DEBUG "${COMPILE_OPTIONS_gfortran} ${DEBUG_OPTIONS_gfortran}") - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${LINK_OPTIONS_gfortran} ${DEBUG_OPTIONS_gfortran}") + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${COMPILE_OPTIONS_gfortran}") + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${PRECISION_gfortran}" ) + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_gfortran}" ) + + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINK_OPTIONS_gfortran}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_gfortran}") # elseif (Fortran_COMPILER_NAME MATCHES "g77") message (FATAL_ERROR "Fortran 77 is not supported.") @@ -327,18 +376,26 @@ endif (Fortran_COMPILER_NAME MATCHES "ifort.*") # additional flag for SPECTRAL solver if (SPECTRAL) set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DSpectral") + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -DSpectral") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DSpectral") - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${LINK_OPTIONS_ifort} -DSpectral") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DSpectral") endif (SPECTRAL) # additional flags for FEM solver if (FEM) set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DFEM") + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -DFEM") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DFEM") - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${LINK_OPTIONS_ifort} -DFEM") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DFEM") endif (FEM) +# set PETSC flags +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DPETSc") +set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -DPETSc") +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DPETSc") +set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DPETSc") + # set default project compiler flags -# NOTE: some file requires different flags for compiling, DAMASK_$FLAGS +# NOTE: some file might need different flags for compiling, DAMASK_$FLAGS # are essentially the swap for this purpose set (DAMASK_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" ) set (DAMASK_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") From 9d89570ffb30cf0d4b4ab0404564fb7788fbc710 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 29 Feb 2016 10:50:35 -0500 Subject: [PATCH 015/183] save before update base --- CMakeLists.txt | 24 ++++++++++++------------ code/CMakeLists.txt | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b461f7d40..52ab21e64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,18 +144,18 @@ set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) # all: # -name as_is: case sensitive Fortran! ################################################################################################### -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -DDAMASKVERSION=\"${DAMASK_V}\"" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -fpp" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -ftz" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -assume byterecl,fpe_summary" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -diag-disable 5268" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn declarations" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn general" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn usage" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn interfaces" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn ignore_loc" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn alignments" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn unused" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -DDAMASKVERSION=${DAMASK_V}" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -fpp" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -ftz" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -assume byterecl,fpe_summary") +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -diag-disable 5268" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn declarations" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn general" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn usage" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn interfaces" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn ignore_loc" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn alignments" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn unused" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 71d373157..55bf78952 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,13 +1,47 @@ -# The dependency detection for Fortran is not working in CMake -# Have to define them explicitly +# The dependency detection in CMake is not functioning for Fortran +# !!! EXPLICIT DEPENDENCY DECLARATION !!! +################################################################################################### +# fno-range-check: Disable range checking on results of simplification of constant expressions during compilation +# --> allows the definition of DAMASK_NaN +#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored +# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external +# --> allows the use of 'isnan' +#-fno-fast-math: +# --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) +################################################################################################### +if (Fortran_COMPILER_NAME MATCHES "ifort.*") + set (SPEICAL_FLAGS "") +elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") + set (SPEICAL_FLAGS "-fno-range-check -fall-intrinsics -fno-fast-math") +else (Fortran_COMPILER_NAME MATCHES "ifort.*") + message (FATAL_ERROR "Unknown Fortrna compiler.") +endif (Fortran_COMPILER_NAME MATCHES "ifort.*") + +set (CMAKE_Fortran_FLAGS_RELEASE "${DAMASK_Fortran_FLAGS_RELEASE} ${SPEICAL_FLAGS}") + add_library(DAMASK_prec "prec.f90") -################################################################################################### +set (CMAKE_Fortran_FLAGS_RELEASE "${DAMASK_Fortran_FLAGS_RELEASE}") +################################################################################################### +# -diag-disable 7410 should disable warning about directory statement in inquire function, +# but does not work. hence the other 2 statements ################################################################################################### if (SPECTRAL) + if (Fortran_COMPILER_NAME MATCHES "ifort.*") + set (SPEICAL_FLAGS "-diag-remark 7410 -stand none -warn nostderrors") + elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") + set (SPEICAL_FLAGS "-fall-intrinsics") + else (Fortran_COMPILER_NAME MATCHES "ifort.*") + message (FATAL_ERROR "Unknown Fortrna compiler.") + endif (Fortran_COMPILER_NAME MATCHES "ifort.*") + + set (CMAKE_Fortran_FLAGS_RELEASE "${DAMASK_Fortran_FLAGS_RELEASE} ${SPEICAL_FLAGS}") + add_library(DAMASK_interface "spectral_interface.f90") target_link_libraries(DAMASK_interface DAMASK_prec) + + set (CMAKE_Fortran_FLAGS_RELEASE "${DAMASK_Fortran_FLAGS_RELEASE}") endif(SPECTRAL) add_library(DAMASK_IO "IO.f90") From e3f82f76292f617140c9ac4ae2009aff173fd805 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 29 Feb 2016 13:57:15 -0500 Subject: [PATCH 016/183] trying to fix the subdirectory issue --- CMakeLists.txt | 29 +++++++-- code/CMakeLists.txt | 111 ++++++++++----------------------- code/Makefile | 2 +- code/kinematics/CMakeLists.txt | 10 ++- code/plastic/CMakeLists.txt | 26 +++++--- code/source/CMakeLists.txt | 12 ++-- 6 files changed, 84 insertions(+), 106 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 52ab21e64..d76fd32e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,7 +79,8 @@ endif (DAMASK_DRIVER STREQUAL "SPECTRAL") # set system include directories -include_directories(${PETSC_DIR}/include +include_directories(${CMAKE_SOURCE_DIR} + ${PETSC_DIR}/include lib ${HDF5_DIR}/include ) @@ -113,7 +114,7 @@ else (OPTIMIZATION STREQUAL "OFF") set (OPTIMIZATION_gfortran "-O2") endif (OPTIMIZATION STREQUAL "OFF") -set (STANDARD_CHECK_ifort "-stand f08 -standard-semantics") +set (STANDARD_CHECK_ifort "-stand none -standard-semantics") set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) ################################################################################################### @@ -144,7 +145,10 @@ set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) # all: # -name as_is: case sensitive Fortran! ################################################################################################### -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -DDAMASKVERSION=${DAMASK_V}" ) +# -diag-disable 7410 should disable warning about directory statement in inquire function, +# but does not work. hence the other 2 statements +################################################################################################### +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -DDAMASKVERSION=\\\"${DAMASK_V}\\\"" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -fpp" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -ftz" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -assume byterecl,fpe_summary") @@ -156,7 +160,9 @@ set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn interfaces" set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn ignore_loc" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn alignments" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn unused" ) - +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -diag-remark 7410" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -stand none" ) +set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn nostderrors" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING # -g: Generate symbolic debugging information in the object file @@ -272,6 +278,14 @@ set (LINK_OPTIONS_ifort "-shared-intel") # -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. # -Wstrict-overflow: ################################################################################################### +# fno-range-check: Disable range checking on results of simplification of constant expressions during compilation +# --> allows the definition of DAMASK_NaN +#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored +# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external +# --> allows the use of 'isnan' +#-fno-fast-math: +# --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) +################################################################################################### set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -DDAMASKVERSION=${DAMASKVERSION}") set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -xf95-cpp-input" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -ffree-line-length-240" ) @@ -286,7 +300,10 @@ set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wsuggest-attribute=n set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wconversion-extra" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wimplicit-procedure" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wno-unused-parameter" ) - +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fno-range-check" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fall-intrinsics" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fno-fast-math" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fall-intrinsics" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING # -ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) @@ -348,6 +365,7 @@ if (Fortran_COMPILER_NAME MATCHES "ifort.*") set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINK_OPTIONS_ifort}" ) set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}") + # elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") set (CMAKE_Fortran_COMPILER "${PETSC_DIR}/bin/mpif90") # for RELEASE @@ -398,6 +416,7 @@ set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DPETSc" # NOTE: some file might need different flags for compiling, DAMASK_$FLAGS # are essentially the swap for this purpose set (DAMASK_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" ) +set (DAMASK_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" ) set (DAMASK_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set (DAMASK_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" ) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 55bf78952..542b637d3 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,51 +1,17 @@ # The dependency detection in CMake is not functioning for Fortran # !!! EXPLICIT DEPENDENCY DECLARATION !!! -################################################################################################### -# fno-range-check: Disable range checking on results of simplification of constant expressions during compilation -# --> allows the definition of DAMASK_NaN -#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored -# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external -# --> allows the use of 'isnan' -#-fno-fast-math: -# --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) -################################################################################################### -if (Fortran_COMPILER_NAME MATCHES "ifort.*") - set (SPEICAL_FLAGS "") -elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") - set (SPEICAL_FLAGS "-fno-range-check -fall-intrinsics -fno-fast-math") -else (Fortran_COMPILER_NAME MATCHES "ifort.*") - message (FATAL_ERROR "Unknown Fortrna compiler.") -endif (Fortran_COMPILER_NAME MATCHES "ifort.*") -set (CMAKE_Fortran_FLAGS_RELEASE "${DAMASK_Fortran_FLAGS_RELEASE} ${SPEICAL_FLAGS}") +add_library(DAMASK_PREC "prec.f90") -add_library(DAMASK_prec "prec.f90") - -set (CMAKE_Fortran_FLAGS_RELEASE "${DAMASK_Fortran_FLAGS_RELEASE}") - -################################################################################################### -# -diag-disable 7410 should disable warning about directory statement in inquire function, -# but does not work. hence the other 2 statements -################################################################################################### if (SPECTRAL) - if (Fortran_COMPILER_NAME MATCHES "ifort.*") - set (SPEICAL_FLAGS "-diag-remark 7410 -stand none -warn nostderrors") - elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") - set (SPEICAL_FLAGS "-fall-intrinsics") - else (Fortran_COMPILER_NAME MATCHES "ifort.*") - message (FATAL_ERROR "Unknown Fortrna compiler.") - endif (Fortran_COMPILER_NAME MATCHES "ifort.*") - - set (CMAKE_Fortran_FLAGS_RELEASE "${DAMASK_Fortran_FLAGS_RELEASE} ${SPEICAL_FLAGS}") - - add_library(DAMASK_interface "spectral_interface.f90") - target_link_libraries(DAMASK_interface DAMASK_prec) - - set (CMAKE_Fortran_FLAGS_RELEASE "${DAMASK_Fortran_FLAGS_RELEASE}") + add_library(DAMASK_INTERFACE "spectral_interface.f90") + target_link_libraries(DAMASK_INTERFACE DAMASK_PREC) +elseif(SPECTRAL) + message(FATAL_ERROR "NOT IMPLEMENTED YET") endif(SPECTRAL) add_library(DAMASK_IO "IO.f90") -target_link_libraries(DAMASK_IO DAMASK_interface) +target_link_libraries(DAMASK_IO DAMASK_INTERFACE) add_library(DAMASK_LIBS "libs.f90") target_link_libraries(DAMASK_LIBS DAMASK_IO) @@ -56,49 +22,38 @@ target_link_libraries(DAMASK_NUMERICS DAMASK_LIBS) add_library(DAMASK_DEBUG "debug.f90") target_link_libraries(DAMASK_DEBUG DAMASK_NUMERICS) -add_library(DAMASK_BASICS ALIAS DAMASK_DEBUG) +add_library(DAMASK_FEsolving "FEsolving.f90") +target_link_libraries(DAMASK_FEsolving DAMASK_DEBUG) -# group sources for base modules -# the FEM modules would require special attention -# will take care of it later. -set (SRC "CPFEM" - "CPFEM2" - "core_quit" - "commercialFEM_fileList" - "compilation_info" - "constitutive" - "crystallite" - "damask_hdf5" - "lattice" - "material" - "math" - "mesh" - "quit__genmod" - ) +add_library(DAMASK_MATH "math.f90") +target_link_libraries(DAMASK_MATH DAMASK_FEsolving) -# compiler base modules -foreach (p ${SRC}) - add_library (${p} "${p}.f90") - target_link_libraries(${p} DAMASK_BASICS) -endforeach (p) +# SPECTRAL solver and FEM solver use different mesh +# source files +if (SPECTRAL) + add_library(DAMASK_MESH "mesh.f90") +endif(SPECTRAL) +if (FEM) + add_library(DAMASK_MESH "${FEM_DIR}/meshFEM.f90") +endif(FEM) +target_link_libraries(DAMASK_MESH DAMASK_MATH) -# set libraries/modules for linking -foreach (p ${SRC}) - set (DAMASK_LIB ${DAMASK_LIB} ${p}) -endforeach (p) +add_library(DAMASK_MATERIAL "material.f90") +target_link_libraries(DAMASK_MATERIAL DAMASK_MESH) -# compile each sub moudel -add_subdirectory(damage) -add_subdirectory(homogenization) -add_subdirectory(hydrogenflux) -add_subdirectory(kinematics) +add_library(DAMASK_LATTICE "lattice.f90") +target_link_libraries(DAMASK_LATTICE DAMASK_MATERIAL) +add_library(DAMASK_DRIVERS ALIAS DAMASK_LATTICE) + +# For each modular section add_subdirectory(plastic) -add_subdirectory(porosity) -add_subdirectory(source) -add_subdirectory(spectral) -add_subdirectory(thermal) -add_subdirectory(vacancyflux) +# add_subdirectory(kinematics) +# add_subdirectory(source) + +# add_library(DAMASK_CONSTITUTIVE "constitutive.f90") +# target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_DRIVERS) +# add_library(DAMASK_DRIVERS ALIAS DAMASK_CONSTITUTIVE) # compile spectral solver add_executable(DAMASKSpectral.exe DAMASK_spectral.f90) -target_link_libraries (DAMASKSpectral.exe ${DAMASK_LIB}) \ No newline at end of file +target_link_libraries (DAMASKSpectral.exe DAMASK_PLASTIC) \ No newline at end of file diff --git a/code/Makefile b/code/Makefile index a18cbebac..66c70e646 100644 --- a/code/Makefile +++ b/code/Makefile @@ -98,7 +98,7 @@ OPTIMIZATION_AGGRESSIVE_gfortran :=-O3 -ffast-math -funroll-loops -ftree-vectori LINK_OPTIONS_ifort :=-shared-intel -COMPILE_OPTIONS_ifort :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ +COMPILE_OPTIONS_ifort :=-DDAMASKVERSION='${DAMASKVERSION}'\ -fpp\ -ftz\ -assume byterecl,fpe_summary\ diff --git a/code/kinematics/CMakeLists.txt b/code/kinematics/CMakeLists.txt index c6eb341d0..af37022fe 100644 --- a/code/kinematics/CMakeLists.txt +++ b/code/kinematics/CMakeLists.txt @@ -6,12 +6,10 @@ set (KINEMATICS "kinematics_cleavage_opening" "kinematics_hydrogen_strain" ) -# compile kinamtic modules +# compile module and cumulatively link the +# compiled libraries foreach (p ${KINEMATICS}) add_library (${p} "${p}.f90") -endforeach (p) - -# set libraries/modules for linking -foreach (p ${KINEMATICS}) - set (DAMASK_LIB ${DAMASK_LIB} ${p}) + target_link_libraries(${p} DAMASK_DRIVERS) + add_library (DAMASK_DRIVERS ALIAS ${p}) endforeach (p) \ No newline at end of file diff --git a/code/plastic/CMakeLists.txt b/code/plastic/CMakeLists.txt index be40539d3..e3fc430d3 100644 --- a/code/plastic/CMakeLists.txt +++ b/code/plastic/CMakeLists.txt @@ -10,12 +10,20 @@ set (PLASTIC "plastic_dislotwin" "plastic_phenoplus" ) -# compile module -foreach (p ${PLASTIC}) - add_library (${p} "${p}.f90") -endforeach (p) - -# set libraries/modules for linking -foreach (p ${PLASTIC}) - set (DAMASK_LIB ${DAMASK_LIB} ${p}) -endforeach (p) \ No newline at end of file +# compile module and cumulatively link the +# compiled libraries +add_library (DAMASK_PLASTIC "plastic_dislotwin.f90" + "plastic_disloUCLA.f90" + "plastic_isotropic.f90" + "plastic_j2.f90" + "plastic_phenopowerlaw.f90" + "plastic_titanmod.f90" + "plastic_nonlocal.f90" + "plastic_none.f90" + "plastic_phenoplus.f90") +target_link_libraries(DAMASK_PLASTIC DAMASK_DRIVERS) +# foreach (p ${PLASTIC}) +# add_library (${p} "${p}.f90") +# target_link_libraries(${p} DAMASK_DRIVERS) +# add_library (DAMASK_DRIVERS ALIAS ${p}) +# endforeach (p) \ No newline at end of file diff --git a/code/source/CMakeLists.txt b/code/source/CMakeLists.txt index 780a8ffac..cd9475ee3 100644 --- a/code/source/CMakeLists.txt +++ b/code/source/CMakeLists.txt @@ -10,12 +10,10 @@ set (SOURCE "source_thermal_dissipation" "source_vacancy_thermalfluc" ) -# compile modules for source -foreach (p ${SOURCE}) +# compile module and cumulatively link the +# compiled libraries +foreach (p ${KINEMATICS}) add_library (${p} "${p}.f90") -endforeach (p) - -# set libraries/modules for linking -foreach (p ${SOURCE}) - set (DAMASK_LIB ${DAMASK_LIB} ${p}) + target_link_libraries(${p} DAMASK_DRIVERS) + add_library (DAMASK_DRIVERS ALIAS ${p}) endforeach (p) \ No newline at end of file From ad6432c173942b83ac22a42d304860609b222d5f Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 29 Feb 2016 14:20:52 -0500 Subject: [PATCH 017/183] revert back to single level design for source code --- CMakeLists.txt | 2 +- code/CMakeLists.txt | 38 +- code/kinematics/CMakeLists.txt | 15 - .../kinematics_cleavage_opening.f90 | 303 -- .../kinematics/kinematics_hydrogen_strain.f90 | 264 -- .../kinematics_slipplane_opening.f90 | 323 -- .../kinematics_thermal_expansion.f90 | 228 - code/kinematics/kinematics_vacancy_strain.f90 | 265 -- code/plastic/CMakeLists.txt | 29 - code/plastic/plastic_disloUCLA.f90 | 2116 --------- code/plastic/plastic_dislotwin.f90 | 2542 ----------- code/plastic/plastic_isotropic.f90 | 678 --- code/plastic/plastic_j2.f90 | 579 --- code/plastic/plastic_none.f90 | 109 - code/plastic/plastic_nonlocal.f90 | 4031 ----------------- code/plastic/plastic_phenoplus.f90 | 1419 ------ code/plastic/plastic_phenopowerlaw.f90 | 1226 ----- code/plastic/plastic_titanmod.f90 | 1913 -------- code/source/CMakeLists.txt | 19 - code/source/source_damage_anisoBrittle.f90 | 425 -- code/source/source_damage_anisoDuctile.f90 | 415 -- code/source/source_damage_isoBrittle.f90 | 383 -- code/source/source_damage_isoDuctile.f90 | 350 -- code/source/source_thermal_dissipation.f90 | 220 - code/source/source_thermal_externalheat.f90 | 277 -- code/source/source_vacancy_irradiation.f90 | 253 -- .../source/source_vacancy_phenoplasticity.f90 | 215 - code/source/source_vacancy_thermalfluc.f90 | 255 -- 28 files changed, 32 insertions(+), 18860 deletions(-) delete mode 100644 code/kinematics/CMakeLists.txt delete mode 100644 code/kinematics/kinematics_cleavage_opening.f90 delete mode 100644 code/kinematics/kinematics_hydrogen_strain.f90 delete mode 100644 code/kinematics/kinematics_slipplane_opening.f90 delete mode 100644 code/kinematics/kinematics_thermal_expansion.f90 delete mode 100644 code/kinematics/kinematics_vacancy_strain.f90 delete mode 100644 code/plastic/CMakeLists.txt delete mode 100644 code/plastic/plastic_disloUCLA.f90 delete mode 100644 code/plastic/plastic_dislotwin.f90 delete mode 100644 code/plastic/plastic_isotropic.f90 delete mode 100644 code/plastic/plastic_j2.f90 delete mode 100644 code/plastic/plastic_none.f90 delete mode 100644 code/plastic/plastic_nonlocal.f90 delete mode 100644 code/plastic/plastic_phenoplus.f90 delete mode 100644 code/plastic/plastic_phenopowerlaw.f90 delete mode 100644 code/plastic/plastic_titanmod.f90 delete mode 100644 code/source/CMakeLists.txt delete mode 100644 code/source/source_damage_anisoBrittle.f90 delete mode 100644 code/source/source_damage_anisoDuctile.f90 delete mode 100644 code/source/source_damage_isoBrittle.f90 delete mode 100644 code/source/source_damage_isoDuctile.f90 delete mode 100644 code/source/source_thermal_dissipation.f90 delete mode 100644 code/source/source_thermal_externalheat.f90 delete mode 100644 code/source/source_vacancy_irradiation.f90 delete mode 100644 code/source/source_vacancy_phenoplasticity.f90 delete mode 100644 code/source/source_vacancy_thermalfluc.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index d76fd32e2..b3f167362 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,7 +79,7 @@ endif (DAMASK_DRIVER STREQUAL "SPECTRAL") # set system include directories -include_directories(${CMAKE_SOURCE_DIR} +include_directories(${CMAKE_SOURCE_DIR}/code ${PETSC_DIR}/include lib ${HDF5_DIR}/include diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 542b637d3..33208a6ed 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -46,14 +46,38 @@ target_link_libraries(DAMASK_LATTICE DAMASK_MATERIAL) add_library(DAMASK_DRIVERS ALIAS DAMASK_LATTICE) # For each modular section -add_subdirectory(plastic) -# add_subdirectory(kinematics) -# add_subdirectory(source) +add_library (DAMASK_PLASTIC "plastic_dislotwin.f90" + "plastic_disloUCLA.f90" + "plastic_isotropic.f90" + "plastic_j2.f90" + "plastic_phenopowerlaw.f90" + "plastic_titanmod.f90" + "plastic_nonlocal.f90" + "plastic_none.f90" + "plastic_phenoplus.f90") +target_link_libraries(DAMASK_PLASTIC DAMASK_DRIVERS) -# add_library(DAMASK_CONSTITUTIVE "constitutive.f90") -# target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_DRIVERS) -# add_library(DAMASK_DRIVERS ALIAS DAMASK_CONSTITUTIVE) +add_library (DAMASK_KINEMATICS "kinematics_cleavage_opening.f90" + "kinematics_slipplane_opening.f90" + "kinematics_thermal_expansion.f90" + "kinematics_vacancy_strain.f90" + "kinematics_hydrogen_strain.f90") +target_link_libraries(DAMASK_KINEMATICS DAMASK_DRIVERS) + +add_library (DAMASK_SOURCE "source_thermal_dissipation.f90" + "source_thermal_externalheat.f90" + "source_damage_isoBrittle.f90" + "source_damage_isoDuctile.f90" + "source_damage_anisoBrittle.f90" + "source_damage_anisoDuctile.f90" + "source_vacancy_phenoplasticity.f90" + "source_vacancy_irradiation.f90" + "source_vacancy_thermalfluc.f90") +target_link_libraries(DAMASK_SOURCE DAMASK_DRIVERS) + +add_library(DAMASK_CONSTITUTIVE "constitutive.f90") +target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_PLASTIC DAMASK_KINEMATICS DAMASK_SOURCE) # compile spectral solver add_executable(DAMASKSpectral.exe DAMASK_spectral.f90) -target_link_libraries (DAMASKSpectral.exe DAMASK_PLASTIC) \ No newline at end of file +target_link_libraries (DAMASKSpectral.exe DAMASK_CONSTITUTIVE) \ No newline at end of file diff --git a/code/kinematics/CMakeLists.txt b/code/kinematics/CMakeLists.txt deleted file mode 100644 index af37022fe..000000000 --- a/code/kinematics/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# group sources -set (KINEMATICS "kinematics_cleavage_opening" - "kinematics_slipplane_opening" - "kinematics_thermal_expansion" - "kinematics_vacancy_strain" - "kinematics_hydrogen_strain" - ) - -# compile module and cumulatively link the -# compiled libraries -foreach (p ${KINEMATICS}) - add_library (${p} "${p}.f90") - target_link_libraries(${p} DAMASK_DRIVERS) - add_library (DAMASK_DRIVERS ALIAS ${p}) -endforeach (p) \ No newline at end of file diff --git a/code/kinematics/kinematics_cleavage_opening.f90 b/code/kinematics/kinematics_cleavage_opening.f90 deleted file mode 100644 index 945e2d08a..000000000 --- a/code/kinematics/kinematics_cleavage_opening.f90 +++ /dev/null @@ -1,303 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from opening of cleavage planes -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_cleavage_opening - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_cleavage_opening_sizePostResults, & !< cumulative size of post results - kinematics_cleavage_opening_offset, & !< which kinematics is my current damage mechanism? - kinematics_cleavage_opening_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_cleavage_opening_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_cleavage_opening_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_cleavage_opening_Noutput !< number of outputs per instance of this damage - - integer(pInt), dimension(:), allocatable, private :: & - kinematics_cleavage_opening_totalNcleavage !< total number of cleavage systems - - integer(pInt), dimension(:,:), allocatable, private :: & - kinematics_cleavage_opening_Ncleavage !< number of cleavage systems per family - - real(pReal), dimension(:), allocatable, private :: & - kinematics_cleavage_opening_sdot_0, & - kinematics_cleavage_opening_N - - real(pReal), dimension(:,:), allocatable, private :: & - kinematics_cleavage_opening_critDisp, & - kinematics_cleavage_opening_critLoad - - public :: & - kinematics_cleavage_opening_init, & - kinematics_cleavage_opening_LiAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_cleavage_opening_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_cleavage_opening_label, & - KINEMATICS_cleavage_opening_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - use lattice, only: & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_cleavage_opening_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_cleavage_opening_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_cleavage_opening_offset(material_Nphase), source=0_pInt) - allocate(kinematics_cleavage_opening_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_cleavage_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_cleavage_opening_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_cleavage_opening_ID) & - kinematics_cleavage_opening_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_cleavage_opening_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_output(maxval(phase_Noutput),maxNinstance)) - kinematics_cleavage_opening_output = '' - allocate(kinematics_cleavage_opening_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(kinematics_cleavage_opening_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(kinematics_cleavage_opening_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_totalNcleavage(maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_sdot_0(maxNinstance), source=0.0_pReal) - allocate(kinematics_cleavage_opening_N(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_cleavage_opening_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('anisobrittle_sdot0') - kinematics_cleavage_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisobrittle_ratesensitivity') - kinematics_cleavage_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('ncleavage') ! - Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_CleavageFamilies - kinematics_cleavage_opening_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticaldisplacement') - do j = 1_pInt, Nchunks_CleavageFamilies - kinematics_cleavage_opening_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticalload') - do j = 1_pInt, Nchunks_CleavageFamilies - kinematics_cleavage_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then - instance = kinematics_cleavage_opening_instance(phase) - kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & - min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested - kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance)) - kinematics_cleavage_opening_totalNcleavage(instance) = sum(kinematics_cleavage_opening_Ncleavage(:,instance)) ! how many cleavage systems altogether - if (kinematics_cleavage_opening_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_cleavage_opening_LABEL//')') - if (any(kinematics_cleavage_opening_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//KINEMATICS_cleavage_opening_LABEL//')') - if (any(kinematics_cleavage_opening_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//KINEMATICS_cleavage_opening_LABEL//')') - if (kinematics_cleavage_opening_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_cleavage_opening_LABEL//')') - endif myPhase - enddo sanityChecks - -end subroutine kinematics_cleavage_opening_init - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) - use prec, only: & - tol_math_check - use material, only: & - phaseAt, phasememberAt, & - material_homog, & - damage, & - damageMapping - use lattice, only: & - lattice_Scleavage, & - lattice_Scleavage_v, & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola-Kirchhoff stress - real(pReal), intent(out), dimension(3,3) :: & - Ld !< damage velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) - integer(pInt) :: & - phase, & - constituent, & - instance, & - homog, damageOffset, & - f, i, index_myFamily, k, l, m, n - real(pReal) :: & - traction_d, traction_t, traction_n, traction_crit, & - udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = kinematics_cleavage_opening_instance(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - Ld = 0.0_pReal - dLd_dTstar3333 = 0.0_pReal - do f = 1_pInt,lattice_maxNcleavageFamily - index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family - do i = 1_pInt,kinematics_cleavage_opening_Ncleavage(f,instance) ! process each (active) cleavage system in family - traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) - traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) - traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) - traction_crit = kinematics_cleavage_opening_critLoad(f,instance)* & - damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) - udotd = & - sign(1.0_pReal,traction_d)* & - kinematics_cleavage_opening_sdot_0(instance)* & - (max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) - if (abs(udotd) > tol_math_check) then - Ld = Ld + udotd*lattice_Scleavage(1:3,1:3,1,index_myFamily+i,phase) - dudotd_dt = sign(1.0_pReal,traction_d)*udotd*kinematics_cleavage_opening_N(instance)/ & - max(0.0_pReal, abs(traction_d) - traction_crit) - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotd_dt*lattice_Scleavage(k,l,1,index_myFamily+i,phase)* & - lattice_Scleavage(m,n,1,index_myFamily+i,phase) - endif - - udott = & - sign(1.0_pReal,traction_t)* & - kinematics_cleavage_opening_sdot_0(instance)* & - (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) - if (abs(udott) > tol_math_check) then - Ld = Ld + udott*lattice_Scleavage(1:3,1:3,2,index_myFamily+i,phase) - dudott_dt = sign(1.0_pReal,traction_t)*udott*kinematics_cleavage_opening_N(instance)/ & - max(0.0_pReal, abs(traction_t) - traction_crit) - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudott_dt*lattice_Scleavage(k,l,2,index_myFamily+i,phase)* & - lattice_Scleavage(m,n,2,index_myFamily+i,phase) - endif - - udotn = & - sign(1.0_pReal,traction_n)* & - kinematics_cleavage_opening_sdot_0(instance)* & - (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) - if (abs(udotn) > tol_math_check) then - Ld = Ld + udotn*lattice_Scleavage(1:3,1:3,3,index_myFamily+i,phase) - dudotn_dt = sign(1.0_pReal,traction_n)*udotn*kinematics_cleavage_opening_N(instance)/ & - max(0.0_pReal, abs(traction_n) - traction_crit) - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotn_dt*lattice_Scleavage(k,l,3,index_myFamily+i,phase)* & - lattice_Scleavage(m,n,3,index_myFamily+i,phase) - endif - - enddo - enddo - -end subroutine kinematics_cleavage_opening_LiAndItsTangent - -end module kinematics_cleavage_opening diff --git a/code/kinematics/kinematics_hydrogen_strain.f90 b/code/kinematics/kinematics_hydrogen_strain.f90 deleted file mode 100644 index ceb3b1ef3..000000000 --- a/code/kinematics/kinematics_hydrogen_strain.f90 +++ /dev/null @@ -1,264 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from interstitial hydrogen -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_hydrogen_strain - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_hydrogen_strain_sizePostResults, & !< cumulative size of post results - kinematics_hydrogen_strain_offset, & !< which kinematics is my current damage mechanism? - kinematics_hydrogen_strain_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_hydrogen_strain_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_hydrogen_strain_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_hydrogen_strain_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - kinematics_hydrogen_strain_coeff - - public :: & - kinematics_hydrogen_strain_init, & - kinematics_hydrogen_strain_initialStrain, & - kinematics_hydrogen_strain_LiAndItsTangent, & - kinematics_hydrogen_strain_ChemPotAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_hydrogen_strain_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_hydrogen_strain_label, & - KINEMATICS_hydrogen_strain_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_hydrogen_strain_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_hydrogen_strain_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_hydrogen_strain_offset(material_Nphase), source=0_pInt) - allocate(kinematics_hydrogen_strain_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_hydrogen_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_hydrogen_strain_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_hydrogen_strain_ID) & - kinematics_hydrogen_strain_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_hydrogen_strain_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_hydrogen_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_hydrogen_strain_output(maxval(phase_Noutput),maxNinstance)) - kinematics_hydrogen_strain_output = '' - allocate(kinematics_hydrogen_strain_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_hydrogen_strain_coeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_hydrogen_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_hydrogen_strain_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('hydrogen_strain_coeff') - kinematics_hydrogen_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - -end subroutine kinematics_hydrogen_strain_init - -!-------------------------------------------------------------------------------------------------- -!> @brief report initial hydrogen strain based on current hydrogen conc deviation from -!> equillibrium (0) -!-------------------------------------------------------------------------------------------------- -pure function kinematics_hydrogen_strain_initialStrain(ipc, ip, el) - use math, only: & - math_I3 - use material, only: & - material_phase, & - material_homog, & - hydrogenConc, & - hydrogenfluxMapping - use lattice, only: & - lattice_equilibriumHydrogenConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - kinematics_hydrogen_strain_initialStrain !< initial thermal strain (should be small strain, though) - integer(pInt) :: & - phase, & - homog, offset, instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_hydrogen_strain_instance(phase) - homog = material_homog(ip,el) - offset = hydrogenfluxMapping(homog)%p(ip,el) - - kinematics_hydrogen_strain_initialStrain = & - (hydrogenConc(homog)%p(offset) - lattice_equilibriumHydrogenConcentration(phase)) * & - kinematics_hydrogen_strain_coeff(instance)* math_I3 - -end function kinematics_hydrogen_strain_initialStrain - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_hydrogen_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - hydrogenConc, & - hydrogenConcRate, & - hydrogenfluxMapping - use math, only: & - math_I3 - use lattice, only: & - lattice_equilibriumHydrogenConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out), dimension(3,3) :: & - Li !< thermal velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) - integer(pInt) :: & - phase, & - instance, & - homog, offset - real(pReal) :: & - Ch, ChEq, ChDot - - phase = material_phase(ipc,ip,el) - instance = kinematics_hydrogen_strain_instance(phase) - homog = material_homog(ip,el) - offset = hydrogenfluxMapping(homog)%p(ip,el) - Ch = hydrogenConc(homog)%p(offset) - ChDot = hydrogenConcRate(homog)%p(offset) - ChEq = lattice_equilibriumHydrogenConcentration(phase) - - Li = ChDot*math_I3* & - kinematics_hydrogen_strain_coeff(instance)/ & - (1.0_pReal + kinematics_hydrogen_strain_coeff(instance)*(Ch - ChEq)) - dLi_dTstar3333 = 0.0_pReal - -end subroutine kinematics_hydrogen_strain_LiAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the kinematic contribution to hydrogen chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCh, Tstar_v, Fi0, Fi, ipc, ip, el) - use material, only: & - material_phase - use math, only: & - math_inv33, & - math_mul33x33, & - math_Mandel6to33, & - math_transpose33 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v - real(pReal), intent(in), dimension(3,3) :: & - Fi0, Fi - real(pReal), intent(out) :: & - ChemPot, dChemPot_dCh - integer(pInt) :: & - phase, & - instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_hydrogen_strain_instance(phase) - - ChemPot = -kinematics_hydrogen_strain_coeff(instance)* & - sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & - math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) - dChemPot_dCh = 0.0_pReal - -end subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent - -end module kinematics_hydrogen_strain diff --git a/code/kinematics/kinematics_slipplane_opening.f90 b/code/kinematics/kinematics_slipplane_opening.f90 deleted file mode 100644 index 8b49e1cf3..000000000 --- a/code/kinematics/kinematics_slipplane_opening.f90 +++ /dev/null @@ -1,323 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from opening of slip planes -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_slipplane_opening - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_slipplane_opening_sizePostResults, & !< cumulative size of post results - kinematics_slipplane_opening_offset, & !< which kinematics is my current damage mechanism? - kinematics_slipplane_opening_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_slipplane_opening_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_slipplane_opening_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_slipplane_opening_Noutput !< number of outputs per instance of this damage - - integer(pInt), dimension(:), allocatable, private :: & - kinematics_slipplane_opening_totalNslip !< total number of slip systems - - integer(pInt), dimension(:,:), allocatable, private :: & - kinematics_slipplane_opening_Nslip !< number of slip systems per family - - real(pReal), dimension(:), allocatable, private :: & - kinematics_slipplane_opening_sdot_0, & - kinematics_slipplane_opening_N - - real(pReal), dimension(:,:), allocatable, private :: & - kinematics_slipplane_opening_critPlasticStrain, & - kinematics_slipplane_opening_critLoad - - public :: & - kinematics_slipplane_opening_init, & - kinematics_slipplane_opening_LiAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_slipplane_opening_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_slipplane_opening_label, & - KINEMATICS_slipplane_opening_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - use lattice, only: & - lattice_maxNslipFamily, & - lattice_NslipSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_slipplane_opening_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_slipplane_opening_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_slipplane_opening_offset(material_Nphase), source=0_pInt) - allocate(kinematics_slipplane_opening_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_slipplane_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_slipplane_opening_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_slipplane_opening_ID) & - kinematics_slipplane_opening_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_slipplane_opening_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_slipplane_opening_output(maxval(phase_Noutput),maxNinstance)) - kinematics_slipplane_opening_output = '' - allocate(kinematics_slipplane_opening_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(kinematics_slipplane_opening_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(kinematics_slipplane_opening_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_totalNslip(maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_N(maxNinstance), source=0.0_pReal) - allocate(kinematics_slipplane_opening_sdot_0(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_slipplane_opening_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('nslip') ! - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - kinematics_slipplane_opening_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_sdot0') - kinematics_slipplane_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalplasticstrain') - do j = 1_pInt, Nchunks_SlipFamilies - kinematics_slipplane_opening_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_ratesensitivity') - kinematics_slipplane_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalload') - do j = 1_pInt, Nchunks_SlipFamilies - kinematics_slipplane_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then - instance = kinematics_slipplane_opening_instance(phase) - kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested - kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance)) - kinematics_slipplane_opening_totalNslip(instance) = sum(kinematics_slipplane_opening_Nslip(:,instance)) - if (kinematics_slipplane_opening_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_slipplane_opening_LABEL//')') - if (any(kinematics_slipplane_opening_critPlasticStrain(:,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//KINEMATICS_slipplane_opening_LABEL//')') - if (kinematics_slipplane_opening_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_slipplane_opening_LABEL//')') - endif myPhase - enddo sanityChecks - - -end subroutine kinematics_slipplane_opening_init - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) - use prec, only: & - tol_math_check - use lattice, only: & - lattice_maxNslipFamily, & - lattice_NslipSystem, & - lattice_sd, & - lattice_st, & - lattice_sn - use material, only: & - phaseAt, phasememberAt, & - material_homog, & - damage, & - damageMapping - use math, only: & - math_Plain3333to99, & - math_I3, & - math_identity4th, & - math_symmetric33, & - math_Mandel33to6, & - math_tensorproduct33, & - math_det33, & - math_mul33x33 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola-Kirchhoff stress - real(pReal), intent(out), dimension(3,3) :: & - Ld !< damage velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) - real(pReal), dimension(3,3) :: & - projection_d, projection_t, projection_n !< projection modes 3x3 tensor - real(pReal), dimension(6) :: & - projection_d_v, projection_t_v, projection_n_v !< projection modes 3x3 vector - integer(pInt) :: & - phase, & - constituent, & - instance, & - homog, damageOffset, & - f, i, index_myFamily, k, l, m, n - real(pReal) :: & - traction_d, traction_t, traction_n, traction_crit, & - udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = kinematics_slipplane_opening_instance(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - Ld = 0.0_pReal - dLd_dTstar3333 = 0.0_pReal - do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,phase)) ! at which index starts my family - do i = 1_pInt,kinematics_slipplane_opening_Nslip(f,instance) ! process each (active) slip system in family - projection_d = math_tensorproduct33(lattice_sd(1:3,index_myFamily+i,phase),& - lattice_sn(1:3,index_myFamily+i,phase)) - projection_t = math_tensorproduct33(lattice_st(1:3,index_myFamily+i,phase),& - lattice_sn(1:3,index_myFamily+i,phase)) - projection_n = math_tensorproduct33(lattice_sn(1:3,index_myFamily+i,phase),& - lattice_sn(1:3,index_myFamily+i,phase)) - - projection_d_v(1:6) = math_Mandel33to6(math_symmetric33(projection_d(1:3,1:3))) - projection_t_v(1:6) = math_Mandel33to6(math_symmetric33(projection_t(1:3,1:3))) - projection_n_v(1:6) = math_Mandel33to6(math_symmetric33(projection_n(1:3,1:3))) - - traction_d = dot_product(Tstar_v,projection_d_v(1:6)) - traction_t = dot_product(Tstar_v,projection_t_v(1:6)) - traction_n = dot_product(Tstar_v,projection_n_v(1:6)) - - traction_crit = kinematics_slipplane_opening_critLoad(f,instance)* & - damage(homog)%p(damageOffset) ! degrading critical load carrying capacity by damage - - udotd = & - sign(1.0_pReal,traction_d)* & - kinematics_slipplane_opening_sdot_0(instance)* & - (abs(traction_d)/traction_crit - & - abs(traction_d)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) - if (abs(udotd) > tol_math_check) then - Ld = Ld + udotd*projection_d - dudotd_dt = udotd*kinematics_slipplane_opening_N(instance)/traction_d - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotd_dt*projection_d(k,l)*projection_d(m,n) - endif - - udott = & - sign(1.0_pReal,traction_t)* & - kinematics_slipplane_opening_sdot_0(instance)* & - (abs(traction_t)/traction_crit - & - abs(traction_t)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) - if (abs(udott) > tol_math_check) then - Ld = Ld + udott*projection_t - dudott_dt = udott*kinematics_slipplane_opening_N(instance)/traction_t - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudott_dt*projection_t(k,l)*projection_t(m,n) - endif - udotn = & - kinematics_slipplane_opening_sdot_0(instance)* & - (max(0.0_pReal,traction_n)/traction_crit - & - max(0.0_pReal,traction_n)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) - if (abs(udotn) > tol_math_check) then - Ld = Ld + udotn*projection_n - dudotn_dt = udotn*kinematics_slipplane_opening_N(instance)/traction_n - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotn_dt*projection_n(k,l)*projection_n(m,n) - endif - enddo - enddo - -end subroutine kinematics_slipplane_opening_LiAndItsTangent - -end module kinematics_slipplane_opening diff --git a/code/kinematics/kinematics_thermal_expansion.f90 b/code/kinematics/kinematics_thermal_expansion.f90 deleted file mode 100644 index b99c499f3..000000000 --- a/code/kinematics/kinematics_thermal_expansion.f90 +++ /dev/null @@ -1,228 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from thermal expansion -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_thermal_expansion - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_thermal_expansion_sizePostResults, & !< cumulative size of post results - kinematics_thermal_expansion_offset, & !< which kinematics is my current damage mechanism? - kinematics_thermal_expansion_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_thermal_expansion_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_thermal_expansion_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_thermal_expansion_Noutput !< number of outputs per instance of this damage - -! enum, bind(c) ! ToDo kinematics need state machinery to deal with sizePostResult -! enumerator :: undefined_ID, & ! possible remedy is to decouple having state vars from having output -! thermalexpansionrate_ID ! which means to separate user-defined types tState + tOutput... -! end enum - public :: & - kinematics_thermal_expansion_init, & - kinematics_thermal_expansion_initialStrain, & - kinematics_thermal_expansion_LiAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_thermal_expansion_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_thermal_expansion_label, & - KINEMATICS_thermal_expansion_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - character(len=65536) :: & - tag = '', & - output = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_thermal_expansion_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_thermal_expansion_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_thermal_expansion_offset(material_Nphase), source=0_pInt) - allocate(kinematics_thermal_expansion_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_thermal_expansion_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_thermal_expansion_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_thermal_expansion_ID) & - kinematics_thermal_expansion_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_thermal_expansion_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_thermal_expansion_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_thermal_expansion_output(maxval(phase_Noutput),maxNinstance)) - kinematics_thermal_expansion_output = '' - allocate(kinematics_thermal_expansion_Noutput(maxNinstance), source=0_pInt) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_thermal_expansion_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_thermal_expansion_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key... - select case(tag) -! case ('(output)') -! output = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) ! ...and corresponding output -! select case(output) -! case ('thermalexpansionrate') -! kinematics_thermal_expansion_Noutput(instance) = kinematics_thermal_expansion_Noutput(instance) + 1_pInt -! kinematics_thermal_expansion_outputID(kinematics_thermal_expansion_Noutput(instance),instance) = & -! thermalexpansionrate_ID -! kinematics_thermal_expansion_output(kinematics_thermal_expansion_Noutput(instance),instance) = output -! ToDo add sizePostResult loop afterwards... - - end select - endif; endif - enddo parsingFile - -end subroutine kinematics_thermal_expansion_init - -!-------------------------------------------------------------------------------------------------- -!> @brief report initial thermal strain based on current temperature deviation from reference -!-------------------------------------------------------------------------------------------------- -pure function kinematics_thermal_expansion_initialStrain(ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - temperature, & - thermalMapping - use lattice, only: & - lattice_thermalExpansion33, & - lattice_referenceTemperature - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - kinematics_thermal_expansion_initialStrain !< initial thermal strain (should be small strain, though) - integer(pInt) :: & - phase, & - homog, offset - - phase = material_phase(ipc,ip,el) - homog = material_homog(ip,el) - offset = thermalMapping(homog)%p(ip,el) - - kinematics_thermal_expansion_initialStrain = & - (temperature(homog)%p(offset) - lattice_referenceTemperature(phase)) * & - lattice_thermalExpansion33(1:3,1:3,phase) - -end function kinematics_thermal_expansion_initialStrain - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - temperature, & - temperatureRate, & - thermalMapping - use lattice, only: & - lattice_thermalExpansion33, & - lattice_referenceTemperature - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out), dimension(3,3) :: & - Li !< thermal velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor defined to be zero) - integer(pInt) :: & - phase, & - homog, offset - real(pReal) :: & - T, TRef, TDot - - phase = material_phase(ipc,ip,el) - homog = material_homog(ip,el) - offset = thermalMapping(homog)%p(ip,el) - T = temperature(homog)%p(offset) - TDot = temperatureRate(homog)%p(offset) - TRef = lattice_referenceTemperature(phase) - - Li = TDot* & - lattice_thermalExpansion33(1:3,1:3,phase)/ & - (1.0_pReal + lattice_thermalExpansion33(1:3,1:3,phase)*(T - TRef)) - dLi_dTstar3333 = 0.0_pReal - -end subroutine kinematics_thermal_expansion_LiAndItsTangent - -end module kinematics_thermal_expansion diff --git a/code/kinematics/kinematics_vacancy_strain.f90 b/code/kinematics/kinematics_vacancy_strain.f90 deleted file mode 100644 index 899bccd9f..000000000 --- a/code/kinematics/kinematics_vacancy_strain.f90 +++ /dev/null @@ -1,265 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from vacancy point defects -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_vacancy_strain - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_vacancy_strain_sizePostResults, & !< cumulative size of post results - kinematics_vacancy_strain_offset, & !< which kinematics is my current damage mechanism? - kinematics_vacancy_strain_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_vacancy_strain_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_vacancy_strain_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_vacancy_strain_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - kinematics_vacancy_strain_coeff - - public :: & - kinematics_vacancy_strain_init, & - kinematics_vacancy_strain_initialStrain, & - kinematics_vacancy_strain_LiAndItsTangent, & - kinematics_vacancy_strain_ChemPotAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_vacancy_strain_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_vacancy_strain_label, & - KINEMATICS_vacancy_strain_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_vacancy_strain_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_vacancy_strain_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_vacancy_strain_offset(material_Nphase), source=0_pInt) - allocate(kinematics_vacancy_strain_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_vacancy_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_vacancy_strain_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_vacancy_strain_ID) & - kinematics_vacancy_strain_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_vacancy_strain_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_vacancy_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_vacancy_strain_output(maxval(phase_Noutput),maxNinstance)) - kinematics_vacancy_strain_output = '' - allocate(kinematics_vacancy_strain_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_vacancy_strain_coeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_vacancy_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_vacancy_strain_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('vacancy_strain_coeff') - kinematics_vacancy_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - -end subroutine kinematics_vacancy_strain_init - -!-------------------------------------------------------------------------------------------------- -!> @brief report initial vacancy strain based on current vacancy conc deviation from equillibrium -!-------------------------------------------------------------------------------------------------- -pure function kinematics_vacancy_strain_initialStrain(ipc, ip, el) - use math, only: & - math_I3 - use material, only: & - material_phase, & - material_homog, & - vacancyConc, & - vacancyfluxMapping - use lattice, only: & - lattice_equilibriumVacancyConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - kinematics_vacancy_strain_initialStrain !< initial thermal strain (should be small strain, though) - integer(pInt) :: & - phase, & - homog, offset, instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_vacancy_strain_instance(phase) - homog = material_homog(ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - - kinematics_vacancy_strain_initialStrain = & - (vacancyConc(homog)%p(offset) - lattice_equilibriumVacancyConcentration(phase)) * & - kinematics_vacancy_strain_coeff(instance)* math_I3 - -end function kinematics_vacancy_strain_initialStrain - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_vacancy_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - vacancyConc, & - vacancyConcRate, & - vacancyfluxMapping - use math, only: & - math_I3 - use lattice, only: & - lattice_equilibriumVacancyConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out), dimension(3,3) :: & - Li !< thermal velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) - integer(pInt) :: & - phase, & - instance, & - homog, offset - real(pReal) :: & - Cv, CvEq, CvDot - - phase = material_phase(ipc,ip,el) - instance = kinematics_vacancy_strain_instance(phase) - homog = material_homog(ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - - Cv = vacancyConc(homog)%p(offset) - CvDot = vacancyConcRate(homog)%p(offset) - CvEq = lattice_equilibriumvacancyConcentration(phase) - - Li = CvDot*math_I3* & - kinematics_vacancy_strain_coeff(instance)/ & - (1.0_pReal + kinematics_vacancy_strain_coeff(instance)*(Cv - CvEq)) - - dLi_dTstar3333 = 0.0_pReal - -end subroutine kinematics_vacancy_strain_LiAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the kinematic contribution to vacancy chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_vacancy_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCv, Tstar_v, Fi0, Fi, ipc, ip, el) - use material, only: & - material_phase - use math, only: & - math_inv33, & - math_mul33x33, & - math_Mandel6to33, & - math_transpose33 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v - real(pReal), intent(in), dimension(3,3) :: & - Fi0, Fi - real(pReal), intent(out) :: & - ChemPot, dChemPot_dCv - integer(pInt) :: & - phase, & - instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_vacancy_strain_instance(phase) - - ChemPot = -kinematics_vacancy_strain_coeff(instance)* & - sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & - math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) - dChemPot_dCv = 0.0_pReal - -end subroutine kinematics_vacancy_strain_ChemPotAndItsTangent - -end module kinematics_vacancy_strain diff --git a/code/plastic/CMakeLists.txt b/code/plastic/CMakeLists.txt deleted file mode 100644 index e3fc430d3..000000000 --- a/code/plastic/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# group sources -set (PLASTIC "plastic_dislotwin" - "plastic_disloUCLA" - "plastic_isotropic" - "plastic_j2" - "plastic_phenopowerlaw" - "plastic_titanmod" - "plastic_nonlocal" - "plastic_none" - "plastic_phenoplus" - ) - -# compile module and cumulatively link the -# compiled libraries -add_library (DAMASK_PLASTIC "plastic_dislotwin.f90" - "plastic_disloUCLA.f90" - "plastic_isotropic.f90" - "plastic_j2.f90" - "plastic_phenopowerlaw.f90" - "plastic_titanmod.f90" - "plastic_nonlocal.f90" - "plastic_none.f90" - "plastic_phenoplus.f90") -target_link_libraries(DAMASK_PLASTIC DAMASK_DRIVERS) -# foreach (p ${PLASTIC}) -# add_library (${p} "${p}.f90") -# target_link_libraries(${p} DAMASK_DRIVERS) -# add_library (DAMASK_DRIVERS ALIAS ${p}) -# endforeach (p) \ No newline at end of file diff --git a/code/plastic/plastic_disloUCLA.f90 b/code/plastic/plastic_disloUCLA.f90 deleted file mode 100644 index d95a5e6a4..000000000 --- a/code/plastic/plastic_disloUCLA.f90 +++ /dev/null @@ -1,2116 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author David Cereceda, Lawrence Livermore National Laboratory -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incoprorating dislocation and twinning physics -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module plastic_disloUCLA - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_disloUCLA_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_disloUCLA_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_disloUCLA_output !< name of each post result output - - real(pReal), parameter, private :: & - kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_disloUCLA_Noutput !< number of outputs per instance of this plasticity - - integer(pInt), dimension(:), allocatable, private :: & - plastic_disloUCLA_totalNslip, & !< total number of active slip systems for each instance - plastic_disloUCLA_totalNtwin !< total number of active twin systems for each instance - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_disloUCLA_Nslip, & !< number of active slip systems for each family and instance - plastic_disloUCLA_Ntwin !< number of active twin systems for each family and instance - - real(pReal), dimension(:), allocatable, private :: & - plastic_disloUCLA_CAtomicVolume, & !< atomic volume in Bugers vector unit - plastic_disloUCLA_D0, & !< prefactor for self-diffusion coefficient - plastic_disloUCLA_Qsd, & !< activation energy for dislocation climb - plastic_disloUCLA_GrainSize, & !< grain size - plastic_disloUCLA_MaxTwinFraction, & !< maximum allowed total twin volume fraction - plastic_disloUCLA_CEdgeDipMinDistance, & !< - plastic_disloUCLA_Cmfptwin, & !< - plastic_disloUCLA_Cthresholdtwin, & !< - plastic_disloUCLA_SolidSolutionStrength, & !< Strength due to elements in solid solution - plastic_disloUCLA_L0, & !< Length of twin nuclei in Burgers vectors - plastic_disloUCLA_xc, & !< critical distance for formation of twin nucleus - plastic_disloUCLA_VcrossSlip, & !< cross slip volume - plastic_disloUCLA_SFE_0K, & !< stacking fault energy at zero K - plastic_disloUCLA_dSFE_dT, & !< temperature dependance of stacking fault energy - plastic_disloUCLA_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful - plastic_disloUCLA_aTolRho, & !< absolute tolerance for integration of dislocation density - plastic_disloUCLA_aTolTwinFrac !< absolute tolerance for integration of twin volume fraction - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_disloUCLA_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_disloUCLA_Ctwin3333 !< twin elasticity matrix for each instance - real(pReal), dimension(:,:), allocatable, private :: & - plastic_disloUCLA_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance - plastic_disloUCLA_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance - plastic_disloUCLA_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance - plastic_disloUCLA_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance - plastic_disloUCLA_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance - plastic_disloUCLA_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance - plastic_disloUCLA_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance - plastic_disloUCLA_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance - plastic_disloUCLA_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance - plastic_disloUCLA_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance - plastic_disloUCLA_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance - plastic_disloUCLA_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance - plastic_disloUCLA_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance - plastic_disloUCLA_tau_r, & !< stress to bring partial close together for each twin system and instance - plastic_disloUCLA_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance - plastic_disloUCLA_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance - plastic_disloUCLA_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_disloUCLA_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_disloUCLA_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance - plastic_disloUCLA_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance - plastic_disloUCLA_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_disloUCLA_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance - plastic_disloUCLA_pPerSlipFamily, & !< p-exponent in glide velocity - plastic_disloUCLA_qPerSlipFamily, & !< q-exponent in glide velocity - !* mobility law parameters - plastic_disloUCLA_kinkheight, & !< height of the kink pair - plastic_disloUCLA_omega, & !< attempt frequency for kink pair nucleation - plastic_disloUCLA_kinkwidth, & !< width of the kink pair - plastic_disloUCLA_dislolength, & !< dislocation length (lamda) - plastic_disloUCLA_friction, & !< friction coeff. B (kMC) - !* - plastic_disloUCLA_rPerTwinFamily, & !< r-exponent in twin nucleation rate - plastic_disloUCLA_nonSchmidCoeff !< non-Schmid coefficients (bcc) - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_disloUCLA_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance - plastic_disloUCLA_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance - plastic_disloUCLA_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance - plastic_disloUCLA_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance - plastic_disloUCLA_forestProjectionEdge !< matrix of forest projections of edge dislocations for each instance - - enum, bind(c) - enumerator :: undefined_ID, & - edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID, & - twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_disloUCLA_outputID !< ID of each post result output - - type, private :: tDisloUCLAState - real(pReal), pointer, dimension(:,:) :: & - rhoEdge, & - rhoEdgeDip, & - accshear_slip, & - twinFraction, & - accshear_twin, & - invLambdaSlip, & - invLambdaSlipTwin, & - invLambdaTwin, & - mfp_slip, & - mfp_twin, & - threshold_stress_slip, & - threshold_stress_twin, & - twinVolume - end type - type(tDisloUCLAState ), allocatable, dimension(:), private :: & - state, & - state0, & - dotState - - public :: & - plastic_disloUCLA_init, & - plastic_disloUCLA_homogenizedC, & - plastic_disloUCLA_microstructure, & - plastic_disloUCLA_LpAndItsTangent, & - plastic_disloUCLA_dotState, & - plastic_disloUCLA_postResults - private :: & - plastic_disloUCLA_stateInit, & - plastic_disloUCLA_aTolState - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333, & - math_mul3x3 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_DISLOUCLA_label, & - PLASTICITY_DISLOUCLA_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,& - f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & - offset_slip, index_myFamily, index_otherFamily, & - startIndex, endIndex - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOUCLA_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOUCLA_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_disloUCLA_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(plastic_disloUCLA_output(maxval(phase_Noutput),maxNinstance)) - plastic_disloUCLA_output = '' - allocate(plastic_disloUCLA_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_disloUCLA_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_CAtomicVolume(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_D0(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Qsd(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_GrainSize(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_MaxTwinFraction(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Cmfptwin(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Cthresholdtwin(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_SolidSolutionStrength(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_L0(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_xc(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_VcrossSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_aTolRho(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_aTolTwinFrac(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_SFE_0K(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_dSFE_dT(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default - allocate(plastic_disloUCLA_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_kinkheight(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_omega(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_kinkwidth(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_dislolength(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_friction(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_disloUCLA_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_disloUCLA_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), source=0.0_pReal) - - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - if(allocated(tempPerTwin)) deallocate(tempPerTwin) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - allocate(tempPerTwin(Nchunks_TwinFamilies)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('edge_density') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_density_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('dipole_density') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = dipole_density_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_slip','shearrate_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('edge_dipole_distance') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_dipole_distance_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stress_exponent') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = stress_exponent_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('twin_fraction') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = twin_fraction_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_twin','shearrate_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip system families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - plastic_disloUCLA_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip',& - 'kink_height','omega','kink_width','dislolength','friction_coeff') - do j = 1_pInt, Nchunks_SlipFamilies - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('rhoedge0') - plastic_disloUCLA_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('rhoedgedip0') - plastic_disloUCLA_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('slipburgers') - plastic_disloUCLA_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('qedge') - plastic_disloUCLA_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('v0') - plastic_disloUCLA_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('clambdaslip') - plastic_disloUCLA_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau_peierls') - if (lattice_structure(phase) /= LATTICE_bcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOUCLA_label//')') - plastic_disloUCLA_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('p_slip') - plastic_disloUCLA_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('q_slip') - plastic_disloUCLA_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('kink_height') - plastic_disloUCLA_kinkheight(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('omega') - plastic_disloUCLA_omega(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('kink_width') - plastic_disloUCLA_kinkwidth(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('dislolength') - plastic_disloUCLA_dislolength(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('friction_coeff') - plastic_disloUCLA_friction(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on slip number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_disloUCLA_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ndot0','twinsize','twinburgers','r_twin') - do j = 1_pInt, Nchunks_TwinFamilies - tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('ndot0') - if (lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOUCLA_label//')') - plastic_disloUCLA_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinsize') - plastic_disloUCLA_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinburgers') - plastic_disloUCLA_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('r_twin') - plastic_disloUCLA_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip','interactionslipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_disloUCLA_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin','interactionsliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_disloUCLA_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip','interactiontwinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_disloUCLA_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin','interactiontwintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_disloUCLA_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt,Nchunks_nonSchmid - plastic_disloUCLA_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin systems - case ('grainsize') - plastic_disloUCLA_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('maxtwinfraction') - plastic_disloUCLA_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('d0') - plastic_disloUCLA_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('qsd') - plastic_disloUCLA_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_rho') - plastic_disloUCLA_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_disloUCLA_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cmfptwin') - plastic_disloUCLA_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cthresholdtwin') - plastic_disloUCLA_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('solidsolutionstrength') - plastic_disloUCLA_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('l0') - plastic_disloUCLA_L0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('xc') - plastic_disloUCLA_xc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('vcrossslip') - plastic_disloUCLA_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cedgedipmindistance') - plastic_disloUCLA_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('catomicvolume') - plastic_disloUCLA_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('sfe_0k') - plastic_disloUCLA_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dsfe_dt') - plastic_disloUCLA_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dipoleformationfactor') - plastic_disloUCLA_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then - instance = phase_plasticityInstance(phase) - if (sum(plastic_disloUCLA_Nslip(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOUCLA_label//')') - if (sum(plastic_disloUCLA_Ntwin(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOUCLA_label//')') - do f = 1_pInt,lattice_maxNslipFamily - if (plastic_disloUCLA_Nslip(f,instance) > 0_pInt) then - if (plastic_disloUCLA_rhoEdge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_rhoEdgeDip0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_v0PerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOUCLA_label//')') - endif - enddo - do f = 1_pInt,lattice_maxNtwinFamily - if (plastic_disloUCLA_Ntwin(f,instance) > 0_pInt) then - if (plastic_disloUCLA_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='ndot0 ('//PLASTICITY_DISLOUCLA_label//')') - endif - enddo - if (plastic_disloUCLA_CAtomicVolume(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_D0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_Qsd(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOUCLA_label//')') - if (sum(plastic_disloUCLA_Ntwin(:,instance)) > 0_pInt) then - if (abs(plastic_disloUCLA_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & - abs(plastic_disloUCLA_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & - lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_aTolTwinFrac(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOUCLA_label//')') - endif - if (abs(plastic_disloUCLA_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & - plastic_disloUCLA_dipoleFormationFactor(instance) /= 1.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOUCLA_label//')') - -!-------------------------------------------------------------------------------------------------- -! Determine total number of active slip or twin systems - plastic_disloUCLA_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_disloUCLA_Nslip(:,instance)) - plastic_disloUCLA_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_disloUCLA_Ntwin(:,instance)) - plastic_disloUCLA_totalNslip(instance) = sum(plastic_disloUCLA_Nslip(:,instance)) - plastic_disloUCLA_totalNtwin(instance) = sum(plastic_disloUCLA_Ntwin(:,instance)) - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - maxTotalNslip = maxval(plastic_disloUCLA_totalNslip) - maxTotalNtwin = maxval(plastic_disloUCLA_totalNtwin) - - allocate(plastic_disloUCLA_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_tau_r(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) - - allocate(plastic_disloUCLA_interactionMatrix_SlipSlip(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from slip activity - maxval(plastic_disloUCLA_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_interactionMatrix_SlipTwin(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from twin activity - maxval(plastic_disloUCLA_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_interactionMatrix_TwinSlip(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_disloUCLA_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_interactionMatrix_TwinTwin(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_disloUCLA_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & - source=0.0_pReal) - allocate(plastic_disloUCLA_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) - - allocate(state(maxNinstance)) - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - myPhase2: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then - NofMyPhase=count(material_phase==phase) - instance = phase_plasticityInstance(phase) - - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputs: do o = 1_pInt,plastic_disloUCLA_Noutput(instance) - select case(plastic_disloUCLA_outputID(o,instance)) - case(edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID & - ) - mySize = ns - case(twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID & - ) - mySize = nt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - plastic_disloUCLA_sizePostResult(o,instance) = mySize - plastic_disloUCLA_sizePostResults(instance) = plastic_disloUCLA_sizePostResults(instance) + mySize - endif - enddo outputs - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - - sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & - + int(size(['twinFraction','accsheartwin']),pInt) * nt - sizeDeltaState = 0_pInt - sizeState = sizeDotState & - + int(size(['invLambdaSlip ','invLambdaSlipTwin ',& - 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & - + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& - 'twinVolume ']),pInt) * nt - - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_disloUCLA_sizePostResults(instance) - plasticState(phase)%nSlip = plastic_disloucla_totalNslip(instance) - plasticState(phase)%nTwin = plastic_disloucla_totalNtwin(instance) - plasticState(phase)%nTrans= 0_pInt - allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - offset_slip = 2_pInt*plasticState(phase)%nSlip - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) - !* Process slip related parameters ------------------------------------------------ - - mySlipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - mySlipSystems: do j = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - - !* Burgers vector, - ! dislocation velocity prefactor, - ! mean free path prefactor, - ! and minimum dipole distance - - plastic_disloUCLA_burgersPerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_burgersPerSlipFamily(f,instance) - - plastic_disloUCLA_QedgePerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_QedgePerSlipFamily(f,instance) - - plastic_disloUCLA_v0PerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_v0PerSlipFamily(f,instance) - - plastic_disloUCLA_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_CLambdaSlipPerSlipFamily(f,instance) - - !* Calculation of forest projections for edge dislocations - !* Interaction matrices - - otherSlipFamilies: do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) - otherSlipSystems: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) - plastic_disloUCLA_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & - abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & - lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) - plastic_disloUCLA_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo otherSlipSystems; enddo otherSlipFamilies - - otherTwinFamilies: do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) - otherTwinSystems: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) - plastic_disloUCLA_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo otherTwinSystems; enddo otherTwinFamilies - - enddo mySlipSystems - enddo mySlipFamilies - - !* Process twin related parameters ------------------------------------------------ - - myTwinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(plastic_disloUCLA_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list - myTwinSystems: do j = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) - - !* Burgers vector, - ! nucleation rate prefactor, - ! and twin size - - plastic_disloUCLA_burgersPerTwinSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_burgersPerTwinFamily(f,instance) - - plastic_disloUCLA_Ndot0PerTwinSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) - - plastic_disloUCLA_twinsizePerTwinSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_twinsizePerTwinFamily(f,instance) - - !* Rotate twin elasticity matrices - index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list - do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt - do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt - plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & - plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & - lattice_C3333(p,q,r,s,instance) * & - lattice_Qtwin(l,p,index_otherFamily+j,phase) * & - lattice_Qtwin(m,q,index_otherFamily+j,phase) * & - lattice_Qtwin(n,r,index_otherFamily+j,phase) * & - lattice_Qtwin(o,s,index_otherFamily+j,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo; enddo - plastic_disloUCLA_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & - math_Mandel3333to66(plastic_disloUCLA_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) - - !* Interaction matrices - otherSlipFamilies2: do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) - otherSlipSystems2: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) - plastic_disloUCLA_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo otherSlipSystems2; enddo otherSlipFamilies2 - - otherTwinFamilies2: do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) - otherTwinSystems2: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) - plastic_disloUCLA_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo otherTwinSystems2; enddo otherTwinFamilies2 - - enddo myTwinSystems - enddo myTwinFamilies - - startIndex=1_pInt - endIndex=ns - state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+ns - state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+ns - state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+nt - state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+nt - state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+ns - state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) - - call plastic_disloUCLA_stateInit(phase,instance) - call plastic_disloUCLA_aTolState(phase,instance) - endif myPhase2 - - enddo initializeInstances - -end subroutine plastic_disloUCLA_init - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_stateInit(ph,instance) - use math, only: & - pi - use lattice, only: & - lattice_maxNslipFamily, & - lattice_mu - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - real(pReal), dimension(plasticState(ph)%sizeState) :: tempState - - integer(pInt) :: i,j,f,ns,nt, index_myFamily - real(pReal), dimension(plastic_disloUCLA_totalNslip(instance)) :: & - rhoEdge0, & - rhoEdgeDip0, & - invLambdaSlip0, & - MeanFreePathSlip0, & - tauSlipThreshold0 - real(pReal), dimension(plastic_disloUCLA_totalNtwin(instance)) :: & - MeanFreePathTwin0,TwinVolume0 - tempState = 0.0_pReal - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables - do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - rhoEdge0(index_myFamily+1_pInt: & - index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & - plastic_disloUCLA_rhoEdge0(f,instance) - rhoEdgeDip0(index_myFamily+1_pInt: & - index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & - plastic_disloUCLA_rhoEdgeDip0(f,instance) - enddo - - tempState(1_pInt:ns) = rhoEdge0 - tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent slip microstructural variables - forall (i = 1_pInt:ns) & - invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_forestProjectionEdge(1:ns,i,instance)))/ & - plastic_disloUCLA_CLambdaSlipPerSlipSystem(i,instance) - tempState(3_pInt*ns+2_pInt*nt+1:4_pInt*ns+2_pInt*nt) = invLambdaSlip0 - - forall (i = 1_pInt:ns) & - MeanFreePathSlip0(i) = & - plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_disloUCLA_GrainSize(instance)) - tempState(5_pInt*ns+3_pInt*nt+1:6_pInt*ns+3_pInt*nt) = MeanFreePathSlip0 - - forall (i = 1_pInt:ns) & - tauSlipThreshold0(i) = & - lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(i,instance) * & - sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_interactionMatrix_SlipSlip(i,1:ns,instance))) - - tempState(6_pInt*ns+4_pInt*nt+1:7_pInt*ns+4_pInt*nt) = tauSlipThreshold0 - - - -!-------------------------------------------------------------------------------------------------- -! initialize dependent twin microstructural variables - forall (j = 1_pInt:nt) & - MeanFreePathTwin0(j) = plastic_disloUCLA_GrainSize(instance) - tempState(6_pInt*ns+3_pInt*nt+1_pInt:6_pInt*ns+4_pInt*nt) = MeanFreePathTwin0 - - forall (j = 1_pInt:nt) & - TwinVolume0(j) = & - (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) - tempState(7_pInt*ns+5_pInt*nt+1_pInt:7_pInt*ns+6_pInt*nt) = TwinVolume0 - -plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) - -end subroutine plastic_disloUCLA_stateInit - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - ph, & - instance ! number specifying the current instance of the plasticity - - ! Tolerance state for dislocation densities - plasticState(ph)%aTolState(1_pInt:2_pInt*plastic_disloUCLA_totalNslip(instance)) = & - plastic_disloUCLA_aTolRho(instance) - - ! Tolerance state for accumulated shear due to slip - plasticState(ph)%aTolState(2_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & - 3_pInt*plastic_disloUCLA_totalNslip(instance))=1e6_pReal - - - ! Tolerance state for twin volume fraction - plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & - 3_pInt*plastic_disloUCLA_totalNslip(instance)+& - plastic_disloUCLA_totalNtwin(instance)) = & - plastic_disloUCLA_aTolTwinFrac(instance) - -! Tolerance state for accumulated shear due to twin - plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+ & - plastic_disloUCLA_totalNtwin(instance)+1_pInt: & - 3_pInt*plastic_disloUCLA_totalNslip(instance)+ & - 2_pInt*plastic_disloUCLA_totalNtwin(instance)) = 1e6_pReal - -end subroutine plastic_disloUCLA_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenized elasticity matrix -!-------------------------------------------------------------------------------------------------- -function plastic_disloUCLA_homogenizedC(ipc,ip,el) - use material, only: & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_C66 - - implicit none - real(pReal), dimension(6,6) :: & - plastic_disloUCLA_homogenizedC - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,i, & - ph, & - of - real(pReal) :: sumf - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - !* Homogenized elasticity matrix - plastic_disloUCLA_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) - do i=1_pInt,nt - plastic_disloUCLA_homogenizedC = plastic_disloUCLA_homogenizedC & - + state(instance)%twinFraction(i,of)*plastic_disloUCLA_Ctwin66(1:6,1:6,i,instance) - enddo - -end function plastic_disloUCLA_homogenizedC - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_microstructure(temperature,ipc,ip,el) - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - phaseAt, phasememberAt - use lattice, only: & - lattice_mu, & - lattice_nu - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - temperature !< temperature at IP - - integer(pInt) :: & - instance, & - ns,nt,s,t, & - ph, & - of - real(pReal) :: & - sumf,sfe,x0 - real(pReal), dimension(plastic_disloUCLA_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Stacking fault energy - sfe = plastic_disloUCLA_SFE_0K(instance) + & - plastic_disloUCLA_dSFE_dT(instance) * Temperature - - !* rescaled twin volume fraction for topology - forall (t = 1_pInt:nt) & - fOverStacksize(t) = & - state(instance)%twinFraction(t,of)/plastic_disloUCLA_twinsizePerTwinSystem(t,instance) - - !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation - forall (s = 1_pInt:ns) & - state(instance)%invLambdaSlip(s,of) = & - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_disloUCLA_forestProjectionEdge(1:ns,s,instance)))/ & - plastic_disloUCLA_CLambdaSlipPerSlipSystem(s,instance) - !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation - !$OMP CRITICAL (evilmatmul) - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal - if (nt > 0_pInt .and. ns > 0_pInt) & - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & - matmul(plastic_disloUCLA_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin - !$OMP CRITICAL (evilmatmul) - if (nt > 0_pInt) & - state(instance)%invLambdaTwin(1_pInt:nt,of) = & - matmul(plastic_disloUCLA_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* mean free path between 2 obstacles seen by a moving dislocation - do s = 1_pInt,ns - if (nt > 0_pInt) then - state(instance)%mfp_slip(s,of) = & - plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+plastic_disloUCLA_GrainSize(instance)*& - (state(instance)%invLambdaSlip(s,of)+state(instance)%invLambdaSlipTwin(s,of))) - else - state(instance)%mfp_slip(s,of) = & - plastic_disloUCLA_GrainSize(instance)/& - (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) - endif - enddo - - !* mean free path between 2 obstacles seen by a growing twin - forall (t = 1_pInt:nt) & - state(instance)%mfp_twin(t,of) = & - (plastic_disloUCLA_Cmfptwin(instance)*plastic_disloUCLA_GrainSize(instance))/& - (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*state(instance)%invLambdaTwin(t,of)) - - !* threshold stress for dislocation motion - forall (s = 1_pInt:ns) & - state(instance)%threshold_stress_slip(s,of) = & - lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(s,instance)*& - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_disloUCLA_interactionMatrix_SlipSlip(s,1:ns,instance))) - - !* threshold stress for growing twin - forall (t = 1_pInt:nt) & - state(instance)%threshold_stress_twin(t,of) = & - plastic_disloUCLA_Cthresholdtwin(instance)*& - (sfe/(3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance))+& - 3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& - (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(t,instance))) - - !* final twin volume after growth - forall (t = 1_pInt:nt) & - state(instance)%twinVolume(t,of) = & - (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(t,instance)*state(instance)%mfp_twin(t,of)**(2.0_pReal) - - !* equilibrium seperation of partial dislocations - do t = 1_pInt,nt - x0 = lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& - (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) - plastic_disloUCLA_tau_r(t,instance)= & - lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& - (1/(x0+plastic_disloUCLA_xc(instance))+cos(pi/3.0_pReal)/x0) !!! used where?? - enddo - -end subroutine plastic_disloUCLA_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - math_Plain3333to99, & - math_Mandel6to33, & - math_Mandel33to6, & - math_spectralDecompositionSym33, & - math_symmetric33, & - math_mul33x3 - use material, only: & - material_phase, & - phase_plasticityInstance, & - !plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily,& - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid, & - lattice_shearTwin, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - integer(pInt), intent(in) :: ipc,ip,el - real(pReal), intent(in) :: Temperature - real(pReal), dimension(6), intent(in) :: Tstar_v - real(pReal), dimension(3,3), intent(out) :: Lp - real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 - - integer(pInt) :: instance,ph,of,ns,nt,f,i,j,k,l,m,n,index_myFamily,s1,s2 - real(pReal) :: sumf,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0, & - tau_slip_pos,tau_slip_neg,vel_slip,dvel_slip,& - dgdot_dtauslip_pos,dgdot_dtauslip_neg,dgdot_dtautwin,tau_twin,gdot_twin,stressRatio - real(pReal), dimension(3,3,2) :: & - nonSchmid_tensor - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar3333 - real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip_pos,gdot_slip_neg - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Dislocation glide part - gdot_slip_pos = 0.0_pReal - gdot_slip_neg = 0.0_pReal - dgdot_dtauslip_pos = 0.0_pReal - dgdot_dtauslip_neg = 0.0_pReal - - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j+1_pInt - !* Boltzmann ratio - BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& - plastic_disloUCLA_v0PerSlipSystem(j,instance) - !* Resolved shear stress on slip system - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k, index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) - enddo nonSchmidSystems - - significantPostitiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratio - stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_pos & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_pos(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_pos) - - !* Derivatives of shear rates - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_pos & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_pos & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - dgdot_dtauslip_pos = DotGamma0 * dvel_slip - - endif significantPostitiveStress - significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratio - stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_neg & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_neg(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_neg) - - !* Derivatives of shear rates - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_neg & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_neg & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - - dgdot_dtauslip_neg = DotGamma0 * dvel_slip - - endif significantNegativeStress - !* Plastic velocity gradient for dislocation glide - Lp = Lp + (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + (dgdot_dtauslip_pos*nonSchmid_tensor(m,n,1)+& - dgdot_dtauslip_neg*nonSchmid_tensor(m,n,2))*0.5_pReal*& - lattice_Sslip(k,l,1,index_myFamily+i,ph) - enddo slipSystems - enddo slipFamilies - -!-------------------------------------------------------------------------------------------------- -! correct Lp and dLp_dTstar3333 for twinned fraction - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - Lp = Lp * (1.0_pReal - sumf) - dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf) - -!-------------------------------------------------------------------------------------------------- -! Mechanical twinning part - gdot_twin = 0.0_pReal - dgdot_dtautwin = 0.0_pReal - j = 0_pInt - twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) - j = j+1_pInt - !* Resolved shear stress on twin system - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_twin > tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then - Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive gdot_slip_pos (= gdot_slip_neg) - abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) - else - Ndot0=0.0_pReal - end if - case default - Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) - end select - gdot_twin = & - (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) - dgdot_dtautwin = ((gdot_twin*plastic_disloUCLA_rPerTwinFamily(f,instance))/tau_twin)*StressRatio_r - endif - - !* Plastic velocity gradient for mechanical twinning - Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin*& - lattice_Stwin(k,l,index_myFamily+i,ph)*& - lattice_Stwin(m,n,index_myFamily+i,ph) - enddo twinSystems - enddo twinFamilies - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - -end subroutine plastic_disloUCLA_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_dotState(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid, & - lattice_sheartwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,f,i,j,k,index_myFamily,s1,s2, & - ph, & - of - real(pReal) :: & - sumf, & - stressRatio_p,& - BoltzmannRatio,& - DotGamma0,& - stressRatio, & - EdgeDipMinDistance,& - AtomicVolume,& - VacancyDiffusion,& - StressRatio_r,& - Ndot0,& - tau_slip_pos,& - tau_slip_neg,& - DotRhoMultiplication,& - EdgeDipDistance, & - DotRhoEdgeDipAnnihilation, & - DotRhoEdgeEdgeAnnihilation, & - ClimbVelocity, & - DotRhoEdgeDipClimb, & - DotRhoDipFormation, & - tau_twin, & - vel_slip, & - gdot_slip - real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip_pos, gdot_slip_neg - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - plasticState(ph)%dotState(:,of) = 0.0_pReal - - !* Dislocation density evolution - gdot_slip_pos = 0.0_pReal - gdot_slip_neg = 0.0_pReal - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j+1_pInt - !* Boltzmann ratio - BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& - plastic_disloUCLA_v0PerSlipSystem(j,instance) - !* Resolved shear stress on slip system - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - - significantPositiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_pos & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_pos(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_pos) - endif significantPositiveStress - significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_neg & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_neg(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_neg) - endif significantNegativeStress - gdot_slip = (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal - !* Multiplication - DotRhoMultiplication = abs(gdot_slip)/& - (plastic_disloUCLA_burgersPerSlipSystem(j,instance)* & - state(instance)%mfp_slip(j,of)) - - !* Dipole formation - EdgeDipMinDistance = & - plastic_disloUCLA_CEdgeDipMinDistance(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance) - if (abs(tau_slip_pos) <= tiny(0.0_pReal)) then - DotRhoDipFormation = 0.0_pReal - else - EdgeDipDistance = & - (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(tau_slip_pos)) - if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) - if (EdgeDipDistance tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then - Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) - abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) - else - Ndot0=0.0_pReal - end if - case default - Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) - end select - - dotState(instance)%twinFraction(j, of) = & - (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*& - state(instance)%twinVolume(j, of)*Ndot0*exp(-StressRatio_r) - !* Dotstate for accumulated shear due to twin - dotState(instance)%accshear_twin(j,of) = dotState(ph)%twinFraction(j,of) * & - lattice_sheartwin(index_myfamily+i,ph) - endif - enddo twinSystems - enddo twinFamilies - -end subroutine plastic_disloUCLA_dotState - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_disloUCLA_postResults(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance,& - !plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid, & - lattice_shearTwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(plastic_disloUCLA_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_disloUCLA_postResults - - integer(pInt) :: & - instance,& - ns,nt,& - f,o,i,c,j,k,index_myFamily,& - s1,s2, & - ph, & - of - real(pReal) :: sumf,tau_twin,StressRatio_p,StressRatio_pminus1,& - BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0,stressRatio - real(pReal) :: dvel_slip, vel_slip - real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip_pos,dgdot_dtauslip_pos,tau_slip_pos,gdot_slip_neg,dgdot_dtauslip_neg,tau_slip_neg - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(ph)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Required output - c = 0_pInt - plastic_disloUCLA_postResults = 0.0_pReal - - do o = 1_pInt,plastic_disloUCLA_Noutput(instance) - select case(plastic_disloUCLA_outputID(o,instance)) - - case (edge_density_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) - c = c + ns - case (dipole_density_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) - c = c + ns - case (shear_rate_slip_ID,shear_rate_twin_ID,stress_exponent_ID) - gdot_slip_pos = 0.0_pReal - gdot_slip_neg = 0.0_pReal - dgdot_dtauslip_pos = 0.0_pReal - dgdot_dtauslip_neg = 0.0_pReal - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j + 1_pInt - !* Boltzmann ratio - BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& - plastic_disloUCLA_v0PerSlipSystem(j,instance) - !* Resolved shear stress on slip system - tau_slip_pos(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - tau_slip_neg(j) = tau_slip_pos(j) - - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - - significantPositiveTau: if((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then - !* Stress ratio - stressRatio = ((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_pos(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_pos(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_pos(j)) - !* Derivatives of shear rates - - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_pos(j) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_pos(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - - dgdot_dtauslip_pos(j) = DotGamma0 * dvel_slip - - endif significantPositiveTau - significantNegativeTau: if((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_neg(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_neg(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_neg(j)) - !* Derivatives of shear rates - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_neg(j) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_neg(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - - - dgdot_dtauslip_neg(j) = DotGamma0 * dvel_slip - - endif significantNegativeTau - enddo slipSystems - enddo slipFamilies - - if (plastic_disloUCLA_outputID(o,instance) == shear_rate_slip_ID) then - plastic_disloUCLA_postResults(c+1:c+ns) = (gdot_slip_pos + gdot_slip_neg)*0.5_pReal - c = c + ns - elseif (plastic_disloUCLA_outputID(o,instance) == shear_rate_twin_ID) then - if (nt > 0_pInt) then - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1,plastic_disloUCLA_Ntwin(f,instance) - j = j + 1_pInt - - !* Resolved shear stress on twin system - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - !* Stress ratios - StressRatio_r = (state(instance)%threshold_stress_twin(j, of)/ & - tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) - - !* Shear rates due to twin - if ( tau_twin > 0.0_pReal ) then - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then - Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) - abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_disloUCLA_L0(instance)*& - plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) - else - Ndot0=0.0_pReal - end if - - case default - Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) - end select - plastic_disloUCLA_postResults(c+j) = & - (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) - endif - enddo twinSystems1 - enddo twinFamilies1 - endif - c = c + nt - elseif(plastic_disloUCLA_outputID(o,instance) == stress_exponent_ID) then - do j = 1_pInt, ns - if (abs(gdot_slip_pos(j)+gdot_slip_neg(j))<=tiny(0.0_pReal)) then - plastic_disloUCLA_postResults(c+j) = 0.0_pReal - else - plastic_disloUCLA_postResults(c+j) = (tau_slip_pos(j)+tau_slip_neg(j))/& - (gdot_slip_pos(j)+gdot_slip_neg(j))*& - (dgdot_dtauslip_pos(j)+dgdot_dtauslip_neg(j))* 0.5_pReal - endif - enddo - c = c + ns - endif - - case (accumulated_shear_slip_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & - state(instance)%accshear_slip(1_pInt:ns, of) - c = c + ns - case (mfp_slip_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) =& - state(instance)%mfp_slip(1_pInt:ns, of) - c = c + ns - case (resolved_stress_slip_ID) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j + 1_pInt - plastic_disloUCLA_postResults(c+j) =& - dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - enddo slipSystems1; enddo slipFamilies1 - c = c + ns - case (threshold_stress_slip_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & - state(instance)%threshold_stress_slip(1_pInt:ns,of) - c = c + ns - case (edge_dipole_distance_ID) - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems2: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j + 1_pInt - plastic_disloUCLA_postResults(c+j) = & - (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) - plastic_disloUCLA_postResults(c+j)=min(plastic_disloUCLA_postResults(c+j),& - state(instance)%mfp_slip(j,of)) - enddo slipSystems2; enddo slipFamilies2 - c = c + ns - case (twin_fraction_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt, of) - c = c + nt - - case (accumulated_shear_twin_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt, of) - c = c + nt - - case (mfp_twin_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt, of) - c = c + nt - - case (resolved_stress_twin_ID) - if (nt > 0_pInt) then - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) - j = j + 1_pInt - plastic_disloUCLA_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - enddo twinSystems2; enddo twinFamilies2 - endif - c = c + nt - case (threshold_stress_twin_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt, of) - c = c + nt - end select - enddo -end function plastic_disloUCLA_postResults - -end module plastic_disloUCLA diff --git a/code/plastic/plastic_dislotwin.f90 b/code/plastic/plastic_dislotwin.f90 deleted file mode 100644 index 532312bfd..000000000 --- a/code/plastic/plastic_dislotwin.f90 +++ /dev/null @@ -1,2542 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incoprorating dislocation and twinning physics -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module plastic_dislotwin - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_dislotwin_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_dislotwin_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_dislotwin_output !< name of each post result output - - real(pReal), parameter, private :: & - kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_dislotwin_Noutput !< number of outputs per instance of this plasticity - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_dislotwin_totalNslip, & !< total number of active slip systems for each instance - plastic_dislotwin_totalNtwin, & !< total number of active twin systems for each instance - plastic_dislotwin_totalNtrans !< number of active transformation systems - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_dislotwin_Nslip, & !< number of active slip systems for each family and instance - plastic_dislotwin_Ntwin, & !< number of active twin systems for each family and instance - plastic_dislotwin_Ntrans !< number of active transformation systems for each family and instance - - real(pReal), dimension(:), allocatable, private :: & - plastic_dislotwin_CAtomicVolume, & !< atomic volume in Bugers vector unit - plastic_dislotwin_D0, & !< prefactor for self-diffusion coefficient - plastic_dislotwin_Qsd, & !< activation energy for dislocation climb - plastic_dislotwin_GrainSize, & !< grain size - plastic_dislotwin_pShearBand, & !< p-exponent in shearband velocity - plastic_dislotwin_qShearBand, & !< q-exponent in shearband velocity - plastic_dislotwin_MaxTwinFraction, & !< maximum allowed total twin volume fraction - plastic_dislotwin_CEdgeDipMinDistance, & !< - plastic_dislotwin_Cmfptwin, & !< - plastic_dislotwin_Cthresholdtwin, & !< - plastic_dislotwin_SolidSolutionStrength, & !< Strength due to elements in solid solution - plastic_dislotwin_L0_twin, & !< Length of twin nuclei in Burgers vectors - plastic_dislotwin_L0_trans, & !< Length of trans nuclei in Burgers vectors - plastic_dislotwin_xc_twin, & !< critical distance for formation of twin nucleus - plastic_dislotwin_xc_trans, & !< critical distance for formation of trans nucleus - plastic_dislotwin_VcrossSlip, & !< cross slip volume - plastic_dislotwin_sbResistance, & !< value for shearband resistance (might become an internal state variable at some point) - plastic_dislotwin_sbVelocity, & !< value for shearband velocity_0 - plastic_dislotwin_sbQedge, & !< value for shearband systems Qedge - plastic_dislotwin_SFE_0K, & !< stacking fault energy at zero K - plastic_dislotwin_dSFE_dT, & !< temperature dependance of stacking fault energy - plastic_dislotwin_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful - plastic_dislotwin_aTolRho, & !< absolute tolerance for integration of dislocation density - plastic_dislotwin_aTolTwinFrac, & !< absolute tolerance for integration of twin volume fraction - plastic_dislotwin_aTolTransFrac, & !< absolute tolerance for integration of trans volume fraction - plastic_dislotwin_deltaG, & !< Free energy difference between austensite and martensite - plastic_dislotwin_Cmfptrans, & !< - plastic_dislotwin_Cthresholdtrans, & !< - plastic_dislotwin_transStackHeight !< Stack height of hex nucleus - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctwin3333 !< twin elasticity matrix for each instance - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctrans66 !< trans elasticity matrix in Mandel notation for each instance - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctrans3333 !< trans elasticity matrix for each instance - real(pReal), dimension(:,:), allocatable, private :: & - plastic_dislotwin_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance - plastic_dislotwin_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance - plastic_dislotwin_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance - plastic_dislotwin_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance - plastic_dislotwin_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance - plastic_dislotwin_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance - plastic_dislotwin_burgersPerTransFamily, & !< absolute length of burgers vector [m] for each trans family and instance - plastic_dislotwin_burgersPerTransSystem, & !< absolute length of burgers vector [m] for each trans system and instance - plastic_dislotwin_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance - plastic_dislotwin_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance - plastic_dislotwin_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance - plastic_dislotwin_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance - plastic_dislotwin_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance - plastic_dislotwin_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance - plastic_dislotwin_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance - plastic_dislotwin_Ndot0PerTransFamily, & !< trans nucleation rate [1/m³s] for each trans family and instance - plastic_dislotwin_Ndot0PerTransSystem, & !< trans nucleation rate [1/m³s] for each trans system and instance - plastic_dislotwin_tau_r_twin, & !< stress to bring partial close together for each twin system and instance - plastic_dislotwin_tau_r_trans, & !< stress to bring partial close together for each trans system and instance - plastic_dislotwin_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance - plastic_dislotwin_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance - plastic_dislotwin_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_dislotwin_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_dislotwin_lamellarsizePerTransFamily, & !< martensite lamellar thickness [m] for each trans family and instance - plastic_dislotwin_lamellarsizePerTransSystem, & !< martensite lamellar thickness [m] for each trans system and instance - plastic_dislotwin_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance - plastic_dislotwin_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance - plastic_dislotwin_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_dislotwin_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance - plastic_dislotwin_interaction_SlipTrans, & !< coefficients for slip-trans interaction for each interaction type and instance - plastic_dislotwin_interaction_TransSlip, & !< coefficients for trans-slip interaction for each interaction type and instance - plastic_dislotwin_interaction_TransTrans, & !< coefficients for trans-trans interaction for each interaction type and instance - plastic_dislotwin_pPerSlipFamily, & !< p-exponent in glide velocity - plastic_dislotwin_qPerSlipFamily, & !< q-exponent in glide velocity - plastic_dislotwin_rPerTwinFamily, & !< r-exponent in twin nucleation rate - plastic_dislotwin_sPerTransFamily !< s-exponent in trans nucleation rate - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_dislotwin_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance - plastic_dislotwin_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance - plastic_dislotwin_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance - plastic_dislotwin_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance - plastic_dislotwin_interactionMatrix_SlipTrans, & !< interaction matrix of slip systems with trans systems for each instance - plastic_dislotwin_interactionMatrix_TransSlip, & !< interaction matrix of trans systems with slip systems for each instance - plastic_dislotwin_interactionMatrix_TransTrans, & !< interaction matrix of the different trans systems for each instance - plastic_dislotwin_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance - plastic_dislotwin_projectionMatrix_Trans !< matrix for projection of slip system shear on fault band (twin) systems for each instance - - real(pReal), dimension(:,:,:,:,:), allocatable, private :: & - plastic_dislotwin_sbSv - - enum, bind(c) - enumerator :: undefined_ID, & - edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID, & - twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID, & - resolved_stress_shearband_ID, & - shear_rate_shearband_ID, & - sb_eigenvalues_ID, & - sb_eigenvectors_ID, & - stress_trans_fraction_ID, & - strain_trans_fraction_ID, & - trans_fraction_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_dislotwin_outputID !< ID of each post result output - type, private :: tDislotwinState - real(pReal), pointer, dimension(:,:) :: & - rhoEdge, & - rhoEdgeDip, & - accshear_slip, & - twinFraction, & - accshear_twin, & - stressTransFraction, & - strainTransFraction , & - invLambdaSlip, & - invLambdaSlipTwin, & - invLambdaTwin, & - invLambdaSlipTrans, & - invLambdaTrans, & - mfp_slip, & - mfp_twin, & - mfp_trans, & - threshold_stress_slip, & - threshold_stress_twin, & - threshold_stress_trans, & - twinVolume, & - martensiteVolume - end type - type(tDislotwinState), allocatable, dimension(:), private :: & - state, & - state0, & - dotState - - public :: & - plastic_dislotwin_init, & - plastic_dislotwin_homogenizedC, & - plastic_dislotwin_microstructure, & - plastic_dislotwin_LpAndItsTangent, & - plastic_dislotwin_dotState, & - plastic_dislotwin_postResults - private :: & - plastic_dislotwin_stateInit, & - plastic_dislotwin_aTolState - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333, & - math_mul3x3 - use mesh, only: & - mesh_maxNips, & - mesh_NcpElems - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - homogenization_maxNgrains, & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_DISLOTWIN_label, & - PLASTICITY_DISLOTWIN_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,maxTotalNtrans,& - f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt,nr, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipTrans = 0_pInt, Nchunks_TransSlip = 0_pInt, Nchunks_TransTrans = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_TransFamilies = 0_pInt, & - offset_slip, index_myFamily, index_otherFamily, & - startIndex, endIndex - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin, tempPerTrans - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOTWIN_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOTWIN_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_dislotwin_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(plastic_dislotwin_output(maxval(phase_Noutput),maxNinstance)) - plastic_dislotwin_output = '' - allocate(plastic_dislotwin_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_dislotwin_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_totalNtrans(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_CAtomicVolume(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_D0(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Qsd(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_GrainSize(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_pShearBand(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_qShearBand(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_MaxTwinFraction(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cmfptwin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cthresholdtwin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_SolidSolutionStrength(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_L0_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_L0_trans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_xc_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_xc_trans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_VcrossSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_aTolRho(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_aTolTwinFrac(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_aTolTransFrac(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_sbResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_sbVelocity(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_sbQedge(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_SFE_0K(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_dSFE_dT(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default - allocate(plastic_dislotwin_deltaG(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cmfptrans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cthresholdtrans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_transStackHeight(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTransFamily(lattice_maxNtransFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTransFamily(lattice_maxNtransFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_SlipTrans(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TransSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TransTrans(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_sbSv(6,6,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) - allocate(plastic_dislotwin_lamellarsizePerTransFamily(lattice_maxNtransFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_sPerTransFamily(lattice_maxNtransFamily,maxNinstance),source=0.0_pReal) - - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) - Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase)> 0_pInt) - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_SlipTrans = maxval(lattice_interactionSlipTrans(:,:,phase)) - Nchunks_TransSlip = maxval(lattice_interactionTransSlip(:,:,phase)) - Nchunks_TransTrans = maxval(lattice_interactionTransTrans(:,:,phase)) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - if(allocated(tempPerTwin)) deallocate(tempPerTwin) - if(allocated(tempPerTrans)) deallocate(tempPerTrans) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - allocate(tempPerTwin(Nchunks_TwinFamilies)) - allocate(tempPerTrans(Nchunks_TransFamilies)) - endif - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('edge_density') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_density_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('dipole_density') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = dipole_density_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_slip','shearrate_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('edge_dipole_distance') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_dipole_distance_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stress_exponent') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_exponent_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('twin_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = twin_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_twin','shearrate_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_shearband') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_shearband_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_shearband','shearrate_shearband') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_shearband_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('sb_eigenvalues') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvalues_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('sb_eigenvectors') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvectors_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stress_trans_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_trans_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('strain_trans_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = strain_trans_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('trans_fraction','total_trans_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = trans_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip system families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - plastic_dislotwin_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip') - do j = 1_pInt, Nchunks_SlipFamilies - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('rhoedge0') - plastic_dislotwin_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('rhoedgedip0') - plastic_dislotwin_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('slipburgers') - plastic_dislotwin_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('qedge') - plastic_dislotwin_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('v0') - plastic_dislotwin_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('clambdaslip') - plastic_dislotwin_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau_peierls') - if (lattice_structure(phase) /= LATTICE_bcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOTWIN_label//')') - plastic_dislotwin_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('p_slip') - plastic_dislotwin_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('q_slip') - plastic_dislotwin_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on slip number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_dislotwin_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ndot0_twin','twinsize','twinburgers','r_twin') - do j = 1_pInt, Nchunks_TwinFamilies - tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('ndot0_twin') - if (lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') - plastic_dislotwin_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinsize') - plastic_dislotwin_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinburgers') - plastic_dislotwin_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('r_twin') - plastic_dislotwin_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of transformation system families - case ('ntrans') - if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & - call IO_warning(53_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - Nchunks_TransFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TransFamilies - plastic_dislotwin_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ndot0_trans','lamellarsize','transburgers','s_trans') - do j = 1_pInt, Nchunks_TransFamilies - tempPerTrans(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('ndot0_trans') - if (lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') - plastic_dislotwin_Ndot0PerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - case ('lamellarsize') - plastic_dislotwin_lamellarsizePerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - case ('transburgers') - plastic_dislotwin_burgersPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - case ('s_trans') - plastic_dislotwin_sPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip','interactionslipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_dislotwin_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin','interactionsliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_dislotwin_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip','interactiontwinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_dislotwin_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin','interactiontwintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_dislotwin_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptrans','interactionsliptrans') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTrans) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_SlipTrans - plastic_dislotwin_interaction_SlipTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_transslip','interactiontransslip') - if (chunkPos(1) < 1_pInt + Nchunks_TransSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TransSlip - plastic_dislotwin_interaction_TransSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_transtrans','interactiontranstrans') - if (chunkPos(1) < 1_pInt + Nchunks_TransTrans) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TransTrans - plastic_dislotwin_interaction_TransTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin/trans systems - case ('grainsize') - plastic_dislotwin_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('maxtwinfraction') - plastic_dislotwin_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('p_shearband') - plastic_dislotwin_pShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('q_shearband') - plastic_dislotwin_qShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('d0') - plastic_dislotwin_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('qsd') - plastic_dislotwin_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_rho') - plastic_dislotwin_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_dislotwin_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_transfrac') - plastic_dislotwin_aTolTransFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cmfptwin') - plastic_dislotwin_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cthresholdtwin') - plastic_dislotwin_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('solidsolutionstrength') - plastic_dislotwin_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('l0_twin') - plastic_dislotwin_L0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('l0_trans') - plastic_dislotwin_L0_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('xc_twin') - plastic_dislotwin_xc_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('xc_trans') - plastic_dislotwin_xc_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('vcrossslip') - plastic_dislotwin_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cedgedipmindistance') - plastic_dislotwin_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('catomicvolume') - plastic_dislotwin_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('sfe_0k') - plastic_dislotwin_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dsfe_dt') - plastic_dislotwin_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dipoleformationfactor') - plastic_dislotwin_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('shearbandresistance') - plastic_dislotwin_sbResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('shearbandvelocity') - plastic_dislotwin_sbVelocity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('qedgepersbsystem') - plastic_dislotwin_sbQedge(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('deltag') - plastic_dislotwin_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cmfptrans') - plastic_dislotwin_Cmfptrans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cthresholdtrans') - plastic_dislotwin_Cthresholdtrans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('transstackheight') - plastic_dislotwin_transStackHeight(instance) = IO_floatValue(line,chunkPos,2_pInt) - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then - instance = phase_plasticityInstance(phase) - - if (sum(plastic_dislotwin_Nslip(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOTWIN_label//')') - if (sum(plastic_dislotwin_Ntwin(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOTWIN_label//')') - if (sum(plastic_dislotwin_Ntrans(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Ntrans ('//PLASTICITY_DISLOTWIN_label//')') - do f = 1_pInt,lattice_maxNslipFamily - if (plastic_dislotwin_Nslip(f,instance) > 0_pInt) then - if (plastic_dislotwin_rhoEdge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_rhoEdgeDip0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_v0PerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOTWIN_label//')') - endif - enddo - do f = 1_pInt,lattice_maxNtwinFamily - if (plastic_dislotwin_Ntwin(f,instance) > 0_pInt) then - if (plastic_dislotwin_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='ndot0_twin ('//PLASTICITY_DISLOTWIN_label//')') - endif - enddo - if (plastic_dislotwin_CAtomicVolume(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_D0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_Qsd(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOTWIN_label//')') - if (sum(plastic_dislotwin_Ntwin(:,instance)) > 0_pInt) then - if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & - abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & - lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_aTolTwinFrac(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOTWIN_label//')') - endif - if (sum(plastic_dislotwin_Ntrans(:,instance)) > 0_pInt) then - if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & - abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & - lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_aTolTransFrac(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolTransFrac ('//PLASTICITY_DISLOTWIN_label//')') - endif - if (plastic_dislotwin_sbResistance(instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sbResistance ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_sbVelocity(instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sbVelocity ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & - plastic_dislotwin_pShearBand(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='pShearBand ('//PLASTICITY_DISLOTWIN_label//')') - if (abs(plastic_dislotwin_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & - plastic_dislotwin_dipoleFormationFactor(instance) /= 1.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & - plastic_dislotwin_qShearBand(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='qShearBand ('//PLASTICITY_DISLOTWIN_label//')') - -!-------------------------------------------------------------------------------------------------- -! Determine total number of active slip or twin systems - plastic_dislotwin_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_dislotwin_Nslip(:,instance)) - plastic_dislotwin_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_dislotwin_Ntwin(:,instance)) - plastic_dislotwin_Ntrans(:,instance)= min(lattice_NtransSystem(:,phase),plastic_dislotwin_Ntrans(:,instance)) - plastic_dislotwin_totalNslip(instance) = sum(plastic_dislotwin_Nslip(:,instance)) - plastic_dislotwin_totalNtwin(instance) = sum(plastic_dislotwin_Ntwin(:,instance)) - plastic_dislotwin_totalNtrans(instance) = sum(plastic_dislotwin_Ntrans(:,instance)) - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - maxTotalNslip = maxval(plastic_dislotwin_totalNslip) - maxTotalNtwin = maxval(plastic_dislotwin_totalNtwin) - maxTotalNtrans = maxval(plastic_dislotwin_totalNtrans) - - allocate(plastic_dislotwin_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_tau_r_twin(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_tau_r_trans(maxTotalNtrans, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_lamellarsizePerTransSystem(maxTotalNtrans, maxNinstance),source=0.0_pReal) - - allocate(plastic_dislotwin_interactionMatrix_SlipSlip(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from slip activity - maxval(plastic_dislotwin_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_SlipTwin(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from twin activity - maxval(plastic_dislotwin_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TwinSlip(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_dislotwin_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TwinTwin(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_dislotwin_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_SlipTrans(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from trans activity - maxval(plastic_dislotwin_totalNtrans),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TransSlip(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from slip activity - maxval(plastic_dislotwin_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TransTrans(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from trans activity - maxval(plastic_dislotwin_totalNtrans),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_projectionMatrix_Trans(maxTotalNtrans,maxTotalNslip,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ctrans66(6,6,maxTotalNtrans,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ctrans3333(3,3,3,3,maxTotalNtrans,maxNinstance), source=0.0_pReal) - - allocate(state(maxNinstance)) - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - myPhase2: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then - NofMyPhase=count(material_phase==phase) - instance = phase_plasticityInstance(phase) - - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_dislotwin_Noutput(instance) - select case(plastic_dislotwin_outputID(o,instance)) - case(edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID & - ) - mySize = ns - case(twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID & - ) - mySize = nt - case(resolved_stress_shearband_ID, & - shear_rate_shearband_ID & - ) - mySize = 6_pInt - case(sb_eigenvalues_ID) - mySize = 3_pInt - case(sb_eigenvectors_ID) - mySize = 9_pInt - case(stress_trans_fraction_ID, & - strain_trans_fraction_ID, & - trans_fraction_ID & - ) - mySize = nr - end select - - if (mySize > 0_pInt) then ! any meaningful output found - plastic_dislotwin_sizePostResult(o,instance) = mySize - plastic_dislotwin_sizePostResults(instance) = plastic_dislotwin_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - - sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & - + int(size(['twinFraction','accsheartwin']),pInt) * nt & - + int(size(['stressTransFraction','strainTransFraction']),pInt) * nr - sizeDeltaState = 0_pInt - sizeState = sizeDotState & - + int(size(['invLambdaSlip ','invLambdaSlipTwin ','invLambdaSlipTrans',& - 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & - + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& - 'twinVolume ']),pInt) * nt & - + int(size(['invLambdaTrans ','meanFreePathTrans','tauTransThreshold', & - 'martensiteVolume ']),pInt) * nr - - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_dislotwin_sizePostResults(instance) - plasticState(phase)%nSlip = plastic_dislotwin_totalNslip(instance) - plasticState(phase)%nTwin = plastic_dislotwin_totalNtwin(instance) - plasticState(phase)%nTrans= plastic_dislotwin_totalNtrans(instance) - allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - offset_slip = 2_pInt*plasticState(phase)%nslip - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) - - !* Process slip related parameters ------------------------------------------------ - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - slipSystemsLoop: do j = 1_pInt,plastic_dislotwin_Nslip(f,instance) - - !* Burgers vector, - ! dislocation velocity prefactor, - ! mean free path prefactor, - ! and minimum dipole distance - - plastic_dislotwin_burgersPerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_burgersPerSlipFamily(f,instance) - - plastic_dislotwin_QedgePerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_QedgePerSlipFamily(f,instance) - - plastic_dislotwin_v0PerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_v0PerSlipFamily(f,instance) - - plastic_dislotwin_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_CLambdaSlipPerSlipFamily(f,instance) - - !* Calculation of forest projections for edge dislocations - !* Interaction matrices - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_dislotwin_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & - abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & - lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) - plastic_dislotwin_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_dislotwin_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtransFamily - index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) - plastic_dislotwin_interactionMatrix_SlipTrans(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_SlipTrans(lattice_interactionSlipTrans( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo slipSystemsLoop - enddo slipFamiliesLoop - - !* Process twin related parameters ------------------------------------------------ - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(plastic_dislotwin_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list - twinSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntwin(f,instance) - - !* Burgers vector, - ! nucleation rate prefactor, - ! and twin size - - plastic_dislotwin_burgersPerTwinSystem(index_myFamily+j,instance) = & - plastic_dislotwin_burgersPerTwinFamily(f,instance) - - plastic_dislotwin_Ndot0PerTwinSystem(index_myFamily+j,instance) = & - plastic_dislotwin_Ndot0PerTwinFamily(f,instance) - - plastic_dislotwin_twinsizePerTwinSystem(index_myFamily+j,instance) = & - plastic_dislotwin_twinsizePerTwinFamily(f,instance) - - !* Rotate twin elasticity matrices - index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list - do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt - do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt - plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & - plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & - lattice_C3333(p,q,r,s,instance) * & - lattice_Qtwin(l,p,index_otherFamily+j,phase) * & - lattice_Qtwin(m,q,index_otherFamily+j,phase) * & - lattice_Qtwin(n,r,index_otherFamily+j,phase) * & - lattice_Qtwin(o,s,index_otherFamily+j,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo; enddo - plastic_dislotwin_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & - math_Mandel3333to66(plastic_dislotwin_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) - - !* Interaction matrices - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_dislotwin_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_dislotwin_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo twinSystemsLoop - enddo twinFamiliesLoop - - !* Process transformation related parameters ------------------------------------------------ - transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily - index_myFamily = sum(plastic_dislotwin_Ntrans(1:f-1_pInt,instance)) ! index in truncated trans system list - transSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntrans(f,instance) - - !* Burgers vector, - ! nucleation rate prefactor, - ! and martensite size - - plastic_dislotwin_burgersPerTransSystem(index_myFamily+j,instance) = & - plastic_dislotwin_burgersPerTransFamily(f,instance) - - plastic_dislotwin_Ndot0PerTransSystem(index_myFamily+j,instance) = & - plastic_dislotwin_Ndot0PerTransFamily(f,instance) - - plastic_dislotwin_lamellarsizePerTransSystem(index_myFamily+j,instance) = & - plastic_dislotwin_lamellarsizePerTransFamily(f,instance) - - !* Rotate trans elasticity matrices - index_otherFamily = sum(lattice_NtransSystem(1:f-1_pInt,phase)) ! index in full lattice trans list - do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt - do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt - plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) = & - plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) + & - lattice_trans_C3333(p,q,r,s,instance) * & - lattice_Qtrans(l,p,index_otherFamily+j,phase) * & - lattice_Qtrans(m,q,index_otherFamily+j,phase) * & - lattice_Qtrans(n,r,index_otherFamily+j,phase) * & - lattice_Qtrans(o,s,index_otherFamily+j,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo; enddo - plastic_dislotwin_Ctrans66(1:6,1:6,index_myFamily+j,instance) = & - math_Mandel3333to66(plastic_dislotwin_Ctrans3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) - - !* Interaction matrices - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_dislotwin_interactionMatrix_TransSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TransSlip(lattice_interactionTransSlip( & - sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtransFamily - index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) - plastic_dislotwin_interactionMatrix_TransTrans(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TransTrans(lattice_interactionTransTrans( & - sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - !* Projection matrices for shear from slip systems to fault-band (twin) systems for strain-induced martensite nucleation - select case(trans_lattice_structure(phase)) - case (LATTICE_bcc_ID) - do o = 1_pInt,lattice_maxNtransFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (trans) - plastic_dislotwin_projectionMatrix_Trans(index_myFamily+j,index_otherFamily+k,instance) = & - lattice_projectionTrans( sum(lattice_NtransSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, phase) - enddo; enddo - end select - - enddo transSystemsLoop - enddo transFamiliesLoop - - startIndex=1_pInt - endIndex=ns - state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%stressTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%stressTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%stressTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%strainTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%strainTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%strainTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlipTrans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlipTrans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%invLambdaTrans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaTrans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%mfp_trans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_trans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%threshold_stress_trans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_trans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%martensiteVolume=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%martensiteVolume=>plasticState(phase)%state0(startIndex:endIndex,:) - - call plastic_dislotwin_stateInit(phase,instance) - call plastic_dislotwin_aTolState(phase,instance) - endif myPhase2 - - enddo initializeInstances -end subroutine plastic_dislotwin_init - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_stateInit(ph,instance) - use math, only: & - pi - use lattice, only: & - lattice_maxNslipFamily, & - lattice_mu - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - real(pReal), dimension(plasticState(ph)%sizeState) :: tempState - - integer(pInt) :: i,j,f,ns,nt,nr, index_myFamily - real(pReal), dimension(plastic_dislotwin_totalNslip(instance)) :: & - rhoEdge0, & - rhoEdgeDip0, & - invLambdaSlip0, & - MeanFreePathSlip0, & - tauSlipThreshold0 - real(pReal), dimension(plastic_dislotwin_totalNtwin(instance)) :: & - MeanFreePathTwin0,TwinVolume0 - real(pReal), dimension(plastic_dislotwin_totalNtrans(instance)) :: & - MeanFreePathTrans0,MartensiteVolume0 - tempState = 0.0_pReal - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables - do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - rhoEdge0(index_myFamily+1_pInt: & - index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & - plastic_dislotwin_rhoEdge0(f,instance) - rhoEdgeDip0(index_myFamily+1_pInt: & - index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & - plastic_dislotwin_rhoEdgeDip0(f,instance) - enddo - - tempState(1_pInt:ns) = rhoEdge0 - tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent slip microstructural variables - forall (i = 1_pInt:ns) & - invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_forestProjectionEdge(1:ns,i,instance)))/ & - plastic_dislotwin_CLambdaSlipPerSlipSystem(i,instance) - tempState(3_pInt*ns+2_pInt*nt+2_pInt*nr+1:4_pInt*ns+2_pInt*nt+2_pInt*nr) = invLambdaSlip0 - - forall (i = 1_pInt:ns) & - MeanFreePathSlip0(i) = & - plastic_dislotwin_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_dislotwin_GrainSize(instance)) - tempState(6_pInt*ns+3_pInt*nt+3_pInt*nr+1:7_pInt*ns+3_pInt*nt+3_pInt*nr) = MeanFreePathSlip0 - - forall (i = 1_pInt:ns) & - tauSlipThreshold0(i) = & - lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(i,instance) * & - sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_interactionMatrix_SlipSlip(i,1:ns,instance))) - - tempState(7_pInt*ns+4_pInt*nt+4_pInt*nr+1:8_pInt*ns+4_pInt*nt+4_pInt*nr) = tauSlipThreshold0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent twin microstructural variables - forall (j = 1_pInt:nt) & - MeanFreePathTwin0(j) = plastic_dislotwin_GrainSize(instance) - tempState(7_pInt*ns+3_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+3_pInt*nr) = MeanFreePathTwin0 - - forall (j = 1_pInt:nt) & - TwinVolume0(j) = & - (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) - tempState(8_pInt*ns+5_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+5_pInt*nr) = TwinVolume0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent trans microstructural variables - forall (j = 1_pInt:nr) & - MeanFreePathTrans0(j) = plastic_dislotwin_GrainSize(instance) - tempState(7_pInt*ns+4_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+4_pInt*nr) = MeanFreePathTrans0 - - forall (j = 1_pInt:nr) & - MartensiteVolume0(j) = & - (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(j,instance)*MeanFreePathTrans0(j)**(2.0_pReal) - tempState(8_pInt*ns+6_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+6_pInt*nr) = MartensiteVolume0 - -plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) - -end subroutine plastic_dislotwin_stateInit - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - ph, & - instance ! number specifying the current instance of the plasticity - - integer(pInt) :: ns, nt, nr - - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - ! Tolerance state for dislocation densities - plasticState(ph)%aTolState(1_pInt: & - 2_pInt*ns) = plastic_dislotwin_aTolRho(instance) - - ! Tolerance state for accumulated shear due to slip - plasticState(ph)%aTolState(2_pInt*ns+1_pInt: & - 3_pInt*ns)=1.0e6_pReal - - ! Tolerance state for twin volume fraction - plasticState(ph)%aTolState(3_pInt*ns+1_pInt: & - 3_pInt*ns+nt) = plastic_dislotwin_aTolTwinFrac(instance) - - ! Tolerance state for accumulated shear due to twin - plasticState(ph)%aTolState(3_pInt*ns+nt+1_pInt: & - 3_pInt*ns+2_pInt*nt) = 1.0e6_pReal - -! Tolerance state for stress-assisted martensite volume fraction - plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+1_pInt: & - 3_pInt*ns+2_pInt*nt+nr) = plastic_dislotwin_aTolTransFrac(instance) - -! Tolerance state for strain-induced martensite volume fraction - plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+nr+1_pInt: & - 3_pInt*ns+2_pInt*nt+2_pInt*nr) = plastic_dislotwin_aTolTransFrac(instance) - -end subroutine plastic_dislotwin_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenized elasticity matrix -!-------------------------------------------------------------------------------------------------- -function plastic_dislotwin_homogenizedC(ipc,ip,el) - use material, only: & - phase_plasticityInstance, & - phaseAt, phasememberAt - use lattice, only: & - lattice_C66 - - implicit none - real(pReal), dimension(6,6) :: & - plastic_dislotwin_homogenizedC - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,nr,i, & - ph, & - of - real(pReal) :: sumf, sumftr - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - - !* Homogenized elasticity matrix - plastic_dislotwin_homogenizedC = (1.0_pReal-sumf-sumftr)*lattice_C66(1:6,1:6,ph) - do i=1_pInt,nt - plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & - + state(instance)%twinFraction(i,of)*plastic_dislotwin_Ctwin66(1:6,1:6,i,instance) - enddo - do i=1_pInt,nr - plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & - + (state(instance)%stressTransFraction(i,of) + state(instance)%strainTransFraction(i,of))*& - plastic_dislotwin_Ctrans66(1:6,1:6,i,instance) - enddo - - end function plastic_dislotwin_homogenizedC - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_microstructure(temperature,ipc,ip,el) - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - !plasticState, & !!!!delete - phaseAt, phasememberAt - use lattice, only: & - lattice_mu, & - lattice_nu - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - temperature !< temperature at IP - - integer(pInt) :: & - instance, & - ns,nt,nr,s,t,r, & - ph, & - of - real(pReal) :: & - sumf,sfe,x0,sumftr - real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize - real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - ftransOverLamellarSize - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - - !* Stacking fault energy - sfe = plastic_dislotwin_SFE_0K(instance) + & - plastic_dislotwin_dSFE_dT(instance) * Temperature - - !* rescaled twin volume fraction for topology - forall (t = 1_pInt:nt) & - fOverStacksize(t) = & - state(instance)%twinFraction(t,of)/plastic_dislotwin_twinsizePerTwinSystem(t,instance) - - !* rescaled trans volume fraction for topology - forall (r = 1_pInt:nr) & - ftransOverLamellarSize(r) = & - (state(instance)%stressTransFraction(r,of)+state(instance)%strainTransFraction(r,of))/& - plastic_dislotwin_lamellarsizePerTransSystem(r,instance) - - !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation - forall (s = 1_pInt:ns) & - state(instance)%invLambdaSlip(s,of) = & - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_dislotwin_forestProjectionEdge(1:ns,s,instance)))/ & - plastic_dislotwin_CLambdaSlipPerSlipSystem(s,instance) - - !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation - !$OMP CRITICAL (evilmatmul) - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal - if (nt > 0_pInt .and. ns > 0_pInt) & - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & - matmul(plastic_dislotwin_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin - !$OMP CRITICAL (evilmatmul) - if (nt > 0_pInt) & - state(instance)%invLambdaTwin(1_pInt:nt,of) = & - matmul(plastic_dislotwin_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* 1/mean free distance between 2 martensite lamellar from different systems seen by a moving dislocation - state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = 0.0_pReal - if (nr > 0_pInt .and. ns > 0_pInt) & - state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = & - matmul(plastic_dislotwin_interactionMatrix_SlipTrans(1:ns,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) - - !* 1/mean free distance between 2 martensite stacks from different systems seen by a growing martensite (1/lambda_trans) - if (nr > 0_pInt) & - state(instance)%invLambdaTrans(1_pInt:nr,of) = & - matmul(plastic_dislotwin_interactionMatrix_TransTrans(1:nr,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) - - !* mean free path between 2 obstacles seen by a moving dislocation - do s = 1_pInt,ns - if ((nt > 0_pInt) .or. (nr > 0_pInt)) then - state(instance)%mfp_slip(s,of) = & - plastic_dislotwin_GrainSize(instance)/(1.0_pReal+plastic_dislotwin_GrainSize(instance)*& - (state(instance)%invLambdaSlip(s,of) + & - state(instance)%invLambdaSlipTwin(s,of) + & - state(instance)%invLambdaSlipTrans(s,of))) - else - state(instance)%mfp_slip(s,of) = & - plastic_dislotwin_GrainSize(instance)/& - (1.0_pReal+plastic_dislotwin_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) !!!!!! correct? - endif - enddo - - !* mean free path between 2 obstacles seen by a growing twin - forall (t = 1_pInt:nt) & - state(instance)%mfp_twin(t,of) = & - plastic_dislotwin_Cmfptwin(instance)*plastic_dislotwin_GrainSize(instance)/& - (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(ph)%invLambdaTwin(t,of)) - - !* mean free path between 2 obstacles seen by a growing martensite - forall (r = 1_pInt:nr) & - state(instance)%mfp_trans(r,of) = & - plastic_dislotwin_Cmfptrans(instance)*plastic_dislotwin_GrainSize(instance)/& - (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(instance)%invLambdaTrans(r,of)) - - !* threshold stress for dislocation motion - forall (s = 1_pInt:ns) & - state(instance)%threshold_stress_slip(s,of) = & - lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(s,instance)*& - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_dislotwin_interactionMatrix_SlipSlip(s,1:ns,instance))) - - !* threshold stress for growing twin - forall (t = 1_pInt:nt) & - state(instance)%threshold_stress_twin(t,of) = & - plastic_dislotwin_Cthresholdtwin(instance)* & - (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)) & - + 3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& - (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(t,instance)) & - ) - - !* threshold stress for growing martensite - forall (r = 1_pInt:nr) & - state(instance)%threshold_stress_trans(r,of) = & - plastic_dislotwin_Cthresholdtrans(instance)* & - (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & - + 3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)*lattice_mu(ph)/& - (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(r,instance))& - + plastic_dislotwin_transStackHeight(instance)*plastic_dislotwin_deltaG(instance)/ & - (3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & - ) - - !* final twin volume after growth - forall (t = 1_pInt:nt) & - state(instance)%twinVolume(t,of) = & - (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(t,instance)*& - state(instance)%mfp_twin(t,of)**(2.0_pReal) - - !* final martensite volume after growth - forall (r = 1_pInt:nr) & - state(instance)%martensiteVolume(r,of) = & - (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(r,instance)*& - state(instance)%mfp_trans(r,of)**(2.0_pReal) - - !* equilibrium separation of partial dislocations (twin) - do t = 1_pInt,nt - x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& - (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) - plastic_dislotwin_tau_r_twin(t,instance)= & - lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& - (1/(x0+plastic_dislotwin_xc_twin(instance))+cos(pi/3.0_pReal)/x0) - enddo - - !* equilibrium separation of partial dislocations (trans) - do r = 1_pInt,nr - x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)**(2.0_pReal)/& - (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) - plastic_dislotwin_tau_r_trans(r,instance)= & - lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)/(2.0_pReal*pi)*& - (1/(x0+plastic_dislotwin_xc_trans(instance))+cos(pi/3.0_pReal)/x0) - enddo - -end subroutine plastic_dislotwin_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - math_Plain3333to99, & - math_Mandel6to33, & - math_Mandel33to6, & - math_spectralDecompositionSym, & - math_tensorproduct33, & - math_symmetric33, & - math_mul33x3 - use material, only: & - material_phase, & - phase_plasticityInstance, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_Strans, & - lattice_Strans_v, & - lattice_maxNslipFamily,& - lattice_maxNtwinFamily, & - lattice_maxNtransFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NtransSystem, & - lattice_shearTwin, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - integer(pInt), intent(in) :: ipc,ip,el - real(pReal), intent(in) :: Temperature - real(pReal), dimension(6), intent(in) :: Tstar_v - real(pReal), dimension(3,3), intent(out) :: Lp - real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 - - integer(pInt) :: instance,ph,of,ns,nt,nr,f,i,j,k,l,m,n,index_myFamily,s1,s2 - real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0_twin,stressRatio, & - Ndot0_trans,StressRatio_s - real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 - real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,dgdot_dtauslip,tau_slip - real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,dgdot_dtautwin,tau_twin - real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_trans,dgdot_dtautrans,tau_trans - real(pReal), dimension(6) :: gdot_sb,dgdot_dtausb,tau_sb - real(pReal), dimension(3,3) :: eigVectors, sb_Smatrix - real(pReal), dimension(3) :: eigValues, sb_s, sb_m - logical :: error - real(pReal), dimension(3,6), parameter :: & - sb_sComposition = & - reshape(real([& - 1, 0, 1, & - 1, 0,-1, & - 1, 1, 0, & - 1,-1, 0, & - 0, 1, 1, & - 0, 1,-1 & - ],pReal),[ 3,6]), & - sb_mComposition = & - reshape(real([& - 1, 0,-1, & - 1, 0,+1, & - 1,-1, 0, & - 1, 1, 0, & - 0, 1,-1, & - 0, 1, 1 & - ],pReal),[ 3,6]) - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Dislocation glide part - gdot_slip = 0.0_pReal - dgdot_dtauslip = 0.0_pReal - j = 0_pInt - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystemsLoop: do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on slip system - tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - - if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) - StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0 & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_dislotwin_qPerSlipFamily(f,instance)) & - * sign(1.0_pReal,tau_slip(j)) - - !* Derivatives of shear rates - dgdot_dtauslip(j) = & - abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& - *plastic_dislotwin_qPerSlipFamily(f,instance)/& - (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) - endif - - !* Plastic velocity gradient for dislocation glide - Lp = Lp + gdot_slip(j)*lattice_Sslip(:,:,1,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& - lattice_Sslip(k,l,1,index_myFamily+i,ph)*& - lattice_Sslip(m,n,1,index_myFamily+i,ph) - enddo slipSystemsLoop - enddo slipFamiliesLoop - -!-------------------------------------------------------------------------------------------------- -! correct Lp and dLp_dTstar3333 for twinned and transformed fraction - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - Lp = Lp * (1.0_pReal - sumf - sumftr) - dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf - sumftr) - -!-------------------------------------------------------------------------------------------------- -! Shear banding (shearband) part - if(abs(plastic_dislotwin_sbVelocity(instance)) > tiny(0.0_pReal) .and. & - abs(plastic_dislotwin_sbResistance(instance)) > tiny(0.0_pReal)) then - gdot_sb = 0.0_pReal - dgdot_dtausb = 0.0_pReal - call math_spectralDecompositionSym(math_Mandel6to33(Tstar_v),eigValues,eigVectors,error) - do j = 1_pInt,6_pInt - sb_s = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_sComposition(1:3,j)) - sb_m = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_mComposition(1:3,j)) - sb_Smatrix = math_tensorproduct33(sb_s,sb_m) - plastic_dislotwin_sbSv(1:6,j,ipc,ip,el) = math_Mandel33to6(math_symmetric33(sb_Smatrix)) - - !* Calculation of Lp - !* Resolved shear stress on shear banding system - tau_sb(j) = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) - - !* Stress ratios - if (abs(tau_sb(j)) < tol_math_check) then - StressRatio_p = 0.0_pReal - StressRatio_pminus1 = 0.0_pReal - else - StressRatio_p = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& - **plastic_dislotwin_pShearBand(instance) - StressRatio_pminus1 = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& - **(plastic_dislotwin_pShearBand(instance)-1.0_pReal) - endif - - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = plastic_dislotwin_sbVelocity(instance) - - !* Shear rates due to shearband - gdot_sb(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qShearBand(instance))*sign(1.0_pReal,tau_sb(j)) - - !* Derivatives of shear rates - dgdot_dtausb(j) = & - ((abs(gdot_sb(j))*BoltzmannRatio*& - plastic_dislotwin_pShearBand(instance)*plastic_dislotwin_qShearBand(instance))/& - plastic_dislotwin_sbResistance(instance))*& - StressRatio_pminus1*(1_pInt-StressRatio_p)**(plastic_dislotwin_qShearBand(instance)-1.0_pReal) - - !* Plastic velocity gradient for shear banding - Lp = Lp + gdot_sb(j)*sb_Smatrix - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtausb(j)*& - sb_Smatrix(k,l)*& - sb_Smatrix(m,n) - enddo - end if - -!-------------------------------------------------------------------------------------------------- -! Mechanical twinning part - gdot_twin = 0.0_pReal - dgdot_dtautwin = 0.0_pReal - j = 0_pInt - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on twin system - tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_twin(j) > tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then - Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(ph)%rhoEdgeDip(s2,of))+& !!!!! correct? - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) - else - Ndot0_twin=0.0_pReal - end if - case default - Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) - end select - gdot_twin(j) = & - (1.0_pReal-sumf-sumftr)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) - dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_dislotwin_rPerTwinFamily(f,instance))/tau_twin(j))*StressRatio_r - endif - - !* Plastic velocity gradient for mechanical twinning - Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& - lattice_Stwin(k,l,index_myFamily+i,ph)*& - lattice_Stwin(m,n,index_myFamily+i,ph) - enddo twinSystemsLoop - enddo twinFamiliesLoop - - !* Phase transformation part - gdot_trans = 0.0_pReal - dgdot_dtautrans = 0.0_pReal - j = 0_pInt - transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily - index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family - transSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) - j = j+1_pInt - - !* Resolved shear stress on transformation system - tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_trans(j) > tol_math_check) then - StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) - !* Shear rates and their derivatives due to transformation - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then - Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !!!!! correct? - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) - else - Ndot0_trans=0.0_pReal - end if - case default - Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) - end select - gdot_trans(j) = & - (1.0_pReal-sumf-sumftr)*& - state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) - dgdot_dtautrans(j) = ((gdot_trans(j)*plastic_dislotwin_sPerTransFamily(f,instance))/tau_trans(j))*StressRatio_s - endif - - !* Plastic velocity gradient for phase transformation - Lp = Lp + gdot_trans(j)*lattice_Strans(:,:,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautrans(j)*& - lattice_Strans(k,l,index_myFamily+i,ph)*& - lattice_Strans(m,n,index_myFamily+i,ph) - - enddo transSystemsLoop - enddo transFamiliesLoop - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - -end subroutine plastic_dislotwin_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_dotState(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_Strans_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_maxNtransFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NtransSystem, & - lattice_sheartwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - lattice_fccTobcc_transNucleationTwinPair, & - lattice_fccTobcc_shearCritTrans, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,nr,f,i,j,index_myFamily,s1,s2, & - ph, & - of - real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,& - EdgeDipMinDistance,AtomicVolume,VacancyDiffusion,StressRatio_r,Ndot0_twin,stressRatio,& - Ndot0_trans,StressRatio_s,EdgeDipDistance, ClimbVelocity,DotRhoEdgeDipClimb,DotRhoEdgeDipAnnihilation, & - DotRhoDipFormation,DotRhoMultiplication,DotRhoEdgeEdgeAnnihilation - real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,tau_slip - - real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - tau_twin - real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - tau_trans - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - plasticState(instance)%dotState(:,of) = 0.0_pReal - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - - !* Dislocation density evolution - gdot_slip = 0.0_pReal - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - !* Resolved shear stress on slip system - tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - - if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) - StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - plasticState(ph)%state(j, of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)** & - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau_slip(j)) - endif - !* Multiplication - DotRhoMultiplication = abs(gdot_slip(j))/& - (plastic_dislotwin_burgersPerSlipSystem(j,instance)*state(instance)%mfp_slip(j,of)) - !* Dipole formation - EdgeDipMinDistance = & - plastic_dislotwin_CEdgeDipMinDistance(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance) - if (abs(tau_slip(j)) <= tiny(0.0_pReal)) then - DotRhoDipFormation = 0.0_pReal - else - EdgeDipDistance = & - (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(tau_slip(j))) - if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) - if (EdgeDipDistance tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/& - tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then - Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) - else - Ndot0_twin=0.0_pReal - end if - case default - Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) - end select - dotState(instance)%twinFraction(j,of) = & - (1.0_pReal-sumf-sumftr)*& - state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) - !* Dotstate for accumulated shear due to twin - dotState(instance)%accshear_twin(j,of) = dotState(instance)%twinFraction(j,of) * & - lattice_sheartwin(index_myfamily+i,ph) - endif - enddo - enddo - - !* Transformation volume fraction evolution - j = 0_pInt - do f = 1_pInt,lattice_maxNtransFamily ! loop over all trans families - index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) ! process each (active) trans system in family - j = j+1_pInt - - !* Resolved shear stress on transformation system - tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_trans(j) > tol_math_check) then - StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/& - tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) - !* Shear rates and their derivatives due to transformation - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then - Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) - else - Ndot0_trans=0.0_pReal - end if - case default - Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) - end select - dotState(instance)%strainTransFraction(j,of) = & - (1.0_pReal-sumf-sumftr)*& - state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) - !* Dotstate for accumulated shear due to transformation - !dotState(instance)%accshear_trans(j,of) = dotState(instance)%strainTransFraction(j,of) * & - ! lattice_sheartrans(index_myfamily+i,ph) - endif - - enddo - enddo - -end subroutine plastic_dislotwin_dotState - - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_dislotwin_postResults(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi, & - math_Mandel6to33, & - math_eigenvaluesSym33, & - math_spectralDecompositionSym33 - use material, only: & - material_phase, & - phase_plasticityInstance,& - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_shearTwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(plastic_dislotwin_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_dislotwin_postResults - integer(pInt) :: & - instance,& - ns,nt,nr,& - f,o,i,c,j,index_myFamily,& - s1,s2, & - ph, & - of - real(pReal) :: sumf,tau,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0_twin,dgdot_dtauslip, & - stressRatio - real(preal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip - real(pReal), dimension(3,3) :: eigVectors - real(pReal), dimension (3) :: eigValues - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Required output - c = 0_pInt - plastic_dislotwin_postResults = 0.0_pReal - do o = 1_pInt,plastic_dislotwin_Noutput(instance) - select case(plastic_dislotwin_outputID(o,instance)) - - case (edge_density_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) - c = c + ns - case (dipole_density_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) - c = c + ns - case (shear_rate_slip_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt ! could be taken from state by now! - - !* Resolved shear stress on slip system - tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - !* Stress ratios - if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau)-state(ph)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) - StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - plastic_dislotwin_postResults(c+j) = & - DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) - else - plastic_dislotwin_postResults(c+j) = 0.0_pReal - endif - - enddo ; enddo - c = c + ns - case (accumulated_shear_slip_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = & - state(instance)%accshear_slip(1_pInt:ns,of) - c = c + ns - case (mfp_slip_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) =& - state(instance)%mfp_slip(1_pInt:ns,of) - c = c + ns - case (resolved_stress_slip_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - plastic_dislotwin_postResults(c+j) =& - dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - enddo; enddo - c = c + ns - case (threshold_stress_slip_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = & - state(instance)%threshold_stress_slip(1_pInt:ns,of) - c = c + ns - case (edge_dipole_distance_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - plastic_dislotwin_postResults(c+j) = & - (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) - plastic_dislotwin_postResults(c+j)=min(plastic_dislotwin_postResults(c+j),& - state(instance)%mfp_slip(j,of)) - ! plastic_dislotwin_postResults(c+j)=max(plastic_dislotwin_postResults(c+j),& - ! plasticState(ph)%state(4*ns+2*nt+2*nr+j, of)) - enddo; enddo - c = c + ns - case (resolved_stress_shearband_ID) - do j = 1_pInt,6_pInt ! loop over all shearband families - plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v, & - plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) - enddo - c = c + 6_pInt - case (shear_rate_shearband_ID) - do j = 1_pInt,6_pInt ! loop over all shearbands - !* Resolved shear stress on shearband system - tau = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) - !* Stress ratios - if (abs(tau) < tol_math_check) then - StressRatio_p = 0.0_pReal - StressRatio_pminus1 = 0.0_pReal - else - StressRatio_p = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& - plastic_dislotwin_pShearBand(instance) - StressRatio_pminus1 = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& - (plastic_dislotwin_pShearBand(instance)-1.0_pReal) - endif - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = plastic_dislotwin_sbVelocity(instance) - ! Shear rate due to shear band - plastic_dislotwin_postResults(c+j) = & - DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**plastic_dislotwin_qShearBand(instance))*& - sign(1.0_pReal,tau) - enddo - c = c + 6_pInt - case (twin_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt,of) - c = c + nt - case (shear_rate_twin_ID) - if (nt > 0_pInt) then - - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - - !* Resolved shear stress on slip system - tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - !* Stress ratios - if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) - else - gdot_slip(j) = 0.0_pReal - endif - enddo;enddo - - j = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily ! loop over all twin families - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1,plastic_dislotwin_Ntwin(f,instance) ! process each (active) twin system in family - j = j + 1_pInt - - tau = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - - !* Shear rates due to twin - if ( tau > 0.0_pReal ) then - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau < plastic_dislotwin_tau_r_twin(j,instance)) then - Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_twin(instance)*& - plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_twin(j,instance)-tau))) - else - Ndot0_twin=0.0_pReal - end if - case default - Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) - end select - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau) & - **plastic_dislotwin_rPerTwinFamily(f,instance) - plastic_dislotwin_postResults(c+j) = & - (plastic_dislotwin_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) - endif - - enddo ; enddo - endif - c = c + nt - case (accumulated_shear_twin_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt,of) - c = c + nt - case (mfp_twin_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt,of) - c = c + nt - case (resolved_stress_twin_ID) - if (nt > 0_pInt) then - j = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily ! loop over all slip families - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - enddo; enddo - endif - c = c + nt - case (threshold_stress_twin_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt,of) - c = c + nt - case (stress_exponent_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - - !* Resolved shear stress on slip system - tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) - - !* Derivatives of shear rates - dgdot_dtauslip = & - abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& - *plastic_dislotwin_qPerSlipFamily(f,instance)/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) - - else - gdot_slip(j) = 0.0_pReal - dgdot_dtauslip = 0.0_pReal - endif - - !* Stress exponent - if (abs(gdot_slip(j))<=tiny(0.0_pReal)) then - plastic_dislotwin_postResults(c+j) = 0.0_pReal - else - plastic_dislotwin_postResults(c+j) = (tau/gdot_slip(j))*dgdot_dtauslip - endif - enddo ; enddo - c = c + ns - case (sb_eigenvalues_ID) - plastic_dislotwin_postResults(c+1_pInt:c+3_pInt) = math_eigenvaluesSym33(math_Mandel6to33(Tstar_v)) - c = c + 3_pInt - case (sb_eigenvectors_ID) - call math_spectralDecompositionSym33(math_Mandel6to33(Tstar_v),eigValues,eigVectors) - plastic_dislotwin_postResults(c+1_pInt:c+9_pInt) = reshape(eigVectors,[9]) - c = c + 9_pInt - case (stress_trans_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nr) = & - state(instance)%stressTransFraction(1_pInt:nr,of) - c = c + nr - case (strain_trans_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nr) = & - state(instance)%strainTransFraction(1_pInt:nr,of) - c = c + nr - case (trans_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nr) = & - state(instance)%stressTransFraction(1_pInt:nr,of) + & - state(instance)%strainTransFraction(1_pInt:nr,of) - c = c + nr - end select - enddo -end function plastic_dislotwin_postResults - -end module plastic_dislotwin \ No newline at end of file diff --git a/code/plastic/plastic_isotropic.f90 b/code/plastic/plastic_isotropic.f90 deleted file mode 100644 index 13481b9a7..000000000 --- a/code/plastic/plastic_isotropic.f90 +++ /dev/null @@ -1,678 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for isotropic (ISOTROPIC) plasticity -!> @details Isotropic (ISOTROPIC) Plasticity which resembles the phenopowerlaw plasticity without -!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an -!! untextured polycrystal -!-------------------------------------------------------------------------------------------------- -module plastic_isotropic -#ifdef HDF - use hdf5, only: & - HID_T -#endif - - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_isotropic_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_isotropic_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_isotropic_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_isotropic_Noutput !< number of outputs per instance - - enum, bind(c) - enumerator :: undefined_ID, & - flowstress_ID, & - strainrate_ID - end enum - - type, private :: tParameters !< container type for internal constitutive parameters - integer(kind(undefined_ID)), allocatable, dimension(:) :: & - outputID - real(pReal) :: & - fTaylor, & - tau0, & - gdot0, & - n, & - h0, & - h0_slopeLnRate, & - tausat, & - a, & - aTolFlowstress, & - aTolShear , & - tausat_SinhFitA, & - tausat_SinhFitB, & - tausat_SinhFitC, & - tausat_SinhFitD - logical :: & - dilatation - end type - - type(tParameters), dimension(:), allocatable, private :: param !< containers of constitutive parameters (len Ninstance) - - type, private :: tIsotropicState !< internal state aliases - real(pReal), pointer, dimension(:) :: & ! scalars along NipcMyInstance - flowstress, & - accumulatedShear - end type - type, private :: tIsotropicAbsTol !< internal alias for abs tolerance in state - real(pReal), pointer :: & ! scalars along NipcMyInstance - flowstress, & - accumulatedShear - end type - type(tIsotropicState), allocatable, dimension(:), private :: & !< state aliases per instance - state, & - state0, & - dotState - type(tIsotropicAbsTol), allocatable, dimension(:), private :: & !< state aliases per instance - stateAbsTol - - public :: & - plastic_isotropic_init, & - plastic_isotropic_LpAndItsTangent, & - plastic_isotropic_LiAndItsTangent, & - plastic_isotropic_dotState, & - plastic_isotropic_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic - use numerics, only: & - analyticJaco, & - worldrank, & - numerics_integrator - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_ISOTROPIC_label, & - PLASTICITY_ISOTROPIC_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - - use lattice - - implicit none - integer(pInt), intent(in) :: fileUnit - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - o, & - phase, & - instance, & - maxNinstance, & - mySize, & - sizeDotState, & - sizeState, & - sizeDeltaState - character(len=65536) :: & - tag = '', & - outputtag = '', & - line = '', & - extmsg = '' - integer(pInt) :: NipcMyPhase - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_ISOTROPIC_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_ISOTROPIC_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_isotropic_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_isotropic_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) - allocate(plastic_isotropic_output(maxval(phase_Noutput), maxNinstance)) - plastic_isotropic_output = '' - allocate(plastic_isotropic_Noutput(maxNinstance), source=0_pInt) - - allocate(param(maxNinstance)) ! one container of parameters per instance - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - phase = phase + 1_pInt ! advance section counter - if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then - instance = phase_plasticityInstance(phase) - - endif - cycle ! skip to next line - endif - if (phase > 0_pInt) then; if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - allocate(param(instance)%outputID(phase_Noutput(phase))) ! allocate space for IDs of every requested output - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - extmsg = trim(tag)//' ('//PLASTICITY_ISOTROPIC_label//')' ! prepare error message identifier - - select case(tag) - case ('(output)') - outputtag = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - select case(outputtag) - case ('flowstress') - plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt - param(instance)%outputID (plastic_isotropic_Noutput(instance)) = flowstress_ID - plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag - case ('strainrate') - plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt - param(instance)%outputID (plastic_isotropic_Noutput(instance)) = strainrate_ID - plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag - - end select - - case ('/dilatation/') - param(instance)%dilatation = .true. - - case ('tau0') - param(instance)%tau0 = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%tau0 < 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('gdot0') - param(instance)%gdot0 = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%gdot0 <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('n') - param(instance)%n = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%n <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('h0') - param(instance)%h0 = IO_floatValue(line,chunkPos,2_pInt) - - case ('h0_slope','slopelnrate') - param(instance)%h0_slopeLnRate = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat') - param(instance)%tausat = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%tausat <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('tausat_sinhfita') - param(instance)%tausat_SinhFitA = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat_sinhfitb') - param(instance)%tausat_SinhFitB = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat_sinhfitc') - param(instance)%tausat_SinhFitC = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat_sinhfitd') - param(instance)%tausat_SinhFitD = IO_floatValue(line,chunkPos,2_pInt) - - case ('a', 'w0') - param(instance)%a = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%a <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('taylorfactor') - param(instance)%fTaylor = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%fTaylor <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('atol_flowstress') - param(instance)%aTolFlowstress = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%aTolFlowstress <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('atol_shear') - param(instance)%aTolShear = IO_floatValue(line,chunkPos,2_pInt) - - case default - - end select - endif; endif - enddo parsingFile - - allocate(state(maxNinstance)) ! internal state aliases - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - allocate(stateAbsTol(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop over every plasticity - myPhase: if (phase_plasticity(phase) == PLASTICITY_isotropic_ID) then ! isolate instances of own constitutive description - NipcMyPhase = count(material_phase == phase) ! number of own material points (including point components ipc) - instance = phase_plasticityInstance(phase) -!-------------------------------------------------------------------------------------------------- -! sanity checks - if (param(instance)%aTolShear <= 0.0_pReal) & - param(instance)%aTolShear = 1.0e-6_pReal ! default absolute tolerance 1e-6 - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) - select case(param(instance)%outputID(o)) - case(flowstress_ID,strainrate_ID) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_isotropic_sizePostResult(o,instance) = mySize - plastic_isotropic_sizePostResults(instance) = & - plastic_isotropic_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = 2_pInt ! flowstress, accumulated_shear - sizeDotState = sizeState ! both evolve - sizeDeltaState = 0_pInt ! no sudden jumps in state - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_isotropic_sizePostResults(instance) - plasticState(phase)%nSlip = 1 - plasticState(phase)%nTwin = 0 - plasticState(phase)%nTrans= 0 - allocate(plasticState(phase)%aTolState ( sizeState)) - - allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase),source=0.0_pReal) - - allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase),source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase),source=0.0_pReal) - -!-------------------------------------------------------------------------------------------------- -! globally required state aliases - plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NipcMyPhase) - plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NipcMyPhase) - -!-------------------------------------------------------------------------------------------------- -! locally defined state aliases - state(instance)%flowstress => plasticState(phase)%state (1,1:NipcMyPhase) - state0(instance)%flowstress => plasticState(phase)%state0 (1,1:NipcMyPhase) - dotState(instance)%flowstress => plasticState(phase)%dotState (1,1:NipcMyPhase) - stateAbsTol(instance)%flowstress => plasticState(phase)%aTolState(1) - - state(instance)%accumulatedShear => plasticState(phase)%state (2,1:NipcMyPhase) - state0(instance)%accumulatedShear => plasticState(phase)%state0 (2,1:NipcMyPhase) - dotState(instance)%accumulatedShear => plasticState(phase)%dotState (2,1:NipcMyPhase) - stateAbsTol(instance)%accumulatedShear => plasticState(phase)%aTolState(2) - -!-------------------------------------------------------------------------------------------------- -! init state - state0(instance)%flowstress = param(instance)%tau0 - state0(instance)%accumulatedShear = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! init absolute state tolerances - stateAbsTol(instance)%flowstress = param(instance)%aTolFlowstress - stateAbsTol(instance)%accumulatedShear = param(instance)%aTolShear - - endif myPhase - enddo initializeInstances - -end subroutine plastic_isotropic_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_g - use math, only: & - math_mul6x6, & - math_Mandel6to33, & - math_Plain3333to99, & - math_deviatoric33, & - math_mul33xx33, & - math_transpose33 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(3,3) :: & - Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal) :: & - gamma_dot, & !< strainrate - norm_Tstar_dev, & !< euclidean norm of Tstar_dev - squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev - integer(pInt) :: & - instance, of, & - k, l, m, n - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - - Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress - squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) - norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) - - if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero - Lp = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - else - gamma_dot = param(instance)%gdot0 & - * ( sqrt(1.5_pReal) * norm_Tstar_dev / param(instance)%fTaylor / state(instance)%flowstress(of) ) & - **param(instance)%n - - Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/param(instance)%fTaylor - - if (iand(debug_level(debug_constitutive), debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i8,1x,i2,1x,i3)') '<< CONST isotropic >> at el ip g ',el,ip,ipc - write(6,'(/,a,/,3(12x,3(f12.4,1x)/))') '<< CONST isotropic >> Tstar (dev) / MPa', & - math_transpose33(Tstar_dev_33(1:3,1:3))*1.0e-6_pReal - write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> norm Tstar / MPa', norm_Tstar_dev*1.0e-6_pReal - write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> gdot', gamma_dot - end if -!-------------------------------------------------------------------------------------------------- -! Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & - Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal - forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & - dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal - dLp_dTstar99 = math_Plain3333to99(gamma_dot / param(instance)%fTaylor * & - dLp_dTstar_3333 / norm_Tstar_dev) - end if -end subroutine plastic_isotropic_LpAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_LiAndItsTangent(Li,dLi_dTstar_3333,Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6, & - math_Mandel6to33, & - math_Plain3333to99, & - math_spherical33, & - math_mul33xx33 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Li !< plastic velocity gradient - - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(3,3) :: & - Tstar_sph_33 !< sphiatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor - real(pReal), dimension(3,3,3,3), intent(out) :: & - dLi_dTstar_3333 !< derivative of Li with respect to Tstar as 4th order tensor - real(pReal) :: & - gamma_dot, & !< strainrate - norm_Tstar_sph, & !< euclidean norm of Tstar_sph - squarenorm_Tstar_sph !< square of the euclidean norm of Tstar_sph - integer(pInt) :: & - instance, of, & - k, l, m, n - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - - Tstar_sph_33 = math_spherical33(math_Mandel6to33(Tstar_v)) ! spherical part of 2nd Piola-Kirchhoff stress - squarenorm_Tstar_sph = math_mul33xx33(Tstar_sph_33,Tstar_sph_33) - norm_Tstar_sph = sqrt(squarenorm_Tstar_sph) - - if (param(instance)%dilatation) then - if (norm_Tstar_sph <= 0.0_pReal) then ! Tstar == 0 --> both Li and dLi_dTstar are zero - Li = 0.0_pReal - dLi_dTstar_3333 = 0.0_pReal - else - gamma_dot = param(instance)%gdot0 & - * (sqrt(1.5_pReal) * norm_Tstar_sph / param(instance)%fTaylor / state(instance)%flowstress(of) ) & - **param(instance)%n - - Li = Tstar_sph_33/norm_Tstar_sph * gamma_dot/param(instance)%fTaylor - - !-------------------------------------------------------------------------------------------------- - ! Calculation of the tangent of Li - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLi_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & - Tstar_sph_33(k,l)*Tstar_sph_33(m,n) / squarenorm_Tstar_sph - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLi_dTstar_3333(k,l,k,l) = dLi_dTstar_3333(k,l,k,l) + 1.0_pReal - - dLi_dTstar_3333 = gamma_dot / param(instance)%fTaylor * & - dLi_dTstar_3333 / norm_Tstar_sph - endif - endif - -end subroutine plastic_isotropic_LiAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_dotState(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6) :: & - Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - gamma_dot, & !< strainrate - hardening, & !< hardening coefficient - saturation, & !< saturation flowstress - norm_Tstar_v !< euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of !< shortcut notation for offset position in state array - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - -!-------------------------------------------------------------------------------------------------- -! norm of (deviatoric) 2nd Piola-Kirchhoff stress - if (param(instance)%dilatation) then - norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) - else - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - end if -!-------------------------------------------------------------------------------------------------- -! strain rate - gamma_dot = param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & - / &!----------------------------------------------------------------------------------- - (param(instance)%fTaylor*state(instance)%flowstress(of) ))**param(instance)%n - -!-------------------------------------------------------------------------------------------------- -! hardening coefficient - if (abs(gamma_dot) > 1e-12_pReal) then - if (abs(param(instance)%tausat_SinhFitA) <= tiny(0.0_pReal)) then - saturation = param(instance)%tausat - else - saturation = ( param(instance)%tausat & - + ( log( ( gamma_dot / param(instance)%tausat_SinhFitA& - )**(1.0_pReal / param(instance)%tausat_SinhFitD)& - + sqrt( ( gamma_dot / param(instance)%tausat_SinhFitA & - )**(2.0_pReal / param(instance)%tausat_SinhFitD) & - + 1.0_pReal ) & - ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) - )**(1.0_pReal / param(instance)%tausat_SinhFitC) & - / ( param(instance)%tausat_SinhFitB & - * (gamma_dot / param(instance)%gdot0)**(1.0_pReal / param(instance)%n) & - ) & - ) - endif - hardening = ( param(instance)%h0 + param(instance)%h0_slopeLnRate * log(gamma_dot) ) & - * abs( 1.0_pReal - state(instance)%flowstress(of)/saturation )**param(instance)%a & - * sign(1.0_pReal, 1.0_pReal - state(instance)%flowstress(of)/saturation) - else - hardening = 0.0_pReal - endif - - dotState(instance)%flowstress (of) = hardening * gamma_dot - dotState(instance)%accumulatedShear(of) = gamma_dot - -end subroutine plastic_isotropic_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_isotropic_postResults(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(plastic_isotropic_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_isotropic_postResults - - real(pReal), dimension(6) :: & - Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - norm_Tstar_v ! euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of, & !< shortcut notation for offset position in state array - c, & - o - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - -!-------------------------------------------------------------------------------------------------- -! norm of (deviatoric) 2nd Piola-Kirchhoff stress - if (param(instance)%dilatation) then - norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) - else - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - end if - - c = 0_pInt - plastic_isotropic_postResults = 0.0_pReal - - outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) - select case(param(instance)%outputID(o)) - case (flowstress_ID) - plastic_isotropic_postResults(c+1_pInt) = state(instance)%flowstress(of) - c = c + 1_pInt - case (strainrate_ID) - plastic_isotropic_postResults(c+1_pInt) = & - param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & - / &!---------------------------------------------------------------------------------- - (param(instance)%fTaylor * state(instance)%flowstress(of)) ) ** param(instance)%n - c = c + 1_pInt - end select - enddo outputsLoop - -end function plastic_isotropic_postResults - - -end module plastic_isotropic diff --git a/code/plastic/plastic_j2.f90 b/code/plastic/plastic_j2.f90 deleted file mode 100644 index 89c022cc9..000000000 --- a/code/plastic/plastic_j2.f90 +++ /dev/null @@ -1,579 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for isotropic (J2) plasticity -!> @details Isotropic (J2) Plasticity which resembles the phenopowerlaw plasticity without -!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an -!! untextured polycrystal -!-------------------------------------------------------------------------------------------------- -module plastic_j2 -#ifdef HDF - use hdf5, only: & - HID_T -#endif - - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_j2_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_j2_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_j2_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_j2_Noutput !< number of outputs per instance - real(pReal), dimension(:), allocatable, private :: & - plastic_j2_fTaylor, & !< Taylor factor - plastic_j2_tau0, & !< initial plastic stress - plastic_j2_gdot0, & !< reference velocity - plastic_j2_n, & !< Visco-plastic parameter -!-------------------------------------------------------------------------------------------------- -! h0 as function of h0 = A + B log (gammadot) - plastic_j2_h0, & - plastic_j2_h0_slopeLnRate, & - plastic_j2_tausat, & !< final plastic stress - plastic_j2_a, & - plastic_j2_aTolResistance, & - plastic_j2_aTolShear, & -!-------------------------------------------------------------------------------------------------- -! tausat += (asinh((gammadot / SinhFitA)**(1 / SinhFitD)))**(1 / SinhFitC) / (SinhFitB * (gammadot / gammadot0)**(1/n)) - plastic_j2_tausat_SinhFitA, & !< fitting parameter for normalized strain rate vs. stress function - plastic_j2_tausat_SinhFitB, & !< fitting parameter for normalized strain rate vs. stress function - plastic_j2_tausat_SinhFitC, & !< fitting parameter for normalized strain rate vs. stress function - plastic_j2_tausat_SinhFitD !< fitting parameter for normalized strain rate vs. stress function - - enum, bind(c) - enumerator :: undefined_ID, & - flowstress_ID, & - strainrate_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_j2_outputID !< ID of each post result output - - -#ifdef HDF - type plastic_j2_tOutput - real(pReal), dimension(:), allocatable, private :: & - flowstress, & - strainrate - logical :: flowstressActive = .false., strainrateActive = .false. ! if we can write the output block wise, this is not needed anymore because we can do an if(allocated(xxx)) - end type plastic_j2_tOutput - type(plastic_j2_tOutput), allocatable, dimension(:) :: plastic_j2_Output2 -integer(HID_T), allocatable, dimension(:) :: outID -#endif - - - public :: & - plastic_j2_init, & - plastic_j2_LpAndItsTangent, & - plastic_j2_dotState, & - plastic_j2_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_j2_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) -#ifdef HDF - use hdf5 -#endif - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic - use numerics, only: & - analyticJaco, & - worldrank, & - numerics_integrator - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_error, & - IO_timeStamp, & -#ifdef HDF - tempResults, & - HDF5_addGroup, & - HDF5_addScalarDataset,& -#endif - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_J2_label, & - PLASTICITY_J2_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - - use lattice - - implicit none - integer(pInt), intent(in) :: fileUnit - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - o, & - phase, & - maxNinstance, & - instance, & - mySize, & - sizeDotState, & - sizeState, & - sizeDeltaState - character(len=65536) :: & - tag = '', & - line = '' - integer(pInt) :: NofMyPhase - -#ifdef HDF - character(len=5) :: & - str1 - integer(HID_T) :: ID,ID2,ID4 -#endif - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_J2_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_J2_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - -#ifdef HDF - allocate(plastic_j2_Output2(maxNinstance)) - allocate(outID(maxNinstance)) -#endif - - allocate(plastic_j2_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_j2_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) - allocate(plastic_j2_output(maxval(phase_Noutput), maxNinstance)) - plastic_j2_output = '' - allocate(plastic_j2_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_j2_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_j2_fTaylor(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tau0(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_gdot0(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_n(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_h0(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_h0_slopeLnRate(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_a(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_aTolResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_aTolShear (maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitA(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitB(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitC(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitD(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - phase = phase + 1_pInt ! advance section counter - if (phase_plasticity(phase) == PLASTICITY_J2_ID) then - instance = phase_plasticityInstance(phase) -#ifdef HDF - outID(instance)=HDF5_addGroup(str1,tempResults) -#endif - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_J2_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('flowstress') - plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt - plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = flowstress_ID - plastic_j2_output(plastic_j2_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) -#ifdef HDF - call HDF5_addScalarDataset(outID(instance),myConstituents,'flowstress','MPa') - allocate(plastic_j2_Output2(instance)%flowstress(myConstituents)) - plastic_j2_Output2(instance)%flowstressActive = .true. -#endif - case ('strainrate') - plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt - plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = strainrate_ID - plastic_j2_output(plastic_j2_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) -#ifdef HDF - call HDF5_addScalarDataset(outID(instance),myConstituents,'strainrate','1/s') - allocate(plastic_j2_Output2(instance)%strainrate(myConstituents)) - plastic_j2_Output2(instance)%strainrateActive = .true. -#endif - case default - - end select - case ('tau0') - plastic_j2_tau0(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_tau0(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('gdot0') - plastic_j2_gdot0(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_gdot0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('n') - plastic_j2_n(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_n(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('h0') - plastic_j2_h0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_slope','slopelnrate') - plastic_j2_h0_slopeLnRate(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat') - plastic_j2_tausat(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_tausat(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('tausat_sinhfita') - plastic_j2_tausat_SinhFitA(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat_sinhfitb') - plastic_j2_tausat_SinhFitB(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat_sinhfitc') - plastic_j2_tausat_SinhFitC(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat_sinhfitd') - plastic_j2_tausat_SinhFitD(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('a', 'w0') - plastic_j2_a(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_a(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('taylorfactor') - plastic_j2_fTaylor(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_fTaylor(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('atol_resistance') - plastic_j2_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_aTolResistance(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('atol_shear') - plastic_j2_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case default - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_j2_ID) then - NofMyPhase=count(material_phase==phase) - instance = phase_plasticityInstance(phase) -!-------------------------------------------------------------------------------------------------- -! sanity checks - if (plastic_j2_aTolShear(instance) <= 0.0_pReal) & - plastic_j2_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) - select case(plastic_j2_outputID(o,instance)) - case(flowstress_ID,strainrate_ID) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_j2_sizePostResult(o,instance) = mySize - plastic_j2_sizePostResults(instance) = & - plastic_j2_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = 2_pInt - sizeDotState = sizeState - sizeDeltaState = 0_pInt - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_j2_sizePostResults(instance) - plasticState(phase)%nSlip = 1 - plasticState(phase)%nTwin = 0 - plasticState(phase)%nTrans= 0 - allocate(plasticState(phase)%aTolState ( sizeState)) - plasticState(phase)%aTolState(1) = plastic_j2_aTolResistance(instance) - plasticState(phase)%aTolState(2) = plastic_j2_aTolShear(instance) - allocate(plasticState(phase)%state0 ( sizeState,NofMyPhase)) - plasticState(phase)%state0(1,1:NofMyPhase) = plastic_j2_tau0(instance) - plasticState(phase)%state0(2,1:NofMyPhase) = 0.0_pReal - allocate(plasticState(phase)%partionedState0 ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase),source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase),source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NofMyPhase) - endif myPhase - enddo initializeInstances - -end subroutine plastic_j2_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_j2_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6, & - math_Mandel6to33, & - math_Plain3333to99, & - math_deviatoric33, & - math_mul33xx33 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(3,3) :: & - Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal) :: & - gamma_dot, & !< strainrate - norm_Tstar_dev, & !< euclidean norm of Tstar_dev - squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & - k, l, m, n - - instance = phase_plasticityInstance(material_phase(ipc,ip,el)) - Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress - squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) - norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) - - if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero - Lp = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - else - gamma_dot = plastic_j2_gdot0(instance) & - * (sqrt(1.5_pReal) * norm_Tstar_dev / (plastic_j2_fTaylor(instance) * & - plasticState(phaseAt(ipc,ip,el))%state(1,phasememberAt(ipc,ip,el)))) & - **plastic_j2_n(instance) - - Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/plastic_j2_fTaylor(instance) - -!-------------------------------------------------------------------------------------------------- -! Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,m,n) = (plastic_j2_n(instance)-1.0_pReal) * & - Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal - forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & - dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal - dLp_dTstar99 = math_Plain3333to99(gamma_dot / plastic_j2_fTaylor(instance) * & - dLp_dTstar_3333 / norm_Tstar_dev) - end if -end subroutine plastic_j2_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_j2_dotState(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6) :: & - Tstar_dev_v !< deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - gamma_dot, & !< strainrate - hardening, & !< hardening coefficient - saturation, & !< saturation resistance - norm_Tstar_dev !< euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of, & !< shortcut notation for offset position in state array - ph !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(material_phase(ipc,ip,el)) - -!-------------------------------------------------------------------------------------------------- -! norm of deviatoric part of 2nd Piola-Kirchhoff stress - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - -!-------------------------------------------------------------------------------------------------- -! strain rate - gamma_dot = plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & - / &!----------------------------------------------------------------------------------- - (plastic_j2_fTaylor(instance)*plasticState(ph)%state(1,of)) )**plastic_j2_n(instance) - -!-------------------------------------------------------------------------------------------------- -! hardening coefficient - if (abs(gamma_dot) > 1e-12_pReal) then - if (abs(plastic_j2_tausat_SinhFitA(instance)) <= tiny(0.0_pReal)) then - saturation = plastic_j2_tausat(instance) - else - saturation = ( plastic_j2_tausat(instance) & - + ( log( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance)& - )**(1.0_pReal / plastic_j2_tausat_SinhFitD(instance))& - + sqrt( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance) & - )**(2.0_pReal / plastic_j2_tausat_SinhFitD(instance)) & - + 1.0_pReal ) & - ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) - )**(1.0_pReal / plastic_j2_tausat_SinhFitC(instance)) & - / ( plastic_j2_tausat_SinhFitB(instance) & - * (gamma_dot / plastic_j2_gdot0(instance))**(1.0_pReal / plastic_j2_n(instance)) & - ) & - ) - endif - hardening = ( plastic_j2_h0(instance) + plastic_j2_h0_slopeLnRate(instance) * log(gamma_dot) ) & - * abs( 1.0_pReal - plasticState(ph)%state(1,of)/saturation )**plastic_j2_a(instance) & - * sign(1.0_pReal, 1.0_pReal - plasticState(ph)%state(1,of)/saturation) - else - hardening = 0.0_pReal - endif - - plasticState(ph)%dotState(1,of) = hardening * gamma_dot - plasticState(ph)%dotState(2,of) = gamma_dot - -end subroutine plastic_j2_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_j2_postResults(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(plastic_j2_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_j2_postResults - - real(pReal), dimension(6) :: & - Tstar_dev_v ! deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - norm_Tstar_dev ! euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of, & !< shortcut notation for offset position in state array - ph, & !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) - c, & - o - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(material_phase(ipc,ip,el)) - -!-------------------------------------------------------------------------------------------------- -! calculate deviatoric part of 2nd Piola-Kirchhoff stress and its norm - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - - c = 0_pInt - plastic_j2_postResults = 0.0_pReal - - outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) - select case(plastic_j2_outputID(o,instance)) - case (flowstress_ID) - plastic_j2_postResults(c+1_pInt) = plasticState(ph)%state(1,of) - c = c + 1_pInt - case (strainrate_ID) - plastic_j2_postResults(c+1_pInt) = & - plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & - / &!---------------------------------------------------------------------------------- - (plastic_j2_fTaylor(instance) * plasticState(ph)%state(1,of)) ) ** plastic_j2_n(instance) - c = c + 1_pInt - end select - enddo outputsLoop - -end function plastic_j2_postResults - - -end module plastic_j2 diff --git a/code/plastic/plastic_none.f90 b/code/plastic/plastic_none.f90 deleted file mode 100644 index f624a80a2..000000000 --- a/code/plastic/plastic_none.f90 +++ /dev/null @@ -1,109 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for purely elastic material -!-------------------------------------------------------------------------------------------------- -module plastic_none - use prec, only: & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_none_sizePostResults - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_none_sizePostResult !< size of each post result output - - public :: & - plastic_none_init - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_none_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic - use IO, only: & - IO_timeStamp - use numerics, only: & - worldrank, & - numerics_integrator - use material, only: & - phase_plasticity, & - PLASTICITY_NONE_label, & - material_phase, & - plasticState, & - PLASTICITY_none_ID - - implicit none - - integer(pInt) :: & - maxNinstance, & - phase, & - NofMyPhase, & - sizeState, & - sizeDotState, & - sizeDeltaState - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONE_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_none_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - if (phase_plasticity(phase) == PLASTICITY_none_ID) then - NofMyPhase=count(material_phase==phase) - - sizeState = 0_pInt - plasticState(phase)%sizeState = sizeState - sizeDotState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - sizeDeltaState = 0_pInt - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = 0_pInt - plasticState(phase)%nSlip = 0_pInt - plasticState(phase)%nTwin = 0_pInt - plasticState(phase)%nTrans = 0_pInt - allocate(plasticState(phase)%aTolState (sizeState)) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase)) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase)) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase)) - allocate(plasticState(phase)%state (sizeState,NofMyPhase)) - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase)) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase)) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase)) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase)) - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase)) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase)) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase)) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase)) - endif - enddo initializeInstances - - allocate(plastic_none_sizePostResults(maxNinstance), source=0_pInt) - -end subroutine plastic_none_init - -end module plastic_none diff --git a/code/plastic/plastic_nonlocal.f90 b/code/plastic/plastic_nonlocal.f90 deleted file mode 100644 index 1922c08e2..000000000 --- a/code/plastic/plastic_nonlocal.f90 +++ /dev/null @@ -1,4031 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Christoph Kords, 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 -!> @brief material subroutine for plasticity including dislocation flux -!-------------------------------------------------------------------------------------------------- -module plastic_nonlocal - use prec, only: & - pReal, & - pInt - - implicit none - private - character(len=22), dimension(11), parameter, private :: & - BASICSTATES = ['rhoSglEdgePosMobile ', & - 'rhoSglEdgeNegMobile ', & - 'rhoSglScrewPosMobile ', & - 'rhoSglScrewNegMobile ', & - 'rhoSglEdgePosImmobile ', & - 'rhoSglEdgeNegImmobile ', & - 'rhoSglScrewPosImmobile', & - 'rhoSglScrewNegImmobile', & - 'rhoDipEdge ', & - 'rhoDipScrew ', & - 'accumulatedshear ' ] !< list of "basic" microstructural state variables that are independent from other state variables - - character(len=16), dimension(3), parameter, private :: & - DEPENDENTSTATES = ['rhoForest ', & - 'tauThreshold ', & - 'tauBack ' ] !< list of microstructural state variables that depend on other state variables - - character(len=20), dimension(6), parameter, private :: & - OTHERSTATES = ['velocityEdgePos ', & - 'velocityEdgeNeg ', & - 'velocityScrewPos ', & - 'velocityScrewNeg ', & - 'maxDipoleHeightEdge ', & - 'maxDipoleHeightScrew' ] !< list of other dependent state variables that are not updated by microstructure - - real(pReal), parameter, private :: & - KB = 1.38e-23_pReal !< Physical parameter, Boltzmann constant in J/Kelvin - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_nonlocal_sizeDotState, & !< number of dotStates = number of basic state variables - plastic_nonlocal_sizeDependentState, & !< number of dependent state variables - plastic_nonlocal_sizeState, & !< total number of state variables - plastic_nonlocal_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_nonlocal_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_nonlocal_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_nonlocal_Noutput !< number of outputs per instance of this plasticity - - integer(pInt), dimension(:,:), allocatable, private :: & - iGamma, & !< state indices for accumulated shear - iRhoF, & !< state indices for forest density - iTauF, & !< state indices for critical resolved shear stress - iTauB !< state indices for backstress - integer(pInt), dimension(:,:,:), allocatable, private :: & - iRhoU, & !< state indices for unblocked density - iRhoB, & !< state indices for blocked density - iRhoD, & !< state indices for dipole density - iV, & !< state indices for dislcation velocities - iD !< state indices for stable dipole height - - integer(pInt), dimension(:), allocatable, public, protected :: & - totalNslip !< total number of active slip systems for each instance - - integer(pInt), dimension(:,:), allocatable, private :: & - Nslip, & !< number of active slip systems for each family and instance - slipFamily, & !< lookup table relating active slip system to slip family for each instance - slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance - colinearSystem !< colinear system to the active slip system (only valid for fcc!) - - real(pReal), dimension(:), allocatable, private :: & - atomicVolume, & !< atomic volume - Dsd0, & !< prefactor for self-diffusion coefficient - selfDiffusionEnergy, & !< activation enthalpy for diffusion - aTolRho, & !< absolute tolerance for dislocation density in state integration - aTolShear, & !< absolute tolerance for accumulated shear in state integration - significantRho, & !< density considered significant - significantN, & !< number of dislocations considered significant - cutoffRadius, & !< cutoff radius for dislocation stress - doublekinkwidth, & !< width of a doubkle kink in multiples of the burgers vector length b - solidSolutionEnergy, & !< activation energy for solid solution in J - solidSolutionSize, & !< solid solution obstacle size in multiples of the burgers vector length - solidSolutionConcentration, & !< concentration of solid solution in atomic parts - pParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) - qParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) - viscosity, & !< viscosity for dislocation glide in Pa s - fattack, & !< attack frequency in Hz - rhoSglScatter, & !< standard deviation of scatter in initial dislocation density - surfaceTransmissivity, & !< transmissivity at free surface - grainboundaryTransmissivity, & !< transmissivity at grain boundary (identified by different texture) - CFLfactor, & !< safety factor for CFL flux condition - fEdgeMultiplication, & !< factor that determines how much edge dislocations contribute to multiplication (0...1) - rhoSglRandom, & - rhoSglRandomBinning, & - linetensionEffect, & - edgeJogFactor - - real(pReal), dimension(:,:), allocatable, private :: & - rhoSglEdgePos0, & !< initial edge_pos dislocation density per slip system for each family and instance - rhoSglEdgeNeg0, & !< initial edge_neg dislocation density per slip system for each family and instance - rhoSglScrewPos0, & !< initial screw_pos dislocation density per slip system for each family and instance - rhoSglScrewNeg0, & !< initial screw_neg dislocation density per slip system for each family and instance - rhoDipEdge0, & !< initial edge dipole dislocation density per slip system for each family and instance - rhoDipScrew0, & !< initial screw dipole dislocation density per slip system for each family and instance - lambda0PerSlipFamily, & !< mean free path prefactor for each family and instance - lambda0, & !< mean free path prefactor for each slip system and instance - burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each family and instance - burgers, & !< absolute length of burgers vector [m] for each slip system and instance - interactionSlipSlip !< coefficients for slip-slip interaction for each interaction type and instance - - real(pReal), dimension(:,:,:), allocatable, private :: & - minDipoleHeightPerSlipFamily, & !< minimum stable edge/screw dipole height for each family and instance - minDipoleHeight, & !< minimum stable edge/screw dipole height for each slip system and instance - peierlsStressPerSlipFamily, & !< Peierls stress (edge and screw) - peierlsStress, & !< Peierls stress (edge and screw) - forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance - forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance - interactionMatrixSlipSlip !< interaction matrix of the different slip systems for each instance - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - lattice2slip, & !< orthogonal transformation matrix from lattice coordinate system to slip coordinate system (passive rotation !!!) - rhoDotEdgeJogsOutput, & - sourceProbability - - real(pReal), dimension(:,:,:,:,:), allocatable, private :: & - rhoDotFluxOutput, & - rhoDotMultiplicationOutput, & - rhoDotSingle2DipoleGlideOutput, & - rhoDotAthermalAnnihilationOutput, & - rhoDotThermalAnnihilationOutput, & - nonSchmidProjection !< combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) - - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - compatibility !< slip system compatibility between me and my neighbors - - real(pReal), dimension(:,:), allocatable, private :: & - nonSchmidCoeff - - logical, dimension(:), allocatable, private :: & - shortRangeStressCorrection, & !< flag indicating the use of the short range stress correction by a excess density gradient term - probabilisticMultiplication - - enum, bind(c) - enumerator :: undefined_ID, & - rho_ID, & - delta_ID, & - rho_edge_ID, & - rho_screw_ID, & - rho_sgl_ID, & - delta_sgl_ID, & - rho_sgl_edge_ID, & - rho_sgl_edge_pos_ID, & - rho_sgl_edge_neg_ID, & - rho_sgl_screw_ID, & - rho_sgl_screw_pos_ID, & - rho_sgl_screw_neg_ID, & - rho_sgl_mobile_ID, & - rho_sgl_edge_mobile_ID, & - rho_sgl_edge_pos_mobile_ID, & - rho_sgl_edge_neg_mobile_ID, & - rho_sgl_screw_mobile_ID, & - rho_sgl_screw_pos_mobile_ID, & - rho_sgl_screw_neg_mobile_ID, & - rho_sgl_immobile_ID, & - rho_sgl_edge_immobile_ID, & - rho_sgl_edge_pos_immobile_ID, & - rho_sgl_edge_neg_immobile_ID, & - rho_sgl_screw_immobile_ID, & - rho_sgl_screw_pos_immobile_ID, & - rho_sgl_screw_neg_immobile_ID, & - rho_dip_ID, & - delta_dip_ID, & - rho_dip_edge_ID, & - rho_dip_screw_ID, & - excess_rho_ID, & - excess_rho_edge_ID, & - excess_rho_screw_ID, & - rho_forest_ID, & - shearrate_ID, & - resolvedstress_ID, & - resolvedstress_external_ID, & - resolvedstress_back_ID, & - resistance_ID, & - rho_dot_ID, & - rho_dot_sgl_ID, & - rho_dot_sgl_mobile_ID, & - rho_dot_dip_ID, & - rho_dot_gen_ID, & - rho_dot_gen_edge_ID, & - rho_dot_gen_screw_ID, & - rho_dot_sgl2dip_ID, & - rho_dot_sgl2dip_edge_ID, & - rho_dot_sgl2dip_screw_ID, & - rho_dot_ann_ath_ID, & - rho_dot_ann_the_ID, & - rho_dot_ann_the_edge_ID, & - rho_dot_ann_the_screw_ID, & - rho_dot_edgejogs_ID, & - rho_dot_flux_ID, & - rho_dot_flux_mobile_ID, & - rho_dot_flux_edge_ID, & - rho_dot_flux_screw_ID, & - velocity_edge_pos_ID, & - velocity_edge_neg_ID, & - velocity_screw_pos_ID, & - velocity_screw_neg_ID, & - slipdirectionx_ID, & - slipdirectiony_ID, & - slipdirectionz_ID, & - slipnormalx_ID, & - slipnormaly_ID, & - slipnormalz_ID, & - fluxdensity_edge_posx_ID, & - fluxdensity_edge_posy_ID, & - fluxdensity_edge_posz_ID, & - fluxdensity_edge_negx_ID, & - fluxdensity_edge_negy_ID, & - fluxdensity_edge_negz_ID, & - fluxdensity_screw_posx_ID, & - fluxdensity_screw_posy_ID, & - fluxdensity_screw_posz_ID, & - fluxdensity_screw_negx_ID, & - fluxdensity_screw_negy_ID, & - fluxdensity_screw_negz_ID, & - maximumdipoleheight_edge_ID, & - maximumdipoleheight_screw_ID, & - accumulatedshear_ID, & - dislocationstress_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_nonlocal_outputID !< ID of each post result output - - public :: & - plastic_nonlocal_init, & - plastic_nonlocal_stateInit, & - plastic_nonlocal_aTolState, & - plastic_nonlocal_microstructure, & - plastic_nonlocal_LpAndItsTangent, & - plastic_nonlocal_dotState, & - plastic_nonlocal_deltaState, & - plastic_nonlocal_updateCompatibility, & - plastic_nonlocal_postResults - - private :: & - plastic_nonlocal_kinetics, & - plastic_nonlocal_dislocationstress - - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_init(fileUnit) -use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) -use math, only: math_Mandel3333to66, & - math_Voigt66to3333, & - math_mul3x3, & - math_transpose33 -use IO, only: IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF -use debug, only: debug_level, & - debug_constitutive, & - debug_levelBasic -use mesh, only: mesh_NcpElems, & - mesh_maxNips, & - mesh_maxNipNeighbors -use material, only: phase_plasticity, & - homogenization_maxNgrains, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_NONLOCAL_label, & - PLASTICITY_NONLOCAL_ID, & - plasticState, & - MATERIAL_partPhase ,& - material_phase -use lattice -use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - -implicit none -integer(pInt), intent(in) :: fileUnit - -!*** local variables -integer(pInt), allocatable, dimension(:) :: chunkPos -integer(pInt) :: phase, & - maxNinstances, & - maxTotalNslip, & - f, & ! index of my slip family - instance, & ! index of my instance of this plasticity - l, & - ns, & ! short notation for total number of active slip systems for the current instance - o, & ! index of my output - s, & ! index of my slip system - s1, & ! index of my slip system - s2, & ! index of my slip system - it, & ! index of my interaction type - t, & ! index of dislocation type - c, & ! index of dislocation character - Nchunks_SlipSlip = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, & - Nchunks_nonSchmid = 0_pInt, & - mySize = 0_pInt ! to suppress warnings, safe as init is called only once - character(len=65536) :: & - tag = '', & - line = '' - - integer(pInt) :: sizeState, sizeDotState,sizeDependentState, sizeDeltaState - - - integer(pInt) :: NofMyPhase - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONLOCAL_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) - if (maxNinstances == 0) return ! we don't have to do anything if there's no instance for this constitutive law - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstances - -!*** memory allocation for global variables - -allocate(plastic_nonlocal_sizeDotState(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizeDependentState(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizeState(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizePostResults(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizePostResult(maxval(phase_Noutput), maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_Noutput(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_output(maxval(phase_Noutput), maxNinstances)) - plastic_nonlocal_output = '' -allocate(plastic_nonlocal_outputID(maxval(phase_Noutput), maxNinstances), source=undefined_ID) -allocate(Nslip(lattice_maxNslipFamily,maxNinstances), source=0_pInt) -allocate(slipFamily(lattice_maxNslip,maxNinstances), source=0_pInt) -allocate(slipSystemLattice(lattice_maxNslip,maxNinstances), source=0_pInt) -allocate(totalNslip(maxNinstances), source=0_pInt) -allocate(atomicVolume(maxNinstances), source=0.0_pReal) -allocate(Dsd0(maxNinstances), source=-1.0_pReal) -allocate(selfDiffusionEnergy(maxNinstances), source=0.0_pReal) -allocate(aTolRho(maxNinstances), source=0.0_pReal) -allocate(aTolShear(maxNinstances), source=0.0_pReal) -allocate(significantRho(maxNinstances), source=0.0_pReal) -allocate(significantN(maxNinstances), source=0.0_pReal) -allocate(cutoffRadius(maxNinstances), source=-1.0_pReal) -allocate(doublekinkwidth(maxNinstances), source=0.0_pReal) -allocate(solidSolutionEnergy(maxNinstances), source=0.0_pReal) -allocate(solidSolutionSize(maxNinstances), source=0.0_pReal) -allocate(solidSolutionConcentration(maxNinstances), source=0.0_pReal) -allocate(pParam(maxNinstances), source=1.0_pReal) -allocate(qParam(maxNinstances), source=1.0_pReal) -allocate(viscosity(maxNinstances), source=0.0_pReal) -allocate(fattack(maxNinstances), source=0.0_pReal) -allocate(rhoSglScatter(maxNinstances), source=0.0_pReal) -allocate(rhoSglRandom(maxNinstances), source=0.0_pReal) -allocate(rhoSglRandomBinning(maxNinstances), source=1.0_pReal) -allocate(surfaceTransmissivity(maxNinstances), source=1.0_pReal) -allocate(grainboundaryTransmissivity(maxNinstances), source=-1.0_pReal) -allocate(CFLfactor(maxNinstances), source=2.0_pReal) -allocate(fEdgeMultiplication(maxNinstances), source=0.0_pReal) -allocate(linetensionEffect(maxNinstances), source=0.0_pReal) -allocate(edgeJogFactor(maxNinstances), source=1.0_pReal) -allocate(shortRangeStressCorrection(maxNinstances), source=.false.) -allocate(probabilisticMultiplication(maxNinstances), source=.false.) - -allocate(rhoSglEdgePos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoSglEdgeNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoSglScrewPos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoSglScrewNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoDipEdge0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoDipScrew0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) -allocate(lambda0PerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) -allocate(interactionSlipSlip(lattice_maxNinteraction,maxNinstances), source=0.0_pReal) -allocate(minDipoleHeightPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=-1.0_pReal) -allocate(peierlsStressPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=0.0_pReal) -allocate(nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstances), source=0.0_pReal) - - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through phases of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_SlipSlip = maxval(lattice_InteractionSlipSlip(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - endif - cycle - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then ! one of my phases. do not short-circuit here (.and. with next if statement). It's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('rho') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('delta') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('delta_sgl') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_sgl_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_pos_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_neg_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_pos_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_neg_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_pos_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_neg_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_pos_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_neg_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('delta_dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dip_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dip_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('excess_rho') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('excess_rho_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('excess_rho_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_forest') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_forest_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = shearrate_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_external') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_external_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_back') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_back_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resistance_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_gen') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_gen_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_gen_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl2dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl2dip_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl2dip_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_ath') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_ath_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_the') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_the_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_the_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_edgejogs') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_edgejogs_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_edge_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_edge_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_screw_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_screw_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipdirection.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipdirection.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectiony_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipdirection.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipnormal.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipnormal.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormaly_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipnormal.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_pos.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_pos.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_pos.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_neg.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_neg.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_neg.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_pos.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_pos.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_pos.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_neg.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_neg.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_neg.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('maximumdipoleheight_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('maximumdipoleheight_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear','accumulated_shear') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = accumulatedshear_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('dislocationstress') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = dislocationstress_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - case ('nslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do f = 1_pInt, Nchunks_SlipFamilies - Nslip(f,instance) = IO_intValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosgledgepos0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglEdgePos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosgledgeneg0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglEdgeNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosglscrewpos0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglScrewPos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosglscrewneg0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglScrewNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhodipedge0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoDipEdge0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhodipscrew0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoDipScrew0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('lambda0') - do f = 1_pInt, Nchunks_SlipFamilies - lambda0PerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('burgers') - do f = 1_pInt, Nchunks_SlipFamilies - burgersPerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('cutoffradius','r') - cutoffRadius(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('minimumdipoleheightedge','ddipminedge') - do f = 1_pInt, Nchunks_SlipFamilies - minDipoleHeightPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('minimumdipoleheightscrew','ddipminscrew') - do f = 1_pInt, Nchunks_SlipFamilies - minDipoleHeightPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('atomicvolume') - atomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('selfdiffusionprefactor','dsd0') - Dsd0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('selfdiffusionenergy','qsd') - selfDiffusionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('atol_rho','atol_density','absolutetolerancedensity','absolutetolerance_density') - aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('atol_shear','atol_plasticshear','atol_accumulatedshear','absolutetoleranceshear','absolutetolerance_shear') - aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('significantrho','significant_rho','significantdensity','significant_density') - significantRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('significantn','significant_n','significantdislocations','significant_dislcations') - significantN(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('interaction_slipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') - do it = 1_pInt,Nchunks_SlipSlip - interactionSlipSlip(it,instance) = IO_floatValue(line,chunkPos,1_pInt+it) - enddo - case('linetension','linetensioneffect','linetension_effect') - linetensionEffect(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('edgejog','edgejogs','edgejogeffect','edgejog_effect') - edgeJogFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('peierlsstressedge','peierlsstress_edge') - do f = 1_pInt, Nchunks_SlipFamilies - peierlsStressPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('peierlsstressscrew','peierlsstress_screw') - do f = 1_pInt, Nchunks_SlipFamilies - peierlsStressPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('doublekinkwidth') - doublekinkwidth(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('solidsolutionenergy') - solidSolutionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('solidsolutionsize') - solidSolutionSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('solidsolutionconcentration') - solidSolutionConcentration(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('p') - pParam(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('q') - qParam(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('viscosity','glideviscosity') - viscosity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('attackfrequency','fattack') - fattack(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('rhosglscatter') - rhoSglScatter(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('rhosglrandom') - rhoSglRandom(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('rhosglrandombinning') - rhoSglRandomBinning(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('surfacetransmissivity') - surfaceTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('grainboundarytransmissivity') - grainboundaryTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('cflfactor') - CFLfactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('fedgemultiplication','edgemultiplicationfactor','edgemultiplication') - fEdgeMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('shortrangestresscorrection') - shortRangeStressCorrection(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_label//')') - do f = 1_pInt,Nchunks_nonSchmid - nonSchmidCoeff(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('probabilisticmultiplication','randomsources','randommultiplication','discretesources') - probabilisticMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then - instance = phase_plasticityInstance(phase) - if (sum(Nslip(:,instance)) <= 0_pInt) & - call IO_error(211_pInt,ext_msg='Nslip ('//PLASTICITY_NONLOCAL_label//')') - do o = 1_pInt,maxval(phase_Noutput) - if(len(plastic_nonlocal_output(o,instance)) > 64_pInt) & - call IO_error(666_pInt) - enddo - do f = 1_pInt,lattice_maxNslipFamily - if (Nslip(f,instance) > 0_pInt) then - if (rhoSglEdgePos0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglEdgePos0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglEdgeNeg0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglEdgeNeg0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglScrewPos0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglScrewPos0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglScrewNeg0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglScrewNeg0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoDipEdge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoDipEdge0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoDipScrew0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoDipScrew0 ('//PLASTICITY_NONLOCAL_label//')') - if (burgersPerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='Burgers ('//PLASTICITY_NONLOCAL_label//')') - if (lambda0PerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='lambda0 ('//PLASTICITY_NONLOCAL_label//')') - if (minDipoleHeightPerSlipFamily(f,1,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='minimumDipoleHeightEdge ('//PLASTICITY_NONLOCAL_label//')') - if (minDipoleHeightPerSlipFamily(f,2,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='minimumDipoleHeightScrew ('//PLASTICITY_NONLOCAL_label//')') - if (peierlsStressPerSlipFamily(f,1,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='peierlsStressEdge ('//PLASTICITY_NONLOCAL_label//')') - if (peierlsStressPerSlipFamily(f,2,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='peierlsStressScrew ('//PLASTICITY_NONLOCAL_label//')') - endif - enddo - if (any(interactionSlipSlip(1:maxval(lattice_interactionSlipSlip(:,:,phase)),instance) < 0.0_pReal)) & - call IO_error(211_pInt,ext_msg='interaction_SlipSlip ('//PLASTICITY_NONLOCAL_label//')') - if (linetensionEffect(instance) < 0.0_pReal .or. linetensionEffect(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='linetension ('//PLASTICITY_NONLOCAL_label//')') - if (edgeJogFactor(instance) < 0.0_pReal .or. edgeJogFactor(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='edgejog ('//PLASTICITY_NONLOCAL_label//')') - if (cutoffRadius(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='r ('//PLASTICITY_NONLOCAL_label//')') - if (atomicVolume(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='atomicVolume ('//PLASTICITY_NONLOCAL_label//')') - if (Dsd0(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='selfDiffusionPrefactor ('//PLASTICITY_NONLOCAL_label//')') - if (selfDiffusionEnergy(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='selfDiffusionEnergy ('//PLASTICITY_NONLOCAL_label//')') - if (aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='aTol_rho ('//PLASTICITY_NONLOCAL_label//')') - if (aTolShear(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='aTol_shear ('//PLASTICITY_NONLOCAL_label//')') - if (significantRho(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='significantRho ('//PLASTICITY_NONLOCAL_label//')') - if (significantN(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='significantN ('//PLASTICITY_NONLOCAL_label//')') - if (doublekinkwidth(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='doublekinkwidth ('//PLASTICITY_NONLOCAL_label//')') - if (solidSolutionEnergy(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='solidSolutionEnergy ('//PLASTICITY_NONLOCAL_label//')') - if (solidSolutionSize(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='solidSolutionSize ('//PLASTICITY_NONLOCAL_label//')') - if (solidSolutionConcentration(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='solidSolutionConcentration ('//PLASTICITY_NONLOCAL_label//')') - if (pParam(instance) <= 0.0_pReal .or. pParam(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='p ('//PLASTICITY_NONLOCAL_label//')') - if (qParam(instance) < 1.0_pReal .or. qParam(instance) > 2.0_pReal) & - call IO_error(211_pInt,ext_msg='q ('//PLASTICITY_NONLOCAL_label//')') - if (viscosity(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='viscosity ('//PLASTICITY_NONLOCAL_label//')') - if (fattack(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='attackFrequency ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglScatter(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglScatter ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglRandom(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglRandom ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglRandomBinning(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglRandomBinning ('//PLASTICITY_NONLOCAL_label//')') - if (surfaceTransmissivity(instance) < 0.0_pReal .or. surfaceTransmissivity(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='surfaceTransmissivity ('//PLASTICITY_NONLOCAL_label//')') - if (grainboundaryTransmissivity(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='grainboundaryTransmissivity ('//PLASTICITY_NONLOCAL_label//')') - if (CFLfactor(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='CFLfactor ('//PLASTICITY_NONLOCAL_label//')') - if (fEdgeMultiplication(instance) < 0.0_pReal .or. fEdgeMultiplication(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='edgemultiplicationfactor ('//PLASTICITY_NONLOCAL_label//')') - - - !*** determine total number of active slip systems - Nslip(1:lattice_maxNslipFamily,instance) = min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase), & - Nslip(1:lattice_maxNslipFamily,instance) ) ! we can't use more slip systems per family than specified in lattice - totalNslip(instance) = sum(Nslip(1:lattice_maxNslipFamily,instance)) - endif myPhase -enddo sanityChecks - - -!*** allocation of variables whose size depends on the total number of active slip systems - -maxTotalNslip = maxval(totalNslip) - -allocate(iRhoU(maxTotalNslip,4,maxNinstances), source=0_pInt) -allocate(iRhoB(maxTotalNslip,4,maxNinstances), source=0_pInt) -allocate(iRhoD(maxTotalNslip,2,maxNinstances), source=0_pInt) -allocate(iV(maxTotalNslip,4,maxNinstances), source=0_pInt) -allocate(iD(maxTotalNslip,2,maxNinstances), source=0_pInt) -allocate(iGamma(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(iRhoF(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(iTauF(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(iTauB(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(burgers(maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(lambda0(maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(minDipoleHeight(maxTotalNslip,2,maxNinstances), source=-1.0_pReal) -allocate(forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(lattice2slip(1:3, 1:3, maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(sourceProbability(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=2.0_pReal) - -allocate(rhoDotFluxOutput(maxTotalNslip,8,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotMultiplicationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotSingle2DipoleGlideOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotAthermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotThermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotEdgeJogsOutput(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) - -allocate(compatibility(2,maxTotalNslip,maxTotalNslip,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(peierlsStress(maxTotalNslip,2,maxNinstances), source=0.0_pReal) -allocate(colinearSystem(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - NofMyPhase=count(material_phase==phase) - myPhase2: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID .and. NofMyPhase/=0) then - instance = phase_plasticityInstance(phase) - !*** Inverse lookup of my slip system family and the slip system in lattice - - l = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily - do s = 1_pInt,Nslip(f,instance) - l = l + 1_pInt - slipFamily(l,instance) = f - slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt, phase)) + s - enddo; enddo - - - !*** determine size of state array - - ns = totalNslip(instance) - - sizeDotState = int(size(BASICSTATES),pInt) * ns - sizeDependentState = int(size(DEPENDENTSTATES),pInt) * ns - sizeState = sizeDotState + sizeDependentState & - + int(size(OTHERSTATES),pInt) * ns - sizeDeltaState = sizeDotState - - !*** determine indices to state array - - l = 0_pInt - do t = 1_pInt,4_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iRhoU(s,t,instance) = l - enddo - enddo - do t = 1_pInt,4_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iRhoB(s,t,instance) = l - enddo - enddo - do c = 1_pInt,2_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iRhoD(s,c,instance) = l - enddo - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iGamma(s,instance) = l - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iRhoF(s,instance) = l - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iTauF(s,instance) = l - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iTauB(s,instance) = l - enddo - do t = 1_pInt,4_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iV(s,t,instance) = l - enddo - enddo - do c = 1_pInt,2_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iD(s,c,instance) = l - enddo - enddo - if (iD(ns,2,instance) /= sizeState) & ! check if last index is equal to size of state - call IO_error(0_pInt, ext_msg = 'state indices not properly set ('//PLASTICITY_NONLOCAL_label//')') - - - !*** determine size of postResults array - - outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) - select case(plastic_nonlocal_outputID(o,instance)) - case( rho_ID, & - delta_ID, & - rho_edge_ID, & - rho_screw_ID, & - rho_sgl_ID, & - delta_sgl_ID, & - rho_sgl_edge_ID, & - rho_sgl_edge_pos_ID, & - rho_sgl_edge_neg_ID, & - rho_sgl_screw_ID, & - rho_sgl_screw_pos_ID, & - rho_sgl_screw_neg_ID, & - rho_sgl_mobile_ID, & - rho_sgl_edge_mobile_ID, & - rho_sgl_edge_pos_mobile_ID, & - rho_sgl_edge_neg_mobile_ID, & - rho_sgl_screw_mobile_ID, & - rho_sgl_screw_pos_mobile_ID, & - rho_sgl_screw_neg_mobile_ID, & - rho_sgl_immobile_ID, & - rho_sgl_edge_immobile_ID, & - rho_sgl_edge_pos_immobile_ID, & - rho_sgl_edge_neg_immobile_ID, & - rho_sgl_screw_immobile_ID, & - rho_sgl_screw_pos_immobile_ID, & - rho_sgl_screw_neg_immobile_ID, & - rho_dip_ID, & - delta_dip_ID, & - rho_dip_edge_ID, & - rho_dip_screw_ID, & - excess_rho_ID, & - excess_rho_edge_ID, & - excess_rho_screw_ID, & - rho_forest_ID, & - shearrate_ID, & - resolvedstress_ID, & - resolvedstress_external_ID, & - resolvedstress_back_ID, & - resistance_ID, & - rho_dot_ID, & - rho_dot_sgl_ID, & - rho_dot_sgl_mobile_ID, & - rho_dot_dip_ID, & - rho_dot_gen_ID, & - rho_dot_gen_edge_ID, & - rho_dot_gen_screw_ID, & - rho_dot_sgl2dip_ID, & - rho_dot_sgl2dip_edge_ID, & - rho_dot_sgl2dip_screw_ID, & - rho_dot_ann_ath_ID, & - rho_dot_ann_the_ID, & - rho_dot_ann_the_edge_ID, & - rho_dot_ann_the_screw_ID, & - rho_dot_edgejogs_ID, & - rho_dot_flux_ID, & - rho_dot_flux_mobile_ID, & - rho_dot_flux_edge_ID, & - rho_dot_flux_screw_ID, & - velocity_edge_pos_ID, & - velocity_edge_neg_ID, & - velocity_screw_pos_ID, & - velocity_screw_neg_ID, & - slipdirectionx_ID, & - slipdirectiony_ID, & - slipdirectionz_ID, & - slipnormalx_ID, & - slipnormaly_ID, & - slipnormalz_ID, & - fluxdensity_edge_posx_ID, & - fluxdensity_edge_posy_ID, & - fluxdensity_edge_posz_ID, & - fluxdensity_edge_negx_ID, & - fluxdensity_edge_negy_ID, & - fluxdensity_edge_negz_ID, & - fluxdensity_screw_posx_ID, & - fluxdensity_screw_posy_ID, & - fluxdensity_screw_posz_ID, & - fluxdensity_screw_negx_ID, & - fluxdensity_screw_negy_ID, & - fluxdensity_screw_negz_ID, & - maximumdipoleheight_edge_ID, & - maximumdipoleheight_screw_ID, & - accumulatedshear_ID ) - mySize = totalNslip(instance) - case(dislocationstress_ID) - mySize = 6_pInt - case default - end select - - if (mySize > 0_pInt) then ! any meaningful output found - plastic_nonlocal_sizePostResult(o,instance) = mySize - plastic_nonlocal_sizePostResults(instance) = plastic_nonlocal_sizePostResults(instance) + mySize - endif - enddo outputsLoop - - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_nonlocal_sizePostResults(instance) - plasticState(phase)%nonlocal = .true. - plasticState(phase)%nSlip = totalNslip(instance) - plasticState(phase)%nTwin = 0_pInt - plasticState(phase)%nTrans= 0_pInt - allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) - - do s1 = 1_pInt,ns - f = slipFamily(s1,instance) - - !*** burgers vector, mean free path prefactor and minimum dipole distance for each slip system - - burgers(s1,instance) = burgersPerSlipFamily(f,instance) - lambda0(s1,instance) = lambda0PerSlipFamily(f,instance) - minDipoleHeight(s1,1:2,instance) = minDipoleHeightPerSlipFamily(f,1:2,instance) - peierlsStress(s1,1:2,instance) = peierlsStressPerSlipFamily(f,1:2,instance) - - do s2 = 1_pInt,ns - - !*** calculation of forest projections for edge and screw dislocations. s2 acts as forest for s1 - - forestProjectionEdge(s1,s2,instance) & - = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & - lattice_st(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of edge dislocations is the projection of (t = b x n) onto the slip normal of the respective slip plane - - forestProjectionScrew(s1,s2,instance) & - = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & - lattice_sd(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of screw dislocations is the projection of b onto the slip normal of the respective splip plane - - !*** calculation of interaction matrices - - interactionMatrixSlipSlip(s1,s2,instance) & - = interactionSlipSlip(lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & - slipSystemLattice(s2,instance), & - phase), instance) - - !*** colinear slip system (only makes sense for fcc like it is defined here) - - if (lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & - slipSystemLattice(s2,instance), & - phase) == 3_pInt) then - colinearSystem(s1,instance) = s2 - endif - - enddo - - !*** rotation matrix from lattice configuration to slip system - - lattice2slip(1:3,1:3,s1,instance) & - = math_transpose33( reshape([ lattice_sd(1:3, slipSystemLattice(s1,instance), phase), & - -lattice_st(1:3, slipSystemLattice(s1,instance), phase), & - lattice_sn(1:3, slipSystemLattice(s1,instance), phase)], [3,3])) - enddo - - - !*** combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) - !* four types t: - !* 1) positive screw at positive resolved stress - !* 2) positive screw at negative resolved stress - !* 3) negative screw at positive resolved stress - !* 4) negative screw at negative resolved stress - - do s = 1_pInt,ns - do l = 1_pInt,lattice_NnonSchmid(phase) - nonSchmidProjection(1:3,1:3,1,s,instance) = nonSchmidProjection(1:3,1:3,1,s,instance) & - + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l,slipSystemLattice(s,instance),phase) - nonSchmidProjection(1:3,1:3,2,s,instance) = nonSchmidProjection(1:3,1:3,2,s,instance) & - + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l+1,slipSystemLattice(s,instance),phase) - enddo - nonSchmidProjection(1:3,1:3,3,s,instance) = -nonSchmidProjection(1:3,1:3,2,s,instance) - nonSchmidProjection(1:3,1:3,4,s,instance) = -nonSchmidProjection(1:3,1:3,1,s,instance) - forall (t = 1:4) & - nonSchmidProjection(1:3,1:3,t,s,instance) = nonSchmidProjection(1:3,1:3,t,s,instance) & - + lattice_Sslip(1:3,1:3,1,slipSystemLattice(s,instance),phase) - enddo - - call plastic_nonlocal_aTolState(phase,instance) - endif myPhase2 - - enddo initializeInstances - -end subroutine plastic_nonlocal_init - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- - -subroutine plastic_nonlocal_stateInit() -use IO, only: IO_error -use lattice, only: lattice_maxNslipFamily -use math, only: math_sampleGaussVar -use mesh, only: mesh_ipVolume, & - mesh_NcpElems, & - mesh_element, & - FE_Nips, & - FE_geomtype -use material, only: material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticity ,& - PLASTICITY_NONLOCAL_ID -implicit none - -integer(pInt) :: e, & - i, & - ns, & ! short notation for total number of active slip systems - f, & ! index of lattice family - from, & - upto, & - s, & ! index of slip system - t, & - j, & - instance, & - maxNinstances -real(pReal), dimension(2) :: noise -real(pReal), dimension(4) :: rnd -real(pReal) meanDensity, & - totalVolume, & - densityBinning, & - minimumIpVolume - -maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) - -do instance = 1_pInt,maxNinstances - ns = totalNslip(instance) - - ! randomly distribute dislocation segments on random slip system and of random type in the volume - if (rhoSglRandom(instance) > 0.0_pReal) then - - ! get the total volume of the instance - - minimumIpVolume = huge(1.0_pReal) - totalVolume = 0.0_pReal - do e = 1_pInt,mesh_NcpElems - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & - .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then - totalVolume = totalVolume + mesh_ipVolume(i,e) - minimumIpVolume = min(minimumIpVolume, mesh_ipVolume(i,e)) - endif - enddo - enddo - densityBinning = rhoSglRandomBinning(instance) / minimumIpVolume ** (2.0_pReal / 3.0_pReal) - - ! subsequently fill random ips with dislocation segments until we reach the desired overall density - - meanDensity = 0.0_pReal - do while(meanDensity < rhoSglRandom(instance)) - call random_number(rnd) - e = nint(rnd(1)*real(mesh_NcpElems,pReal)+0.5_pReal,pInt) - i = nint(rnd(2)*real(FE_Nips(FE_geomtype(mesh_element(2,e))),pReal)+0.5_pReal,pInt) - if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & - .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then - s = nint(rnd(3)*real(ns,pReal)+0.5_pReal,pInt) - t = nint(rnd(4)*4.0_pReal+0.5_pReal,pInt) - meanDensity = meanDensity + densityBinning * mesh_ipVolume(i,e) / totalVolume - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) = & - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) & - + densityBinning - endif - enddo - ! homogeneous distribution of density with some noise - else - do e = 1_pInt,mesh_NcpElems - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & - .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then - do f = 1_pInt,lattice_maxNslipFamily - from = 1_pInt + sum(Nslip(1:f-1_pInt,instance)) - upto = sum(Nslip(1:f,instance)) - do s = from,upto - do j = 1_pInt,2_pInt - noise(j) = math_sampleGaussVar(0.0_pReal, rhoSglScatter(instance)) - enddo - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,1,instance),phasememberAt(1,i,e)) = & - rhoSglEdgePos0(f,instance) + noise(1) - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,2,instance),phasememberAt(1,i,e)) = & - rhoSglEdgeNeg0(f,instance) + noise(1) - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,3,instance),phasememberAt(1,i,e)) = & - rhoSglScrewPos0(f,instance) + noise(2) - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,4,instance),phasememberAt(1,i,e)) = & - rhoSglScrewNeg0(f,instance) + noise(2) - enddo - plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,1,instance),phasememberAt(1,i,e)) = & - rhoDipEdge0(f,instance) - plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,2,instance),phasememberAt(1,i,e)) = & - rhoDipScrew0(f,instance) - enddo - endif - enddo - enddo - endif -enddo - -end subroutine plastic_nonlocal_stateInit - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - integer(pInt) :: & - ns, & - t, c - - ns = totalNslip(instance) - forall (t = 1_pInt:4_pInt) - plasticState(ph)%aTolState(iRhoU(1:ns,t,instance)) = aTolRho(instance) - plasticState(ph)%aTolState(iRhoB(1:ns,t,instance)) = aTolRho(instance) - end forall - forall (c = 1_pInt:2_pInt) & - plasticState(ph)%aTolState(iRhoD(1:ns,c,instance)) = aTolRho(instance) - - plasticState(ph)%aTolState(iGamma(1:ns,instance)) = aTolShear(instance) - -end subroutine plastic_nonlocal_aTolState - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates quantities characterizing the microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_microstructure(Fe, Fp, ip, el) -use IO, only: & - IO_error -use math, only: & - pi, & - math_mul33x3, & - math_mul3x3, & - math_inv33, & - math_transpose33 -use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use mesh, only: & - mesh_element, & - mesh_ipNeighborhood, & - mesh_ipCoordinates, & - mesh_ipVolume, & - mesh_ipAreaNormal, & - mesh_ipArea, & - FE_NipNeighbors, & - mesh_maxNipNeighbors, & - FE_geomtype, & - FE_celltype -use material, only: & - material_phase, & - phase_localPlasticity, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance -use lattice, only: & - lattice_sd, & - lattice_st, & - lattice_mu, & - lattice_nu, & - lattice_structure, & - LATTICE_bcc_ID, & - LATTICE_fcc_ID - -implicit none - -integer(pInt), intent(in) :: ip, & ! current integration point - el ! current element -real(pReal), dimension(3,3), intent(in) :: & - Fe, & ! elastic deformation gradient - Fp ! elastic deformation gradient - - integer(pInt) :: & - ph, & !< phase - of, & !< offset - np, & !< neighbor phase - no !< nieghbor offset - -integer(pInt) neighbor_el, & ! element number of neighboring material point - neighbor_ip, & ! integration point of neighboring material point - instance, & ! my instance of this plasticity - neighbor_instance, & ! instance of this plasticity of neighboring material point - neighbor_phase, & - ns, & ! total number of active slip systems at my material point - neighbor_ns, & ! total number of active slip systems at neighboring material point - c, & ! index of dilsocation character (edge, screw) - s, & ! slip system index - t, & ! index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) - dir, & - n, & - nRealNeighbors ! number of really existing neighbors -integer(pInt), dimension(2) :: neighbors -real(pReal) FVsize, & - correction, & - myRhoForest -real(pReal), dimension(2) :: rhoExcessGradient, & - rhoExcessGradient_over_rho, & - rhoTotal -real(pReal), dimension(3) :: rhoExcessDifferences, & - normal_latticeConf -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoForest, & ! forest dislocation density - tauBack, & ! back stress from pileup on same slip system - tauThreshold ! threshold shear stress -real(pReal), dimension(3,3) :: invFe, & ! inverse of elastic deformation gradient - invFp, & ! inverse of plastic deformation gradient - connections, & - invConnections -real(pReal), dimension(3,mesh_maxNipNeighbors) :: & - connection_latticeConf -real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoExcess -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - rhoDip ! dipole dislocation density (edge, screw) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))), & - totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - myInteractionMatrix ! corrected slip interaction matrix -real(pReal), dimension(2,maxval(totalNslip),mesh_maxNipNeighbors) :: & - neighbor_rhoExcess, & ! excess density at neighboring material point - neighbor_rhoTotal ! total density at neighboring material point -real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - m ! direction of dislocation motion - -ph = phaseAt(1,ip,el) -of = phasememberAt(1,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - -!*** get basic states - - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities - -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal -where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoDip) < significantRho(instance)) & - rhoDip = 0.0_pReal - -!*** calculate the forest dislocation density -!*** (= projection of screw and edge dislocations) - -forall (s = 1_pInt:ns) & - rhoForest(s) = dot_product((sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1)), & - forestProjectionEdge(s,1:ns,instance)) & - + dot_product((sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2)), & - forestProjectionScrew(s,1:ns,instance)) - - -!*** calculate the threshold shear stress for dislocation slip -!*** coefficients are corrected for the line tension effect -!*** (see Kubin,Devincre,Hoc; 2008; Modeling dislocation storage rates and mean free paths in face-centered cubic crystals) - -myInteractionMatrix = 0.0_pReal -myInteractionMatrix(1:ns,1:ns) = interactionMatrixSlipSlip(1:ns,1:ns,instance) -if (lattice_structure(ph) == LATTICE_bcc_ID .or. lattice_structure(ph) == LATTICE_fcc_ID) then ! only fcc and bcc - do s = 1_pInt,ns - myRhoForest = max(rhoForest(s),significantRho(instance)) - correction = ( 1.0_pReal - linetensionEffect(instance) & - + linetensionEffect(instance) & - * log(0.35_pReal * burgers(s,instance) * sqrt(myRhoForest)) & - / log(0.35_pReal * burgers(s,instance) * 1e6_pReal)) ** 2.0_pReal - myInteractionMatrix(s,1:ns) = correction * myInteractionMatrix(s,1:ns) - enddo -endif -forall (s = 1_pInt:ns) & - tauThreshold(s) = lattice_mu(ph) * burgers(s,instance) & - * sqrt(dot_product((sum(abs(rhoSgl),2) + sum(abs(rhoDip),2)), myInteractionMatrix(s,1:ns))) - - -!*** calculate the dislocation stress of the neighboring excess dislocation densities -!*** zero for material points of local plasticity - -tauBack = 0.0_pReal - -if (.not. phase_localPlasticity(ph) .and. shortRangeStressCorrection(instance)) then - invFe = math_inv33(Fe) - invFp = math_inv33(Fp) - rhoExcess(1,1:ns) = rhoSgl(1:ns,1) - rhoSgl(1:ns,2) - rhoExcess(2,1:ns) = rhoSgl(1:ns,3) - rhoSgl(1:ns,4) - FVsize = mesh_ipVolume(ip,el) ** (1.0_pReal/3.0_pReal) - - !* loop through my neighborhood and get the connection vectors (in lattice frame) and the excess densities - - nRealNeighbors = 0_pInt - neighbor_rhoTotal = 0.0_pReal - do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) - neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - np = phaseAt(1,neighbor_ip,neighbor_el) - no = phasememberAt(1,neighbor_ip,neighbor_el) - if (neighbor_el > 0 .and. neighbor_ip > 0) then - neighbor_phase = material_phase(1,neighbor_ip,neighbor_el) - neighbor_instance = phase_plasticityInstance(neighbor_phase) - neighbor_ns = totalNslip(neighbor_instance) - if (.not. phase_localPlasticity(neighbor_phase) & - .and. neighbor_instance == instance) then ! same instance should be same structure - if (neighbor_ns == ns) then - nRealNeighbors = nRealNeighbors + 1_pInt - forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - - neighbor_rhoExcess(c,s,n) = & - max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles - - max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) ! negative mobiles - neighbor_rhoTotal(c,s,n) = & - max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles - + max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) & ! negative mobiles - + abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads - + abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance), no)) & ! negative deads - + max(plasticState(np)%state(iRhoD(s,c,neighbor_instance), no), 0.0_pReal) ! dipoles - - endforall - connection_latticeConf(1:3,n) = & - math_mul33x3(invFe, mesh_ipCoordinates(1:3,neighbor_ip,neighbor_el) & - - mesh_ipCoordinates(1:3,ip,el)) - normal_latticeConf = math_mul33x3(math_transpose33(invFp), mesh_ipAreaNormal(1:3,n,ip,el)) - if (math_mul3x3(normal_latticeConf,connection_latticeConf(1:3,n)) < 0.0_pReal) then ! neighboring connection points in opposite direction to face normal: must be periodic image - connection_latticeConf(1:3,n) = normal_latticeConf * mesh_ipVolume(ip,el) & - / mesh_ipArea(n,ip,el) ! instead take the surface normal scaled with the diameter of the cell - endif - else - ! different number of active slip systems - call IO_error(-1_pInt,ext_msg='different number of active slip systems in neighboring IPs of same crystal structure') - endif - else - ! local neighbor or different lattice structure or different constitution instance -> use central values instead - connection_latticeConf(1:3,n) = 0.0_pReal - neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess - endif - else - ! free surface -> use central values instead - connection_latticeConf(1:3,n) = 0.0_pReal - neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess - endif - enddo - - - !* loop through the slip systems and calculate the dislocation gradient by - !* 1. interpolation of the excess density in the neighorhood - !* 2. interpolation of the dead dislocation density in the central volume - - m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) - m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) - - do s = 1_pInt,ns - - !* gradient from interpolation of neighboring excess density - - do c = 1_pInt,2_pInt - do dir = 1_pInt,3_pInt - neighbors(1) = 2_pInt * dir - 1_pInt - neighbors(2) = 2_pInt * dir - connections(dir,1:3) = connection_latticeConf(1:3,neighbors(1)) & - - connection_latticeConf(1:3,neighbors(2)) - rhoExcessDifferences(dir) = neighbor_rhoExcess(c,s,neighbors(1)) & - - neighbor_rhoExcess(c,s,neighbors(2)) - enddo - invConnections = math_inv33(connections) - if (all(abs(invConnections) <= tiny(0.0_pReal))) & ! check for failed in version (math_inv33 returns 0) and avoid floating point equality comparison - call IO_error(-1_pInt,ext_msg='back stress calculation: inversion error') - rhoExcessGradient(c) = math_mul3x3(m(1:3,s,c), & - math_mul33x3(invConnections,rhoExcessDifferences)) - enddo - - !* plus gradient from deads - - do t = 1_pInt,4_pInt - c = (t - 1_pInt) / 2_pInt + 1_pInt - rhoExcessGradient(c) = rhoExcessGradient(c) + rhoSgl(s,t+4_pInt) / FVsize - enddo - - !* normalized with the total density - - rhoExcessGradient_over_rho = 0.0_pReal - forall (c = 1_pInt:2_pInt) & - rhoTotal(c) = (sum(abs(rhoSgl(s,[2*c-1,2*c,2*c+3,2*c+4]))) + rhoDip(s,c) & - + sum(neighbor_rhoTotal(c,s,:))) / real(1_pInt + nRealNeighbors,pReal) - forall (c = 1_pInt:2_pInt, rhoTotal(c) > 0.0_pReal) & - rhoExcessGradient_over_rho(c) = rhoExcessGradient(c) / rhoTotal(c) - - !* gives the local stress correction when multiplied with a factor - - tauBack(s) = - lattice_mu(ph) * burgers(s,instance) / (2.0_pReal * pi) & - * (rhoExcessGradient_over_rho(1) / (1.0_pReal - lattice_nu(ph)) & - + rhoExcessGradient_over_rho(2)) - - enddo -endif - - -!*** set dependent states -plasticState(ph)%state(iRhoF(1:ns,instance),of) = rhoForest -plasticState(ph)%state(iTauF(1:ns,instance),of) = tauThreshold -plasticState(ph)%state(iTauB(1:ns,instance),of) = tauBack - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_microstructure at el ip ',el,ip - write(6,'(a,/,12x,12(e10.3,1x))') '<< CONST >> rhoForest', rhoForest - write(6,'(a,/,12x,12(f10.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold/1e6 - write(6,'(a,/,12x,12(f10.5,1x),/)') '<< CONST >> tauBack / MPa', tauBack/1e6 - endif -#endif - -end subroutine plastic_nonlocal_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates kinetics -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_kinetics(v, dv_dtau, dv_dtauNS, tau, tauNS, & - tauThreshold, c, Temperature, ip, el) - -use debug, only: debug_level, & - debug_constitutive, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use material, only: material_phase, & - phase_plasticityInstance - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el, & !< current element number - c !< dislocation character (1:edge, 2:screw) -real(pReal), intent(in) :: Temperature !< temperature -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & - intent(in) :: tau, & !< resolved external shear stress (without non Schmid effects) - tauNS, & !< resolved external shear stress (including non Schmid effects) - tauThreshold !< threshold shear stress - -!*** output variables -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & - intent(out) :: v, & !< velocity - dv_dtau, & !< velocity derivative with respect to resolved shear stress (without non Schmid contributions) - dv_dtauNS !< velocity derivative with respect to resolved shear stress (including non Schmid contributions) - -!*** local variables -integer(pInt) :: instance, & !< current instance of this plasticity - ns, & !< short notation for the total number of active slip systems - s !< index of my current slip system -real(pReal) tauRel_P, & - tauRel_S, & - tauEff, & !< effective shear stress - tPeierls, & !< waiting time in front of a peierls barriers - tSolidSolution, & !< waiting time in front of a solid solution obstacle - vViscous, & !< viscous glide velocity - dtPeierls_dtau, & !< derivative with respect to resolved shear stress - dtSolidSolution_dtau, & !< derivative with respect to resolved shear stress - meanfreepath_S, & !< mean free travel distance for dislocations between two solid solution obstacles - meanfreepath_P, & !< mean free travel distance for dislocations between two Peierls barriers - jumpWidth_P, & !< depth of activated area - jumpWidth_S, & !< depth of activated area - activationLength_P, & !< length of activated dislocation line - activationLength_S, & !< length of activated dislocation line - activationVolume_P, & !< volume that needs to be activated to overcome barrier - activationVolume_S, & !< volume that needs to be activated to overcome barrier - activationEnergy_P, & !< energy that is needed to overcome barrier - activationEnergy_S, & !< energy that is needed to overcome barrier - criticalStress_P, & !< maximum obstacle strength - criticalStress_S, & !< maximum obstacle strength - mobility !< dislocation mobility - - -instance = phase_plasticityInstance(material_phase(1_pInt,ip,el)) -ns = totalNslip(instance) - -v = 0.0_pReal -dv_dtau = 0.0_pReal -dv_dtauNS = 0.0_pReal - - -if (Temperature > 0.0_pReal) then - do s = 1_pInt,ns - if (abs(tau(s)) > tauThreshold(s)) then - - !* Peierls contribution - !* Effective stress includes non Schmid constributions - !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity - - tauEff = max(0.0_pReal, abs(tauNS(s)) - tauThreshold(s)) ! ensure that the effective stress is positive - meanfreepath_P = burgers(s,instance) - jumpWidth_P = burgers(s,instance) - activationLength_P = doublekinkwidth(instance) * burgers(s,instance) - activationVolume_P = activationLength_P * jumpWidth_P * burgers(s,instance) - criticalStress_P = peierlsStress(s,c,instance) - activationEnergy_P = criticalStress_P * activationVolume_P - tauRel_P = min(1.0_pReal, tauEff / criticalStress_P) ! ensure that the activation probability cannot become greater than one - tPeierls = 1.0_pReal / fattack(instance) & - * exp(activationEnergy_P / (KB * Temperature) & - * (1.0_pReal - tauRel_P**pParam(instance))**qParam(instance)) - if (tauEff < criticalStress_P) then - dtPeierls_dtau = tPeierls * pParam(instance) * qParam(instance) * activationVolume_P / (KB * Temperature) & - * (1.0_pReal - tauRel_P**pParam(instance))**(qParam(instance)-1.0_pReal) & - * tauRel_P**(pParam(instance)-1.0_pReal) - else - dtPeierls_dtau = 0.0_pReal - endif - - - !* Contribution from solid solution strengthening - !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity - - tauEff = abs(tau(s)) - tauThreshold(s) - meanfreepath_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) - jumpWidth_S = solidSolutionSize(instance) * burgers(s,instance) - activationLength_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) - activationVolume_S = activationLength_S * jumpWidth_S * burgers(s,instance) - activationEnergy_S = solidSolutionEnergy(instance) - criticalStress_S = activationEnergy_S / activationVolume_S - tauRel_S = min(1.0_pReal, tauEff / criticalStress_S) ! ensure that the activation probability cannot become greater than one - tSolidSolution = 1.0_pReal / fattack(instance) & - * exp(activationEnergy_S / (KB * Temperature) & - * (1.0_pReal - tauRel_S**pParam(instance))**qParam(instance)) - if (tauEff < criticalStress_S) then - dtSolidSolution_dtau = tSolidSolution * pParam(instance) * qParam(instance) & - * activationVolume_S / (KB * Temperature) & - * (1.0_pReal - tauRel_S**pParam(instance))**(qParam(instance)-1.0_pReal) & - * tauRel_S**(pParam(instance)-1.0_pReal) - else - dtSolidSolution_dtau = 0.0_pReal - endif - - - !* viscous glide velocity - - tauEff = abs(tau(s)) - tauThreshold(s) - mobility = burgers(s,instance) / viscosity(instance) - vViscous = mobility * tauEff - - - !* Mean velocity results from waiting time at peierls barriers and solid solution obstacles with respective meanfreepath of - !* free flight at glide velocity in between. - !* adopt sign from resolved stress - - v(s) = sign(1.0_pReal,tau(s)) & - / (tPeierls / meanfreepath_P + tSolidSolution / meanfreepath_S + 1.0_pReal / vViscous) - dv_dtau(s) = v(s) * v(s) * (dtSolidSolution_dtau / meanfreepath_S & - + mobility / (vViscous * vViscous)) - dv_dtauNS(s) = v(s) * v(s) * dtPeierls_dtau / meanfreepath_P - endif - enddo -endif - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_kinetics at el ip',el,ip - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold / 1e6_pReal - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tau / MPa', tau / 1e6_pReal - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauNS / MPa', tauNS / 1e6_pReal - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> v / 1e-3m/s', v * 1e3 - write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtau', dv_dtau - write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtauNS', dv_dtauNS - endif -#endif - -end subroutine plastic_nonlocal_kinetics - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_LpAndItsTangent(Lp, dLp_dTstar99, Tstar_v, Temperature, ip, el) - -use math, only: math_Plain3333to99, & - math_mul6x6, & - math_mul33xx33, & - math_Mandel6to33 -use debug, only: debug_level, & - debug_constitutive, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use material, only: material_phase, & - plasticState, & - phaseAt, phasememberAt,& - phase_plasticityInstance -use lattice, only: lattice_Sslip, & - lattice_Sslip_v, & - lattice_NnonSchmid -use mesh, only: mesh_ipVolume - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el !< current element number -real(pReal), intent(in) :: Temperature !< temperature -real(pReal), dimension(6), intent(in) :: Tstar_v !< 2nd Piola-Kirchhoff stress in Mandel notation - - -!*** output variables -real(pReal), dimension(3,3), intent(out) :: Lp !< plastic velocity gradient -real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 !< derivative of Lp with respect to Tstar (9x9 matrix) - -!*** local variables -integer(pInt) instance, & !< current instance of this plasticity - ns, & !< short notation for the total number of active slip systems - i, & - j, & - k, & - l, & - ph, & !phase number - of, & !offset - t, & !< dislocation type - s, & !< index of my current slip system - sLattice !< index of my current slip system according to lattice order -real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 !< derivative of Lp with respect to Tstar (3x3x3x3 matrix) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl !< single dislocation densities (including blocked) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - v, & !< velocity - tauNS, & !< resolved shear stress including non Schmid and backstress terms - dv_dtau, & !< velocity derivative with respect to the shear stress - dv_dtauNS !< velocity derivative with respect to the shear stress -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - tau, & !< resolved shear stress including backstress terms - gdotTotal, & !< shear rate - tauBack, & !< back stress from dislocation gradients on same slip system - tauThreshold !< threshold shear stress -!*** shortcut for mapping -ph = phaseAt(1_pInt,ip,el) -of = phasememberAt(1_pInt,ip,el) - -!*** initialize local variables - -Lp = 0.0_pReal -dLp_dTstar3333 = 0.0_pReal - -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - - -!*** shortcut to state variables - - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - - rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) -endforall -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal - -tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) -tauThreshold = plasticState(ph)%state(iTauF(1:ns,instance),of) - - -!*** get resolved shear stress -!*** for screws possible non-schmid contributions are also taken into account - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) - tauNS(s,1) = tau(s) - tauNS(s,2) = tau(s) - if (tau(s) > 0.0_pReal) then - tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,1,s,instance)) - tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,3,s,instance)) - else - tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,2,s,instance)) - tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,4,s,instance)) - endif -enddo -forall (t = 1_pInt:4_pInt) & - tauNS(1:ns,t) = tauNS(1:ns,t) + tauBack ! add backstress -tau = tau + tauBack ! add backstress - - -!*** get dislocation velocity and its tangent and store the velocity in the state array - -! edges -call plastic_nonlocal_kinetics(v(1:ns,1), dv_dtau(1:ns,1), dv_dtauNS(1:ns,1), & - tau(1:ns), tauNS(1:ns,1), tauThreshold(1:ns), & - 1_pInt, Temperature, ip, el) -v(1:ns,2) = v(1:ns,1) -dv_dtau(1:ns,2) = dv_dtau(1:ns,1) -dv_dtauNS(1:ns,2) = dv_dtauNS(1:ns,1) - -!screws -if (lattice_NnonSchmid(ph) == 0_pInt) then ! no non-Schmid contributions - forall(t = 3_pInt:4_pInt) - v(1:ns,t) = v(1:ns,1) - dv_dtau(1:ns,t) = dv_dtau(1:ns,1) - dv_dtauNS(1:ns,t) = dv_dtauNS(1:ns,1) - endforall -else ! take non-Schmid contributions into account - do t = 3_pInt,4_pInt - call plastic_nonlocal_kinetics(v(1:ns,t), dv_dtau(1:ns,t), dv_dtauNS(1:ns,t), & - tau(1:ns), tauNS(1:ns,t), tauThreshold(1:ns), & - 2_pInt , Temperature, ip, el) - enddo -endif - - -!*** store velocity in state - -forall (t = 1_pInt:4_pInt) & - plasticState(ph)%state(iV(1:ns,t,instance),of) = v(1:ns,t) -!*** Bauschinger effect - -forall (s = 1_pInt:ns, t = 5_pInt:8_pInt, rhoSgl(s,t) * v(s,t-4_pInt) < 0.0_pReal) & - rhoSgl(s,t-4_pInt) = rhoSgl(s,t-4_pInt) + abs(rhoSgl(s,t)) - - -!*** Calculation of Lp and its tangent - -gdotTotal = sum(rhoSgl(1:ns,1:4) * v, 2) * burgers(1:ns,instance) - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - Lp = Lp + gdotTotal(s) * lattice_Sslip(1:3,1:3,1,sLattice,ph) - - ! Schmid contributions to tangent - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & - + lattice_Sslip(i,j,1,sLattice,ph) * lattice_Sslip(k,l,1,sLattice,ph) & - * sum(rhoSgl(s,1:4) * dv_dtau(s,1:4)) * burgers(s,instance) - - ! non Schmid contributions to tangent - if (tau(s) > 0.0_pReal) then - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & - + lattice_Sslip(i,j,1,sLattice,ph) & - * ( nonSchmidProjection(k,l,1,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & - + nonSchmidProjection(k,l,3,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & - * burgers(s,instance) - else - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & - + lattice_Sslip(i,j,1,sLattice,ph) & - * ( nonSchmidProjection(k,l,2,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & - + nonSchmidProjection(k,l,4,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & - * burgers(s,instance) - endif -enddo -dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_LpandItsTangent at el ip',el,ip - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> gdot total / 1e-3',gdotTotal*1e3_pReal - write(6,'(a,/,3(12x,3(f12.7,1x),/))') '<< CONST >> Lp',transpose(Lp) - endif -#endif - -end subroutine plastic_nonlocal_LpAndItsTangent - - - -!-------------------------------------------------------------------------------------------------- -!> @brief (instantaneous) incremental change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_deltaState(Tstar_v,ip,el) -use debug, only: debug_level, & - debug_constitutive, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use math, only: pi, & - math_mul6x6 -use lattice, only: lattice_Sslip_v ,& - lattice_mu, & - lattice_nu -use mesh, only: mesh_ipVolume -use material, only: material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - -implicit none -integer(pInt), intent(in) :: ip, & ! current grain number - el ! current element number -real(pReal), dimension(6), intent(in) :: Tstar_v ! current 2nd Piola-Kirchhoff stress in Mandel notation - - - integer(pInt) :: & - ph, & !< phase - of !< offset - -integer(pInt) ::instance, & ! current instance of this plasticity - ns, & ! short notation for the total number of active slip systems - c, & ! character of dislocation - t, & ! type of dislocation - s, & ! index of my current slip system - sLattice ! index of my current slip system according to lattice order -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),10) :: & - deltaRho, & ! density increment - deltaRhoRemobilization, & ! density increment by remobilization - deltaRhoDipole2SingleStress ! density increment by dipole dissociation (by stress change) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),8) :: & - rhoSgl ! current single dislocation densities (positive/negative screw and edge without dipoles) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),4) :: & - v ! dislocation glide velocity -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - tau, & ! current resolved shear stress - tauBack ! current back stress from pileups on same slip system -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),2) :: & - rhoDip, & ! current dipole dislocation densities (screw and edge dipoles) - dLower, & ! minimum stable dipole distance for edges and screws - dUpper, & ! current maximum stable dipole distance for edges and screws - dUpperOld, & ! old maximum stable dipole distance for edges and screws - deltaDUpper ! change in maximum stable dipole distance for edges and screws - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_deltaState at el ip ',el,ip -#endif - - ph = phaseAt(1,ip,el) - of = phasememberAt(1,ip,el) - instance = phase_plasticityInstance(ph) - ns = totalNslip(instance) - - -!*** shortcut to state variables - - forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) - v(s,t) = plasticState(ph)%state(iV(s,t,instance),of) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities - dUpperOld(s,c) = plasticState(ph)%state(iD(s,c,instance),of) -endforall - tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) - -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal -where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoDip) < significantRho(instance)) & - rhoDip = 0.0_pReal - - - - -!**************************************************************************** -!*** dislocation remobilization (bauschinger effect) - -deltaRhoRemobilization = 0.0_pReal -do t = 1_pInt,4_pInt - do s = 1_pInt,ns - if (rhoSgl(s,t+4_pInt) * v(s,t) < 0.0_pReal) then - deltaRhoRemobilization(s,t) = abs(rhoSgl(s,t+4_pInt)) - rhoSgl(s,t) = rhoSgl(s,t) + abs(rhoSgl(s,t+4_pInt)) - deltaRhoRemobilization(s,t+4_pInt) = - rhoSgl(s,t+4_pInt) - rhoSgl(s,t+4_pInt) = 0.0_pReal - endif - enddo -enddo - - - -!**************************************************************************** -!*** calculate dipole formation and dissociation by stress change - -!*** calculate limits for stable dipole height - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) - if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal -enddo -dLower = minDipoleHeight(1:ns,1:2,instance) -dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & - / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) -dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) / (4.0_pReal * pi * abs(tau)) - - -forall (c = 1_pInt:2_pInt) - where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& - abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & - + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & - dUpper(1:ns,c)) -end forall -dUpper = max(dUpper,dLower) -deltaDUpper = dUpper - dUpperOld - - -!*** dissociation by stress increase -deltaRhoDipole2SingleStress = 0.0_pReal -forall (c=1_pInt:2_pInt, s=1_pInt:ns, deltaDUpper(s,c) < 0.0_pReal .and. & - abs(dUpperOld(s,c) - dLower(s,c)) > tiny(0.0_pReal)) & - deltaRhoDipole2SingleStress(s,8_pInt+c) = rhoDip(s,c) * deltaDUpper(s,c) & - / (dUpperOld(s,c) - dLower(s,c)) - -forall (t=1_pInt:4_pInt) & - deltaRhoDipole2SingleStress(1_pInt:ns,t) = -0.5_pReal & - * deltaRhoDipole2SingleStress(1_pInt:ns,(t-1_pInt)/2_pInt+9_pInt) - - -!*** store new maximum dipole height in state - -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - plasticState(ph)%state(iD(s,c,instance),of) = dUpper(s,c) - - - -!**************************************************************************** -!*** assign the changes in the dislocation densities to deltaState - -deltaRho = deltaRhoRemobilization & - + deltaRhoDipole2SingleStress -plasticState(ph)%deltaState(:,of) = 0.0_pReal -forall (s = 1:ns, t = 1_pInt:4_pInt) - plasticState(ph)%deltaState(iRhoU(s,t,instance),of)= deltaRho(s,t) - plasticState(ph)%deltaState(iRhoB(s,t,instance),of) = deltaRho(s,t+4_pInt) -endforall -forall (s = 1:ns, c = 1_pInt:2_pInt) & - plasticState(ph)%deltaState(iRhoD(s,c,instance),of) = deltaRho(s,c+8_pInt) - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation remobilization', deltaRhoRemobilization(1:ns,1:8) - write(6,'(a,/,10(12x,12(e12.5,1x),/),/)') '<< CONST >> dipole dissociation by stress increase', deltaRhoDipole2SingleStress - endif -#endif - -end subroutine plastic_nonlocal_deltaState - -!--------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!--------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_dotState(Tstar_v, Fe, Fp, Temperature, & - timestep,subfrac, ip,el) - -use prec, only: DAMASK_NaN -use numerics, only: numerics_integrationMode, & - numerics_timeSyncing -use IO, only: IO_error -use debug, only: debug_level, & - debug_constitutive, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_g, & - debug_i, & - debug_e -use math, only: math_mul6x6, & - math_mul3x3, & - math_mul33x3, & - math_mul33x33, & - math_inv33, & - math_det33, & - math_transpose33, & - pi -use mesh, only: mesh_NcpElems, & - mesh_maxNips, & - mesh_element, & - mesh_ipNeighborhood, & - mesh_ipVolume, & - mesh_ipArea, & - mesh_ipAreaNormal, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype -use material, only: homogenization_maxNgrains, & - material_phase, & - phase_plasticityInstance, & - phase_localPlasticity, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticity ,& - PLASTICITY_NONLOCAL_ID -use lattice, only: lattice_Sslip_v, & - lattice_sd, & - lattice_st ,& - lattice_mu, & - lattice_nu, & - lattice_structure, & - LATTICE_bcc_ID, & - LATTICE_fcc_ID - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el !< current element number -real(pReal), intent(in) :: Temperature, & !< temperature - timestep !< substepped crystallite time increment -real(pReal), dimension(6), intent(in) :: Tstar_v !< current 2nd Piola-Kirchhoff stress in Mandel notation -real(pReal), dimension(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - subfrac !< fraction of timestep at the beginning of the substepped crystallite time increment -real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - Fe, & !< elastic deformation gradient - Fp !< plastic deformation gradient - - -!*** local variables -integer(pInt) :: ph, & - instance, & !< current instance of this plasticity - neighbor_instance, & !< instance of my neighbor's plasticity - ns, & !< short notation for the total number of active slip systems - c, & !< character of dislocation - n, & !< index of my current neighbor - neighbor_el, & !< element number of my neighbor - neighbor_ip, & !< integration point of my neighbor - neighbor_n, & !< neighbor index pointing to me when looking from my neighbor - opposite_neighbor, & !< index of my opposite neighbor - opposite_ip, & !< ip of my opposite neighbor - opposite_el, & !< element index of my opposite neighbor - opposite_n, & !< neighbor index pointing to me when looking from my opposite neighbor - t, & !< type of dislocation - o,& !< offset shortcut - no,& !< neighbour offset shortcut - p,& !< phase shortcut - np,& !< neighbour phase shortcut - topp, & !< type of dislocation with opposite sign to t - s, & !< index of my current slip system - sLattice !< index of my current slip system according to lattice order -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),10) :: & - rhoDot, & !< density evolution - rhoDotMultiplication, & !< density evolution by multiplication - rhoDotFlux, & !< density evolution by flux - rhoDotSingle2DipoleGlide, & !< density evolution by dipole formation (by glide) - rhoDotAthermalAnnihilation, & !< density evolution by athermal annihilation - rhoDotThermalAnnihilation !< density evolution by thermal annihilation -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) - rhoSglOriginal, & - neighbor_rhoSgl, & !< current single dislocation densities of neighboring ip (positive/negative screw and edge without dipoles) - rhoSgl0, & !< single dislocation densities at start of cryst inc (positive/negative screw and edge without dipoles) - my_rhoSgl !< single dislocation densities of central ip (positive/negative screw and edge without dipoles) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - v, & !< current dislocation glide velocity - v0, & !< dislocation glide velocity at start of cryst inc - my_v, & !< dislocation glide velocity of central ip - neighbor_v, & !< dislocation glide velocity of enighboring ip - gdot !< shear rates -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoForest, & !< forest dislocation density - tauThreshold, & !< threshold shear stress - tau, & !< current resolved shear stress - tauBack, & !< current back stress from pileups on same slip system - vClimb, & !< climb velocity of edge dipoles - nSources -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) - rhoDipOriginal, & - dLower, & !< minimum stable dipole distance for edges and screws - dUpper !< current maximum stable dipole distance for edges and screws -real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - m !< direction of dislocation motion -real(pReal), dimension(3,3) :: my_F, & !< my total deformation gradient - neighbor_F, & !< total deformation gradient of my neighbor - my_Fe, & !< my elastic deformation gradient - neighbor_Fe, & !< elastic deformation gradient of my neighbor - Favg !< average total deformation gradient of me and my neighbor -real(pReal), dimension(3) :: normal_neighbor2me, & !< interface normal pointing from my neighbor to me in neighbor's lattice configuration - normal_neighbor2me_defConf, & !< interface normal pointing from my neighbor to me in shared deformed configuration - normal_me2neighbor, & !< interface normal pointing from me to my neighbor in my lattice configuration - normal_me2neighbor_defConf !< interface normal pointing from me to my neighbor in shared deformed configuration -real(pReal) area, & !< area of the current interface - transmissivity, & !< overall transmissivity of dislocation flux to neighboring material point - lineLength, & !< dislocation line length leaving the current interface - selfDiffusion, & !< self diffusion - rnd, & - meshlength -logical considerEnteringFlux, & - considerLeavingFlux - - - p = phaseAt(1,ip,el) - o = phasememberAt(1,ip,el) - - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_dotState at el ip ',el,ip -#endif - -ph = material_phase(1_pInt,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - -tau = 0.0_pReal -gdot = 0.0_pReal - - -!*** shortcut to state variables - - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) - v(s,t) = plasticState(p)%state(iV (s,t,instance),o) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - rhoDip(s,c) = max(plasticState(p)%state(iRhoD(s,c,instance),o), 0.0_pReal) ! ensure positive dipole densities -endforall -rhoForest = plasticState(p)%state(iRhoF(1:ns,instance),o) -tauThreshold = plasticState(p)%state(iTauF(1:ns,instance),o) -tauBack = plasticState(p)%state(iTauB(1:ns,instance),o) - -rhoSglOriginal = rhoSgl -rhoDipOriginal = rhoDip -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal -where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoDip) < significantRho(instance)) & - rhoDip = 0.0_pReal - -if (numerics_timeSyncing) then - forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl0(s,t) = max(plasticState(p)%state0(iRhoU(s,t,instance),o), 0.0_pReal) - rhoSgl0(s,t+4_pInt) = plasticState(p)%state0(iRhoB(s,t,instance),o) - v0(s,t) = plasticState(p)%state0(iV (s,t,instance),o) - endforall - where (abs(rhoSgl0) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl0) < significantRho(instance)) & - rhoSgl0 = 0.0_pReal -endif - - - -!*** sanity check for timestep - -if (timestep <= 0.0_pReal) then ! if illegal timestep... Why here and not on function entry?? - plasticState(p)%dotState = 0.0_pReal ! ...return without doing anything (-> zero dotState) - return -endif - - - -!**************************************************************************** -!*** Calculate shear rate - -forall (t = 1_pInt:4_pInt) & - gdot(1_pInt:ns,t) = rhoSgl(1_pInt:ns,t) * burgers(1:ns,instance) * v(1:ns,t) - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> rho / 1/m^2', rhoSgl, rhoDip - write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> gdot / 1/s',gdot - endif -#endif - - - -!**************************************************************************** -!*** calculate limits for stable dipole height - -do s = 1_pInt,ns ! loop over slip systems - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) - if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal -enddo - -dLower = minDipoleHeight(1:ns,1:2,instance) -dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & - / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) -dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & - / (4.0_pReal * pi * abs(tau)) -forall (c = 1_pInt:2_pInt) - where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& - abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & - + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & - dUpper(1:ns,c)) -end forall -dUpper = max(dUpper,dLower) - -!**************************************************************************** -!*** calculate dislocation multiplication - -rhoDotMultiplication = 0.0_pReal -if (lattice_structure(ph) == LATTICE_bcc_ID) then ! BCC - forall (s = 1:ns, sum(abs(v(s,1:4))) > 0.0_pReal) - rhoDotMultiplication(s,1:2) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication - * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path - ! * 2.0_pReal * sum(abs(v(s,3:4))) / sum(abs(v(s,1:4))) ! ratio of screw to overall velocity determines edge generation - rhoDotMultiplication(s,3:4) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication - * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path - ! * 2.0_pReal * sum(abs(v(s,1:2))) / sum(abs(v(s,1:4))) ! ratio of edge to overall velocity determines screw generation - endforall - -else ! ALL OTHER STRUCTURES - if (probabilisticMultiplication(instance)) then - meshlength = mesh_ipVolume(ip,el)**0.333_pReal - where(sum(rhoSgl(1:ns,1:4),2) > 0.0_pReal) - nSources = (sum(rhoSgl(1:ns,1:2),2) * fEdgeMultiplication(instance) + sum(rhoSgl(1:ns,3:4),2)) & - / sum(rhoSgl(1:ns,1:4),2) * meshlength / lambda0(1:ns,instance)*sqrt(rhoForest(1:ns)) - elsewhere - nSources = meshlength / lambda0(1:ns,instance) * sqrt(rhoForest(1:ns)) - endwhere - do s = 1_pInt,ns - if (nSources(s) < 1.0_pReal) then - if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal) then - call random_number(rnd) - sourceProbability(s,1_pInt,ip,el) = rnd - !$OMP FLUSH(sourceProbability) - endif - if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal - nSources(s)) then - rhoDotMultiplication(s,1:4) = sum(rhoSglOriginal(s,1:4) * abs(v(s,1:4))) / meshlength - endif - else - sourceProbability(s,1_pInt,ip,el) = 2.0_pReal - rhoDotMultiplication(s,1:4) = & - (sum(abs(gdot(s,1:2))) * fEdgeMultiplication(instance) + sum(abs(gdot(s,3:4)))) & - / burgers(s,instance) * sqrt(rhoForest(s)) / lambda0(s,instance) - endif - enddo -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) & - write(6,'(a,/,4(12x,12(f12.5,1x),/,/))') '<< CONST >> sources', nSources -#endif - else - rhoDotMultiplication(1:ns,1:4) = spread( & - (sum(abs(gdot(1:ns,1:2)),2) * fEdgeMultiplication(instance) + sum(abs(gdot(1:ns,3:4)),2)) & - * sqrt(rhoForest(1:ns)) / lambda0(1:ns,instance) / burgers(1:ns,instance), 2, 4) - endif -endif - - - -!**************************************************************************** -!*** calculate dislocation fluxes (only for nonlocal plasticity) - -rhoDotFlux = 0.0_pReal -!? why needed here -if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then ! only for nonlocal plasticity - - !*** check CFL (Courant-Friedrichs-Lewy) condition for flux - - if (any( abs(gdot) > 0.0_pReal & ! any active slip system ... - .and. CFLfactor(instance) * abs(v) * timestep & - > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el)))) then ! ...with velocity above critical value (we use the reference volume and area for simplicity here) -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then - write(6,'(a,i5,a,i2)') '<< CONST >> CFL condition not fullfilled at el ',el,' ip ',ip - write(6,'(a,e10.3,a,e10.3)') '<< CONST >> velocity is at ', & - maxval(abs(v), abs(gdot) > 0.0_pReal & - .and. CFLfactor(instance) * abs(v) * timestep & - > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el))), & - ' at a timestep of ',timestep - write(6,'(a)') '<< CONST >> enforcing cutback !!!' - endif -#endif - plasticState(p)%dotState = DAMASK_NaN ! -> return NaN and, hence, enforce cutback - return - endif - - - !*** be aware of the definition of lattice_st = lattice_sd x lattice_sn !!! - !*** opposite sign to our p vector in the (s,p,n) triplet !!! - - m(1:3,1:ns,1) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) - m(1:3,1:ns,2) = -lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) - m(1:3,1:ns,3) = -lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) - m(1:3,1:ns,4) = lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) - - my_Fe = Fe(1:3,1:3,1_pInt,ip,el) - my_F = math_mul33x33(my_Fe, Fp(1:3,1:3,1_pInt,ip,el)) - - do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) ! loop through my neighbors -! write(6,*) 'c' - neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - neighbor_n = mesh_ipNeighborhood(3,n,ip,el) - np = phaseAt(1,neighbor_ip,neighbor_el) - no = phasememberAt(1,neighbor_ip,neighbor_el) - - opposite_neighbor = n + mod(n,2_pInt) - mod(n+1_pInt,2_pInt) - opposite_el = mesh_ipNeighborhood(1,opposite_neighbor,ip,el) - opposite_ip = mesh_ipNeighborhood(2,opposite_neighbor,ip,el) - opposite_n = mesh_ipNeighborhood(3,opposite_neighbor,ip,el) - - if (neighbor_n > 0_pInt) then ! if neighbor exists, average deformation gradient - neighbor_instance = phase_plasticityInstance(material_phase(1_pInt,neighbor_ip,neighbor_el)) - neighbor_Fe = Fe(1:3,1:3,1_pInt,neighbor_ip,neighbor_el) - neighbor_F = math_mul33x33(neighbor_Fe, Fp(1:3,1:3,1_pInt,neighbor_ip,neighbor_el)) - Favg = 0.5_pReal * (my_F + neighbor_F) - else ! if no neighbor, take my value as average - Favg = my_F - endif - - - !* FLUX FROM MY NEIGHBOR TO ME - !* This is only considered, if I have a neighbor of nonlocal plasticity - !* (also nonlocal constitutive law with local properties) that is at least a little bit - !* compatible. - !* If it's not at all compatible, no flux is arriving, because everything is dammed in front of - !* my neighbor's interface. - !* The entering flux from my neighbor will be distributed on my slip systems according to the - !*compatibility - - considerEnteringFlux = .false. - neighbor_v = 0.0_pReal ! needed for check of sign change in flux density below - neighbor_rhoSgl = 0.0_pReal - if (neighbor_n > 0_pInt) then - if (phase_plasticity(material_phase(1,neighbor_ip,neighbor_el)) == PLASTICITY_NONLOCAL_ID & - .and. any(compatibility(:,:,:,n,ip,el) > 0.0_pReal)) & - considerEnteringFlux = .true. - endif - - if (considerEnteringFlux) then - if(numerics_timeSyncing .and. (subfrac(1_pInt,neighbor_ip,neighbor_el) /= subfrac(1_pInt,ip,el))) & - then ! for timesyncing: in case of a timestep at the interface we have to use "state0" to make sure that fluxes n both sides are equal - forall (s = 1:ns, t = 1_pInt:4_pInt) - - neighbor_v(s,t) = plasticState(np)%state0(iV (s,t,neighbor_instance),no) - neighbor_rhoSgl(s,t) = max(plasticState(np)%state0(iRhoU(s,t,neighbor_instance),no),0.0_pReal) - - endforall - else - forall (s = 1:ns, t = 1_pInt:4_pInt) - neighbor_v(s,t) = plasticState(np)%state(iV (s,t,neighbor_instance),no) - neighbor_rhoSgl(s,t) = max(plasticState(np)%state(iRhoU(s,t,neighbor_instance),no), & - 0.0_pReal) - endforall - endif - - where (neighbor_rhoSgl * mesh_ipVolume(neighbor_ip,neighbor_el) ** 0.667_pReal < significantN(instance) & - .or. neighbor_rhoSgl < significantRho(instance)) & - neighbor_rhoSgl = 0.0_pReal - normal_neighbor2me_defConf = math_det33(Favg) * math_mul33x3(math_inv33(transpose(Favg)), & - mesh_ipAreaNormal(1:3,neighbor_n,neighbor_ip,neighbor_el)) ! calculate the normal of the interface in (average) deformed configuration (now pointing from my neighbor to me!!!) - normal_neighbor2me = math_mul33x3(transpose(neighbor_Fe), normal_neighbor2me_defConf) & - / math_det33(neighbor_Fe) ! interface normal in the lattice configuration of my neighbor - area = mesh_ipArea(neighbor_n,neighbor_ip,neighbor_el) * norm2(normal_neighbor2me) - normal_neighbor2me = normal_neighbor2me / norm2(normal_neighbor2me) ! normalize the surface normal to unit length - do s = 1_pInt,ns - do t = 1_pInt,4_pInt - c = (t + 1_pInt) / 2 - topp = t + mod(t,2_pInt) - mod(t+1_pInt,2_pInt) - if (neighbor_v(s,t) * math_mul3x3(m(1:3,s,t), normal_neighbor2me) > 0.0_pReal & ! flux from my neighbor to me == entering flux for me - .and. v(s,t) * neighbor_v(s,t) >= 0.0_pReal ) then ! ... only if no sign change in flux density - lineLength = neighbor_rhoSgl(s,t) * neighbor_v(s,t) & - * math_mul3x3(m(1:3,s,t), normal_neighbor2me) * area ! positive line length that wants to enter through this interface - where (compatibility(c,1_pInt:ns,s,n,ip,el) > 0.0_pReal) & ! positive compatibility... - rhoDotFlux(1_pInt:ns,t) = rhoDotFlux(1_pInt:ns,t) & - + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to equally signed mobile dislocation type - * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal - where (compatibility(c,1_pInt:ns,s,n,ip,el) < 0.0_pReal) & ! ..negative compatibility... - rhoDotFlux(1_pInt:ns,topp) = rhoDotFlux(1_pInt:ns,topp) & - + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to opposite signed mobile dislocation type - * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal - endif - enddo - enddo - endif - - - !* FLUX FROM ME TO MY NEIGHBOR - !* This is not considered, if my opposite neighbor has a different constitutive law than nonlocal (still considered for nonlocal law with lcal properties). - !* Then, we assume, that the opposite(!) neighbor sends an equal amount of dislocations to me. - !* So the net flux in the direction of my neighbor is equal to zero: - !* leaving flux to neighbor == entering flux from opposite neighbor - !* In case of reduced transmissivity, part of the leaving flux is stored as dead dislocation density. - !* That means for an interface of zero transmissivity the leaving flux is fully converted to dead dislocations. - - considerLeavingFlux = .true. - if (opposite_n > 0_pInt) then - if (phase_plasticity(material_phase(1,opposite_ip,opposite_el)) /= PLASTICITY_NONLOCAL_ID) & - considerLeavingFlux = .false. - endif - - if (considerLeavingFlux) then - - !* timeSyncing mode: If the central ip has zero subfraction, always use "state0". This is needed in case of - !* a synchronization step for the central ip, because then "state" contains the values at the end of the - !* previously converged full time step. Also, if either me or my neighbor has zero subfraction, we have to - !* use "state0" to make sure that fluxes on both sides of the (potential) timestep are equal. - my_rhoSgl = rhoSgl - my_v = v - if(numerics_timeSyncing) then - if (abs(subfrac(1_pInt,ip,el))<= tiny(0.0_pReal)) then - my_rhoSgl = rhoSgl0 - my_v = v0 - elseif (neighbor_n > 0_pInt) then - if (abs(subfrac(1_pInt,neighbor_ip,neighbor_el))<= tiny(0.0_pReal)) then - my_rhoSgl = rhoSgl0 - my_v = v0 - endif - endif - endif - - normal_me2neighbor_defConf = math_det33(Favg) & - * math_mul33x3(math_inv33(math_transpose33(Favg)), & - mesh_ipAreaNormal(1:3,n,ip,el)) ! calculate the normal of the interface in (average) deformed configuration (pointing from me to my neighbor!!!) - normal_me2neighbor = math_mul33x3(math_transpose33(my_Fe), normal_me2neighbor_defConf) & - / math_det33(my_Fe) ! interface normal in my lattice configuration - area = mesh_ipArea(n,ip,el) * norm2(normal_me2neighbor) - normal_me2neighbor = normal_me2neighbor / norm2(normal_me2neighbor) ! normalize the surface normal to unit length - do s = 1_pInt,ns - do t = 1_pInt,4_pInt - c = (t + 1_pInt) / 2_pInt - if (my_v(s,t) * math_mul3x3(m(1:3,s,t), normal_me2neighbor) > 0.0_pReal ) then ! flux from me to my neighbor == leaving flux for me (might also be a pure flux from my mobile density to dead density if interface not at all transmissive) - if (my_v(s,t) * neighbor_v(s,t) >= 0.0_pReal) then ! no sign change in flux density - transmissivity = sum(compatibility(c,1_pInt:ns,s,n,ip,el)**2.0_pReal) ! overall transmissivity from this slip system to my neighbor - else ! sign change in flux density means sign change in stress which does not allow for dislocations to arive at the neighbor - transmissivity = 0.0_pReal - endif - lineLength = my_rhoSgl(s,t) * my_v(s,t) & - * math_mul3x3(m(1:3,s,t), normal_me2neighbor) * area ! positive line length of mobiles that wants to leave through this interface - rhoDotFlux(s,t) = rhoDotFlux(s,t) - lineLength / mesh_ipVolume(ip,el) ! subtract dislocation flux from current type - rhoDotFlux(s,t+4_pInt) = rhoDotFlux(s,t+4_pInt) & - + lineLength / mesh_ipVolume(ip,el) * (1.0_pReal - transmissivity) & - * sign(1.0_pReal, my_v(s,t)) ! dislocation flux that is not able to leave through interface (because of low transmissivity) will remain as immobile single density at the material point - endif - enddo - enddo - endif - - enddo ! neighbor loop -endif - - - -!**************************************************************************** -!*** calculate dipole formation and annihilation - -!*** formation by glide - -do c = 1_pInt,2_pInt - rhoDotSingle2DipoleGlide(1:ns,2*c-1) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile - + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile - + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) ! positive mobile --> negative immobile - - rhoDotSingle2DipoleGlide(1:ns,2*c) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile - + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile - + abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c))) ! negative mobile --> positive immobile - - rhoDotSingle2DipoleGlide(1:ns,2*c+3) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * rhoSgl(1:ns,2*c+3) * abs(gdot(1:ns,2*c)) ! negative mobile --> positive immobile - - rhoDotSingle2DipoleGlide(1:ns,2*c+4) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * rhoSgl(1:ns,2*c+4) * abs(gdot(1:ns,2*c-1)) ! positive mobile --> negative immobile - - rhoDotSingle2DipoleGlide(1:ns,c+8) = - rhoDotSingle2DipoleGlide(1:ns,2*c-1) & - - rhoDotSingle2DipoleGlide(1:ns,2*c) & - + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+3)) & - + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+4)) -enddo - - -!*** athermal annihilation - -rhoDotAthermalAnnihilation = 0.0_pReal - -forall (c=1_pInt:2_pInt) & - rhoDotAthermalAnnihilation(1:ns,c+8_pInt) = -2.0_pReal * dLower(1:ns,c) / burgers(1:ns,instance) & - * ( 2.0_pReal * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1))) & ! was single hitting single - + 2.0_pReal * (abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c)) + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) & ! was single hitting immobile single or was immobile single hit by single - + rhoDip(1:ns,c) * (abs(gdot(1:ns,2*c-1)) + abs(gdot(1:ns,2*c)))) ! single knocks dipole constituent -! annihilated screw dipoles leave edge jogs behind on the colinear system -if (lattice_structure(ph) == LATTICE_fcc_ID) & ! only fcc - forall (s = 1:ns, colinearSystem(s,instance) > 0_pInt) & - rhoDotAthermalAnnihilation(colinearSystem(s,instance),1:2) = - rhoDotAthermalAnnihilation(s,10) & - * 0.25_pReal * sqrt(rhoForest(s)) * (dUpper(s,2) + dLower(s,2)) * edgeJogFactor(instance) - - - -!*** thermally activated annihilation of edge dipoles by climb - -rhoDotThermalAnnihilation = 0.0_pReal -selfDiffusion = Dsd0(instance) * exp(-selfDiffusionEnergy(instance) / (KB * Temperature)) -vClimb = atomicVolume(instance) * selfDiffusion / ( KB * Temperature ) & - * lattice_mu(ph) / ( 2.0_pReal * PI * (1.0_pReal-lattice_nu(ph)) ) & - * 2.0_pReal / ( dUpper(1:ns,1) + dLower(1:ns,1) ) -forall (s = 1_pInt:ns, dUpper(s,1) > dLower(s,1)) & - rhoDotThermalAnnihilation(s,9) = max(- 4.0_pReal * rhoDip(s,1) * vClimb(s) / (dUpper(s,1) - dLower(s,1)), & - - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & - - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have - - - -!**************************************************************************** -!*** assign the rates of dislocation densities to my dotState -!*** if evolution rates lead to negative densities, a cutback is enforced - -rhoDot = 0.0_pReal -rhoDot = rhoDotFlux & - + rhoDotMultiplication & - + rhoDotSingle2DipoleGlide & - + rhoDotAthermalAnnihilation & - + rhoDotThermalAnnihilation - -if (numerics_integrationMode == 1_pInt) then ! save rates for output if in central integration mode - rhoDotFluxOutput(1:ns,1:8,1_pInt,ip,el) = rhoDotFlux(1:ns,1:8) - rhoDotMultiplicationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotMultiplication(1:ns,[1,3]) - rhoDotSingle2DipoleGlideOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotSingle2DipoleGlide(1:ns,9:10) - rhoDotAthermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotAthermalAnnihilation(1:ns,9:10) - rhoDotThermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotThermalAnnihilation(1:ns,9:10) - rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) = 2.0_pReal * rhoDotThermalAnnihilation(1:ns,1) -endif - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip .and. debug_g == 1_pInt)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> dislocation multiplication', & - rhoDotMultiplication(1:ns,1:4) * timestep - write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation flux', & - rhoDotFlux(1:ns,1:8) * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> dipole formation by glide', & - rhoDotSingle2DipoleGlide * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> athermal dipole annihilation', & - rhoDotAthermalAnnihilation * timestep - write(6,'(a,/,2(12x,12(e12.5,1x),/))') '<< CONST >> thermally activated dipole annihilation', & - rhoDotThermalAnnihilation(1:ns,9:10) * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> total density change', & - rhoDot * timestep - write(6,'(a,/,10(12x,12(f12.5,1x),/))') '<< CONST >> relative density change', & - rhoDot(1:ns,1:8) * timestep / (abs(rhoSglOriginal)+1.0e-10), & - rhoDot(1:ns,9:10) * timestep / (rhoDipOriginal+1.0e-10) - write(6,*) - endif -#endif - - -if ( any(rhoSglOriginal(1:ns,1:4) + rhoDot(1:ns,1:4) * timestep < -aTolRho(instance)) & - .or. any(rhoDipOriginal(1:ns,1:2) + rhoDot(1:ns,9:10) * timestep < -aTolRho(instance))) then -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then - write(6,'(a,i5,a,i2)') '<< CONST >> evolution rate leads to negative density at el ',el,' ip ',ip - write(6,'(a)') '<< CONST >> enforcing cutback !!!' - endif -#endif - plasticState(p)%dotState = DAMASK_NaN - return -else - forall (s = 1:ns, t = 1_pInt:4_pInt) - plasticState(p)%dotState(iRhoU(s,t,instance),o) = rhoDot(s,t) - plasticState(p)%dotState(iRhoB(s,t,instance),o) = rhoDot(s,t+4_pInt) - endforall - forall (s = 1:ns, c = 1_pInt:2_pInt) & - plasticState(p)%dotState(iRhoD(s,c,instance),o) = rhoDot(s,c+8_pInt) - forall (s = 1:ns) & - plasticState(p)%dotState(iGamma(s,instance),o) = sum(gdot(s,1:4)) -endif - -end subroutine plastic_nonlocal_dotState - - -!********************************************************************* -!* COMPATIBILITY UPDATE * -!* Compatibility is defined as normalized product of signed cosine * -!* of the angle between the slip plane normals and signed cosine of * -!* the angle between the slip directions. Only the largest values * -!* that sum up to a total of 1 are considered, all others are set to * -!* zero. * -!********************************************************************* -subroutine plastic_nonlocal_updateCompatibility(orientation,i,e) - -use math, only: math_mul3x3, & - math_qRot -use material, only: material_phase, & - material_texture, & - phase_localPlasticity, & - phase_plasticityInstance, & - homogenization_maxNgrains -use mesh, only: mesh_element, & - mesh_ipNeighborhood, & - mesh_maxNips, & - mesh_NcpElems, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype -use lattice, only: lattice_sn, & - lattice_sd, & - lattice_qDisorientation - -implicit none - -!* input variables -integer(pInt), intent(in) :: i, & ! ip index - e ! element index -real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - orientation ! crystal orientation in quaternions - -!* local variables -integer(pInt) Nneighbors, & ! number of neighbors - n, & ! neighbor index - neighbor_e, & ! element index of my neighbor - neighbor_i, & ! integration point index of my neighbor - ph, & - neighbor_phase, & - textureID, & - neighbor_textureID, & - instance, & ! instance of plasticity - ns, & ! number of active slip systems - s1, & ! slip system index (me) - s2 ! slip system index (my neighbor) -real(pReal), dimension(4) :: absoluteMisorientation ! absolute misorientation (without symmetry) between me and my neighbor -real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& - totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& - FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e))))) :: & - my_compatibility ! my_compatibility for current element and ip -real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & - slipNormal, & - slipDirection -real(pReal) my_compatibilitySum, & - thresholdValue, & - nThresholdValues -logical, dimension(totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & - belowThreshold - - -Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) -ph = material_phase(1,i,e) -textureID = material_texture(1,i,e) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) -slipNormal(1:3,1:ns) = lattice_sn(1:3, slipSystemLattice(1:ns,instance), ph) -slipDirection(1:3,1:ns) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) - - -!*** start out fully compatible - -my_compatibility = 0.0_pReal -forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,1:Nneighbors) = 1.0_pReal - - -!*** Loop thrugh neighbors and check whether there is any my_compatibility. - -do n = 1_pInt,Nneighbors - neighbor_e = mesh_ipNeighborhood(1,n,i,e) - neighbor_i = mesh_ipNeighborhood(2,n,i,e) - - - !* FREE SURFACE - !* Set surface transmissivity to the value specified in the material.config - - if (neighbor_e <= 0_pInt .or. neighbor_i <= 0_pInt) then - forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,n) = sqrt(surfaceTransmissivity(instance)) - cycle - endif - - - !* PHASE BOUNDARY - !* If we encounter a different nonlocal "cpfem" phase at the neighbor, - !* we consider this to be a real "physical" phase boundary, so completely incompatible. - !* If one of the two "CPFEM" phases has a local plasticity law, - !* we do not consider this to be a phase boundary, so completely compatible. - - neighbor_phase = material_phase(1,neighbor_i,neighbor_e) - if (neighbor_phase /= ph) then - if (.not. phase_localPlasticity(neighbor_phase) .and. .not. phase_localPlasticity(ph)) then - forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,n) = 0.0_pReal ! = sqrt(0.0) - endif - cycle - endif - - - !* GRAIN BOUNDARY ! - !* fixed transmissivity for adjacent ips with different texture (only if explicitly given in material.config) - - if (grainboundaryTransmissivity(instance) >= 0.0_pReal) then - neighbor_textureID = material_texture(1,neighbor_i,neighbor_e) - if (neighbor_textureID /= textureID) then - if (.not. phase_localPlasticity(neighbor_phase)) then - forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,n) = sqrt(grainboundaryTransmissivity(instance)) - endif - cycle - endif - - - !* GRAIN BOUNDARY ? - !* Compatibility defined by relative orientation of slip systems: - !* The my_compatibility value is defined as the product of the slip normal projection and the slip direction projection. - !* Its sign is always positive for screws, for edges it has the same sign as the slip normal projection. - !* Since the sum for each slip system can easily exceed one (which would result in a transmissivity larger than one), - !* only values above or equal to a certain threshold value are considered. This threshold value is chosen, such that - !* the number of compatible slip systems is minimized with the sum of the original my_compatibility values exceeding one. - !* Finally the smallest my_compatibility value is decreased until the sum is exactly equal to one. - !* All values below the threshold are set to zero. - else - absoluteMisorientation = lattice_qDisorientation(orientation(1:4,1,i,e), & - orientation(1:4,1,neighbor_i,neighbor_e)) ! no symmetry - do s1 = 1_pInt,ns ! my slip systems - do s2 = 1_pInt,ns ! my neighbor's slip systems - my_compatibility(1,s2,s1,n) = math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2))) & - * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) - my_compatibility(2,s2,s1,n) = abs(math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2)))) & - * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) - enddo - - my_compatibilitySum = 0.0_pReal - belowThreshold = .true. - do while (my_compatibilitySum < 1.0_pReal .and. any(belowThreshold(1:ns))) - thresholdValue = maxval(my_compatibility(2,1:ns,s1,n), belowThreshold(1:ns)) ! screws always positive - nThresholdValues = real(count(my_compatibility(2,1:ns,s1,n) == thresholdValue),pReal) - where (my_compatibility(2,1:ns,s1,n) >= thresholdValue) & - belowThreshold(1:ns) = .false. - if (my_compatibilitySum + thresholdValue * nThresholdValues > 1.0_pReal) & - where (abs(my_compatibility(1:2,1:ns,s1,n)) == thresholdValue) & ! MD: rather check below threshold? - my_compatibility(1:2,1:ns,s1,n) = sign((1.0_pReal - my_compatibilitySum) & - / nThresholdValues, my_compatibility(1:2,1:ns,s1,n)) - my_compatibilitySum = my_compatibilitySum + nThresholdValues * thresholdValue - enddo - where (belowThreshold(1:ns)) my_compatibility(1,1:ns,s1,n) = 0.0_pReal - where (belowThreshold(1:ns)) my_compatibility(2,1:ns,s1,n) = 0.0_pReal - enddo ! my slip systems cycle - endif - -enddo ! neighbor cycle - -compatibility(1:2,1:ns,1:ns,1:Nneighbors,i,e) = my_compatibility - -end subroutine plastic_nonlocal_updateCompatibility - -!********************************************************************* -!* calculates quantities characterizing the microstructure * -!********************************************************************* -function plastic_nonlocal_dislocationstress(Fe, ip, el) -use math, only: math_mul33x33, & - math_mul33x3, & - math_inv33, & - math_transpose33, & - pi -use mesh, only: mesh_NcpElems, & - mesh_maxNips, & - mesh_element, & - mesh_node0, & - mesh_cellCenterCoordinates, & - mesh_ipVolume, & - mesh_periodicSurface, & - FE_Nips, & - FE_geomtype -use material, only: homogenization_maxNgrains, & - material_phase, & - plasticState, & - phaseAt, phasememberAt,& - phase_localPlasticity, & - phase_plasticityInstance -use lattice, only: lattice_mu, & - lattice_nu - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el !< current element -real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - Fe !< elastic deformation gradient - -!*** output variables -real(pReal), dimension(3,3) :: plastic_nonlocal_dislocationstress - -!*** local variables -integer(pInt) neighbor_el, & !< element number of neighbor material point - neighbor_ip, & !< integration point of neighbor material point - instance, & !< my instance of this plasticity - neighbor_instance, & !< instance of this plasticity of neighbor material point - ph, & - neighbor_phase, & - ns, & !< total number of active slip systems at my material point - neighbor_ns, & !< total number of active slip systems at neighbor material point - c, & !< index of dilsocation character (edge, screw) - s, & !< slip system index - o,& !< offset shortcut - no,& !< neighbour offset shortcut - p,& !< phase shortcut - np,& !< neighbour phase shortcut - t, & !< index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) - dir, & - deltaX, deltaY, deltaZ, & - side, & - j -integer(pInt), dimension(2,3) :: periodicImages -real(pReal) x, y, z, & !< coordinates of connection vector in neighbor lattice frame - xsquare, ysquare, zsquare, & !< squares of respective coordinates - distance, & !< length of connection vector - segmentLength, & !< segment length of dislocations - lambda, & - R, Rsquare, Rcube, & - denominator, & - flipSign, & - neighbor_ipVolumeSideLength -real(pReal), dimension(3) :: connection, & !< connection vector between me and my neighbor in the deformed configuration - connection_neighborLattice, & !< connection vector between me and my neighbor in the lattice configuration of my neighbor - connection_neighborSlip, & !< connection vector between me and my neighbor in the slip system frame of my neighbor - maxCoord, minCoord, & - meshSize, & - coords, & !< x,y,z coordinates of cell center of ip volume - neighbor_coords !< x,y,z coordinates of cell center of neighbor ip volume -real(pReal), dimension(3,3) :: sigma, & !< dislocation stress for one slip system in neighbor material point's slip system frame - Tdislo_neighborLattice, & !< dislocation stress as 2nd Piola-Kirchhoff stress at neighbor material point - invFe, & !< inverse of my elastic deformation gradient - neighbor_invFe, & - neighborLattice2myLattice !< mapping from neighbor MPs lattice configuration to my lattice configuration -real(pReal), dimension(2,2,maxval(totalNslip)) :: & - neighbor_rhoExcess !< excess density at neighbor material point (edge/screw,mobile/dead,slipsystem) -real(pReal), dimension(2,maxval(totalNslip)) :: & - rhoExcessDead -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) - -ph = material_phase(1_pInt,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) -p = phaseAt(1,ip,el) -o = phasememberAt(1,ip,el) - -!*** get basic states - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) -endforall - - - -!*** calculate the dislocation stress of the neighboring excess dislocation densities -!*** zero for material points of local plasticity - -plastic_nonlocal_dislocationstress = 0.0_pReal - -if (.not. phase_localPlasticity(ph)) then - invFe = math_inv33(Fe(1:3,1:3,1_pInt,ip,el)) - - !* in case of periodic surfaces we have to find out how many periodic images in each direction we need - - do dir = 1_pInt,3_pInt - maxCoord(dir) = maxval(mesh_node0(dir,:)) - minCoord(dir) = minval(mesh_node0(dir,:)) - enddo - meshSize = maxCoord - minCoord - coords = mesh_cellCenterCoordinates(ip,el) - periodicImages = 0_pInt - do dir = 1_pInt,3_pInt - if (mesh_periodicSurface(dir)) then - periodicImages(1,dir) = floor((coords(dir) - cutoffRadius(instance) - minCoord(dir)) / meshSize(dir), pInt) - periodicImages(2,dir) = ceiling((coords(dir) + cutoffRadius(instance) - maxCoord(dir)) / meshSize(dir), pInt) - endif - enddo - - - !* loop through all material points (also through their periodic images if present), - !* but only consider nonlocal neighbors within a certain cutoff radius R - - do neighbor_el = 1_pInt,mesh_NcpElems - ipLoop: do neighbor_ip = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,neighbor_el))) - neighbor_phase = material_phase(1_pInt,neighbor_ip,neighbor_el) - np = phaseAt(1,neighbor_ip,neighbor_el) - no = phasememberAt(1,neighbor_ip,neighbor_el) - - if (phase_localPlasticity(neighbor_phase)) cycle - neighbor_instance = phase_plasticityInstance(neighbor_phase) - neighbor_ns = totalNslip(neighbor_instance) - neighbor_invFe = math_inv33(Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) - neighbor_ipVolumeSideLength = mesh_ipVolume(neighbor_ip,neighbor_el) ** (1.0_pReal/3.0_pReal) ! reference volume used here - - forall (s = 1_pInt:neighbor_ns, c = 1_pInt:2_pInt) - neighbor_rhoExcess(c,1,s) = plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no) & ! positive mobiles - - plasticState(np)%state(iRhoU(s,2*c,neighbor_instance),no) ! negative mobiles - neighbor_rhoExcess(c,2,s) = abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads - - abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance),no)) ! negative deads - - endforall - Tdislo_neighborLattice = 0.0_pReal - do deltaX = periodicImages(1,1),periodicImages(2,1) - do deltaY = periodicImages(1,2),periodicImages(2,2) - do deltaZ = periodicImages(1,3),periodicImages(2,3) - - - !* regular case - - if (neighbor_el /= el .or. neighbor_ip /= ip & - .or. deltaX /= 0_pInt .or. deltaY /= 0_pInt .or. deltaZ /= 0_pInt) then - - neighbor_coords = mesh_cellCenterCoordinates(neighbor_ip,neighbor_el) & - + [real(deltaX,pReal), real(deltaY,pReal), real(deltaZ,pReal)] * meshSize - connection = neighbor_coords - coords - distance = sqrt(sum(connection * connection)) - if (distance > cutoffRadius(instance)) cycle - - - !* the segment length is the minimum of the third root of the control volume and the ip distance - !* this ensures, that the central MP never sits on a neighbor dislocation segment - - connection_neighborLattice = math_mul33x3(neighbor_invFe, connection) - segmentLength = min(neighbor_ipVolumeSideLength, distance) - - - !* loop through all slip systems of the neighbor material point - !* and add up the stress contributions from egde and screw excess on these slip systems (if significant) - - do s = 1_pInt,neighbor_ns - if (all(abs(neighbor_rhoExcess(:,:,s)) < significantRho(instance))) cycle ! not significant - - - !* map the connection vector from the lattice into the slip system frame - - connection_neighborSlip = math_mul33x3(lattice2slip(1:3,1:3,s,neighbor_instance), & - connection_neighborLattice) - - - !* edge contribution to stress - sigma = 0.0_pReal - - x = connection_neighborSlip(1) - y = connection_neighborSlip(2) - z = connection_neighborSlip(3) - xsquare = x * x - ysquare = y * y - zsquare = z * z - - do j = 1_pInt,2_pInt - if (abs(neighbor_rhoExcess(1,j,s)) < significantRho(instance)) then - cycle - elseif (j > 1_pInt) then - x = connection_neighborSlip(1) & - + sign(0.5_pReal * segmentLength, & - plasticState(np)%state(iRhoB(s,1,neighbor_instance),no) & - - plasticState(np)%state(iRhoB(s,2,neighbor_instance),no)) - - xsquare = x * x - endif - - flipSign = sign(1.0_pReal, -y) - do side = 1_pInt,-1_pInt,-2_pInt - lambda = real(side,pReal) * 0.5_pReal * segmentLength - y - R = sqrt(xsquare + zsquare + lambda * lambda) - Rsquare = R * R - Rcube = Rsquare * R - denominator = R * (R + flipSign * lambda) - if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop - - sigma(1,1) = sigma(1,1) - real(side,pReal) & - * flipSign * z / denominator & - * (1.0_pReal + xsquare / Rsquare + xsquare / denominator) & - * neighbor_rhoExcess(1,j,s) - sigma(2,2) = sigma(2,2) - real(side,pReal) & - * (flipSign * 2.0_pReal * lattice_nu(ph) * z / denominator + z * lambda / Rcube) & - * neighbor_rhoExcess(1,j,s) - sigma(3,3) = sigma(3,3) + real(side,pReal) & - * flipSign * z / denominator & - * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & - * neighbor_rhoExcess(1,j,s) - sigma(1,2) = sigma(1,2) + real(side,pReal) & - * x * z / Rcube * neighbor_rhoExcess(1,j,s) - sigma(1,3) = sigma(1,3) + real(side,pReal) & - * flipSign * x / denominator & - * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & - * neighbor_rhoExcess(1,j,s) - sigma(2,3) = sigma(2,3) - real(side,pReal) & - * (lattice_nu(ph) / R - zsquare / Rcube) * neighbor_rhoExcess(1,j,s) - enddo - enddo - - !* screw contribution to stress - - x = connection_neighborSlip(1) ! have to restore this value, because position might have been adapted for edge deads before - do j = 1_pInt,2_pInt - if (abs(neighbor_rhoExcess(2,j,s)) < significantRho(instance)) then - cycle - elseif (j > 1_pInt) then - y = connection_neighborSlip(2) & - + sign(0.5_pReal * segmentLength, & - plasticState(np)%state(iRhoB(s,3,neighbor_instance),no) & - - plasticState(np)%state(iRhoB(s,4,neighbor_instance),no)) - ysquare = y * y - endif - - flipSign = sign(1.0_pReal, x) - do side = 1_pInt,-1_pInt,-2_pInt - lambda = x + real(side,pReal) * 0.5_pReal * segmentLength - R = sqrt(ysquare + zsquare + lambda * lambda) - Rsquare = R * R - Rcube = Rsquare * R - denominator = R * (R + flipSign * lambda) - if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop - - sigma(1,2) = sigma(1,2) - real(side,pReal) * flipSign * z & - * (1.0_pReal - lattice_nu(ph)) / denominator & - * neighbor_rhoExcess(2,j,s) - sigma(1,3) = sigma(1,3) + real(side,pReal) * flipSign * y & - * (1.0_pReal - lattice_nu(ph)) / denominator & - * neighbor_rhoExcess(2,j,s) - enddo - enddo - - if (all(abs(sigma) < 1.0e-10_pReal)) cycle ! SIGMA IS NOT A REAL STRESS, THATS WHY WE NEED A REALLY SMALL VALUE HERE - - !* copy symmetric parts - - sigma(2,1) = sigma(1,2) - sigma(3,1) = sigma(1,3) - sigma(3,2) = sigma(2,3) - - - !* scale stresses and map them into the neighbor material point's lattice configuration - - sigma = sigma * lattice_mu(neighbor_phase) * burgers(s,neighbor_instance) & - / (4.0_pReal * pi * (1.0_pReal - lattice_nu(neighbor_phase))) & - * mesh_ipVolume(neighbor_ip,neighbor_el) / segmentLength ! reference volume is used here (according to the segment length calculation) - Tdislo_neighborLattice = Tdislo_neighborLattice & - + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,neighbor_instance)), & - math_mul33x33(sigma, lattice2slip(1:3,1:3,s,neighbor_instance))) - - enddo ! slip system loop - - - !* special case of central ip volume - !* only consider dead dislocations - !* we assume that they all sit at a distance equal to half the third root of V - !* in direction of the according slip direction - - else - - forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - - rhoExcessDead(c,s) = plasticState(p)%state(iRhoB(s,2*c-1,instance),o) & ! positive deads (here we use symmetry: if this has negative sign it is - !treated as negative density at positive position instead of positive - !density at negative position) - + plasticState(p)%state(iRhoB(s,2*c,instance),o) ! negative deads (here we use symmetry: if this has negative sign it is - !treated as positive density at positive position instead of negative - !density at negative position) - do s = 1_pInt,ns - if (all(abs(rhoExcessDead(:,s)) < significantRho(instance))) cycle ! not significant - sigma = 0.0_pReal ! all components except for sigma13 are zero - sigma(1,3) = - (rhoExcessDead(1,s) + rhoExcessDead(2,s) * (1.0_pReal - lattice_nu(ph))) & - * neighbor_ipVolumeSideLength * lattice_mu(ph) * burgers(s,instance) & - / (sqrt(2.0_pReal) * pi * (1.0_pReal - lattice_nu(ph))) - sigma(3,1) = sigma(1,3) - - Tdislo_neighborLattice = Tdislo_neighborLattice & - + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,instance)), & - math_mul33x33(sigma, lattice2slip(1:3,1:3,s,instance))) - - enddo ! slip system loop - - endif - - enddo ! deltaZ loop - enddo ! deltaY loop - enddo ! deltaX loop - - - !* map the stress from the neighbor MP's lattice configuration into the deformed configuration - !* and back into my lattice configuration - - neighborLattice2myLattice = math_mul33x33(invFe, Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) - plastic_nonlocal_dislocationstress = plastic_nonlocal_dislocationstress & - + math_mul33x33(neighborLattice2myLattice, & - math_mul33x33(Tdislo_neighborLattice, & - math_transpose33(neighborLattice2myLattice))) - - enddo ipLoop - enddo ! element loop - -endif - -end function plastic_nonlocal_dislocationstress - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_nonlocal_postResults(Tstar_v,Fe,ip,el) - use math, only: & - math_mul6x6, & - math_mul33x3, & - math_mul33x33, & - pi - use mesh, only: & - mesh_NcpElems, & - mesh_maxNips - use material, only: & - homogenization_maxNgrains, & - material_phase, & - phaseAt, phasememberAt, & - plasticState, & - phase_plasticityInstance - use lattice, only: & - lattice_Sslip_v, & - lattice_sd, & - lattice_st, & - lattice_sn, & - lattice_mu, & - lattice_nu - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - Fe !< elastic deformation gradient - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - - real(pReal), dimension(plastic_nonlocal_sizePostResults(& - phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - plastic_nonlocal_postResults - - integer(pInt) :: & - ph, & - instance, & !< current instance of this plasticity - ns, & !< short notation for the total number of active slip systems - c, & !< character of dislocation - cs, & !< constitutive result index - o, & !< index of current output - of,& !< offset shortcut - t, & !< type of dislocation - s, & !< index of my current slip system - sLattice !< index of my current slip system according to lattice order - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) - rhoDotSgl !< evolution rate of single dislocation densities (positive/negative screw and edge without dipoles) - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - gdot, & !< shear rates - v !< velocities - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoForest, & !< forest dislocation density - tauThreshold, & !< threshold shear stress - tau, & !< current resolved shear stress - tauBack !< back stress from pileups on same slip system - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) - rhoDotDip, & !< evolution rate of dipole dislocation densities (screw and edge dipoles) - dLower, & !< minimum stable dipole distance for edges and screws - dUpper !< current maximum stable dipole distance for edges and screws - real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - m, & !< direction of dislocation motion for edge and screw (unit vector) - m_currentconf !< direction of dislocation motion for edge and screw (unit vector) in current configuration - real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - n_currentconf !< slip system normal (unit vector) in current configuration - real(pReal), dimension(3,3) :: & - sigma - -ph = phaseAt(1,ip,el) -of = phasememberAt(1,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - -cs = 0_pInt -plastic_nonlocal_postResults = 0.0_pReal - - -!* short hand notations for state variables - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = plasticState(ph)%State(iRhoU(s,t,instance),of) - rhoSgl(s,t+4_pInt) = plasticState(ph)%State(iRhoB(s,t,instance),of) - v(s,t) = plasticState(ph)%State(iV(s,t,instance),of) - rhoDotSgl(s,t) = plasticState(ph)%dotState(iRhoU(s,t,instance),of) - rhoDotSgl(s,t+4_pInt) = plasticState(ph)%dotState(iRhoB(s,t,instance),of) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - rhoDip(s,c) = plasticState(ph)%State(iRhoD(s,c,instance),of) - rhoDotDip(s,c) = plasticState(ph)%dotState(iRhoD(s,c,instance),of) -endforall -rhoForest = plasticState(ph)%State(iRhoF(1:ns,instance),of) -tauThreshold = plasticState(ph)%State(iTauF(1:ns,instance),of) -tauBack = plasticState(ph)%State(iTauB(1:ns,instance),of) - -!* Calculate shear rate - -forall (t = 1_pInt:4_pInt) & - gdot(1:ns,t) = rhoSgl(1:ns,t) * burgers(1:ns,instance) * v(1:ns,t) - - -!* calculate limits for stable dipole height - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) - if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal -enddo - -dLower = minDipoleHeight(1:ns,1:2,instance) -dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & - / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) -dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & - / (4.0_pReal * pi * abs(tau)) -forall (c = 1_pInt:2_pInt) - where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& - abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & - + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & - dUpper(1:ns,c)) -end forall -dUpper = max(dUpper,dLower) - - -!*** dislocation motion - -m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) -m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) -forall (c = 1_pInt:2_pInt, s = 1_pInt:ns) & - m_currentconf(1:3,s,c) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), m(1:3,s,c)) -forall (s = 1_pInt:ns) & - n_currentconf(1:3,s) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), & - lattice_sn(1:3,slipSystemLattice(s,instance),ph)) - - -outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) - select case(plastic_nonlocal_outputID(o,instance)) - case (rho_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) + sum(rhoDip,2) - cs = cs + ns - - case (rho_sgl_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) - cs = cs + ns - - case (rho_sgl_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,1:4)),2) - cs = cs + ns - - case (rho_sgl_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:8),2) - cs = cs + ns - - case (rho_dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDip,2) - cs = cs + ns - - case (rho_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1) - cs = cs + ns - - case (rho_sgl_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) - cs = cs + ns - - case (rho_sgl_edge_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,1:2),2) - cs = cs + ns - - case (rho_sgl_edge_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:6),2) - cs = cs + ns - - case (rho_sgl_edge_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5)) - cs = cs + ns - - case (rho_sgl_edge_pos_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) - cs = cs + ns - - case (rho_sgl_edge_pos_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,5) - cs = cs + ns - - case (rho_sgl_edge_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6)) - cs = cs + ns - - case (rho_sgl_edge_neg_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) - cs = cs + ns - - case (rho_sgl_edge_neg_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,6) - cs = cs + ns - - case (rho_dip_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,1) - cs = cs + ns - - case (rho_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2) - cs = cs + ns - - case (rho_sgl_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) - cs = cs + ns - - case (rho_sgl_screw_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,3:4),2) - cs = cs + ns - - case (rho_sgl_screw_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,7:8),2) - cs = cs + ns - - case (rho_sgl_screw_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7)) - cs = cs + ns - - case (rho_sgl_screw_pos_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) - cs = cs + ns - - case (rho_sgl_screw_pos_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,7) - cs = cs + ns - - case (rho_sgl_screw_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8)) - cs = cs + ns - - case (rho_sgl_screw_neg_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) - cs = cs + ns - - case (rho_sgl_screw_neg_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,8) - cs = cs + ns - - case (rho_dip_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,2) - cs = cs + ns - - case (excess_rho_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & - - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) & - + (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & - - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) - cs = cs + ns - - case (excess_rho_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & - - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) - cs = cs + ns - - case (excess_rho_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & - - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) - cs = cs + ns - - case (rho_forest_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoForest - cs = cs + ns - - case (delta_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2) + sum(rhoDip,2)) - cs = cs + ns - - case (delta_sgl_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2)) - cs = cs + ns - - case (delta_dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(rhoDip,2)) - cs = cs + ns - - case (shearrate_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(gdot,2) - cs = cs + ns - - case (resolvedstress_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tau - cs = cs + ns - - case (resolvedstress_back_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauBack - cs = cs + ns - - case (resolvedstress_external_ID) - do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - plastic_nonlocal_postResults(cs+s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) - enddo - cs = cs + ns - - case (resistance_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauThreshold - cs = cs + ns - - case (rho_dot_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & - + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) & - + sum(rhoDotDip,2) - cs = cs + ns - - case (rho_dot_sgl_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & - + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) - cs = cs + ns - - case (rho_dot_sgl_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) - cs = cs + ns - - case (rho_dot_dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotDip,2) - cs = cs + ns - - case (rho_dot_gen_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_gen_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_gen_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_sgl2dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_sgl2dip_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_sgl2dip_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_ath_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotAthermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotAthermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_the_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_the_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_the_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_edgejogs_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_flux_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) - cs = cs + ns - - case (rho_dot_flux_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) & - + sum(rhoDotFluxOutput(1:ns,5:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) - cs = cs + ns - - case (rho_dot_flux_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:2,1_pInt,ip,el),2) & - + sum(rhoDotFluxOutput(1:ns,5:6,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:6)),2) - cs = cs + ns - - case (rho_dot_flux_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,3:4,1_pInt,ip,el),2) & - + sum(rhoDotFluxOutput(1:ns,7:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,7:8)),2) - cs = cs + ns - - case (velocity_edge_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,1) - cs = cs + ns - - case (velocity_edge_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,2) - cs = cs + ns - - case (velocity_screw_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,3) - cs = cs + ns - - case (velocity_screw_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,4) - cs = cs + ns - - case (slipdirectionx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(1,1:ns,1) - cs = cs + ns - - case (slipdirectiony_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(2,1:ns,1) - cs = cs + ns - - case (slipdirectionz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(3,1:ns,1) - cs = cs + ns - - case (slipnormalx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(1,1:ns) - cs = cs + ns - - case (slipnormaly_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(2,1:ns) - cs = cs + ns - - case (slipnormalz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(3,1:ns) - cs = cs + ns - - case (fluxdensity_edge_posx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(1,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_posy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(2,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_posz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(3,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_negx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(1,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_negy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(2,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_negz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(3,1:ns,1) - cs = cs + ns - - case (fluxdensity_screw_posx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(1,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_posy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(2,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_posz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(3,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_negx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(1,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_negy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(2,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_negz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(3,1:ns,2) - cs = cs + ns - - case (maximumdipoleheight_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,1) - cs = cs + ns - - case (maximumdipoleheight_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,2) - cs = cs + ns - - case(dislocationstress_ID) - sigma = plastic_nonlocal_dislocationstress(Fe, ip, el) - plastic_nonlocal_postResults(cs+1_pInt) = sigma(1,1) - plastic_nonlocal_postResults(cs+2_pInt) = sigma(2,2) - plastic_nonlocal_postResults(cs+3_pInt) = sigma(3,3) - plastic_nonlocal_postResults(cs+4_pInt) = sigma(1,2) - plastic_nonlocal_postResults(cs+5_pInt) = sigma(2,3) - plastic_nonlocal_postResults(cs+6_pInt) = sigma(3,1) - cs = cs + 6_pInt - - case(accumulatedshear_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = plasticState(ph)%state(iGamma(1:ns,instance),of) - cs = cs + ns - - end select -enddo outputsLoop - -end function plastic_nonlocal_postResults - -end module plastic_nonlocal diff --git a/code/plastic/plastic_phenoplus.f90 b/code/plastic/plastic_phenoplus.f90 deleted file mode 100644 index 0a40edd84..000000000 --- a/code/plastic/plastic_phenoplus.f90 +++ /dev/null @@ -1,1419 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Chen Zhang, Michigan State University -!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw -!... fitting -!-------------------------------------------------------------------------------------------------- -module plastic_phenoplus - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenoplus_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_phenoplus_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_phenoplus_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_phenoplus_Noutput !< number of outputs per instance of this constitution - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenoplus_totalNslip, & !< no. of slip system used in simulation - plastic_phenoplus_totalNtwin, & !< no. of twin system used in simulation - plastic_phenoplus_totalNtrans !< no. of trans system used in simulation - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_phenoplus_Nslip, & !< active number of slip systems per family (input parameter, per family) - plastic_phenoplus_Ntwin, & !< active number of twin systems per family (input parameter, per family) - plastic_phenoplus_Ntrans !< active number of trans systems per family (input parameter, per family) - - real(pReal), dimension(:), allocatable, private :: & - plastic_phenoplus_gdot0_slip, & !< reference shear strain rate for slip (input parameter) - plastic_phenoplus_gdot0_twin, & !< reference shear strain rate for twin (input parameter) - plastic_phenoplus_n_slip, & !< stress exponent for slip (input parameter) - plastic_phenoplus_n_twin, & !< stress exponent for twin (input parameter) - plastic_phenoplus_spr, & !< push-up factor for slip saturation due to twinning - plastic_phenoplus_twinB, & - plastic_phenoplus_twinC, & - plastic_phenoplus_twinD, & - plastic_phenoplus_twinE, & - plastic_phenoplus_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) - plastic_phenoplus_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) - plastic_phenoplus_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) - plastic_phenoplus_a_slip, & - plastic_phenoplus_aTolResistance, & - plastic_phenoplus_aTolShear, & - plastic_phenoplus_aTolTwinfrac, & - plastic_phenoplus_aTolTransfrac, & - plastic_phenoplus_Cnuc, & !< coefficient for strain-induced martensite nucleation - plastic_phenoplus_Cdwp, & !< coefficient for double well potential - plastic_phenoplus_Cgro, & !< coefficient for stress-assisted martensite growth - plastic_phenoplus_deltaG, & !< free energy difference between austensite and martensite [MPa] - plastic_phenoplus_kappa_max !< capped kappa for each slip system - - real(pReal), dimension(:,:), allocatable, private :: & - plastic_phenoplus_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) - plastic_phenoplus_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) - plastic_phenoplus_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) - plastic_phenoplus_nonSchmidCoeff, & - - plastic_phenoplus_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) - plastic_phenoplus_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) - plastic_phenoplus_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) - plastic_phenoplus_interaction_TwinTwin !< interaction factors twin - twin (input parameter) - - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_phenoplus_hardeningMatrix_SlipSlip, & - plastic_phenoplus_hardeningMatrix_SlipTwin, & - plastic_phenoplus_hardeningMatrix_TwinSlip, & - plastic_phenoplus_hardeningMatrix_TwinTwin - - enum, bind(c) - enumerator :: undefined_ID, & - resistance_slip_ID, & - accumulatedshear_slip_ID, & - shearrate_slip_ID, & - resolvedstress_slip_ID, & - kappa_slip_ID, & - totalshear_ID, & - resistance_twin_ID, & - accumulatedshear_twin_ID, & - shearrate_twin_ID, & - resolvedstress_twin_ID, & - totalvolfrac_twin_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_phenoplus_outputID !< ID of each post result output - - public :: & - plastic_phenoplus_init, & - plastic_phenoplus_microstructure, & - plastic_phenoplus_LpAndItsTangent, & - plastic_phenoplus_dotState, & - plastic_phenoplus_postResults - private :: & - plastic_phenoplus_aTolState, & - plastic_phenoplus_stateInit - - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_PHENOPLUS_label, & - PLASTICITY_PHENOPLUS_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - maxNinstance, & - instance,phase,j,k, f,o, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & - Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & - NipcMyPhase, & - offset_slip, index_myFamily, index_otherFamily, & - mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPLUS_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPLUS_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_phenoplus_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_sizePostResult(maxval(phase_Noutput),maxNinstance), & - source=0_pInt) - allocate(plastic_phenoplus_output(maxval(phase_Noutput),maxNinstance)) - plastic_phenoplus_output = '' - allocate(plastic_phenoplus_outputID(maxval(phase_Noutput),maxNinstance),source=undefined_ID) - allocate(plastic_phenoplus_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_Ntrans(lattice_maxNtransFamily,maxNinstance),source=0_pInt) - allocate(plastic_phenoplus_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_totalNtrans(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_gdot0_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_n_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_tau0_slip(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_tausat_slip(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_gdot0_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_n_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_tau0_twin(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_spr(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinB(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinC(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinD(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinE(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_h0_SlipSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_h0_TwinSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_h0_TwinTwin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_a_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolShear(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolTwinfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolTransfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_Cnuc(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_Cdwp(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_Cgro(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_deltaG(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_kappa_max(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase - Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('resistance_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_slip','accumulated_shear_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('kappa_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = kappa_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalshear') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalshear_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_twin','accumulated_shear_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalvolfrac_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalvolfrac_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case default - - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) - do j = 1_pInt, Nchunks_SlipFamilies - plastic_phenoplus_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tausat_slip','tau0_slip') - tempPerSlip = 0.0_pReal - do j = 1_pInt, Nchunks_SlipFamilies - if (plastic_phenoplus_Nslip(j,instance) > 0_pInt) & - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('tausat_slip') - plastic_phenoplus_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau0_slip') - plastic_phenoplus_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_phenoplus_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0_twin') - do j = 1_pInt, Nchunks_TwinFamilies - if (plastic_phenoplus_Ntwin(j,instance) > 0_pInt) & - plastic_phenoplus_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of transformation families - case ('ntrans') - if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - Nchunks_TransFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TransFamilies - plastic_phenoplus_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_phenoplus_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_phenoplus_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_phenoplus_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_phenoplus_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt,Nchunks_nonSchmid - plastic_phenoplus_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin systems - case ('gdot0_slip') - plastic_phenoplus_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_slip') - plastic_phenoplus_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('a_slip', 'w0_slip') - plastic_phenoplus_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('gdot0_twin') - plastic_phenoplus_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_twin') - plastic_phenoplus_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('s_pr') - plastic_phenoplus_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_b') - plastic_phenoplus_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_c') - plastic_phenoplus_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_d') - plastic_phenoplus_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_e') - plastic_phenoplus_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_slipslip') - plastic_phenoplus_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twinslip') - plastic_phenoplus_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twintwin') - plastic_phenoplus_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_resistance') - plastic_phenoplus_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_shear') - plastic_phenoplus_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_phenoplus_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_transfrac') - plastic_phenoplus_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('kappa_max') - plastic_phenoplus_kappa_max(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cnuc') - plastic_phenoplus_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cdwp') - plastic_phenoplus_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cgro') - plastic_phenoplus_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('deltag') - plastic_phenoplus_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) - case default - - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then - instance = phase_plasticityInstance(phase) - plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested - plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance)) - plastic_phenoplus_Ntwin(1:lattice_maxNtwinFamily,instance) = & - min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested - plastic_phenoplus_Ntwin(:,instance)) - plastic_phenoplus_totalNslip(instance) = sum(plastic_phenoplus_Nslip(:,instance)) ! how many slip systems altogether - plastic_phenoplus_totalNtwin(instance) = sum(plastic_phenoplus_Ntwin(:,instance)) ! how many twin systems altogether - plastic_phenoplus_totalNtrans(instance) = sum(plastic_phenoplus_Ntrans(:,instance)) ! how many trans systems altogether - - if (any(plastic_phenoplus_tau0_slip(:,instance) < 0.0_pReal .and. & - plastic_phenoplus_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (plastic_phenoplus_gdot0_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (plastic_phenoplus_n_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (any(plastic_phenoplus_tausat_slip(:,instance) <= 0.0_pReal .and. & - plastic_phenoplus_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (any(abs(plastic_phenoplus_a_slip(instance)) <= tiny(0.0_pReal) .and. & - plastic_phenoplus_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (any(plastic_phenoplus_tau0_twin(:,instance) < 0.0_pReal .and. & - plastic_phenoplus_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPLUS_label//')') - if ( plastic_phenoplus_gdot0_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenoplus_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPLUS_label//')') - if ( plastic_phenoplus_n_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenoplus_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPLUS_label//')') - if (plastic_phenoplus_aTolResistance(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa - if (plastic_phenoplus_aTolShear(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenoplus_aTolTwinfrac(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenoplus_aTolTransfrac(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - allocate(plastic_phenoplus_hardeningMatrix_SlipSlip(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from slip activity - maxval(plastic_phenoplus_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_hardeningMatrix_SlipTwin(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from twin activity - maxval(plastic_phenoplus_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_hardeningMatrix_TwinSlip(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_phenoplus_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_hardeningMatrix_TwinTwin(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_phenoplus_totalNtwin),& - maxNinstance), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config - myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then ! only consider my phase - NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase - instance = phase_plasticityInstance(phase) ! which instance of my phase - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) - select case(plastic_phenoplus_outputID(o,instance)) - case(resistance_slip_ID, & - shearrate_slip_ID, & - accumulatedshear_slip_ID, & - resolvedstress_slip_ID, & - kappa_slip_ID & - ) - mySize = plastic_phenoplus_totalNslip(instance) - case(resistance_twin_ID, & - shearrate_twin_ID, & - accumulatedshear_twin_ID, & - resolvedstress_twin_ID & - ) - mySize = plastic_phenoplus_totalNtwin(instance) - case(totalshear_ID, & - totalvolfrac_twin_ID & - ) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_phenoplus_sizePostResult(o,instance) = mySize - plastic_phenoplus_sizePostResults(instance) = plastic_phenoplus_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = plastic_phenoplus_totalNslip(instance) & ! s_slip - + plastic_phenoplus_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) - + plastic_phenoplus_totalNslip(instance) & ! accshear_slip - + plastic_phenoplus_totalNtwin(instance) & ! accshear_twin - + plastic_phenoplus_totalNslip(instance) ! kappa - - !sizeDotState = sizeState ! same as sizeState - !QUICK FIX: the dotState cannot have redundancy, which could cause unknown error - ! explicitly specify the size of the dotState to avoid this potential - ! memory leak issue. - sizeDotState = plastic_phenoplus_totalNslip(instance) & ! s_slip - + plastic_phenoplus_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) - + plastic_phenoplus_totalNslip(instance) & ! accshear_slip - + plastic_phenoplus_totalNtwin(instance) ! accshear_twin - - sizeDeltaState = 0_pInt - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_phenoplus_sizePostResults(instance) - plasticState(phase)%nSlip =plastic_phenoplus_totalNslip(instance) - plasticState(phase)%nTwin =plastic_phenoplus_totalNtwin(instance) - plasticState(phase)%nTrans=plastic_phenoplus_totalNtrans(instance) - allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) - - offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - - do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X - index_myFamily = sum(plastic_phenoplus_Nslip(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenoplus_Nslip(f,instance) ! loop over (active) systems in my family (slip) - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenoplus_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenoplus_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - - do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X - index_myFamily = sum(plastic_phenoplus_Ntwin(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenoplus_Ntwin(f,instance) ! loop over (active) systems in my family (twin) - - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenoplus_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenoplus_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - - call plastic_phenoplus_stateInit(phase,instance) - call plastic_phenoplus_aTolState(phase,instance) - endif myPhase2 - enddo initializeInstances - -end subroutine plastic_phenoplus_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_stateInit(ph,instance) - use lattice, only: & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - integer(pInt) :: & - i - real(pReal), dimension(plasticState(ph)%sizeState) :: & - tempState - - tempState = 0.0_pReal - do i = 1_pInt,lattice_maxNslipFamily - tempState(1+sum(plastic_phenoplus_Nslip(1:i-1,instance)) : & - sum(plastic_phenoplus_Nslip(1:i ,instance))) = & - plastic_phenoplus_tau0_slip(i,instance) - enddo - - do i = 1_pInt,lattice_maxNtwinFamily - tempState(1+sum(plastic_phenoplus_Nslip(:,instance))+& - sum(plastic_phenoplus_Ntwin(1:i-1,instance)) : & - sum(plastic_phenoplus_Nslip(:,instance))+& - sum(plastic_phenoplus_Ntwin(1:i ,instance))) = & - plastic_phenoplus_tau0_twin(i,instance) - enddo - - plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array - 2, & ! along dimension 2 - size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) - -end subroutine plastic_phenoplus_stateInit - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - plasticState(ph)%aTolState(1:plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance)) = & - plastic_phenoplus_aTolResistance(instance) - plasticState(ph)%aTolState(1+plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance)) = & - plastic_phenoplus_aTolShear(instance) - plasticState(ph)%aTolState(2+plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance)) = & - plastic_phenoplus_aTolTwinFrac(instance) - plasticState(ph)%aTolState(3+plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance): & - 2+2*(plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance))) = & - plastic_phenoplus_aTolShear(instance) - -end subroutine plastic_phenoplus_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate push-up factors (kappa) for each voxel based on its neighbors -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el) - use math, only: pi, & - math_mul33x33, & - math_mul3x3, & - math_transpose33, & - math_qDot, & - math_qRot, & - indeg - - use mesh, only: mesh_element, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype, & - mesh_maxNips, & - mesh_NcpElems, & - mesh_ipNeighborhood - - use material, only: material_phase, & - material_texture, & - phase_plasticityInstance, & - phaseAt, phasememberAt, & - homogenization_maxNgrains, & - plasticState - - use lattice, only: lattice_sn, & - lattice_sd, & - lattice_qDisorientation - - !***input variables - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - orientation ! crystal orientation in quaternions - - !***local variables - integer(pInt) instance, & !my instance of this plasticity - ph, & !my phase - of, & !my spatial position in memory (offset) - textureID, & !my texture - Nneighbors, & !number of neighbors (<= 6) - vld_Nneighbors, & !number of my valid neighbors - n, & !neighbor index (for iterating through all neighbors) - ns, & !number of slip system - nt, & !number of twin system - me_slip, & !my slip system index - neighbor_el, & !element number of neighboring material point - neighbor_ip, & !integration point of neighboring material point - neighbor_n, & !I have no idea what is this - neighbor_of, & !spatial position in memory for this neighbor (offset) - neighbor_ph, & !neighbor's phase - neighbor_tex, & !neighbor's texture ID - ne_slip_ac, & !loop to find neighbor shear - ne_slip, & !slip system index for neighbor - index_kappa, & !index of pushup factors in plasticState - offset_acshear_slip, & !offset in PlasticState for the accumulative shear - j !quickly loop through slip families - - real(pReal) kappa_max, & ! - tmp_myshear_slip, & !temp storage for accumulative shear for me - mprime_cut, & !m' cutoff to consider neighboring effect - avg_acshear_ne, & !the average accumulative shear from my neighbor - tmp_mprime, & !temp holder for m' value - tmp_acshear !temp holder for accumulative shear for m' - - - real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - m_primes, & !m' between me_alpha(one) and neighbor beta(all) - me_acshear, & !temp storage for ac_shear of one particular system for me - ne_acshear !temp storage for ac_shear of one particular system for one of my neighbor - - real(pReal), dimension(3,plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - slipNormal, & - slipDirect - - real(pReal), dimension(4) :: my_orientation, & !store my orientation - neighbor_orientation, & !store my neighbor orientation - absMisorientation - - real(pReal), dimension(FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) :: & - ne_mprimes !m' between each neighbor - - !***Get my properties - Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) - ph = phaseAt(ipc,ip,el) !get my phase - of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory - textureID = material_texture(1,ip,el) !get my texture ID - instance = phase_plasticityInstance(ph) !get my instance based on phase ID - ns = plastic_phenoplus_totalNslip(instance) - nt = plastic_phenoplus_totalNtwin(instance) - offset_acshear_slip = ns + nt + 2_pInt - index_kappa = ns + nt + 2_pInt + ns + nt !location of kappa in plasticState - mprime_cut = 0.7_pReal !set by Dr.Bieler - - !***gather my accumulative shear from palsticState - FINDMYSHEAR: do j = 1_pInt,ns - me_acshear(j) = plasticState(ph)%state(offset_acshear_slip+j, of) - enddo FINDMYSHEAR - - !***gather my orientation and slip systems - my_orientation = orientation(1:4, ipc, ip, el) - slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) - slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) - kappa_max = plastic_phenoplus_kappa_max(instance) !maximum pushups allowed (READIN) - - !***calculate kappa between me and all my neighbors - LOOPMYSLIP: DO me_slip=1_pInt,ns - vld_Nneighbors = Nneighbors - tmp_myshear_slip = me_acshear(me_slip) - tmp_mprime = 0.0_pReal !highest m' from all neighbors - tmp_acshear = 0.0_pReal !accumulative shear from highest m' - - !***go through my neighbors to find highest m' - LOOPNEIGHBORS: DO n=1_pInt,Nneighbors - neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - neighbor_n = 1 !It is ipc - neighbor_of = phasememberAt( neighbor_n, neighbor_ip, neighbor_el) - neighbor_ph = phaseAt( neighbor_n, neighbor_ip, neighbor_el) - neighbor_tex = material_texture(1,neighbor_ip,neighbor_el) - neighbor_orientation = orientation(1:4, neighbor_n, neighbor_ip, neighbor_el) !ipc is always 1. - absMisorientation = lattice_qDisorientation(my_orientation, & - neighbor_orientation, & - 0_pInt) !no need for explicit calculation of symmetry - - !***find the accumulative shear for this neighbor - LOOPFINDNEISHEAR: DO ne_slip_ac=1_pInt, ns - ne_acshear(ne_slip_ac) = plasticState(ph)%state(offset_acshear_slip+ne_slip_ac, & - neighbor_of) - ENDDO LOOPFINDNEISHEAR - - !***calculate the average accumulative shear and use it as cutoff - avg_acshear_ne = SUM(ne_acshear)/ns - - !*** - IF (ph==neighbor_ph) THEN - !***walk through all the - LOOPNEIGHBORSLIP: DO ne_slip=1_pInt,ns - !***only consider slip system that is active (above average accumulative shear) - IF (ne_acshear(ne_slip) > avg_acshear_ne) THEN - m_primes(ne_slip) = abs(math_mul3x3(slipNormal(1:3,me_slip), & - math_qRot(absMisorientation, slipNormal(1:3,ne_slip)))) & - *abs(math_mul3x3(slipDirect(1:3,me_slip), & - math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) - !***find the highest m' and corresponding accumulative shear - IF (m_primes(ne_slip) > tmp_mprime) THEN - tmp_mprime = m_primes(ne_slip) - tmp_acshear = ne_acshear(ne_slip) - ENDIF - ENDIF - ENDDO LOOPNEIGHBORSLIP - - ELSE - ne_mprimes(n) = 0.0_pReal - vld_Nneighbors = vld_Nneighbors - 1_pInt - ENDIF - - ENDDO LOOPNEIGHBORS - - !***check if this element close to rim - IF (vld_Nneighbors < Nneighbors) THEN - !***rim voxel, no modification allowed - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal - ELSE - !***patch voxel, started to calculate push up factor for gamma_dot - IF ((tmp_mprime > mprime_cut) .AND. (tmp_acshear > tmp_myshear_slip)) THEN - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal / tmp_mprime - ELSE - !***minimum damping factor is 0.5 - plasticState(ph)%state(index_kappa+me_slip, of) = 0.5_pReal + tmp_mprime * 0.5_pReal - ENDIF - ENDIF - - ENDDO LOOPMYSLIP - -end subroutine plastic_phenoplus_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use math, only: & - math_Plain3333to99, & - math_Mandel6to33 - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - use material, only: & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - - integer(pInt) :: & - instance, & - nSlip, & - nTwin,index_Gamma,index_F,index_myFamily, index_kappa, & - f,i,j,k,l,m,n, & - of, & - ph - real(pReal) :: & - tau_slip_pos,tau_slip_neg, & - gdot_slip_pos,gdot_slip_neg, & - dgdot_dtauslip_pos,dgdot_dtauslip_neg, & - gdot_twin,dgdot_dtautwin,tau_twin - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal), dimension(3,3,2) :: & - nonSchmid_tensor - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - nSlip = plastic_phenoplus_totalNslip(instance) - nTwin = plastic_phenoplus_totalNtwin(instance) - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - index_kappa = nSlip + nTwin + 2_pInt +nSlip + nTwin - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Slip part - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) - enddo - - !***insert non-local effect here by modify gdot with kappa in plastic state - !***this implementation will most likely cause convergence issue - ! gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ! ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of)* & - ! plasticState(ph)%state(j+index_kappa, of))) & !in-place modification of gdot - ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) - - ! gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ! ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of)* & - ! plasticState(ph)%state(j+index_kappa, of))) & !?should we make it direction aware - ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) - - !***original calculation - gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of))) & !in-place modification of gdot - **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) - - gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of))) & !?should we make it direction aware - **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) - - !***MAGIC HERE***! - !***directly modify the amount of shear happens considering neighborhood - gdot_slip_pos = gdot_slip_pos * plasticState(ph)%state(j+index_kappa, of) - gdot_slip_neg = gdot_slip_neg * plasticState(ph)%state(j+index_kappa, of) - - Lp = Lp + (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then - dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenoplus_n_slip(instance)/tau_slip_pos - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,1) - endif - - if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then - dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenoplus_n_slip(instance)/tau_slip_neg - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,2) - endif - enddo slipSystems - enddo slipFamilies - -!-------------------------------------------------------------------------------------------------- -! Twinning part - j = 0_pInt - twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenoplus_gdot0_twin(instance)*& - (abs(tau_twin)/plasticState(ph)%state(nSlip+j,of))**& - plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_twin) > tiny(0.0_pReal)) then - dgdot_dtautwin = gdot_twin*plastic_phenoplus_n_twin(instance)/tau_twin - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & - lattice_Stwin(m,n,index_myFamily+i,ph) - endif - enddo twinSystems - enddo twinFamilies - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - - -end subroutine plastic_phenoplus_LpAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_dotState(Tstar_v,ipc,ip,el) - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_shearTwin, & - lattice_NnonSchmid - use material, only: & - material_phase, & - phaseAt, phasememberAt, & - plasticState, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - integer(pInt) :: & - instance,ph, & - nSlip,nTwin, & - f,i,j,k, & - index_Gamma,index_F,index_myFamily,& - offset_accshear_slip,offset_accshear_twin, offset_kappa, & - of - real(pReal) :: & - c_SlipSlip,c_TwinSlip,c_TwinTwin, & - ssat_offset, & - tau_slip_pos,tau_slip_neg,tau_twin - - real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip - real(pReal), dimension(plastic_phenoplus_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenoplus_totalNslip(instance) - nTwin = plastic_phenoplus_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - offset_accshear_slip = nSlip + nTwin + 2_pInt - offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip - offset_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin - plasticState(ph)%dotState(:,of) = 0.0_pReal - - -!-------------------------------------------------------------------------------------------------- -! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices - c_SlipSlip = plastic_phenoplus_h0_SlipSlip(instance)*& - (1.0_pReal + plastic_phenoplus_twinC(instance)*plasticState(ph)%state(index_F,of)**& - plastic_phenoplus_twinB(instance)) - c_TwinSlip = plastic_phenoplus_h0_TwinSlip(instance)*& - plasticState(ph)%state(index_Gamma,of)**plastic_phenoplus_twinE(instance) - c_TwinTwin = plastic_phenoplus_h0_TwinTwin(instance)*& - plasticState(ph)%state(index_F,of)**plastic_phenoplus_twinD(instance) - -!-------------------------------------------------------------------------------------------------- -! calculate left and right vectors and calculate dot gammas - ssat_offset = plastic_phenoplus_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j+1_pInt - left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part - left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part - !***original implementation - right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & - **plastic_phenoplus_a_slip(instance)& - *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) - !***modify a_slip to get nonlocal effect - ! right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & - ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & - ! **(plastic_phenoplus_a_slip(instance)*plasticState(ph)%state(j+offset_kappa, of))& - ! *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & - ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) - right_TwinSlip(j) = 1.0_pReal ! no system-dependent part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot gamma - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - gdot_slip(j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance) & - +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - enddo slipSystems1 - enddo slipFamilies1 - - - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j+1_pInt - left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part - left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part - right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part - right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot vol frac - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenoplus_gdot0_twin(instance)*& - (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& - plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - enddo twinSystems1 - enddo twinFamilies1 - -!-------------------------------------------------------------------------------------------------- -! calculate the overall hardening based on above - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j - c_SlipSlip * left_SlipSlip(j) * & - dot_product(plastic_phenoplus_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & - right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - dot_product(plastic_phenoplus_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & - right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & - abs(gdot_slip(j)) - plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) - enddo slipSystems2 - enddo slipFamilies2 - - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j - c_TwinSlip * left_TwinSlip(j) * & - dot_product(plastic_phenoplus_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & - right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - c_TwinTwin * left_TwinTwin(j) * & - dot_product(plastic_phenoplus_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & - right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 - plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & - gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) - plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) - enddo twinSystems2 - enddo twinFamilies2 - - -end subroutine plastic_phenoplus_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_phenoplus_postResults(Tstar_v,ipc,ip,el) - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - real(pReal), dimension(plastic_phenoplus_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_phenoplus_postResults - - integer(pInt) :: & - instance,ph, of, & - nSlip,nTwin, & - o,f,i,c,j,k, & - index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily,index_kappa - real(pReal) :: & - tau_slip_pos,tau_slip_neg,tau - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenoplus_totalNslip(instance) - nTwin = plastic_phenoplus_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - index_accshear_slip = nSlip + nTwin + 2_pInt + 1_pInt - index_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + 1_pInt - index_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin + 1_pInt - - plastic_phenoplus_postResults = 0.0_pReal - c = 0_pInt - - outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) - select case(plastic_phenoplus_outputID(o,instance)) - case (resistance_slip_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) - c = c + nSlip - - case (accumulatedshear_slip_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& - index_accshear_slip+nSlip-1_pInt,of) - c = c + nSlip - - case (shearrate_slip_ID) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j + 1_pInt - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo - plastic_phenoplus_postResults(c+j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance) & - +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - - enddo slipSystems1 - enddo slipFamilies1 - c = c + nSlip - - case (resolvedstress_slip_ID) - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j + 1_pInt - plastic_phenoplus_postResults(c+j) = & - dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - enddo slipSystems2 - enddo slipFamilies2 - c = c + nSlip - - case (kappa_slip_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = & - plasticState(ph)%state(index_kappa:index_kappa+nSlip-1_pInt,of) - c = c + nSlip - - case (totalshear_ID) - plastic_phenoplus_postResults(c+1_pInt) = & - plasticState(ph)%state(index_Gamma,of) - c = c + 1_pInt - - case (resistance_twin_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) - c = c + nTwin - - case (accumulatedshear_twin_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) - c = c + nTwin - - case (shearrate_twin_ID) - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j + 1_pInt - tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - plastic_phenoplus_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenoplus_gdot0_twin(instance)*& - (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& - plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) - enddo twinSystems1 - enddo twinFamilies1 - c = c + nTwin - - case (resolvedstress_twin_ID) - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j + 1_pInt - plastic_phenoplus_postResults(c+j) = & - dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - enddo twinSystems2 - enddo twinFamilies2 - c = c + nTwin - - case (totalvolfrac_twin_ID) - plastic_phenoplus_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) - c = c + 1_pInt - - end select - enddo outputsLoop - -end function plastic_phenoplus_postResults - -end module plastic_phenoplus diff --git a/code/plastic/plastic_phenopowerlaw.f90 b/code/plastic/plastic_phenopowerlaw.f90 deleted file mode 100644 index 1f8e16250..000000000 --- a/code/plastic/plastic_phenopowerlaw.f90 +++ /dev/null @@ -1,1226 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw -!! fitting -!-------------------------------------------------------------------------------------------------- -module plastic_phenopowerlaw - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenopowerlaw_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_phenopowerlaw_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_phenopowerlaw_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_phenopowerlaw_Noutput !< number of outputs per instance of this constitution - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenopowerlaw_totalNslip, & !< no. of slip system used in simulation - plastic_phenopowerlaw_totalNtwin, & !< no. of twin system used in simulation - plastic_phenopowerlaw_totalNtrans !< no. of trans system used in simulation - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_phenopowerlaw_Nslip, & !< active number of slip systems per family (input parameter, per family) - plastic_phenopowerlaw_Ntwin, & !< active number of twin systems per family (input parameter, per family) - plastic_phenopowerlaw_Ntrans !< active number of trans systems per family (input parameter, per family) - - real(pReal), dimension(:), allocatable, private :: & - plastic_phenopowerlaw_gdot0_slip, & !< reference shear strain rate for slip (input parameter) - plastic_phenopowerlaw_gdot0_twin, & !< reference shear strain rate for twin (input parameter) - plastic_phenopowerlaw_n_slip, & !< stress exponent for slip (input parameter) - plastic_phenopowerlaw_n_twin, & !< stress exponent for twin (input parameter) - plastic_phenopowerlaw_spr, & !< push-up factor for slip saturation due to twinning - plastic_phenopowerlaw_twinB, & - plastic_phenopowerlaw_twinC, & - plastic_phenopowerlaw_twinD, & - plastic_phenopowerlaw_twinE, & - plastic_phenopowerlaw_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) - plastic_phenopowerlaw_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) - plastic_phenopowerlaw_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) - plastic_phenopowerlaw_a_slip, & - plastic_phenopowerlaw_aTolResistance, & - plastic_phenopowerlaw_aTolShear, & - plastic_phenopowerlaw_aTolTwinfrac, & - plastic_phenopowerlaw_aTolTransfrac, & - plastic_phenopowerlaw_Cnuc, & !< coefficient for strain-induced martensite nucleation - plastic_phenopowerlaw_Cdwp, & !< coefficient for double well potential - plastic_phenopowerlaw_Cgro, & !< coefficient for stress-assisted martensite growth - plastic_phenopowerlaw_deltaG !< free energy difference between austensite and martensite [MPa] - - real(pReal), dimension(:,:), allocatable, private :: & - plastic_phenopowerlaw_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) - plastic_phenopowerlaw_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) - plastic_phenopowerlaw_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) - plastic_phenopowerlaw_nonSchmidCoeff, & - - plastic_phenopowerlaw_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) - plastic_phenopowerlaw_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) - plastic_phenopowerlaw_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) - plastic_phenopowerlaw_interaction_TwinTwin !< interaction factors twin - twin (input parameter) - - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_phenopowerlaw_hardeningMatrix_SlipSlip, & - plastic_phenopowerlaw_hardeningMatrix_SlipTwin, & - plastic_phenopowerlaw_hardeningMatrix_TwinSlip, & - plastic_phenopowerlaw_hardeningMatrix_TwinTwin - - enum, bind(c) - enumerator :: undefined_ID, & - resistance_slip_ID, & - accumulatedshear_slip_ID, & - shearrate_slip_ID, & - resolvedstress_slip_ID, & - totalshear_ID, & - resistance_twin_ID, & - accumulatedshear_twin_ID, & - shearrate_twin_ID, & - resolvedstress_twin_ID, & - totalvolfrac_twin_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_phenopowerlaw_outputID !< ID of each post result output - - type, private :: tPhenopowerlawState - real(pReal), pointer, dimension(:,:) :: & - s_slip, & - s_twin, & - accshear_slip, & - accshear_twin - real(pReal), pointer, dimension(:) :: & - sumGamma, & - sumF - end type - - type(tPhenopowerlawState), allocatable, dimension(:), private :: & - dotState, & - state, & - state0 - - public :: & - plastic_phenopowerlaw_init, & - plastic_phenopowerlaw_LpAndItsTangent, & - plastic_phenopowerlaw_dotState, & - plastic_phenopowerlaw_postResults - private :: & - plastic_phenopowerlaw_aTolState, & - plastic_phenopowerlaw_stateInit - - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_PHENOPOWERLAW_label, & - PLASTICITY_PHENOPOWERLAW_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - maxNinstance, & - instance,phase,j,k, f,o, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & - Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & - NipcMyPhase, & - offset_slip, index_myFamily, index_otherFamily, & - mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState, & - startIndex, endIndex - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPOWERLAW_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPOWERLAW_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - - allocate(plastic_phenopowerlaw_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_sizePostResult(maxval(phase_Noutput),maxNinstance), & - source=0_pInt) - allocate(plastic_phenopowerlaw_output(maxval(phase_Noutput),maxNinstance)) - plastic_phenopowerlaw_output = '' - allocate(plastic_phenopowerlaw_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_phenopowerlaw_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_totalNtrans(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_gdot0_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_n_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_tau0_slip(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_tausat_slip(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_phenopowerlaw_gdot0_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_n_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_tau0_twin(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_spr(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinB(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinC(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinD(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinE(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_h0_SlipSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_h0_TwinSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_h0_TwinTwin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_a_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolShear(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolTwinfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolTransfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_Cnuc(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_Cdwp(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_Cgro(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_deltaG(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase - Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('resistance_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_slip','accumulated_shear_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalshear') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalshear_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_twin','accumulated_shear_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalvolfrac_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalvolfrac_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case default - - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) - do j = 1_pInt, Nchunks_SlipFamilies - plastic_phenopowerlaw_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tausat_slip','tau0_slip') - tempPerSlip = 0.0_pReal - do j = 1_pInt, Nchunks_SlipFamilies - if (plastic_phenopowerlaw_Nslip(j,instance) > 0_pInt) & - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('tausat_slip') - plastic_phenopowerlaw_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau0_slip') - plastic_phenopowerlaw_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_phenopowerlaw_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0_twin') - do j = 1_pInt, Nchunks_TwinFamilies - if (plastic_phenopowerlaw_Ntwin(j,instance) > 0_pInt) & - plastic_phenopowerlaw_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of transformation families - case ('ntrans') - if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - Nchunks_TransFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TransFamilies - plastic_phenopowerlaw_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_phenopowerlaw_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_phenopowerlaw_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_phenopowerlaw_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_phenopowerlaw_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt,Nchunks_nonSchmid - plastic_phenopowerlaw_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin systems - case ('gdot0_slip') - plastic_phenopowerlaw_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_slip') - plastic_phenopowerlaw_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('a_slip', 'w0_slip') - plastic_phenopowerlaw_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('gdot0_twin') - plastic_phenopowerlaw_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_twin') - plastic_phenopowerlaw_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('s_pr') - plastic_phenopowerlaw_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_b') - plastic_phenopowerlaw_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_c') - plastic_phenopowerlaw_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_d') - plastic_phenopowerlaw_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_e') - plastic_phenopowerlaw_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_slipslip') - plastic_phenopowerlaw_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twinslip') - plastic_phenopowerlaw_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twintwin') - plastic_phenopowerlaw_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_resistance') - plastic_phenopowerlaw_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_shear') - plastic_phenopowerlaw_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_phenopowerlaw_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_transfrac') - plastic_phenopowerlaw_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cnuc') - plastic_phenopowerlaw_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cdwp') - plastic_phenopowerlaw_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cgro') - plastic_phenopowerlaw_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('deltag') - plastic_phenopowerlaw_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) - case default - - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then - instance = phase_plasticityInstance(phase) - plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested - plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance)) - plastic_phenopowerlaw_Ntwin(1:lattice_maxNtwinFamily,instance) = & - min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested - plastic_phenopowerlaw_Ntwin(:,instance)) - plastic_phenopowerlaw_totalNslip(instance) = sum(plastic_phenopowerlaw_Nslip(:,instance)) ! how many slip systems altogether - plastic_phenopowerlaw_totalNtwin(instance) = sum(plastic_phenopowerlaw_Ntwin(:,instance)) ! how many twin systems altogether - plastic_phenopowerlaw_totalNtrans(instance) = sum(plastic_phenopowerlaw_Ntrans(:,instance)) ! how many trans systems altogether - - if (any(plastic_phenopowerlaw_tau0_slip(:,instance) < 0.0_pReal .and. & - plastic_phenopowerlaw_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (plastic_phenopowerlaw_gdot0_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (plastic_phenopowerlaw_n_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (any(plastic_phenopowerlaw_tausat_slip(:,instance) <= 0.0_pReal .and. & - plastic_phenopowerlaw_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (any(abs(plastic_phenopowerlaw_a_slip(instance)) <= tiny(0.0_pReal) .and. & - plastic_phenopowerlaw_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (any(plastic_phenopowerlaw_tau0_twin(:,instance) < 0.0_pReal .and. & - plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') - if ( plastic_phenopowerlaw_gdot0_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') - if ( plastic_phenopowerlaw_n_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (plastic_phenopowerlaw_aTolResistance(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa - if (plastic_phenopowerlaw_aTolShear(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenopowerlaw_aTolTwinfrac(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenopowerlaw_aTolTransfrac(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - allocate(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from slip activity - maxval(plastic_phenopowerlaw_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from twin activity - maxval(plastic_phenopowerlaw_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_phenopowerlaw_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_phenopowerlaw_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(state(maxNinstance)) - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config - myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then ! only consider my phase - NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase - instance = phase_plasticityInstance(phase) ! which instance of my phase - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) - select case(plastic_phenopowerlaw_outputID(o,instance)) - case(resistance_slip_ID, & - shearrate_slip_ID, & - accumulatedshear_slip_ID, & - resolvedstress_slip_ID & - ) - mySize = plastic_phenopowerlaw_totalNslip(instance) - case(resistance_twin_ID, & - shearrate_twin_ID, & - accumulatedshear_twin_ID, & - resolvedstress_twin_ID & - ) - mySize = plastic_phenopowerlaw_totalNtwin(instance) - case(totalshear_ID, & - totalvolfrac_twin_ID & - ) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_phenopowerlaw_sizePostResult(o,instance) = mySize - plastic_phenopowerlaw_sizePostResults(instance) = plastic_phenopowerlaw_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = plastic_phenopowerlaw_totalNslip(instance) & ! s_slip - + plastic_phenopowerlaw_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) - + plastic_phenopowerlaw_totalNslip(instance) & ! accshear_slip - + plastic_phenopowerlaw_totalNtwin(instance) ! accshear_twin - - sizeDotState = sizeState - sizeDeltaState = 0_pInt - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_phenopowerlaw_sizePostResults(instance) - plasticState(phase)%nSlip =plastic_phenopowerlaw_totalNslip(instance) - plasticState(phase)%nTwin =plastic_phenopowerlaw_totalNtwin(instance) - plasticState(phase)%nTrans=plastic_phenopowerlaw_totalNtrans(instance) - allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) - - offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - - do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X - index_myFamily = sum(plastic_phenopowerlaw_Nslip(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) ! loop over (active) systems in my family (slip) - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenopowerlaw_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenopowerlaw_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - - do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X - index_myFamily = sum(plastic_phenopowerlaw_Ntwin(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) ! loop over (active) systems in my family (twin) - - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenopowerlaw_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenopowerlaw_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - startIndex = 1_pInt - endIndex = plastic_phenopowerlaw_totalNslip(instance) - state (instance)%s_slip=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%s_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%s_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex + plastic_phenopowerlaw_totalNtwin(instance) - state (instance)%s_twin=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%s_twin=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%s_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex + 1_pInt - state (instance)%sumGamma=>plasticState(phase)%state (startIndex,:) - state0 (instance)%sumGamma=>plasticState(phase)%state0 (startIndex,:) - dotState(instance)%sumGamma=>plasticState(phase)%dotState(startIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex + 1_pInt - state (instance)%sumF=>plasticState(phase)%state (startIndex,:) - state0 (instance)%sumF=>plasticState(phase)%state0 (startIndex,:) - dotState(instance)%sumF=>plasticState(phase)%dotState(startIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex +plastic_phenopowerlaw_totalNslip(instance) - state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex +plastic_phenopowerlaw_totalNtwin(instance) - state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - - call plastic_phenopowerlaw_stateInit(phase,instance) - call plastic_phenopowerlaw_aTolState(phase,instance) - endif myPhase2 - enddo initializeInstances - -end subroutine plastic_phenopowerlaw_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_stateInit(ph,instance) - use lattice, only: & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - integer(pInt) :: & - i - real(pReal), dimension(plasticState(ph)%sizeState) :: & - tempState - - tempState = 0.0_pReal - do i = 1_pInt,lattice_maxNslipFamily - tempState(1+sum(plastic_phenopowerlaw_Nslip(1:i-1,instance)) : & - sum(plastic_phenopowerlaw_Nslip(1:i ,instance))) = & - plastic_phenopowerlaw_tau0_slip(i,instance) - enddo - - do i = 1_pInt,lattice_maxNtwinFamily - tempState(1+sum(plastic_phenopowerlaw_Nslip(:,instance))+& - sum(plastic_phenopowerlaw_Ntwin(1:i-1,instance)) : & - sum(plastic_phenopowerlaw_Nslip(:,instance))+& - sum(plastic_phenopowerlaw_Ntwin(1:i ,instance))) = & - plastic_phenopowerlaw_tau0_twin(i,instance) - enddo - - plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array - 2, & ! along dimension 2 - size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) - -end subroutine plastic_phenopowerlaw_stateInit - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - plasticState(ph)%aTolState(1:plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance)) = & - plastic_phenopowerlaw_aTolResistance(instance) - plasticState(ph)%aTolState(1+plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance)) = & - plastic_phenopowerlaw_aTolShear(instance) - plasticState(ph)%aTolState(2+plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance)) = & - plastic_phenopowerlaw_aTolTwinFrac(instance) - plasticState(ph)%aTolState(3+plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance): & - 2+2*(plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance))) = & - plastic_phenopowerlaw_aTolShear(instance) - -end subroutine plastic_phenopowerlaw_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use math, only: & - math_Plain3333to99, & - math_Mandel6to33 - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - use material, only: & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - - integer(pInt) :: & - instance, & - index_myFamily, & - f,i,j,k,l,m,n, & - of, & - ph - real(pReal) :: & - tau_slip_pos,tau_slip_neg, & - gdot_slip_pos,gdot_slip_neg, & - dgdot_dtauslip_pos,dgdot_dtauslip_neg, & - gdot_twin,dgdot_dtautwin,tau_twin - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal), dimension(3,3,2) :: & - nonSchmid_tensor - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Slip part - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) - enddo - gdot_slip_pos = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & - ((abs(tau_slip_pos)/(state(instance)%s_slip(j,of))) & - **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) - - gdot_slip_neg = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & - ((abs(tau_slip_neg)/(state(instance)%s_slip(j,of))) & - **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) - - Lp = Lp + (1.0_pReal-state(instance)%sumF(of))*& ! 1-F - (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then - dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenopowerlaw_n_slip(instance)/tau_slip_pos - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,1) - endif - - if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then - dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenopowerlaw_n_slip(instance)/tau_slip_neg - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,2) - endif - enddo slipSystems - enddo slipFamilies - -!-------------------------------------------------------------------------------------------------- -! Twinning part - j = 0_pInt - twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin = (1.0_pReal-state(instance)%sumF(of))*& ! 1-F - plastic_phenopowerlaw_gdot0_twin(instance)*& - (abs(tau_twin)/state(instance)%s_twin(j,of))**& - plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_twin) > tiny(0.0_pReal)) then - dgdot_dtautwin = gdot_twin*plastic_phenopowerlaw_n_twin(instance)/tau_twin - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & - lattice_Stwin(m,n,index_myFamily+i,ph) - endif - enddo twinSystems - enddo twinFamilies - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - - -end subroutine plastic_phenopowerlaw_LpAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_dotState(Tstar_v,ipc,ip,el) - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_shearTwin, & - lattice_NnonSchmid - use material, only: & - material_phase, & - phaseAt, phasememberAt, & - plasticState, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - integer(pInt) :: & - instance,ph, & - nSlip,nTwin, & - f,i,j,k, & - index_Gamma,index_F,index_myFamily, & - offset_accshear_slip,offset_accshear_twin, & - of - real(pReal) :: & - c_SlipSlip,c_TwinSlip,c_TwinTwin, & - ssat_offset, & - tau_slip_pos,tau_slip_neg,tau_twin - - real(pReal), dimension(plastic_phenopowerlaw_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip - real(pReal), dimension(plastic_phenopowerlaw_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenopowerlaw_totalNslip(instance) - nTwin = plastic_phenopowerlaw_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - offset_accshear_slip = nSlip + nTwin + 2_pInt - offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip - plasticState(ph)%dotState(:,of) = 0.0_pReal - - -!-------------------------------------------------------------------------------------------------- -! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices - c_SlipSlip = plastic_phenopowerlaw_h0_SlipSlip(instance)*& - (1.0_pReal + plastic_phenopowerlaw_twinC(instance)*plasticState(ph)%state(index_F,of)**& - plastic_phenopowerlaw_twinB(instance)) - c_TwinSlip = plastic_phenopowerlaw_h0_TwinSlip(instance)*& - plasticState(ph)%state(index_Gamma,of)**plastic_phenopowerlaw_twinE(instance) - c_TwinTwin = plastic_phenopowerlaw_h0_TwinTwin(instance)*& - plasticState(ph)%state(index_F,of)**plastic_phenopowerlaw_twinD(instance) - -!-------------------------------------------------------------------------------------------------- -! calculate left and right vectors and calculate dot gammas - ssat_offset = plastic_phenopowerlaw_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j+1_pInt - left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part - left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part - right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) & - **plastic_phenopowerlaw_a_slip(instance)& - *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) - right_TwinSlip(j) = 1.0_pReal ! no system-dependent part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot gamma - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - gdot_slip(j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance) & - +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - enddo slipSystems1 - enddo slipFamilies1 - - - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j+1_pInt - left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part - left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part - right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part - right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot vol frac - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenopowerlaw_gdot0_twin(instance)*& - (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& - plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - enddo twinSystems1 - enddo twinFamilies1 - -!-------------------------------------------------------------------------------------------------- -! calculate the overall hardening based on above - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j - c_SlipSlip * left_SlipSlip(j) * & - dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & - right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & - right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & - abs(gdot_slip(j)) - plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) - enddo slipSystems2 - enddo slipFamilies2 - - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j - c_TwinSlip * left_TwinSlip(j) * & - dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & - right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - c_TwinTwin * left_TwinTwin(j) * & - dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & - right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 - plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & - gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) - plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) - enddo twinSystems2 - enddo twinFamilies2 - - -end subroutine plastic_phenopowerlaw_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_phenopowerlaw_postResults(Tstar_v,ipc,ip,el) - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - real(pReal), dimension(plastic_phenopowerlaw_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_phenopowerlaw_postResults - - integer(pInt) :: & - instance,ph, of, & - nSlip,nTwin, & - o,f,i,c,j,k, & - index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily - real(pReal) :: & - tau_slip_pos,tau_slip_neg,tau - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenopowerlaw_totalNslip(instance) - nTwin = plastic_phenopowerlaw_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - index_accshear_slip = nSlip + nTwin + 3_pInt - index_accshear_twin = nSlip + nTwin + 3_pInt + nSlip - - plastic_phenopowerlaw_postResults = 0.0_pReal - c = 0_pInt - - outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) - select case(plastic_phenopowerlaw_outputID(o,instance)) - case (resistance_slip_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) - c = c + nSlip - - case (accumulatedshear_slip_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& - index_accshear_slip+nSlip-1_pInt,of) - c = c + nSlip - - case (shearrate_slip_ID) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j + 1_pInt - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo - plastic_phenopowerlaw_postResults(c+j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance) & - +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - - enddo slipSystems1 - enddo slipFamilies1 - c = c + nSlip - - case (resolvedstress_slip_ID) - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j + 1_pInt - plastic_phenopowerlaw_postResults(c+j) = & - dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - enddo slipSystems2 - enddo slipFamilies2 - c = c + nSlip - - case (totalshear_ID) - plastic_phenopowerlaw_postResults(c+1_pInt) = & - plasticState(ph)%state(index_Gamma,of) - c = c + 1_pInt - - case (resistance_twin_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) - c = c + nTwin - - case (accumulatedshear_twin_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) - c = c + nTwin - case (shearrate_twin_ID) - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j + 1_pInt - tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - plastic_phenopowerlaw_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenopowerlaw_gdot0_twin(instance)*& - (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& - plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) - enddo twinSystems1 - enddo twinFamilies1 - c = c + nTwin - - case (resolvedstress_twin_ID) - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j + 1_pInt - plastic_phenopowerlaw_postResults(c+j) = & - dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - enddo twinSystems2 - enddo twinFamilies2 - c = c + nTwin - - case (totalvolfrac_twin_ID) - plastic_phenopowerlaw_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) - c = c + 1_pInt - - end select - enddo outputsLoop - -end function plastic_phenopowerlaw_postResults - -end module plastic_phenopowerlaw diff --git a/code/plastic/plastic_titanmod.f90 b/code/plastic/plastic_titanmod.f90 deleted file mode 100644 index abc6d661b..000000000 --- a/code/plastic/plastic_titanmod.f90 +++ /dev/null @@ -1,1913 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Alankar Alankar, 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 -!> @brief material subroutine for titanium -!-------------------------------------------------------------------------------------------------- -module plastic_titanmod - use prec, only: & - pReal, & - pInt - - implicit none - private - character(len=18), dimension(3), parameter, private :: & - plastic_titanmod_listBasicSlipStates = & - ['rho_edge ', 'rho_screw ', 'shear_system'] - character(len=18), dimension(1), parameter, private :: & - plastic_titanmod_listBasicTwinStates = ['gdot_twin'] - character(len=19), dimension(11), parameter, private :: & - plastic_titanmod_listDependentSlipStates = & - ['segment_edge ', 'segment_screw ', & - 'resistance_edge ', 'resistance_screw ', & - 'tau_slip ', & - 'velocity_edge ', 'velocity_screw ', & - 'gdot_slip_edge ', 'gdot_slip_screw ', & - 'stressratio_edge_p ', 'stressratio_screw_p' ] - character(len=18), dimension(2), parameter, private :: & - plastic_titanmod_listDependentTwinStates = & - ['twin_fraction', 'tau_twin '] - real(pReal), parameter, private :: & - kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin - - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_titanmod_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_titanmod_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_titanmod_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_titanmod_Noutput !< number of outputs per instance of this plasticity !< ID of the lattice structure - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_titanmod_totalNslip, & !< total number of active slip systems for each instance - plastic_titanmod_totalNtwin !< total number of active twin systems for each instance - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_titanmod_Nslip, & !< number of active slip systems for each family and instance - plastic_titanmod_Ntwin, & !< number of active twin systems for each family and instance - plastic_titanmod_slipFamily, & !< lookup table relating active slip system to slip family for each instance - plastic_titanmod_twinFamily, & !< lookup table relating active twin system to twin family for each instance - plastic_titanmod_slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance - plastic_titanmod_twinSystemLattice !< lookup table relating active twin system index to lattice twin system index for each instance - - real(pReal), dimension(:), allocatable, private :: & - plastic_titanmod_debyefrequency, & !< Debye frequency - plastic_titanmod_kinkf0, & !< - plastic_titanmod_CAtomicVolume, & !< atomic volume in Bugers vector unit - plastic_titanmod_dc, & !< prefactor for self-diffusion coefficient - plastic_titanmod_twinhpconstant, & !< activation energy for dislocation climb - plastic_titanmod_GrainSize, & !< grain size - Not being used - plastic_titanmod_MaxTwinFraction, & !< maximum allowed total twin volume fraction - plastic_titanmod_r, & !< r-exponent in twin nucleation rate - plastic_titanmod_CEdgeDipMinDistance, & !< Not being used - plastic_titanmod_Cmfptwin, & !< Not being used - plastic_titanmod_Cthresholdtwin, & !< Not being used - plastic_titanmod_aTolRho !< absolute tolerance for integration of dislocation density - - real(pReal), dimension(:,:), allocatable, private :: & - plastic_titanmod_rho_edge0, & !< initial edge dislocation density per slip system for each family and instance - plastic_titanmod_rho_screw0, & !< initial screw dislocation density per slip system for each family and instance - plastic_titanmod_shear_system0, & !< accumulated shear on each system - plastic_titanmod_burgersPerSlipFam, & !< absolute length of burgers vector [m] for each slip family and instance - plastic_titanmod_burgersPerSlipSys, & !< absolute length of burgers vector [m] for each slip system and instance - plastic_titanmod_burgersPerTwinFam, & !< absolute length of burgers vector [m] for each twin family and instance - plastic_titanmod_burgersPerTwinSys, & !< absolute length of burgers vector [m] for each twin system and instance - plastic_titanmod_f0_PerSlipFam, & !< activation energy for glide [J] for each slip family and instance - plastic_titanmod_f0_PerSlipSys, & !< activation energy for glide [J] for each slip system and instance - plastic_titanmod_twinf0_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance - plastic_titanmod_twinf0_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance - plastic_titanmod_twinshearconstant_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance - plastic_titanmod_twinshearconstant_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance - plastic_titanmod_tau0e_PerSlipFam, & !< Initial yield stress for edge dislocations per slip family - plastic_titanmod_tau0e_PerSlipSys, & !< Initial yield stress for edge dislocations per slip system - plastic_titanmod_tau0s_PerSlipFam, & !< Initial yield stress for screw dislocations per slip family - plastic_titanmod_tau0s_PerSlipSys, & !< Initial yield stress for screw dislocations per slip system - plastic_titanmod_twintau0_PerTwinFam, & !< Initial yield stress for edge dislocations per twin family - plastic_titanmod_twintau0_PerTwinSys, & !< Initial yield stress for edge dislocations per twin system - plastic_titanmod_capre_PerSlipFam, & !< Capture radii for edge dislocations per slip family - plastic_titanmod_capre_PerSlipSys, & !< Capture radii for edge dislocations per slip system - plastic_titanmod_caprs_PerSlipFam, & !< Capture radii for screw dislocations per slip family - plastic_titanmod_caprs_PerSlipSys, & !< Capture radii for screw dislocations per slip system - plastic_titanmod_pe_PerSlipFam, & !< p-exponent in glide velocity - plastic_titanmod_ps_PerSlipFam, & !< p-exponent in glide velocity - plastic_titanmod_qe_PerSlipFam, & !< q-exponent in glide velocity - plastic_titanmod_qs_PerSlipFam, & !< q-exponent in glide velocity - plastic_titanmod_pe_PerSlipSys, & !< p-exponent in glide velocity - plastic_titanmod_ps_PerSlipSys, & !< p-exponent in glide velocity - plastic_titanmod_qe_PerSlipSys, & !< q-exponent in glide velocity - plastic_titanmod_qs_PerSlipSys, & !< q-exponent in glide velocity - plastic_titanmod_twinp_PerTwinFam, & !< p-exponent in glide velocity - plastic_titanmod_twinq_PerTwinFam, & !< q-exponent in glide velocity - plastic_titanmod_twinp_PerTwinSys, & !< p-exponent in glide velocity - plastic_titanmod_twinq_PerTwinSys, & !< p-exponent in glide velocity - plastic_titanmod_v0e_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance - plastic_titanmod_v0e_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance - plastic_titanmod_v0s_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance - plastic_titanmod_v0s_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance - plastic_titanmod_twingamma0_PerTwinFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance - plastic_titanmod_twingamma0_PerTwinSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance - plastic_titanmod_kinkcriticallength_PerSlipFam, & !< screw dislocation mobility prefactor for kink-pairs per slip family - plastic_titanmod_kinkcriticallength_PerSlipSys, & !< screw dislocation mobility prefactor for kink-pairs per slip system - plastic_titanmod_twinsizePerTwinFam, & !< twin thickness [m] for each twin family and instance - plastic_titanmod_twinsizePerTwinSys, & !< twin thickness [m] for each twin system and instance - plastic_titanmod_CeLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_titanmod_CeLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_titanmod_CsLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_titanmod_CsLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_titanmod_twinLambdaSlipPerTwinFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_titanmod_twinLambdaSlipPerTwinSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_titanmod_interactionSlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance - plastic_titanmod_interaction_ee, & !< coefficients for e-e interaction for each interaction type and instance - plastic_titanmod_interaction_ss, & !< coefficients for s-s interaction for each interaction type and instance - plastic_titanmod_interaction_es, & !< coefficients for e-s-twin interaction for each interaction type and instance - plastic_titanmod_interactionSlipTwin, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_titanmod_interactionTwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_titanmod_interactionTwinTwin !< coefficients for twin-twin interaction for each interaction type and instance - - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_titanmod_interactionMatrixSlipSlip, & !< interaction matrix of the different slip systems for each instance - plastic_titanmod_interactionMatrix_ee, & !< interaction matrix of e-e for each instance - plastic_titanmod_interactionMatrix_ss, & !< interaction matrix of s-s for each instance - plastic_titanmod_interactionMatrix_es, & !< interaction matrix of e-s for each instance - plastic_titanmod_interactionMatrixSlipTwin, & !< interaction matrix of slip systems with twin systems for each instance - plastic_titanmod_interactionMatrixTwinSlip, & !< interaction matrix of twin systems with slip systems for each instance - plastic_titanmod_interactionMatrixTwinTwin, & !< interaction matrix of the different twin systems for each instance - plastic_titanmod_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance - plastic_titanmod_forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance - plastic_titanmod_TwinforestProjectionEdge, & !< matrix of forest projections of edge dislocations in twin system for each instance - plastic_titanmod_TwinforestProjectionScrew !< matrix of forest projections of screw dislocations in twin system for each instance - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_titanmod_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance - - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_titanmod_Ctwin3333 !< twin elasticity matrix for each instance - - enum, bind(c) - enumerator :: undefined_ID, & - rhoedge_ID, rhoscrew_ID, & - segment_edge_ID, segment_screw_ID, & - resistance_edge_ID, resistance_screw_ID, & - velocity_edge_ID, velocity_screw_ID, & - tau_slip_ID, & - gdot_slip_edge_ID, gdot_slip_screw_ID, & - gdot_slip_ID, & - stressratio_edge_p_ID, stressratio_screw_p_ID, & - shear_system_ID, & - twin_fraction_ID, & - shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & - rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & - rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & - shear_total_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_titanmod_outputID !< ID of each post result output - - public :: & - plastic_titanmod_microstructure, & - plastic_titanmod_stateInit, & - plastic_titanmod_init, & - plastic_titanmod_LpAndItsTangent, & - plastic_titanmod_dotState, & - plastic_titanmod_postResults, & - plastic_titanmod_homogenizedC - - contains - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66,& - math_Voigt66to3333,& - math_mul3x3 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_TITANMOD_label, & - PLASTICITY_TITANMOD_ID, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - phase, & - instance, j, k, l, m, n, p, q, r, & - f, o, & - s, s1, s2, & - t, t1, t2, & - ns, nt, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & - offset_slip, mySize, & - maxTotalNslip,maxTotalNtwin, maxNinstance - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase = 0_pInt - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_TITANMOD_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_TITANMOD_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_titanmod_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_titanmod_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) - allocate(plastic_titanmod_output(maxval(phase_Noutput),maxNinstance)) - plastic_titanmod_output = '' - allocate(plastic_titanmod_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_titanmod_Noutput(maxNinstance), source=0_pInt) - - allocate(plastic_titanmod_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_slipFamily(lattice_maxNslip,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_twinFamily(lattice_maxNtwin,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_slipSystemLattice(lattice_maxNslip,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_twinSystemLattice(lattice_maxNtwin,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_titanmod_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_titanmod_debyefrequency(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_kinkf0(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CAtomicVolume(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_dc(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinhpconstant(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_GrainSize(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_MaxTwinFraction(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_r(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Cmfptwin(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Cthresholdtwin(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_aTolRho(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_rho_edge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_rho_screw0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_shear_system0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_burgersPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_burgersPerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_f0_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_capre_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_caprs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_pe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_ps_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_kinkcriticallength_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinsizePerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CeLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CsLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_twinf0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinshearconstant_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twintau0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinp_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinq_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twingamma0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinLambdaSlipPerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_interactionSlipSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interaction_ee(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interaction_ss(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interaction_es(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionSlipTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionTwinSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionTwinTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - phase = phase + 1_pInt ! advance section counter - if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then ! one of my sections. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('rhoedge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('segment_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('segment_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('tau_slip') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = tau_slip_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('gdot_slip_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('gdot_slip_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('gdot_slip') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stressratio_edge_p') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_edge_p_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stressratio_screw_p') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_screw_p_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_system') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_system_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('twin_fraction') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = twin_fraction_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_basal') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_basal_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_prism') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_prism_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_pyra') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyra_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_pyrca') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyrca_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_basal') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_basal_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_prism') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_prism_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_pyra') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyra_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_pyrca') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyrca_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_basal') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_basal_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_prism') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_prism_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_pyra') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyra_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_pyrca') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyrca_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_total') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_total_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - case ('debyefrequency') - plastic_titanmod_debyefrequency(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('kinkf0') - plastic_titanmod_kinkf0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('nslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ntwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinFamilies) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('rho_edge0') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_rho_edge0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('rho_screw0') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_rho_screw0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('slipburgers') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_burgersPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinburgers') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_burgersPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('f0') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_f0_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinf0') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinf0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0e') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_tau0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twintau0') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twintau0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0s') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_tau0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('capre') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_capre_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('caprs') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_caprs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('v0e') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_v0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twingamma0') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twingamma0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('v0s') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_v0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('kinkcriticallength') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_kinkcriticallength_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinsize') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinsizePerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('celambdaslip') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_CeLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinlambdaslip') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinlambdaslipPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('cslambdaslip') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_CsLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('grainsize') - plastic_titanmod_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('maxtwinfraction') - plastic_titanmod_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('pe') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_pe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinp') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinp_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('ps') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_ps_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('qe') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_qe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinq') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinq_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('qs') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_qs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinshearconstant') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinshearconstant_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('dc') - plastic_titanmod_dc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twinhpconstant') - plastic_titanmod_twinhpconstant(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_rho') - plastic_titanmod_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('interactionee') - do j = 1_pInt, lattice_maxNinteraction - plastic_titanmod_interaction_ee(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interactionss') - do j = 1_pInt, lattice_maxNinteraction - plastic_titanmod_interaction_ss(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interactiones') - do j = 1_pInt, lattice_maxNinteraction - plastic_titanmod_interaction_es(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_slipslip','interactionslipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_titanmod_interactionSlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin','interactionsliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_titanmod_interactionSlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip','interactiontwinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_titanmod_interactionTwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin','interactiontwintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_titanmod_interactionTwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then - instance = phase_plasticityInstance(phase) - if (sum(plastic_titanmod_Nslip(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='nslip ('//PLASTICITY_TITANMOD_label//')') - if (sum(plastic_titanmod_Ntwin(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='ntwin ('//PLASTICITY_TITANMOD_label//')') - do f = 1_pInt,lattice_maxNslipFamily - if (plastic_titanmod_Nslip(f,instance) > 0_pInt) then - if (plastic_titanmod_rho_edge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rho_edge0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_rho_screw0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rho_screw0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_burgersPerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='slipburgers ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_f0_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='f0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_tau0e_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau0e ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_tau0s_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau0s ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_capre_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='capre ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_caprs_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='caprs ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_v0e_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0e ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_v0s_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0s ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='kinkCriticalLength ('//PLASTICITY_TITANMOD_label//')') - endif - enddo - do f = 1_pInt,lattice_maxNtwinFamily - if (plastic_titanmod_Ntwin(f,instance) > 0_pInt) then - if (plastic_titanmod_burgersPerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twinf0_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinf0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinshearconstant ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twintau0_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twintau0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twingamma0_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twingamma0 ('//PLASTICITY_TITANMOD_label//')') - endif - enddo - if (plastic_titanmod_dc(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='dc ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twinhpconstant(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinhpconstant ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTol_rho ('//PLASTICITY_TITANMOD_label//')') - -!-------------------------------------------------------------------------------------------------- -! determine total number of active slip or twin systems - plastic_titanmod_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_titanmod_Nslip(:,instance)) - plastic_titanmod_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_titanmod_Ntwin(:,instance)) - plastic_titanmod_totalNslip(instance) = sum(plastic_titanmod_Nslip(:,instance)) - plastic_titanmod_totalNtwin(instance) = sum(plastic_titanmod_Ntwin(:,instance)) - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - maxTotalNslip = maxval(plastic_titanmod_totalNslip) - maxTotalNtwin = maxval(plastic_titanmod_totalNtwin) - - allocate(plastic_titanmod_burgersPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_f0_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_capre_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_caprs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_pe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_ps_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_kinkcriticallength_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CeLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CsLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_burgersPerTwinSys(maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinf0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinshearconstant_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twintau0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinp_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinq_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twingamma0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinsizePerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinLambdaSlipPerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Ctwin66 (6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Ctwin3333 (3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrix_ee(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrix_ss(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrix_es(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrixSlipTwin(maxTotalNslip,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrixTwinSlip(maxTotalNtwin,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrixTwinTwin(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_TwinforestProjectionEdge(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_TwinforestProjectionScrew(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then - instance = phase_plasticityInstance(phase) - -!-------------------------------------------------------------------------------------------------- -! inverse lookup of slip system family - l = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily - do s = 1_pInt,plastic_titanmod_Nslip(f,instance) - l = l + 1_pInt - plastic_titanmod_slipFamily(l,instance) = f - plastic_titanmod_slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt,phase)) + s - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! inverse lookup of twin system family - l = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily - do t = 1_pInt,plastic_titanmod_Ntwin(f,instance) - l = l + 1_pInt - plastic_titanmod_twinFamily(l,instance) = f - plastic_titanmod_twinSystemLattice(l,instance) = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) + t - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! determine size of state array - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - sizeDotState = & - size(plastic_titanmod_listBasicSlipStates)*ns + & - size(plastic_titanmod_listBasicTwinStates)*nt - sizeState = sizeDotState+ & - size(plastic_titanmod_listDependentSlipStates)*ns + & - size(plastic_titanmod_listDependentTwinStates)*nt - sizeDeltaState = 0_pInt - -!-------------------------------------------------------------------------------------------------- -! determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_titanmod_Noutput(instance) - mySize = 0_pInt - select case(plastic_titanmod_outputID(o,instance)) - case(rhoedge_ID, rhoscrew_ID, & - segment_edge_ID, segment_screw_ID, & - resistance_edge_ID, resistance_screw_ID, & - velocity_edge_ID, velocity_screw_ID, & - tau_slip_ID, & - gdot_slip_edge_ID, gdot_slip_screw_ID, & - gdot_slip_ID, & - stressratio_edge_p_ID, stressratio_screw_p_ID, & - shear_system_ID) - mySize = plastic_titanmod_totalNslip(instance) - case(twin_fraction_ID) - mySize = plastic_titanmod_totalNtwin(instance) - case(shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & ! use only if all 4 slip families in hex are considered - rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & - rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & - shear_total_ID) - mySize = 1_pInt - case default - call IO_error(105_pInt,ext_msg=plastic_titanmod_output(o,instance)// & - ' ('//PLASTICITY_TITANMOD_label//')') - end select - - outputFound: if (mySize > 0_pInt) then - plastic_titanmod_sizePostResult(o,instance) = mySize - plastic_titanmod_sizePostResults(instance) = plastic_titanmod_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop -! Determine size of state array - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_titanmod_sizePostResults(instance) - plasticState(phase)%nSlip =plastic_titanmod_totalNslip(instance) - plasticState(phase)%nTwin = 0_pInt - plasticState(phase)%nTrans= 0_pInt - allocate(plasticState(phase)%aTolState (sizeState), source=plastic_titanmod_aTolRho(instance)) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - offset_slip = 2_pInt*plasticState(phase)%nSlip+1 - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) -!-------------------------------------------------------------------------------------------------- -! construction of the twin elasticity matrices - do j=1_pInt,lattice_maxNtwinFamily - do k=1_pInt,plastic_titanmod_Ntwin(j,instance) - do l=1_pInt,3_pInt ; do m=1_pInt,3_pInt ; do n=1_pInt,3_pInt ; do o=1_pInt,3_pInt - do p=1_pInt,3_pInt ; do q=1_pInt,3_pInt ; do r=1_pInt,3_pInt ; do s=1_pInt,3_pInt - plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) = & - plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) + & - lattice_C3333(p,q,r,s,phase)*& - lattice_Qtwin(l,p,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & - lattice_Qtwin(m,q,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & - lattice_Qtwin(n,r,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & - lattice_Qtwin(o,s,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo ; enddo - plastic_titanmod_Ctwin66(1:6,1:6,k,instance) = & - math_Mandel3333to66(plastic_titanmod_Ctwin3333(1:3,1:3,1:3,1:3,k,instance)) - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! Burgers vector, dislocation velocity prefactor for each slip system - do s = 1_pInt,plastic_titanmod_totalNslip(instance) - f = plastic_titanmod_slipFamily(s,instance) - - plastic_titanmod_burgersPerSlipSys(s,instance) = & - plastic_titanmod_burgersPerSlipFam(f,instance) - - plastic_titanmod_f0_PerSlipSys(s,instance) = & - plastic_titanmod_f0_PerSlipFam(f,instance) - - plastic_titanmod_tau0e_PerSlipSys(s,instance) = & - plastic_titanmod_tau0e_PerSlipFam(f,instance) - - plastic_titanmod_tau0s_PerSlipSys(s,instance) = & - plastic_titanmod_tau0s_PerSlipFam(f,instance) - - plastic_titanmod_capre_PerSlipSys(s,instance) = & - plastic_titanmod_capre_PerSlipFam(f,instance) - - plastic_titanmod_caprs_PerSlipSys(s,instance) = & - plastic_titanmod_caprs_PerSlipFam(f,instance) - - plastic_titanmod_v0e_PerSlipSys(s,instance) = & - plastic_titanmod_v0e_PerSlipFam(f,instance) - - plastic_titanmod_v0s_PerSlipSys(s,instance) = & - plastic_titanmod_v0s_PerSlipFam(f,instance) - - plastic_titanmod_kinkcriticallength_PerSlipSys(s,instance) = & - plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) - - plastic_titanmod_pe_PerSlipSys(s,instance) = & - plastic_titanmod_pe_PerSlipFam(f,instance) - - plastic_titanmod_ps_PerSlipSys(s,instance) = & - plastic_titanmod_ps_PerSlipFam(f,instance) - - plastic_titanmod_qe_PerSlipSys(s,instance) = & - plastic_titanmod_qe_PerSlipFam(f,instance) - - plastic_titanmod_qs_PerSlipSys(s,instance) = & - plastic_titanmod_qs_PerSlipFam(f,instance) - - plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance) = & - plastic_titanmod_CeLambdaSlipPerSlipFam(f,instance) - - plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance) = & - plastic_titanmod_CsLambdaSlipPerSlipFam(f,instance) - enddo - -!-------------------------------------------------------------------------------------------------- -! Burgers vector, nucleation rate prefactor and twin size for each twin system - do t = 1_pInt,plastic_titanmod_totalNtwin(instance) - f = plastic_titanmod_twinFamily(t,instance) - - plastic_titanmod_burgersPerTwinSys(t,instance) = & - plastic_titanmod_burgersPerTwinFam(f,instance) - - plastic_titanmod_twinsizePerTwinSys(t,instance) = & - plastic_titanmod_twinsizePerTwinFam(f,instance) - - plastic_titanmod_twinf0_PerTwinSys(t,instance) = & - plastic_titanmod_twinf0_PerTwinFam(f,instance) - - plastic_titanmod_twinshearconstant_PerTwinSys(t,instance) = & - plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) - - plastic_titanmod_twintau0_PerTwinSys(t,instance) = & - plastic_titanmod_twintau0_PerTwinFam(f,instance) - - plastic_titanmod_twingamma0_PerTwinSys(t,instance) = & - plastic_titanmod_twingamma0_PerTwinFam(f,instance) - - plastic_titanmod_twinp_PerTwinSys(t,instance) = & - plastic_titanmod_twinp_PerTwinFam(f,instance) - - plastic_titanmod_twinq_PerTwinSys(t,instance) = & - plastic_titanmod_twinq_PerTwinFam(f,instance) - - plastic_titanmod_twinLambdaSlipPerTwinSys(t,instance) = & - plastic_titanmod_twinLambdaSlipPerTwinFam(f,instance) - enddo - -!-------------------------------------------------------------------------------------------------- -! Construction of interaction matrices - do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) - do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) - plastic_titanmod_interactionMatrixSlipSlip(s1,s2,instance) = & - plastic_titanmod_interactionSlipSlip(lattice_interactionSlipSlip( & - plastic_titanmod_slipSystemLattice(s1,instance),& - plastic_titanmod_slipSystemLattice(s2,instance),phase),instance) - - plastic_titanmod_interactionMatrix_ee(s1,s2,instance) = & - plastic_titanmod_interaction_ee(lattice_interactionSlipSlip ( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - - plastic_titanmod_interactionMatrix_ss(s1,s2,instance) = & - plastic_titanmod_interaction_ss(lattice_interactionSlipSlip( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - - plastic_titanmod_interactionMatrix_es(s1,s2,instance) = & - plastic_titanmod_interaction_es(lattice_interactionSlipSlip( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - enddo; enddo - - do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) - do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) - plastic_titanmod_interactionMatrixSlipTwin(s1,t2,instance) = & - plastic_titanmod_interactionSlipTwin(lattice_interactionSlipTwin( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) - enddo; enddo - - do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) - do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) - plastic_titanmod_interactionMatrixTwinSlip(t1,s2,instance) = & - plastic_titanmod_interactionTwinSlip(lattice_interactionTwinSlip( & - plastic_titanmod_twinSystemLattice(t1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - enddo; enddo - - do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) - do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) - plastic_titanmod_interactionMatrixTwinTwin(t1,t2,instance) = & - plastic_titanmod_interactionTwinTwin(lattice_interactionTwinTwin( & - plastic_titanmod_twinSystemLattice(t1,instance), & - plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) - enddo; enddo - - do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) - do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for edge dislocations - plastic_titanmod_forestProjectionEdge(s1,s2,instance) = & - abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & - lattice_st(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) - -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for screw dislocations - plastic_titanmod_forestProjectionScrew(s1,s2,instance) = & - abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & - lattice_sd(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for edge dislocations in twin system - do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) - do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) - plastic_titanmod_TwinforestProjectionEdge(t1,t2,instance) = & - abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & - lattice_tt(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) - -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for screw dislocations in twin system - plastic_titanmod_TwinforestProjectionScrew(t1,t2,instance) = & - abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & - lattice_td(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) - enddo; enddo - call plastic_titanmod_stateInit(phase,instance) - endif - enddo initializeInstances - -end subroutine plastic_titanmod_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_stateInit(ph,instance) - use lattice, only: & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_mu - - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: instance !< number specifying the instance of the plasticity - integer(pInt), intent(in) :: ph !< number specifying the phase of the plasticity - - - integer(pInt) :: & - s,s0,s1, & - t,t0,t1, & - ns,nt,f - real(pReal), dimension(plastic_titanmod_totalNslip(instance)) :: & - rho_edge0, & - rho_screw0, & - shear_system0, & - segment_edge0, & - segment_screw0, & - resistance_edge0, & - resistance_screw0 - real(pReal), dimension(plastic_titanmod_totalNtwin(instance)) :: & - twingamma_dot0, & - resistance_twin0 - real(pReal), dimension(plasticState(ph)%sizeState) :: tempState !!!!!!!!!????????? check - - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - tempState = 0.0_pReal -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables for slip - s1 = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily - s0 = s1 + 1_pInt - s1 = s0 + plastic_titanmod_Nslip(f,instance) - 1_pInt - do s = s0,s1 - rho_edge0(s) = plastic_titanmod_rho_edge0(f,instance) - rho_screw0(s) = plastic_titanmod_rho_screw0(f,instance) - shear_system0(s) = 0.0_pReal - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables for twin - t1 = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily - t0 = t1 + 1_pInt - t1 = t0 + plastic_titanmod_Ntwin(f,instance) - 1_pInt - do t = t0,t1 - twingamma_dot0(t)=0.0_pReal - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! initialize dependent slip microstructural variables - forall (s = 1_pInt:ns) - segment_edge0(s) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) - segment_screw0(s) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) - resistance_edge0(s) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & - sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & - dot_product((rho_screw0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) - resistance_screw0(s) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & - sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & - dot_product((rho_screw0), plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) - end forall - - forall (t = 1_pInt:nt) & - resistance_twin0(t) = 0.0_pReal - -tempState = 0.0_pReal -tempState (1:ns) = rho_edge0 -tempState (1_pInt*ns+1_pInt:2_pInt*ns) = rho_screw0 -tempState (2_pInt*ns+1_pInt:3_pInt*ns) = shear_system0 -tempState (3_pInt*ns+1_pInt:3_pInt*ns+nt) = twingamma_dot0 -tempState (3_pInt*ns+nt+1_pInt:4_pInt*ns+nt) = segment_edge0 -tempState (4_pInt*ns+nt+1_pInt:5_pInt*ns+nt) = segment_screw0 -tempState (5_pInt*ns+nt+1_pInt:6_pInt*ns+nt) = resistance_edge0 -tempState (6_pInt*ns+nt+1_pInt:7_pInt*ns+nt) = resistance_screw0 -tempState (7_pInt*ns+nt+1_pInt:7_pInt*ns+2_pInt*nt)=resistance_twin0 - -plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) -end subroutine plastic_titanmod_stateInit - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenized elasticity matrix -!-------------------------------------------------------------------------------------------------- -function plastic_titanmod_homogenizedC(ipc,ip,el) - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_C66 - -implicit none - real(pReal), dimension(6,6) :: & - plastic_titanmod_homogenizedC - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element -real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - volumefraction_PerTwinSys - integer(pInt) :: & - ph, & - of, & - instance, & - ns, nt, & - i - real(pReal) :: & - sumf - -!-------------------------------------------------------------------------------------------------- -! shortened notation -! ph = material_phase(ipc,ip,el) - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! total twin volume fraction - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - enddo - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - -!-------------------------------------------------------------------------------------------------- -! homogenized elasticity matrix - plastic_titanmod_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) - do i=1_pInt,nt - plastic_titanmod_homogenizedC = plastic_titanmod_homogenizedC & - + volumefraction_PerTwinSys(i)*& - plastic_titanmod_Ctwin66(1:6,1:6,i,instance) - enddo - -end function plastic_titanmod_homogenizedC - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_microstructure(temperature,ipc,ip,el) - - use material, only: & - material_phase,& - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_mu - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - temperature !< temperature at IP - integer(pInt) :: & - instance, & - ns, nt, s, t, & - i, & - ph, & - of - real(pReal) :: & - sumf, & - sfe ! stacking fault energy - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - volumefraction_PerTwinSys - -!-------------------------------------------------------------------------------------------------- - -!Shortened notation - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! total twin volume fraction - forall (i = 1_pInt:nt) & - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - - sfe = 0.0002_pReal*Temperature-0.0396_pReal - -!-------------------------------------------------------------------------------------------------- -! average segment length for edge dislocations in matrix - forall (s = 1_pInt:ns) & - plasticState(ph)%state(3_pInt*ns+nt+s, of) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product(plasticState(ph)%state(1:ns, of), & - plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & - plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! average segment length for screw dislocations in matrix - forall (s = 1_pInt:ns) & - plasticState(ph)%state(4_pInt*ns+nt+s, of) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product(plasticState(ph)%state(1:ns, of), & - plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & - plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! threshold stress or slip resistance for edge dislocation motion - forall (s = 1_pInt:ns) & - plasticState(ph)%state(5_pInt*ns+nt+s, of) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& - sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& - plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & - dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& - plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! threshold stress or slip resistance for screw dislocation motion - forall (s = 1_pInt:ns) & - plasticState(ph)%state(6_pInt*ns+nt+s, of) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& - sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& - plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & - dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& - plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! threshold stress or slip resistance for dislocation motion in twin - forall (t = 1_pInt:nt) & - plasticState(ph)%state(7_pInt*ns+nt+t, of) = & - lattice_mu(ph)*plastic_titanmod_burgersPerTwinSys(t,instance)*& - (dot_product((abs(plasticState(ph)%state(2_pInt*ns+1_pInt:2_pInt*ns+nt, of))),& - plastic_titanmod_interactionMatrixTwinTwin(1:nt,t,instance))) - -! state=tempState - -end subroutine plastic_titanmod_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,temperature,ipc,ip,el) - use math, only: & - math_Plain3333to99, & - math_Mandel6to33 - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_structure, & - LATTICE_hex_ID - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at IP - integer(pInt) :: & - index_myFamily, instance, & - ns,nt, & - f,i,j,k,l,m,n, & - ph, & - of - real(pReal) :: sumf, & - StressRatio_edge_p, minusStressRatio_edge_p, StressRatio_edge_pminus1, BoltzmannRatioedge, & - StressRatio_screw_p, minusStressRatio_screw_p, StressRatio_screw_pminus1, BoltzmannRatioscrew, & - twinStressRatio_p, twinminusStressRatio_p, twinStressRatio_pminus1, BoltzmannRatiotwin, & - twinDotGamma0, bottomstress_edge, bottomstress_screw, screwvelocity_prefactor - real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 - real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,dgdot_dtauslip,tau_slip, & - edge_velocity, screw_velocity, & - gdot_slip_edge, gdot_slip_screw - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,dgdot_dtautwin,tau_twin, volumefraction_PerTwinSys - -! tempState=state - - - -!-------------------------------------------------------------------------------------------------- -! shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - - enddo - - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - - !* Dislocation glide part - gdot_slip = 0.0_pReal - gdot_slip_edge = 0.0_pReal - gdot_slip_screw = 0.0_pReal - dgdot_dtauslip = 0.0_pReal - j = 0_pInt - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on slip system - tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - if(lattice_structure(ph)==LATTICE_hex_ID) then ! only for prismatic and pyr systems in hex - screwvelocity_prefactor=plastic_titanmod_debyefrequency(instance)* & - plasticState(ph)%state(4_pInt*ns+nt+j, of)*(plastic_titanmod_burgersPerSlipSys(j,instance)/ & - plastic_titanmod_kinkcriticallength_PerSlipSys(j,instance))**2 - - !* Stress ratio for screw ! No slip resistance for screw dislocations, only Peierls stress - bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) - StressRatio_screw_p = ((abs(tau_slip(j)))/ & - ( bottomstress_screw) & - )**plastic_titanmod_ps_PerSlipSys(j,instance) - - if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then - minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p - else - minusStressRatio_screw_p=0.001_pReal - endif - - bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) - StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/ & - ( bottomstress_screw) & - )**(plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio for screw - BoltzmannRatioscrew = plastic_titanmod_kinkf0(instance)/(kB*Temperature) - - else ! if the structure is not hex or the slip family is basal - screwvelocity_prefactor=plastic_titanmod_v0s_PerSlipSys(j,instance) - bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance)+ & - plasticState(ph)%state(6*ns+nt+j, of) - StressRatio_screw_p = ((abs(tau_slip(j)))/( bottomstress_screw ))**plastic_titanmod_ps_PerSlipSys(j,instance) - - if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then - minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p - else - minusStressRatio_screw_p=0.001_pReal - endif - - StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/( bottomstress_screw))** & - (plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio for screw - BoltzmannRatioscrew = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) - - endif - - !* Stress ratio for edge - bottomstress_edge=plastic_titanmod_tau0e_PerSlipSys(j,instance)+ & - plasticState(ph)%state(5*ns+nt+j, of) - StressRatio_edge_p = ((abs(tau_slip(j)))/ & - ( bottomstress_edge) & - )**plastic_titanmod_pe_PerSlipSys(j,instance) - - if((1.0_pReal-StressRatio_edge_p)>0.001_pReal) then - minusStressRatio_edge_p=1.0_pReal-StressRatio_edge_p - else - minusStressRatio_edge_p=0.001_pReal - endif - - StressRatio_edge_pminus1 = ((abs(tau_slip(j)))/( bottomstress_edge))** & - (plastic_titanmod_pe_PerSlipSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio for edge. For screws it is defined above - BoltzmannRatioedge = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) - - screw_velocity(j) =screwvelocity_prefactor * & ! there is no v0 for screw now because it is included in the prefactor - exp(-BoltzmannRatioscrew*(minusStressRatio_screw_p)** & - plastic_titanmod_qs_PerSlipSys(j,instance)) - - edge_velocity(j) =plastic_titanmod_v0e_PerSlipSys(j,instance)*exp(-BoltzmannRatioedge* & - (minusStressRatio_edge_p)** & - plastic_titanmod_qe_PerSlipSys(j,instance)) - - !* Shear rates due to edge slip - gdot_slip_edge(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(j, of)* & - edge_velocity(j))* sign(1.0_pReal,tau_slip(j)) - !* Shear rates due to screw slip - gdot_slip_screw(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(ns+j, of) * & - screw_velocity(j))* sign(1.0_pReal,tau_slip(j)) - !Total shear rate - - gdot_slip(j) = gdot_slip_edge(j) + gdot_slip_screw(j) - - plasticState(ph)%state( 7*ns+2*nt+j, of)= edge_velocity(j) - plasticState(ph)%state( 8*ns+2*nt+j, of)= screw_velocity(j) - plasticState(ph)%state( 9*ns+2*nt+j, of)= tau_slip(j) - plasticState(ph)%state(10*ns+2*nt+j, of)= gdot_slip_edge(j) - plasticState(ph)%state(11*ns+2*nt+j, of)= gdot_slip_screw(j) - plasticState(ph)%state(12*ns+2*nt+j, of)= StressRatio_edge_p - plasticState(ph)%state(13*ns+2*nt+j, of)= StressRatio_screw_p - - !* Derivatives of shear rates - dgdot_dtauslip(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(( & - ( & - ( & - ( & - (edge_velocity(j)*plasticState(ph)%state(j, of))) * & - BoltzmannRatioedge*& - plastic_titanmod_pe_PerSlipSys(j,instance)* & - plastic_titanmod_qe_PerSlipSys(j,instance) & - )/ & - bottomstress_edge & - )*& - StressRatio_edge_pminus1*(minusStressRatio_edge_p)** & - (plastic_titanmod_qe_PerSlipSys(j,instance)-1.0_pReal) & - ) + & - ( & - ( & - ( & - (plasticState(ph)%state(ns+j, of) * screw_velocity(j)) * & - BoltzmannRatioscrew* & - plastic_titanmod_ps_PerSlipSys(j,instance)* & - plastic_titanmod_qs_PerSlipSys(j,instance) & - )/ & - bottomstress_screw & - )*& - StressRatio_screw_pminus1*(minusStressRatio_screw_p)**(plastic_titanmod_qs_PerSlipSys(j,instance)-1.0_pReal) & - ) & - ) !* sign(1.0_pReal,tau_slip(j)) - - - -!************************************************* -!sumf=0.0_pReal - !* Plastic velocity gradient for dislocation glide - Lp = Lp + (1.0_pReal - sumf)*gdot_slip(j)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& - lattice_Sslip(k,l,1,index_myFamily+i,ph)*& - lattice_Sslip(m,n,1,index_myFamily+i,ph) - enddo - enddo slipFamiliesLoop - -!* Mechanical twinning part - gdot_twin = 0.0_pReal - dgdot_dtautwin = 0.0_pReal - j = 0_pInt - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on twin system - tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - -!************************************************************************************** - !* Stress ratios -! StressRatio_r = (plasticState(ph)%state6*ns+3*nt+j, of)/tau_twin(j))**plastic_titanmod_r(instance) - - !* Shear rates and their derivatives due to twin -! if ( tau_twin(j) > 0.0_pReal ) !then -! gdot_twin(j) = 0.0_pReal!& -! (plastic_titanmod_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& -! plasticState(ph)%state(6*ns+4*nt+j, of)*plastic_titanmod_Ndot0PerTwinSys(f,instance)*exp(-StressRatio_r) -! dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_titanmod_r(instance))/tau_twin(j))*StressRatio_r -! endif -!************************************************************************************** - - !* Stress ratio for edge - twinStressRatio_p = ((abs(tau_twin(j)))/ & - ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & - )**plastic_titanmod_twinp_PerTwinSys(j,instance) - - if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then - twinminusStressRatio_p=1.0_pReal-twinStressRatio_p - else - twinminusStressRatio_p=0.001_pReal - endif - - twinStressRatio_pminus1 = ((abs(tau_twin(j)))/ & - ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & - )**(plastic_titanmod_twinp_PerTwinSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio - BoltzmannRatiotwin = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) - - !* Initial twin shear rates - TwinDotGamma0 = & - plastic_titanmod_twingamma0_PerTwinSys(j,instance) - - !* Shear rates due to twin - gdot_twin(j) =sign(1.0_pReal,tau_twin(j))*plastic_titanmod_twingamma0_PerTwinSys(j,instance)* & - exp(-BoltzmannRatiotwin*(twinminusStressRatio_p)**plastic_titanmod_twinq_PerTwinSys(j,instance)) - - - !* Derivatives of shear rates in twin - dgdot_dtautwin(j) = ( & - ( & - ( & - (abs(gdot_twin(j))) * & - BoltzmannRatiotwin*& - plastic_titanmod_twinp_PerTwinSys(j,instance)* & - plastic_titanmod_twinq_PerTwinSys(j,instance) & - )/ & - plastic_titanmod_twintau0_PerTwinSys(j,instance) & - )*& - twinStressRatio_pminus1*(twinminusStressRatio_p)** & - (plastic_titanmod_twinq_PerTwinSys(j,instance)-1.0_pReal) & - ) !* sign(1.0_pReal,tau_slip(j)) - - !* Plastic velocity gradient for mechanical twinning -! Lp = Lp + sumf*gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) - Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& - lattice_Stwin(k,l,index_myFamily+i,ph)*& - lattice_Stwin(m,n,index_myFamily+i,ph) - enddo - enddo twinFamiliesLoop - -dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) -! tempState=state - - -end subroutine plastic_titanmod_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_dotState(Tstar_v,temperature,ipc,ip,el) - use lattice, only: & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - -implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: & - index_myFamily, instance, & - ns,nt,& - f,i,j, & - ph, & - of - real(pReal) :: & - sumf,BoltzmannRatio, & - twinStressRatio_p,twinminusStressRatio_p - real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - DotRhoEdgeGeneration, & - DotRhoEdgeAnnihilation, & - DotRhoScrewGeneration, & - DotRhoScrewAnnihilation - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin, & - tau_twin, & - volumefraction_PerTwinSys - -!-------------------------------------------------------------------------------------------------- -! shortened notation - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - - enddo - - sumf = sum(abs(volumefraction_PerTwinSys(1_pInt:nt))) ! safe for nt == 0 - - plasticState(ph)%dotState(:,of) = 0.0_pReal - j = 0_pInt - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - DotRhoEdgeGeneration(j) = & ! multiplication of edge dislocations - plasticState(ph)%state(ns+j, of)*plasticState(ph)%state(8*ns+2*nt+j, of)/plasticState(ph)%state(4*ns+nt+j, of) - DotRhoScrewGeneration(j) = & ! multiplication of screw dislocations - plasticState(ph)%state(j, of)*plasticState(ph)%state(7*ns+2*nt+j, of)/plasticState(ph)%state(3*ns+nt+j, of) - DotRhoEdgeAnnihilation(j) = -((plasticState(ph)%state(j, of))**2)* & ! annihilation of edge dislocations - plastic_titanmod_capre_PerSlipSys(j,instance)*plasticState(ph)%state(7*ns+2*nt+j, of)*0.5_pReal - DotRhoScrewAnnihilation(j) = -((plasticState(ph)%state(ns+j, of))**2)* & ! annihilation of screw dislocations - plastic_titanmod_caprs_PerSlipSys(j,instance)*plasticState(ph)%state(8*ns+2*nt+j, of)*0.5_pReal - plasticState(ph)%dotState(j, of) = & ! edge dislocation density rate of change - DotRhoEdgeGeneration(j)+DotRhoEdgeAnnihilation(j) - - plasticState(ph)%dotState(ns+j, of) = & ! screw dislocation density rate of change - DotRhoScrewGeneration(j)+DotRhoScrewAnnihilation(j) - - plasticState(ph)%dotState(2*ns+j, of) = & ! sum of shear due to edge and screw - plasticState(ph)%state(10*ns+2*nt+j, of)+plasticState(ph)%state(11*ns+2*nt+j, of) - enddo - enddo slipFamiliesLoop - -!* Twin fraction evolution - j = 0_pInt - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) twin system in family - j = j+1_pInt - - !* Resolved shear stress on twin system - tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - !* Stress ratio for edge - twinStressRatio_p = ((abs(tau_twin(j)))/ & - ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & - )**(plastic_titanmod_twinp_PerTwinSys(j,instance)) - - - if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then - twinminusStressRatio_p=1.0_pReal-twinStressRatio_p - else - twinminusStressRatio_p=0.001_pReal - endif - - BoltzmannRatio = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) - - gdot_twin(j) =plastic_titanmod_twingamma0_PerTwinSys(j,instance)*exp(-BoltzmannRatio* & - (twinminusStressRatio_p)** & - plastic_titanmod_twinq_PerTwinSys(j,instance))*sign(1.0_pReal,tau_twin(j)) - - plasticState(ph)%dotState(3*ns+j, of)=gdot_twin(j) - - enddo - enddo twinFamiliesLoop - -end subroutine plastic_titanmod_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_titanmod_postResults(ipc,ip,el) - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(plastic_titanmod_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_titanmod_postResults - - integer(pInt) :: & - instance, & - ns,nt,& - o,i,c, & - ph, & - of - real(pReal) :: sumf - - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - volumefraction_PerTwinSys - -!-------------------------------------------------------------------------------------------------- -! shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - enddo - - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - - -!-------------------------------------------------------------------------------------------------- -! required output - c = 0_pInt - plastic_titanmod_postResults = 0.0_pReal - - do o = 1_pInt,plastic_titanmod_Noutput(instance) - select case(plastic_titanmod_outputID(o,instance)) - case (rhoedge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(1_pInt:ns, of) - c = c + ns - case (rhoscrew_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of) - c = c + ns - case (segment_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(3_pInt*ns+nt+1_pInt:4_pInt*ns+nt, of) - c = c + ns - case (segment_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(4_pInt*ns+nt+1_pInt:5_pInt*ns+nt, of) - c = c + ns - case (resistance_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(5_pInt*ns+nt+1_pInt:6_pInt*ns+nt, of) - c = c + ns - case (resistance_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(6_pInt*ns+nt+1_pInt:7_pInt*ns+nt, of) - c = c + ns - case (velocity_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(7*ns+2*nt+1:8*ns+2*nt, of) - c = c + ns - case (velocity_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(8*ns+2*nt+1:9*ns+2*nt, of) - c = c + ns - case (tau_slip_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(9*ns+2*nt+1:10*ns+2*nt, of)) - c = c + ns - case (gdot_slip_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) - c = c + ns - case (gdot_slip_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) - c = c + ns - case (gdot_slip_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) + & - abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) - c = c + ns - case (stressratio_edge_p_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(12*ns+2*nt+1:13*ns+2*nt, of)) - c = c + ns - case (stressratio_screw_p_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(13*ns+2*nt+1:14*ns+2*nt, of)) - c = c + ns - case (shear_system_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(2*ns+1:3*ns, of)) - c = c + ns - case (shear_basal_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:2*ns+3, of))) - c = c + 1_pInt - case (shear_prism_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+4:2*ns+6, of))) - c = c + 1_pInt - case (shear_pyra_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+7:2*ns+12, of))) - c = c + 1_pInt - case (shear_pyrca_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+13:2*ns+24, of))) - c = c + 1_pInt - - case (rhoedge_basal_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(1:3, of)) - c = c + 1_pInt - case (rhoedge_prism_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(4:6, of)) - c = c + 1_pInt - case (rhoedge_pyra_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(7:12,of)) - c = c + 1_pInt - case (rhoedge_pyrca_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(13:24, of)) - c = c + 1_pInt - - case (rhoscrew_basal_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+1:ns+3, of)) - c = c + 1_pInt - case (rhoscrew_prism_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+4:ns+6, of)) - c = c + 1_pInt - case (rhoscrew_pyra_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+7:ns+12, of)) - c = c + 1_pInt - case (rhoscrew_pyrca_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+13:ns+24, of)) - c = c + 1_pInt - case (shear_total_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:3*ns, of))) - c = c + 1_pInt - case (twin_fraction_ID) - plastic_titanmod_postResults(c+1_pInt:c+nt) = abs(volumefraction_PerTwinSys(1:nt)) - c = c + nt - end select - enddo - -end function plastic_titanmod_postResults - -end module plastic_titanmod diff --git a/code/source/CMakeLists.txt b/code/source/CMakeLists.txt deleted file mode 100644 index cd9475ee3..000000000 --- a/code/source/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -# group source -set (SOURCE "source_thermal_dissipation" - "source_thermal_externalheat" - "source_damage_isoBrittle" - "source_damage_isoDuctile" - "source_damage_anisoBrittle" - "source_damage_anisoDuctile" - "source_vacancy_phenoplasticity" - "source_vacancy_irradiation" - "source_vacancy_thermalfluc" - ) - -# compile module and cumulatively link the -# compiled libraries -foreach (p ${KINEMATICS}) - add_library (${p} "${p}.f90") - target_link_libraries(${p} DAMASK_DRIVERS) - add_library (DAMASK_DRIVERS ALIAS ${p}) -endforeach (p) \ No newline at end of file diff --git a/code/source/source_damage_anisoBrittle.f90 b/code/source/source_damage_anisoBrittle.f90 deleted file mode 100644 index a751eefdc..000000000 --- a/code/source/source_damage_anisoBrittle.f90 +++ /dev/null @@ -1,425 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @brief material subroutine incorporating anisotropic brittle damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_anisoBrittle - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_anisoBrittle_sizePostResults, & !< cumulative size of post results - source_damage_anisoBrittle_offset, & !< which source is my current source mechanism? - source_damage_anisoBrittle_instance !< instance of source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_anisoBrittle_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_anisoBrittle_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_anisoBrittle_Noutput !< number of outputs per instance of this source - - integer(pInt), dimension(:), allocatable, private :: & - source_damage_anisoBrittle_totalNcleavage !< total number of cleavage systems - - integer(pInt), dimension(:,:), allocatable, private :: & - source_damage_anisoBrittle_Ncleavage !< number of cleavage systems per family - - real(pReal), dimension(:), allocatable, private :: & - source_damage_anisoBrittle_aTol, & - source_damage_anisoBrittle_sdot_0, & - source_damage_anisoBrittle_N - - real(pReal), dimension(:,:), allocatable, private :: & - source_damage_anisoBrittle_critDisp, & - source_damage_anisoBrittle_critLoad - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_anisoBrittle_outputID !< ID of each post result output - - - public :: & - source_damage_anisoBrittle_init, & - source_damage_anisoBrittle_dotState, & - source_damage_anisobrittle_getRateAndItsTangent, & - source_damage_anisoBrittle_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoBrittle_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_anisoBrittle_label, & - SOURCE_damage_anisoBrittle_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - use lattice, only: & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoBrittle_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_anisoBrittle_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_anisoBrittle_offset(material_Nphase), source=0_pInt) - allocate(source_damage_anisoBrittle_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_anisoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoBrittle_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_anisoBrittle_ID) & - source_damage_anisoBrittle_offset(phase) = source - enddo - enddo - - allocate(source_damage_anisoBrittle_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_output(maxval(phase_Noutput),maxNinstance)) - source_damage_anisoBrittle_output = '' - allocate(source_damage_anisoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_anisoBrittle_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_totalNcleavage(maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_aTol(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_sdot_0(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_N(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_anisoBrittle_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('anisobrittle_drivingforce') - source_damage_anisoBrittle_Noutput(instance) = source_damage_anisoBrittle_Noutput(instance) + 1_pInt - source_damage_anisoBrittle_outputID(source_damage_anisoBrittle_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_anisoBrittle_output(source_damage_anisoBrittle_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('anisobrittle_atol') - source_damage_anisoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisobrittle_sdot0') - source_damage_anisoBrittle_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisobrittle_ratesensitivity') - source_damage_anisoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('ncleavage') ! - Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_CleavageFamilies - source_damage_anisoBrittle_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticaldisplacement') - do j = 1_pInt, Nchunks_CleavageFamilies - source_damage_anisoBrittle_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticalload') - do j = 1_pInt, Nchunks_CleavageFamilies - source_damage_anisoBrittle_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then - instance = source_damage_anisoBrittle_instance(phase) - source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & - min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested - source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance)) - source_damage_anisoBrittle_totalNcleavage(instance) = sum(source_damage_anisoBrittle_Ncleavage(:,instance)) ! how many cleavage systems altogether - if (source_damage_anisoBrittle_aTol(instance) < 0.0_pReal) & - source_damage_anisoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_anisoBrittle_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoBrittle_LABEL//')') - if (any(source_damage_anisoBrittle_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//SOURCE_damage_anisoBrittle_LABEL//')') - if (any(source_damage_anisoBrittle_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//SOURCE_damage_anisoBrittle_LABEL//')') - if (source_damage_anisoBrittle_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoBrittle_LABEL//')') - endif myPhase - enddo sanityChecks - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_anisoBrittle_instance(phase) - sourceOffset = source_damage_anisoBrittle_offset(phase) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) - select case(source_damage_anisoBrittle_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_anisoBrittle_sizePostResult(o,instance) = mySize - source_damage_anisoBrittle_sizePostResults(instance) = source_damage_anisoBrittle_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoBrittle_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_anisoBrittle_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_anisoBrittle_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoBrittle_dotState(Tstar_v, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState, & - material_homog, & - damage, & - damageMapping - use lattice, only: & - lattice_Scleavage_v, & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) - integer(pInt) :: & - phase, & - constituent, & - instance, & - sourceOffset, & - damageOffset, & - homog, & - f, i, index_myFamily - real(pReal) :: & - traction_d, traction_t, traction_n, traction_crit - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoBrittle_instance(phase) - sourceOffset = source_damage_anisoBrittle_offset(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal - do f = 1_pInt,lattice_maxNcleavageFamily - index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family - do i = 1_pInt,source_damage_anisoBrittle_Ncleavage(f,instance) ! process each (active) cleavage system in family - traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) - traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) - traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) - - traction_crit = source_damage_anisoBrittle_critLoad(f,instance)* & - damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & - source_damage_anisoBrittle_sdot_0(instance)* & - ((max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & - (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & - (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance))/ & - source_damage_anisoBrittle_critDisp(f,instance) - - enddo - enddo - -end subroutine source_damage_anisoBrittle_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_damage_anisoBrittle_offset(phase) - - localphiDot = 1.0_pReal - & - sourceState(phase)%p(sourceOffset)%state(1,constituent)*phi - - dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_anisobrittle_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_anisoBrittle_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_anisoBrittle_sizePostResults( & - source_damage_anisoBrittle_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_anisoBrittle_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoBrittle_instance(phase) - sourceOffset = source_damage_anisoBrittle_offset(phase) - - c = 0_pInt - source_damage_anisoBrittle_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) - select case(source_damage_anisoBrittle_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_anisoBrittle_postResults(c+1_pInt) = & - sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1_pInt - - end select - enddo -end function source_damage_anisoBrittle_postResults - -end module source_damage_anisoBrittle diff --git a/code/source/source_damage_anisoDuctile.f90 b/code/source/source_damage_anisoDuctile.f90 deleted file mode 100644 index 028fd479a..000000000 --- a/code/source/source_damage_anisoDuctile.f90 +++ /dev/null @@ -1,415 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating anisotropic ductile damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_anisoDuctile - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_anisoDuctile_sizePostResults, & !< cumulative size of post results - source_damage_anisoDuctile_offset, & !< which source is my current damage mechanism? - source_damage_anisoDuctile_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_anisoDuctile_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_anisoDuctile_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_anisoDuctile_Noutput !< number of outputs per instance of this damage - - integer(pInt), dimension(:), allocatable, private :: & - source_damage_anisoDuctile_totalNslip !< total number of slip systems - - integer(pInt), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_Nslip !< number of slip systems per family - - real(pReal), dimension(:), allocatable, private :: & - source_damage_anisoDuctile_aTol - - real(pReal), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_critPlasticStrain - - real(pReal), dimension(:), allocatable, private :: & - source_damage_anisoDuctile_sdot_0, & - source_damage_anisoDuctile_N - - real(pReal), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_critLoad - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_outputID !< ID of each post result output - - - public :: & - source_damage_anisoDuctile_init, & - source_damage_anisoDuctile_dotState, & - source_damage_anisoDuctile_getRateAndItsTangent, & - source_damage_anisoDuctile_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoDuctile_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_anisoDuctile_label, & - SOURCE_damage_anisoDuctile_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - use lattice, only: & - lattice_maxNslipFamily, & - lattice_NslipSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoDuctile_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_anisoDuctile_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_anisoDuctile_offset(material_Nphase), source=0_pInt) - allocate(source_damage_anisoDuctile_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_anisoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoDuctile_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_anisoDuctile_ID) & - source_damage_anisoDuctile_offset(phase) = source - enddo - enddo - - allocate(source_damage_anisoDuctile_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_damage_anisoDuctile_output(maxval(phase_Noutput),maxNinstance)) - source_damage_anisoDuctile_output = '' - allocate(source_damage_anisoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_anisoDuctile_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoDuctile_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(source_damage_anisoDuctile_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_totalNslip(maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_N(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoDuctile_sdot_0(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoDuctile_aTol(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_anisoDuctile_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('anisoductile_drivingforce') - source_damage_anisoDuctile_Noutput(instance) = source_damage_anisoDuctile_Noutput(instance) + 1_pInt - source_damage_anisoDuctile_outputID(source_damage_anisoDuctile_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_anisoDuctile_output(source_damage_anisoDuctile_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('anisoductile_atol') - source_damage_anisoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('nslip') ! - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - source_damage_anisoDuctile_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_sdot0') - source_damage_anisoDuctile_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalplasticstrain') - do j = 1_pInt, Nchunks_SlipFamilies - source_damage_anisoDuctile_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_ratesensitivity') - source_damage_anisoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalload') - do j = 1_pInt, Nchunks_SlipFamilies - source_damage_anisoDuctile_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, size(phase_source) - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then - instance = source_damage_anisoDuctile_instance(phase) - source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested - source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance)) - source_damage_anisoDuctile_totalNslip(instance) = sum(source_damage_anisoDuctile_Nslip(:,instance)) - if (source_damage_anisoDuctile_aTol(instance) < 0.0_pReal) & - source_damage_anisoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_anisoDuctile_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoDuctile_LABEL//')') - if (any(source_damage_anisoDuctile_critPlasticStrain(:,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//SOURCE_damage_anisoDuctile_LABEL//')') - if (source_damage_anisoDuctile_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoDuctile_LABEL//')') - endif myPhase - enddo sanityChecks - - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_anisoDuctile_instance(phase) - sourceOffset = source_damage_anisoDuctile_offset(phase) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) - select case(source_damage_anisoDuctile_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_anisoDuctile_sizePostResult(o,instance) = mySize - source_damage_anisoDuctile_sizePostResults(instance) = source_damage_anisoDuctile_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoDuctile_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_anisoDuctile_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_anisoDuctile_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoDuctile_dotState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - sourceState, & - material_homog, & - damage, & - damageMapping - use lattice, only: & - lattice_maxNslipFamily - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, & - constituent, & - sourceOffset, & - homog, damageOffset, & - instance, & - index, f, i - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoDuctile_instance(phase) - sourceOffset = source_damage_anisoDuctile_offset(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - index = 1_pInt - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal - do f = 1_pInt,lattice_maxNslipFamily - do i = 1_pInt,source_damage_anisoDuctile_Nslip(f,instance) ! process each (active) slip system in family - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & - plasticState(phase)%slipRate(index,constituent)/ & - ((damage(homog)%p(damageOffset))**source_damage_anisoDuctile_N(instance))/ & - source_damage_anisoDuctile_critPlasticStrain(f,instance) - - index = index + 1_pInt - enddo - enddo - -end subroutine source_damage_anisoDuctile_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_damage_anisoDuctile_offset(phase) - - localphiDot = 1.0_pReal - & - sourceState(phase)%p(sourceOffset)%state(1,constituent)* & - phi - - dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_anisoDuctile_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_anisoDuctile_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_anisoDuctile_sizePostResults( & - source_damage_anisoDuctile_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_anisoDuctile_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoDuctile_instance(phase) - sourceOffset = source_damage_anisoDuctile_offset(phase) - - c = 0_pInt - source_damage_anisoDuctile_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) - select case(source_damage_anisoDuctile_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_anisoDuctile_postResults(c+1_pInt) = & - sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1_pInt - - end select - enddo -end function source_damage_anisoDuctile_postResults - -end module source_damage_anisoDuctile diff --git a/code/source/source_damage_isoBrittle.f90 b/code/source/source_damage_isoBrittle.f90 deleted file mode 100644 index c063ae86f..000000000 --- a/code/source/source_damage_isoBrittle.f90 +++ /dev/null @@ -1,383 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incoprorating isotropic brittle damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_isoBrittle - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_isoBrittle_sizePostResults, & !< cumulative size of post results - source_damage_isoBrittle_offset, & !< which source is my current damage mechanism? - source_damage_isoBrittle_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_isoBrittle_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_isoBrittle_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_isoBrittle_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_damage_isoBrittle_aTol, & - source_damage_isoBrittle_N, & - source_damage_isoBrittle_critStrainEnergy - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_isoBrittle_outputID !< ID of each post result output - - - public :: & - source_damage_isoBrittle_init, & - source_damage_isoBrittle_deltaState, & - source_damage_isoBrittle_getRateAndItsTangent, & - source_damage_isoBrittle_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoBrittle_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_isoBrittle_label, & - SOURCE_damage_isoBrittle_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoBrittle_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_isoBrittle_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_isoBrittle_offset(material_Nphase), source=0_pInt) - allocate(source_damage_isoBrittle_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_isoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoBrittle_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_isoBrittle_ID) & - source_damage_isoBrittle_offset(phase) = source - enddo - enddo - - allocate(source_damage_isoBrittle_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_isoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_damage_isoBrittle_output(maxval(phase_Noutput),maxNinstance)) - source_damage_isoBrittle_output = '' - allocate(source_damage_isoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_isoBrittle_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_isoBrittle_critStrainEnergy(maxNinstance), source=0.0_pReal) - allocate(source_damage_isoBrittle_N(maxNinstance), source=1.0_pReal) - allocate(source_damage_isoBrittle_aTol(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_isoBrittle_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('isobrittle_drivingforce') - source_damage_isoBrittle_Noutput(instance) = source_damage_isoBrittle_Noutput(instance) + 1_pInt - source_damage_isoBrittle_outputID(source_damage_isoBrittle_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_isoBrittle_output(source_damage_isoBrittle_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('isobrittle_criticalstrainenergy') - source_damage_isoBrittle_critStrainEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isobrittle_n') - source_damage_isoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isobrittle_atol') - source_damage_isoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then - instance = source_damage_isoBrittle_instance(phase) - if (source_damage_isoBrittle_aTol(instance) < 0.0_pReal) & - source_damage_isoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_isoBrittle_critStrainEnergy(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='criticalStrainEnergy ('//SOURCE_damage_isoBrittle_LABEL//')') - endif myPhase - enddo sanityChecks - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_isoBrittle_instance(phase) - sourceOffset = source_damage_isoBrittle_offset(phase) -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) - select case(source_damage_isoBrittle_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_isoBrittle_sizePostResult(o,instance) = mySize - source_damage_isoBrittle_sizePostResults(instance) = source_damage_isoBrittle_sizePostResults(instance) + mySize - endif - enddo outputsLoop -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 1_pInt - sizeState = 1_pInt - - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoBrittle_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_isoBrittle_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_isoBrittle_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoBrittle_deltaState(C, Fe, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState, & - material_homog, & - phase_NstiffnessDegradations, & - phase_stiffnessDegradation, & - porosity, & - porosityMapping, & - STIFFNESS_DEGRADATION_porosity_ID - use math, only : & - math_mul33x33, & - math_mul66x6, & - math_Mandel33to6, & - math_transpose33, & - math_I3 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(3,3) :: & - Fe - real(pReal), intent(in), dimension(6,6) :: & - C - integer(pInt) :: & - phase, constituent, instance, sourceOffset, mech - real(pReal) :: & - strain(6), & - stiffness(6,6), & - strainenergy - - phase = phaseAt(ipc,ip,el) !< phase ID at ipc,ip,el - constituent = phasememberAt(ipc,ip,el) !< state array offset for phase ID at ipc,ip,el - ! ToDo: capability for multiple instances of SAME source within given phase. Needs Ninstance loop from here on! - instance = source_damage_isoBrittle_instance(phase) !< instance of damage_isoBrittle source - sourceOffset = source_damage_isoBrittle_offset(phase) - - stiffness = C - do mech = 1_pInt, phase_NstiffnessDegradations(phase) - select case(phase_stiffnessDegradation(mech,phase)) - case (STIFFNESS_DEGRADATION_porosity_ID) - stiffness = porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & - porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & - stiffness - end select - enddo - strain = 0.5_pReal*math_Mandel33to6(math_mul33x33(math_transpose33(Fe),Fe)-math_I3) - - strainenergy = 2.0_pReal*sum(strain*math_mul66x6(stiffness,strain))/ & - source_damage_isoBrittle_critStrainEnergy(instance) - if (strainenergy > sourceState(phase)%p(sourceOffset)%subState0(1,constituent)) then - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - strainenergy - sourceState(phase)%p(sourceOffset)%state(1,constituent) - else - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - sourceState(phase)%p(sourceOffset)%subState0(1,constituent) - & - sourceState(phase)%p(sourceOffset)%state(1,constituent) - endif - -end subroutine source_damage_isoBrittle_deltaState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoBrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, instance, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoBrittle_instance(phase) - sourceOffset = source_damage_isoBrittle_offset(phase) - - localphiDot = (1.0_pReal - phi)**(source_damage_isoBrittle_N(instance) - 1.0_pReal) - & - phi*sourceState(phase)%p(sourceOffset)%state(1,constituent) - dLocalphiDot_dPhi = - (source_damage_isoBrittle_N(instance) - 1.0_pReal)* & - (1.0_pReal - phi)**max(0.0_pReal,source_damage_isoBrittle_N(instance) - 2.0_pReal) & - - sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_isoBrittle_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_isoBrittle_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_isoBrittle_sizePostResults( & - source_damage_isoBrittle_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_isoBrittle_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoBrittle_instance(phase) - sourceOffset = source_damage_isoBrittle_offset(phase) - - c = 0_pInt - source_damage_isoBrittle_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) - select case(source_damage_isoBrittle_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_isoBrittle_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1 - - end select - enddo -end function source_damage_isoBrittle_postResults - -end module source_damage_isoBrittle diff --git a/code/source/source_damage_isoDuctile.f90 b/code/source/source_damage_isoDuctile.f90 deleted file mode 100644 index b0290264c..000000000 --- a/code/source/source_damage_isoDuctile.f90 +++ /dev/null @@ -1,350 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @brief material subroutine incoprorating isotropic ductile damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_isoDuctile - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_isoDuctile_sizePostResults, & !< cumulative size of post results - source_damage_isoDuctile_offset, & !< which source is my current damage mechanism? - source_damage_isoDuctile_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_isoDuctile_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_isoDuctile_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_isoDuctile_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_damage_isoDuctile_aTol, & - source_damage_isoDuctile_critPlasticStrain, & - source_damage_isoDuctile_N - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_isoDuctile_outputID !< ID of each post result output - - - public :: & - source_damage_isoDuctile_init, & - source_damage_isoDuctile_dotState, & - source_damage_isoDuctile_getRateAndItsTangent, & - source_damage_isoDuctile_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoDuctile_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_isoDuctile_label, & - SOURCE_damage_isoDuctile_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoDuctile_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_isoDuctile_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_isoDuctile_offset(material_Nphase), source=0_pInt) - allocate(source_damage_isoDuctile_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_isoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoDuctile_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_isoDuctile_ID) & - source_damage_isoDuctile_offset(phase) = source - enddo - enddo - - allocate(source_damage_isoDuctile_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_isoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_damage_isoDuctile_output(maxval(phase_Noutput),maxNinstance)) - source_damage_isoDuctile_output = '' - allocate(source_damage_isoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_isoDuctile_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_isoDuctile_critPlasticStrain(maxNinstance), source=0.0_pReal) - allocate(source_damage_isoDuctile_N(maxNinstance), source=0.0_pReal) - allocate(source_damage_isoDuctile_aTol(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_isoDuctile_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('isoductile_drivingforce') - source_damage_isoDuctile_Noutput(instance) = source_damage_isoDuctile_Noutput(instance) + 1_pInt - source_damage_isoDuctile_outputID(source_damage_isoDuctile_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_isoDuctile_output(source_damage_isoDuctile_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('isoductile_criticalplasticstrain') - source_damage_isoDuctile_critPlasticStrain(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isoductile_ratesensitivity') - source_damage_isoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isoductile_atol') - source_damage_isoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then - instance = source_damage_isoDuctile_instance(phase) - if (source_damage_isoDuctile_aTol(instance) < 0.0_pReal) & - source_damage_isoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_isoDuctile_critPlasticStrain(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='critical plastic strain ('//SOURCE_damage_isoDuctile_LABEL//')') - endif myPhase - enddo sanityChecks - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_isoDuctile_instance(phase) - sourceOffset = source_damage_isoDuctile_offset(phase) -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) - select case(source_damage_isoDuctile_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_isoDuctile_sizePostResult(o,instance) = mySize - source_damage_isoDuctile_sizePostResults(instance) = source_damage_isoDuctile_sizePostResults(instance) + mySize - endif - enddo outputsLoop -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoDuctile_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_isoDuctile_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_isoDuctile_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoDuctile_dotState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - sourceState, & - material_homog, & - damage, & - damageMapping - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, constituent, instance, homog, sourceOffset, damageOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoDuctile_instance(phase) - sourceOffset = source_damage_isoDuctile_offset(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & - sum(plasticState(phase)%slipRate(:,constituent))/ & - ((damage(homog)%p(damageOffset))**source_damage_isoDuctile_N(instance))/ & - source_damage_isoDuctile_critPlasticStrain(instance) - -end subroutine source_damage_isoDuctile_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_damage_isoDuctile_offset(phase) - - localphiDot = 1.0_pReal - & - sourceState(phase)%p(sourceOffset)%state(1,constituent)* & - phi - - dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_isoDuctile_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_isoDuctile_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_isoDuctile_sizePostResults( & - source_damage_isoDuctile_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_isoDuctile_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoDuctile_instance(phase) - sourceOffset = source_damage_isoDuctile_offset(phase) - - c = 0_pInt - source_damage_isoDuctile_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) - select case(source_damage_isoDuctile_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_isoDuctile_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1 - - end select - enddo -end function source_damage_isoDuctile_postResults - -end module source_damage_isoDuctile diff --git a/code/source/source_thermal_dissipation.f90 b/code/source/source_thermal_dissipation.f90 deleted file mode 100644 index 83ad85167..000000000 --- a/code/source/source_thermal_dissipation.f90 +++ /dev/null @@ -1,220 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for thermal source due to plastic dissipation -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_thermal_dissipation - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_thermal_dissipation_sizePostResults, & !< cumulative size of post results - source_thermal_dissipation_offset, & !< which source is my current thermal dissipation mechanism? - source_thermal_dissipation_instance !< instance of thermal dissipation source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_thermal_dissipation_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_thermal_dissipation_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_thermal_dissipation_Noutput !< number of outputs per instance of this source - - real(pReal), dimension(:), allocatable, private :: & - source_thermal_dissipation_coldworkCoeff - - public :: & - source_thermal_dissipation_init, & - source_thermal_dissipation_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_dissipation_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_thermal_dissipation_label, & - SOURCE_thermal_dissipation_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_dissipation_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_thermal_dissipation_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_thermal_dissipation_offset(material_Nphase), source=0_pInt) - allocate(source_thermal_dissipation_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_thermal_dissipation_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_dissipation_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == SOURCE_thermal_dissipation_ID) & - source_thermal_dissipation_offset(phase) = source - enddo - enddo - - allocate(source_thermal_dissipation_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_thermal_dissipation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_thermal_dissipation_output (maxval(phase_Noutput),maxNinstance)) - source_thermal_dissipation_output = '' - allocate(source_thermal_dissipation_Noutput(maxNinstance), source=0_pInt) - allocate(source_thermal_dissipation_coldworkCoeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_thermal_dissipation_instance(phase) ! which instance of my source is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('dissipation_coldworkcoeff') - source_thermal_dissipation_coldworkCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_thermal_dissipation_instance(phase) - sourceOffset = source_thermal_dissipation_offset(phase) - - sizeDotState = 0_pInt - sizeDeltaState = 0_pInt - sizeState = 0_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_dissipation_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_thermal_dissipation_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_dissipation_getRateAndItsTangent(TDot, dTDOT_dT, Tstar_v, Lp, ipc, ip, el) - use math, only: & - math_Mandel6to33 - use material, only: & - phaseAt, phasememberAt - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) - real(pReal), intent(in), dimension(3,3) :: & - Lp - real(pReal), intent(out) :: & - TDot, & - dTDOT_dT - integer(pInt) :: & - instance, phase, constituent - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_thermal_dissipation_instance(phase) - - TDot = source_thermal_dissipation_coldworkCoeff(instance)* & - sum(abs(math_Mandel6to33(Tstar_v)*Lp)) - dTDOT_dT = 0.0_pReal - -end subroutine source_thermal_dissipation_getRateAndItsTangent - -end module source_thermal_dissipation diff --git a/code/source/source_thermal_externalheat.f90 b/code/source/source_thermal_externalheat.f90 deleted file mode 100644 index 257012c06..000000000 --- a/code/source/source_thermal_externalheat.f90 +++ /dev/null @@ -1,277 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for thermal source due to plastic dissipation -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_thermal_externalheat - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_thermal_externalheat_sizePostResults, & !< cumulative size of post results - source_thermal_externalheat_offset, & !< which source is my current thermal dissipation mechanism? - source_thermal_externalheat_instance !< instance of thermal dissipation source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_thermal_externalheat_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_thermal_externalheat_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_thermal_externalheat_Noutput !< number of outputs per instance of this source - - integer(pInt), dimension(:), allocatable, private :: & - source_thermal_externalheat_nIntervals - - real(pReal), dimension(:,:), allocatable, private :: & - source_thermal_externalheat_time, & - source_thermal_externalheat_rate - - public :: & - source_thermal_externalheat_init, & - source_thermal_externalheat_dotState, & - source_thermal_externalheat_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_externalheat_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_thermal_externalheat_label, & - SOURCE_thermal_externalheat_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase,interval - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), allocatable, dimension(:,:) :: temp_time, temp_rate - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_externalheat_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_thermal_externalheat_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_thermal_externalheat_offset(material_Nphase), source=0_pInt) - allocate(source_thermal_externalheat_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_thermal_externalheat_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_externalheat_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == SOURCE_thermal_externalheat_ID) & - source_thermal_externalheat_offset(phase) = source - enddo - enddo - - allocate(source_thermal_externalheat_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_thermal_externalheat_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_thermal_externalheat_output (maxval(phase_Noutput),maxNinstance)) - source_thermal_externalheat_output = '' - allocate(source_thermal_externalheat_Noutput(maxNinstance), source=0_pInt) - allocate(source_thermal_externalheat_nIntervals(maxNinstance), source=0_pInt) - - allocate(temp_time(maxNinstance,1000), source=0.0_pReal) - allocate(temp_rate(maxNinstance,1000), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_thermal_externalheat_instance(phase) ! which instance of my source is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('externalheat_time') - if (chunkPos(1) <= 2_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//SOURCE_thermal_externalheat_label//')') - source_thermal_externalheat_nIntervals(instance) = chunkPos(1) - 2_pInt - do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt - temp_time(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) - enddo - - case ('externalheat_rate') - do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt - temp_rate(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) - enddo - - end select - endif; endif - enddo parsingFile - - allocate(source_thermal_externalheat_time(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) - allocate(source_thermal_externalheat_rate(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_thermal_externalheat_instance(phase) - sourceOffset = source_thermal_externalheat_offset(phase) - source_thermal_externalheat_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & - temp_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) - source_thermal_externalheat_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & - temp_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) - - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_externalheat_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.00001_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_thermal_externalheat_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_externalheat_dotState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, & - constituent, & - sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_thermal_externalheat_offset(phase) - - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 1.0_pReal - -end subroutine source_thermal_externalheat_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_externalheat_getRateAndItsTangent(TDot, dTDot_dT, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - TDot, & - dTDot_dT - integer(pInt) :: & - instance, phase, constituent, sourceOffset, interval - real(pReal) :: & - norm_time - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_thermal_externalheat_instance(phase) - sourceOffset = source_thermal_externalheat_offset(phase) - - do interval = 1, source_thermal_externalheat_nIntervals(instance) - norm_time = (sourceState(phase)%p(sourceOffset)%state(1,constituent) - & - source_thermal_externalheat_time(instance,interval)) / & - (source_thermal_externalheat_time(instance,interval+1) - & - source_thermal_externalheat_time(instance,interval)) - if (norm_time >= 0.0_pReal .and. norm_time < 1.0_pReal) & - TDot = source_thermal_externalheat_rate(instance,interval ) * (1.0_pReal - norm_time) + & - source_thermal_externalheat_rate(instance,interval+1) * norm_time - enddo - dTDot_dT = 0.0 - -end subroutine source_thermal_externalheat_getRateAndItsTangent - -end module source_thermal_externalheat diff --git a/code/source/source_vacancy_irradiation.f90 b/code/source/source_vacancy_irradiation.f90 deleted file mode 100644 index c4bcfba04..000000000 --- a/code/source/source_vacancy_irradiation.f90 +++ /dev/null @@ -1,253 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for vacancy generation due to irradiation -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_vacancy_irradiation - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_vacancy_irradiation_sizePostResults, & !< cumulative size of post results - source_vacancy_irradiation_offset, & !< which source is my current damage mechanism? - source_vacancy_irradiation_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_vacancy_irradiation_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_vacancy_irradiation_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_vacancy_irradiation_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_vacancy_irradiation_cascadeProb, & - source_vacancy_irradiation_cascadeVolume - - public :: & - source_vacancy_irradiation_init, & - source_vacancy_irradiation_deltaState, & - source_vacancy_irradiation_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_irradiation_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_vacancy_irradiation_label, & - SOURCE_vacancy_irradiation_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_irradiation_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_vacancy_irradiation_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_vacancy_irradiation_offset(material_Nphase), source=0_pInt) - allocate(source_vacancy_irradiation_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_vacancy_irradiation_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_irradiation_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_vacancy_irradiation_ID) & - source_vacancy_irradiation_offset(phase) = source - enddo - enddo - - allocate(source_vacancy_irradiation_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_vacancy_irradiation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_vacancy_irradiation_output(maxval(phase_Noutput),maxNinstance)) - source_vacancy_irradiation_output = '' - allocate(source_vacancy_irradiation_Noutput(maxNinstance), source=0_pInt) - allocate(source_vacancy_irradiation_cascadeProb(maxNinstance), source=0.0_pReal) - allocate(source_vacancy_irradiation_cascadeVolume(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_vacancy_irradiation_instance(phase) ! which instance of my vacancy is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('irradiation_cascadeprobability') - source_vacancy_irradiation_cascadeProb(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('irradiation_cascadevolume') - source_vacancy_irradiation_cascadeVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_vacancy_irradiation_instance(phase) - sourceOffset = source_vacancy_irradiation_offset(phase) - - sizeDotState = 2_pInt - sizeDeltaState = 2_pInt - sizeState = 2_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_irradiation_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_vacancy_irradiation_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_irradiation_deltaState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, constituent, sourceOffset - real(pReal) :: & - randNo - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_vacancy_irradiation_offset(phase) - - call random_number(randNo) - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - randNo - sourceState(phase)%p(sourceOffset)%state(1,constituent) - call random_number(randNo) - sourceState(phase)%p(sourceOffset)%deltaState(2,constituent) = & - randNo - sourceState(phase)%p(sourceOffset)%state(2,constituent) - -end subroutine source_vacancy_irradiation_deltaState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_irradiation_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - CvDot, dCvDot_dCv - integer(pInt) :: & - instance, phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_vacancy_irradiation_instance(phase) - sourceOffset = source_vacancy_irradiation_offset(phase) - - CvDot = 0.0_pReal - dCvDot_dCv = 0.0_pReal - if (sourceState(phase)%p(sourceOffset)%state0(1,constituent) < source_vacancy_irradiation_cascadeProb(instance)) & - CvDot = sourceState(phase)%p(sourceOffset)%state0(2,constituent)*source_vacancy_irradiation_cascadeVolume(instance) - -end subroutine source_vacancy_irradiation_getRateAndItsTangent - -end module source_vacancy_irradiation diff --git a/code/source/source_vacancy_phenoplasticity.f90 b/code/source/source_vacancy_phenoplasticity.f90 deleted file mode 100644 index f9e766b2c..000000000 --- a/code/source/source_vacancy_phenoplasticity.f90 +++ /dev/null @@ -1,215 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for vacancy generation due to plasticity -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_vacancy_phenoplasticity - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_vacancy_phenoplasticity_sizePostResults, & !< cumulative size of post results - source_vacancy_phenoplasticity_offset, & !< which source is my current damage mechanism? - source_vacancy_phenoplasticity_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_vacancy_phenoplasticity_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_vacancy_phenoplasticity_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_vacancy_phenoplasticity_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_vacancy_phenoplasticity_rateCoeff - - public :: & - source_vacancy_phenoplasticity_init, & - source_vacancy_phenoplasticity_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_phenoplasticity_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_vacancy_phenoplasticity_label, & - SOURCE_vacancy_phenoplasticity_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_phenoplasticity_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_vacancy_phenoplasticity_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_vacancy_phenoplasticity_offset(material_Nphase), source=0_pInt) - allocate(source_vacancy_phenoplasticity_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_vacancy_phenoplasticity_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_phenoplasticity_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_vacancy_phenoplasticity_ID) & - source_vacancy_phenoplasticity_offset(phase) = source - enddo - enddo - - allocate(source_vacancy_phenoplasticity_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_vacancy_phenoplasticity_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_vacancy_phenoplasticity_output(maxval(phase_Noutput),maxNinstance)) - source_vacancy_phenoplasticity_output = '' - allocate(source_vacancy_phenoplasticity_Noutput(maxNinstance), source=0_pInt) - allocate(source_vacancy_phenoplasticity_rateCoeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_vacancy_phenoplasticity_instance(phase) ! which instance of my vacancy is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('phenoplasticity_ratecoeff') - source_vacancy_phenoplasticity_rateCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_vacancy_phenoplasticity_instance(phase) - sourceOffset = source_vacancy_phenoplasticity_offset(phase) - - sizeDotState = 0_pInt - sizeDeltaState = 0_pInt - sizeState = 0_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_phenoplasticity_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_vacancy_phenoplasticity_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_phenoplasticity_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - plasticState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - CvDot, dCvDot_dCv - integer(pInt) :: & - instance, phase, constituent - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_vacancy_phenoplasticity_instance(phase) - - CvDot = & - source_vacancy_phenoplasticity_rateCoeff(instance)* & - sum(plasticState(phase)%slipRate(:,constituent)) - dCvDot_dCv = 0.0_pReal - -end subroutine source_vacancy_phenoplasticity_getRateAndItsTangent - -end module source_vacancy_phenoplasticity diff --git a/code/source/source_vacancy_thermalfluc.f90 b/code/source/source_vacancy_thermalfluc.f90 deleted file mode 100644 index c86406430..000000000 --- a/code/source/source_vacancy_thermalfluc.f90 +++ /dev/null @@ -1,255 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for vacancy generation due to thermal fluctuations -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_vacancy_thermalfluc - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_vacancy_thermalfluc_sizePostResults, & !< cumulative size of post results - source_vacancy_thermalfluc_offset, & !< which source is my current damage mechanism? - source_vacancy_thermalfluc_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_vacancy_thermalfluc_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_vacancy_thermalfluc_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_vacancy_thermalfluc_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_vacancy_thermalfluc_amplitude, & - source_vacancy_thermalfluc_normVacancyEnergy - - public :: & - source_vacancy_thermalfluc_init, & - source_vacancy_thermalfluc_deltaState, & - source_vacancy_thermalfluc_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_thermalfluc_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use lattice, only: & - lattice_vacancyFormationEnergy - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_vacancy_thermalfluc_label, & - SOURCE_vacancy_thermalfluc_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_thermalfluc_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_vacancy_thermalfluc_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_vacancy_thermalfluc_offset(material_Nphase), source=0_pInt) - allocate(source_vacancy_thermalfluc_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_vacancy_thermalfluc_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_thermalfluc_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_vacancy_thermalfluc_ID) & - source_vacancy_thermalfluc_offset(phase) = source - enddo - enddo - - allocate(source_vacancy_thermalfluc_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_vacancy_thermalfluc_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_vacancy_thermalfluc_output(maxval(phase_Noutput),maxNinstance)) - source_vacancy_thermalfluc_output = '' - allocate(source_vacancy_thermalfluc_Noutput(maxNinstance), source=0_pInt) - allocate(source_vacancy_thermalfluc_amplitude(maxNinstance), source=0.0_pReal) - allocate(source_vacancy_thermalfluc_normVacancyEnergy(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_vacancy_thermalfluc_instance(phase) ! which instance of my vacancy is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('thermalfluctuation_amplitude') - source_vacancy_thermalfluc_amplitude(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_vacancy_thermalfluc_instance(phase) - source_vacancy_thermalfluc_normVacancyEnergy(instance) = & - lattice_vacancyFormationEnergy(phase)/1.3806488e-23_pReal - sourceOffset = source_vacancy_thermalfluc_offset(phase) - - sizeDotState = 1_pInt - sizeDeltaState = 1_pInt - sizeState = 1_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_thermalfluc_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_vacancy_thermalfluc_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_thermalfluc_deltaState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, constituent, sourceOffset - real(pReal) :: & - randNo - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_vacancy_thermalfluc_offset(phase) - - call random_number(randNo) - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - randNo - 0.5_pReal - sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_vacancy_thermalfluc_deltaState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_thermalfluc_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - material_homog, & - temperature, & - thermalMapping, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - CvDot, dCvDot_dCv - integer(pInt) :: & - instance, phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_vacancy_thermalfluc_instance(phase) - sourceOffset = source_vacancy_thermalfluc_offset(phase) - - CvDot = source_vacancy_thermalfluc_amplitude(instance)* & - sourceState(phase)%p(sourceOffset)%state0(2,constituent)* & - exp(-source_vacancy_thermalfluc_normVacancyEnergy(instance)/ & - temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))) - dCvDot_dCv = 0.0_pReal - -end subroutine source_vacancy_thermalfluc_getRateAndItsTangent - -end module source_vacancy_thermalfluc From e406bfabcf9e9abac08ac56beb96981d5b2847ba Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 29 Feb 2016 14:21:47 -0500 Subject: [PATCH 018/183] reverting back to single level gradually --- code/kinematics_cleavage_opening.f90 | 303 ++ code/kinematics_hydrogen_strain.f90 | 264 ++ code/kinematics_slipplane_opening.f90 | 323 ++ code/kinematics_thermal_expansion.f90 | 228 ++ code/kinematics_vacancy_strain.f90 | 265 ++ code/plastic_disloUCLA.f90 | 2116 ++++++++++++ code/plastic_dislotwin.f90 | 2542 ++++++++++++++ code/plastic_isotropic.f90 | 678 ++++ code/plastic_j2.f90 | 579 ++++ code/plastic_none.f90 | 109 + code/plastic_nonlocal.f90 | 4031 +++++++++++++++++++++++ code/plastic_phenoplus.f90 | 1419 ++++++++ code/plastic_phenopowerlaw.f90 | 1226 +++++++ code/plastic_titanmod.f90 | 1913 +++++++++++ code/source_damage_anisoBrittle.f90 | 425 +++ code/source_damage_anisoDuctile.f90 | 415 +++ code/source_damage_isoBrittle.f90 | 383 +++ code/source_damage_isoDuctile.f90 | 350 ++ code/source_thermal_dissipation.f90 | 220 ++ code/source_thermal_externalheat.f90 | 277 ++ code/source_vacancy_irradiation.f90 | 253 ++ code/source_vacancy_phenoplasticity.f90 | 215 ++ code/source_vacancy_thermalfluc.f90 | 255 ++ compile.log | 3 + 24 files changed, 18792 insertions(+) create mode 100644 code/kinematics_cleavage_opening.f90 create mode 100644 code/kinematics_hydrogen_strain.f90 create mode 100644 code/kinematics_slipplane_opening.f90 create mode 100644 code/kinematics_thermal_expansion.f90 create mode 100644 code/kinematics_vacancy_strain.f90 create mode 100644 code/plastic_disloUCLA.f90 create mode 100644 code/plastic_dislotwin.f90 create mode 100644 code/plastic_isotropic.f90 create mode 100644 code/plastic_j2.f90 create mode 100644 code/plastic_none.f90 create mode 100644 code/plastic_nonlocal.f90 create mode 100644 code/plastic_phenoplus.f90 create mode 100644 code/plastic_phenopowerlaw.f90 create mode 100644 code/plastic_titanmod.f90 create mode 100644 code/source_damage_anisoBrittle.f90 create mode 100644 code/source_damage_anisoDuctile.f90 create mode 100644 code/source_damage_isoBrittle.f90 create mode 100644 code/source_damage_isoDuctile.f90 create mode 100644 code/source_thermal_dissipation.f90 create mode 100644 code/source_thermal_externalheat.f90 create mode 100644 code/source_vacancy_irradiation.f90 create mode 100644 code/source_vacancy_phenoplasticity.f90 create mode 100644 code/source_vacancy_thermalfluc.f90 create mode 100644 compile.log diff --git a/code/kinematics_cleavage_opening.f90 b/code/kinematics_cleavage_opening.f90 new file mode 100644 index 000000000..945e2d08a --- /dev/null +++ b/code/kinematics_cleavage_opening.f90 @@ -0,0 +1,303 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from opening of cleavage planes +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_cleavage_opening + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_cleavage_opening_sizePostResults, & !< cumulative size of post results + kinematics_cleavage_opening_offset, & !< which kinematics is my current damage mechanism? + kinematics_cleavage_opening_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_cleavage_opening_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_cleavage_opening_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_cleavage_opening_Noutput !< number of outputs per instance of this damage + + integer(pInt), dimension(:), allocatable, private :: & + kinematics_cleavage_opening_totalNcleavage !< total number of cleavage systems + + integer(pInt), dimension(:,:), allocatable, private :: & + kinematics_cleavage_opening_Ncleavage !< number of cleavage systems per family + + real(pReal), dimension(:), allocatable, private :: & + kinematics_cleavage_opening_sdot_0, & + kinematics_cleavage_opening_N + + real(pReal), dimension(:,:), allocatable, private :: & + kinematics_cleavage_opening_critDisp, & + kinematics_cleavage_opening_critLoad + + public :: & + kinematics_cleavage_opening_init, & + kinematics_cleavage_opening_LiAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_cleavage_opening_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_cleavage_opening_label, & + KINEMATICS_cleavage_opening_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + use lattice, only: & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_cleavage_opening_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_cleavage_opening_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_cleavage_opening_offset(material_Nphase), source=0_pInt) + allocate(kinematics_cleavage_opening_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_cleavage_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_cleavage_opening_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_cleavage_opening_ID) & + kinematics_cleavage_opening_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_cleavage_opening_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_output(maxval(phase_Noutput),maxNinstance)) + kinematics_cleavage_opening_output = '' + allocate(kinematics_cleavage_opening_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(kinematics_cleavage_opening_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(kinematics_cleavage_opening_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_totalNcleavage(maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_sdot_0(maxNinstance), source=0.0_pReal) + allocate(kinematics_cleavage_opening_N(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_cleavage_opening_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('anisobrittle_sdot0') + kinematics_cleavage_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisobrittle_ratesensitivity') + kinematics_cleavage_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('ncleavage') ! + Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_CleavageFamilies + kinematics_cleavage_opening_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticaldisplacement') + do j = 1_pInt, Nchunks_CleavageFamilies + kinematics_cleavage_opening_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticalload') + do j = 1_pInt, Nchunks_CleavageFamilies + kinematics_cleavage_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then + instance = kinematics_cleavage_opening_instance(phase) + kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & + min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested + kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance)) + kinematics_cleavage_opening_totalNcleavage(instance) = sum(kinematics_cleavage_opening_Ncleavage(:,instance)) ! how many cleavage systems altogether + if (kinematics_cleavage_opening_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_cleavage_opening_LABEL//')') + if (any(kinematics_cleavage_opening_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//KINEMATICS_cleavage_opening_LABEL//')') + if (any(kinematics_cleavage_opening_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//KINEMATICS_cleavage_opening_LABEL//')') + if (kinematics_cleavage_opening_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_cleavage_opening_LABEL//')') + endif myPhase + enddo sanityChecks + +end subroutine kinematics_cleavage_opening_init + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) + use prec, only: & + tol_math_check + use material, only: & + phaseAt, phasememberAt, & + material_homog, & + damage, & + damageMapping + use lattice, only: & + lattice_Scleavage, & + lattice_Scleavage_v, & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola-Kirchhoff stress + real(pReal), intent(out), dimension(3,3) :: & + Ld !< damage velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) + integer(pInt) :: & + phase, & + constituent, & + instance, & + homog, damageOffset, & + f, i, index_myFamily, k, l, m, n + real(pReal) :: & + traction_d, traction_t, traction_n, traction_crit, & + udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = kinematics_cleavage_opening_instance(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + Ld = 0.0_pReal + dLd_dTstar3333 = 0.0_pReal + do f = 1_pInt,lattice_maxNcleavageFamily + index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family + do i = 1_pInt,kinematics_cleavage_opening_Ncleavage(f,instance) ! process each (active) cleavage system in family + traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) + traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) + traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) + traction_crit = kinematics_cleavage_opening_critLoad(f,instance)* & + damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) + udotd = & + sign(1.0_pReal,traction_d)* & + kinematics_cleavage_opening_sdot_0(instance)* & + (max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) + if (abs(udotd) > tol_math_check) then + Ld = Ld + udotd*lattice_Scleavage(1:3,1:3,1,index_myFamily+i,phase) + dudotd_dt = sign(1.0_pReal,traction_d)*udotd*kinematics_cleavage_opening_N(instance)/ & + max(0.0_pReal, abs(traction_d) - traction_crit) + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotd_dt*lattice_Scleavage(k,l,1,index_myFamily+i,phase)* & + lattice_Scleavage(m,n,1,index_myFamily+i,phase) + endif + + udott = & + sign(1.0_pReal,traction_t)* & + kinematics_cleavage_opening_sdot_0(instance)* & + (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) + if (abs(udott) > tol_math_check) then + Ld = Ld + udott*lattice_Scleavage(1:3,1:3,2,index_myFamily+i,phase) + dudott_dt = sign(1.0_pReal,traction_t)*udott*kinematics_cleavage_opening_N(instance)/ & + max(0.0_pReal, abs(traction_t) - traction_crit) + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudott_dt*lattice_Scleavage(k,l,2,index_myFamily+i,phase)* & + lattice_Scleavage(m,n,2,index_myFamily+i,phase) + endif + + udotn = & + sign(1.0_pReal,traction_n)* & + kinematics_cleavage_opening_sdot_0(instance)* & + (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) + if (abs(udotn) > tol_math_check) then + Ld = Ld + udotn*lattice_Scleavage(1:3,1:3,3,index_myFamily+i,phase) + dudotn_dt = sign(1.0_pReal,traction_n)*udotn*kinematics_cleavage_opening_N(instance)/ & + max(0.0_pReal, abs(traction_n) - traction_crit) + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotn_dt*lattice_Scleavage(k,l,3,index_myFamily+i,phase)* & + lattice_Scleavage(m,n,3,index_myFamily+i,phase) + endif + + enddo + enddo + +end subroutine kinematics_cleavage_opening_LiAndItsTangent + +end module kinematics_cleavage_opening diff --git a/code/kinematics_hydrogen_strain.f90 b/code/kinematics_hydrogen_strain.f90 new file mode 100644 index 000000000..ceb3b1ef3 --- /dev/null +++ b/code/kinematics_hydrogen_strain.f90 @@ -0,0 +1,264 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from interstitial hydrogen +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_hydrogen_strain + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_hydrogen_strain_sizePostResults, & !< cumulative size of post results + kinematics_hydrogen_strain_offset, & !< which kinematics is my current damage mechanism? + kinematics_hydrogen_strain_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_hydrogen_strain_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_hydrogen_strain_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_hydrogen_strain_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + kinematics_hydrogen_strain_coeff + + public :: & + kinematics_hydrogen_strain_init, & + kinematics_hydrogen_strain_initialStrain, & + kinematics_hydrogen_strain_LiAndItsTangent, & + kinematics_hydrogen_strain_ChemPotAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_hydrogen_strain_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_hydrogen_strain_label, & + KINEMATICS_hydrogen_strain_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_hydrogen_strain_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_hydrogen_strain_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_hydrogen_strain_offset(material_Nphase), source=0_pInt) + allocate(kinematics_hydrogen_strain_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_hydrogen_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_hydrogen_strain_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_hydrogen_strain_ID) & + kinematics_hydrogen_strain_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_hydrogen_strain_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_hydrogen_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_hydrogen_strain_output(maxval(phase_Noutput),maxNinstance)) + kinematics_hydrogen_strain_output = '' + allocate(kinematics_hydrogen_strain_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_hydrogen_strain_coeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_hydrogen_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_hydrogen_strain_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('hydrogen_strain_coeff') + kinematics_hydrogen_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + +end subroutine kinematics_hydrogen_strain_init + +!-------------------------------------------------------------------------------------------------- +!> @brief report initial hydrogen strain based on current hydrogen conc deviation from +!> equillibrium (0) +!-------------------------------------------------------------------------------------------------- +pure function kinematics_hydrogen_strain_initialStrain(ipc, ip, el) + use math, only: & + math_I3 + use material, only: & + material_phase, & + material_homog, & + hydrogenConc, & + hydrogenfluxMapping + use lattice, only: & + lattice_equilibriumHydrogenConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + kinematics_hydrogen_strain_initialStrain !< initial thermal strain (should be small strain, though) + integer(pInt) :: & + phase, & + homog, offset, instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_hydrogen_strain_instance(phase) + homog = material_homog(ip,el) + offset = hydrogenfluxMapping(homog)%p(ip,el) + + kinematics_hydrogen_strain_initialStrain = & + (hydrogenConc(homog)%p(offset) - lattice_equilibriumHydrogenConcentration(phase)) * & + kinematics_hydrogen_strain_coeff(instance)* math_I3 + +end function kinematics_hydrogen_strain_initialStrain + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_hydrogen_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + hydrogenConc, & + hydrogenConcRate, & + hydrogenfluxMapping + use math, only: & + math_I3 + use lattice, only: & + lattice_equilibriumHydrogenConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out), dimension(3,3) :: & + Li !< thermal velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) + integer(pInt) :: & + phase, & + instance, & + homog, offset + real(pReal) :: & + Ch, ChEq, ChDot + + phase = material_phase(ipc,ip,el) + instance = kinematics_hydrogen_strain_instance(phase) + homog = material_homog(ip,el) + offset = hydrogenfluxMapping(homog)%p(ip,el) + Ch = hydrogenConc(homog)%p(offset) + ChDot = hydrogenConcRate(homog)%p(offset) + ChEq = lattice_equilibriumHydrogenConcentration(phase) + + Li = ChDot*math_I3* & + kinematics_hydrogen_strain_coeff(instance)/ & + (1.0_pReal + kinematics_hydrogen_strain_coeff(instance)*(Ch - ChEq)) + dLi_dTstar3333 = 0.0_pReal + +end subroutine kinematics_hydrogen_strain_LiAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the kinematic contribution to hydrogen chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCh, Tstar_v, Fi0, Fi, ipc, ip, el) + use material, only: & + material_phase + use math, only: & + math_inv33, & + math_mul33x33, & + math_Mandel6to33, & + math_transpose33 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v + real(pReal), intent(in), dimension(3,3) :: & + Fi0, Fi + real(pReal), intent(out) :: & + ChemPot, dChemPot_dCh + integer(pInt) :: & + phase, & + instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_hydrogen_strain_instance(phase) + + ChemPot = -kinematics_hydrogen_strain_coeff(instance)* & + sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & + math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) + dChemPot_dCh = 0.0_pReal + +end subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent + +end module kinematics_hydrogen_strain diff --git a/code/kinematics_slipplane_opening.f90 b/code/kinematics_slipplane_opening.f90 new file mode 100644 index 000000000..8b49e1cf3 --- /dev/null +++ b/code/kinematics_slipplane_opening.f90 @@ -0,0 +1,323 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from opening of slip planes +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_slipplane_opening + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_slipplane_opening_sizePostResults, & !< cumulative size of post results + kinematics_slipplane_opening_offset, & !< which kinematics is my current damage mechanism? + kinematics_slipplane_opening_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_slipplane_opening_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_slipplane_opening_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_slipplane_opening_Noutput !< number of outputs per instance of this damage + + integer(pInt), dimension(:), allocatable, private :: & + kinematics_slipplane_opening_totalNslip !< total number of slip systems + + integer(pInt), dimension(:,:), allocatable, private :: & + kinematics_slipplane_opening_Nslip !< number of slip systems per family + + real(pReal), dimension(:), allocatable, private :: & + kinematics_slipplane_opening_sdot_0, & + kinematics_slipplane_opening_N + + real(pReal), dimension(:,:), allocatable, private :: & + kinematics_slipplane_opening_critPlasticStrain, & + kinematics_slipplane_opening_critLoad + + public :: & + kinematics_slipplane_opening_init, & + kinematics_slipplane_opening_LiAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_slipplane_opening_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_slipplane_opening_label, & + KINEMATICS_slipplane_opening_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + use lattice, only: & + lattice_maxNslipFamily, & + lattice_NslipSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_slipplane_opening_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_slipplane_opening_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_slipplane_opening_offset(material_Nphase), source=0_pInt) + allocate(kinematics_slipplane_opening_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_slipplane_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_slipplane_opening_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_slipplane_opening_ID) & + kinematics_slipplane_opening_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_slipplane_opening_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_slipplane_opening_output(maxval(phase_Noutput),maxNinstance)) + kinematics_slipplane_opening_output = '' + allocate(kinematics_slipplane_opening_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(kinematics_slipplane_opening_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(kinematics_slipplane_opening_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_totalNslip(maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_N(maxNinstance), source=0.0_pReal) + allocate(kinematics_slipplane_opening_sdot_0(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_slipplane_opening_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('nslip') ! + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + kinematics_slipplane_opening_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_sdot0') + kinematics_slipplane_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalplasticstrain') + do j = 1_pInt, Nchunks_SlipFamilies + kinematics_slipplane_opening_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_ratesensitivity') + kinematics_slipplane_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalload') + do j = 1_pInt, Nchunks_SlipFamilies + kinematics_slipplane_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then + instance = kinematics_slipplane_opening_instance(phase) + kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested + kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance)) + kinematics_slipplane_opening_totalNslip(instance) = sum(kinematics_slipplane_opening_Nslip(:,instance)) + if (kinematics_slipplane_opening_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_slipplane_opening_LABEL//')') + if (any(kinematics_slipplane_opening_critPlasticStrain(:,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//KINEMATICS_slipplane_opening_LABEL//')') + if (kinematics_slipplane_opening_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_slipplane_opening_LABEL//')') + endif myPhase + enddo sanityChecks + + +end subroutine kinematics_slipplane_opening_init + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) + use prec, only: & + tol_math_check + use lattice, only: & + lattice_maxNslipFamily, & + lattice_NslipSystem, & + lattice_sd, & + lattice_st, & + lattice_sn + use material, only: & + phaseAt, phasememberAt, & + material_homog, & + damage, & + damageMapping + use math, only: & + math_Plain3333to99, & + math_I3, & + math_identity4th, & + math_symmetric33, & + math_Mandel33to6, & + math_tensorproduct33, & + math_det33, & + math_mul33x33 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola-Kirchhoff stress + real(pReal), intent(out), dimension(3,3) :: & + Ld !< damage velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) + real(pReal), dimension(3,3) :: & + projection_d, projection_t, projection_n !< projection modes 3x3 tensor + real(pReal), dimension(6) :: & + projection_d_v, projection_t_v, projection_n_v !< projection modes 3x3 vector + integer(pInt) :: & + phase, & + constituent, & + instance, & + homog, damageOffset, & + f, i, index_myFamily, k, l, m, n + real(pReal) :: & + traction_d, traction_t, traction_n, traction_crit, & + udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = kinematics_slipplane_opening_instance(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + Ld = 0.0_pReal + dLd_dTstar3333 = 0.0_pReal + do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,phase)) ! at which index starts my family + do i = 1_pInt,kinematics_slipplane_opening_Nslip(f,instance) ! process each (active) slip system in family + projection_d = math_tensorproduct33(lattice_sd(1:3,index_myFamily+i,phase),& + lattice_sn(1:3,index_myFamily+i,phase)) + projection_t = math_tensorproduct33(lattice_st(1:3,index_myFamily+i,phase),& + lattice_sn(1:3,index_myFamily+i,phase)) + projection_n = math_tensorproduct33(lattice_sn(1:3,index_myFamily+i,phase),& + lattice_sn(1:3,index_myFamily+i,phase)) + + projection_d_v(1:6) = math_Mandel33to6(math_symmetric33(projection_d(1:3,1:3))) + projection_t_v(1:6) = math_Mandel33to6(math_symmetric33(projection_t(1:3,1:3))) + projection_n_v(1:6) = math_Mandel33to6(math_symmetric33(projection_n(1:3,1:3))) + + traction_d = dot_product(Tstar_v,projection_d_v(1:6)) + traction_t = dot_product(Tstar_v,projection_t_v(1:6)) + traction_n = dot_product(Tstar_v,projection_n_v(1:6)) + + traction_crit = kinematics_slipplane_opening_critLoad(f,instance)* & + damage(homog)%p(damageOffset) ! degrading critical load carrying capacity by damage + + udotd = & + sign(1.0_pReal,traction_d)* & + kinematics_slipplane_opening_sdot_0(instance)* & + (abs(traction_d)/traction_crit - & + abs(traction_d)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) + if (abs(udotd) > tol_math_check) then + Ld = Ld + udotd*projection_d + dudotd_dt = udotd*kinematics_slipplane_opening_N(instance)/traction_d + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotd_dt*projection_d(k,l)*projection_d(m,n) + endif + + udott = & + sign(1.0_pReal,traction_t)* & + kinematics_slipplane_opening_sdot_0(instance)* & + (abs(traction_t)/traction_crit - & + abs(traction_t)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) + if (abs(udott) > tol_math_check) then + Ld = Ld + udott*projection_t + dudott_dt = udott*kinematics_slipplane_opening_N(instance)/traction_t + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudott_dt*projection_t(k,l)*projection_t(m,n) + endif + udotn = & + kinematics_slipplane_opening_sdot_0(instance)* & + (max(0.0_pReal,traction_n)/traction_crit - & + max(0.0_pReal,traction_n)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) + if (abs(udotn) > tol_math_check) then + Ld = Ld + udotn*projection_n + dudotn_dt = udotn*kinematics_slipplane_opening_N(instance)/traction_n + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotn_dt*projection_n(k,l)*projection_n(m,n) + endif + enddo + enddo + +end subroutine kinematics_slipplane_opening_LiAndItsTangent + +end module kinematics_slipplane_opening diff --git a/code/kinematics_thermal_expansion.f90 b/code/kinematics_thermal_expansion.f90 new file mode 100644 index 000000000..b99c499f3 --- /dev/null +++ b/code/kinematics_thermal_expansion.f90 @@ -0,0 +1,228 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from thermal expansion +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_thermal_expansion + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_thermal_expansion_sizePostResults, & !< cumulative size of post results + kinematics_thermal_expansion_offset, & !< which kinematics is my current damage mechanism? + kinematics_thermal_expansion_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_thermal_expansion_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_thermal_expansion_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_thermal_expansion_Noutput !< number of outputs per instance of this damage + +! enum, bind(c) ! ToDo kinematics need state machinery to deal with sizePostResult +! enumerator :: undefined_ID, & ! possible remedy is to decouple having state vars from having output +! thermalexpansionrate_ID ! which means to separate user-defined types tState + tOutput... +! end enum + public :: & + kinematics_thermal_expansion_init, & + kinematics_thermal_expansion_initialStrain, & + kinematics_thermal_expansion_LiAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_thermal_expansion_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_thermal_expansion_label, & + KINEMATICS_thermal_expansion_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + character(len=65536) :: & + tag = '', & + output = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_thermal_expansion_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_thermal_expansion_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_thermal_expansion_offset(material_Nphase), source=0_pInt) + allocate(kinematics_thermal_expansion_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_thermal_expansion_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_thermal_expansion_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_thermal_expansion_ID) & + kinematics_thermal_expansion_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_thermal_expansion_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_thermal_expansion_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_thermal_expansion_output(maxval(phase_Noutput),maxNinstance)) + kinematics_thermal_expansion_output = '' + allocate(kinematics_thermal_expansion_Noutput(maxNinstance), source=0_pInt) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_thermal_expansion_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_thermal_expansion_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key... + select case(tag) +! case ('(output)') +! output = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) ! ...and corresponding output +! select case(output) +! case ('thermalexpansionrate') +! kinematics_thermal_expansion_Noutput(instance) = kinematics_thermal_expansion_Noutput(instance) + 1_pInt +! kinematics_thermal_expansion_outputID(kinematics_thermal_expansion_Noutput(instance),instance) = & +! thermalexpansionrate_ID +! kinematics_thermal_expansion_output(kinematics_thermal_expansion_Noutput(instance),instance) = output +! ToDo add sizePostResult loop afterwards... + + end select + endif; endif + enddo parsingFile + +end subroutine kinematics_thermal_expansion_init + +!-------------------------------------------------------------------------------------------------- +!> @brief report initial thermal strain based on current temperature deviation from reference +!-------------------------------------------------------------------------------------------------- +pure function kinematics_thermal_expansion_initialStrain(ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + temperature, & + thermalMapping + use lattice, only: & + lattice_thermalExpansion33, & + lattice_referenceTemperature + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + kinematics_thermal_expansion_initialStrain !< initial thermal strain (should be small strain, though) + integer(pInt) :: & + phase, & + homog, offset + + phase = material_phase(ipc,ip,el) + homog = material_homog(ip,el) + offset = thermalMapping(homog)%p(ip,el) + + kinematics_thermal_expansion_initialStrain = & + (temperature(homog)%p(offset) - lattice_referenceTemperature(phase)) * & + lattice_thermalExpansion33(1:3,1:3,phase) + +end function kinematics_thermal_expansion_initialStrain + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + temperature, & + temperatureRate, & + thermalMapping + use lattice, only: & + lattice_thermalExpansion33, & + lattice_referenceTemperature + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out), dimension(3,3) :: & + Li !< thermal velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor defined to be zero) + integer(pInt) :: & + phase, & + homog, offset + real(pReal) :: & + T, TRef, TDot + + phase = material_phase(ipc,ip,el) + homog = material_homog(ip,el) + offset = thermalMapping(homog)%p(ip,el) + T = temperature(homog)%p(offset) + TDot = temperatureRate(homog)%p(offset) + TRef = lattice_referenceTemperature(phase) + + Li = TDot* & + lattice_thermalExpansion33(1:3,1:3,phase)/ & + (1.0_pReal + lattice_thermalExpansion33(1:3,1:3,phase)*(T - TRef)) + dLi_dTstar3333 = 0.0_pReal + +end subroutine kinematics_thermal_expansion_LiAndItsTangent + +end module kinematics_thermal_expansion diff --git a/code/kinematics_vacancy_strain.f90 b/code/kinematics_vacancy_strain.f90 new file mode 100644 index 000000000..899bccd9f --- /dev/null +++ b/code/kinematics_vacancy_strain.f90 @@ -0,0 +1,265 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from vacancy point defects +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_vacancy_strain + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_vacancy_strain_sizePostResults, & !< cumulative size of post results + kinematics_vacancy_strain_offset, & !< which kinematics is my current damage mechanism? + kinematics_vacancy_strain_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_vacancy_strain_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_vacancy_strain_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_vacancy_strain_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + kinematics_vacancy_strain_coeff + + public :: & + kinematics_vacancy_strain_init, & + kinematics_vacancy_strain_initialStrain, & + kinematics_vacancy_strain_LiAndItsTangent, & + kinematics_vacancy_strain_ChemPotAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_vacancy_strain_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_vacancy_strain_label, & + KINEMATICS_vacancy_strain_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_vacancy_strain_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_vacancy_strain_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_vacancy_strain_offset(material_Nphase), source=0_pInt) + allocate(kinematics_vacancy_strain_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_vacancy_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_vacancy_strain_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_vacancy_strain_ID) & + kinematics_vacancy_strain_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_vacancy_strain_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_vacancy_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_vacancy_strain_output(maxval(phase_Noutput),maxNinstance)) + kinematics_vacancy_strain_output = '' + allocate(kinematics_vacancy_strain_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_vacancy_strain_coeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_vacancy_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_vacancy_strain_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('vacancy_strain_coeff') + kinematics_vacancy_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + +end subroutine kinematics_vacancy_strain_init + +!-------------------------------------------------------------------------------------------------- +!> @brief report initial vacancy strain based on current vacancy conc deviation from equillibrium +!-------------------------------------------------------------------------------------------------- +pure function kinematics_vacancy_strain_initialStrain(ipc, ip, el) + use math, only: & + math_I3 + use material, only: & + material_phase, & + material_homog, & + vacancyConc, & + vacancyfluxMapping + use lattice, only: & + lattice_equilibriumVacancyConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + kinematics_vacancy_strain_initialStrain !< initial thermal strain (should be small strain, though) + integer(pInt) :: & + phase, & + homog, offset, instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_vacancy_strain_instance(phase) + homog = material_homog(ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + + kinematics_vacancy_strain_initialStrain = & + (vacancyConc(homog)%p(offset) - lattice_equilibriumVacancyConcentration(phase)) * & + kinematics_vacancy_strain_coeff(instance)* math_I3 + +end function kinematics_vacancy_strain_initialStrain + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_vacancy_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + vacancyConc, & + vacancyConcRate, & + vacancyfluxMapping + use math, only: & + math_I3 + use lattice, only: & + lattice_equilibriumVacancyConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out), dimension(3,3) :: & + Li !< thermal velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) + integer(pInt) :: & + phase, & + instance, & + homog, offset + real(pReal) :: & + Cv, CvEq, CvDot + + phase = material_phase(ipc,ip,el) + instance = kinematics_vacancy_strain_instance(phase) + homog = material_homog(ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + + Cv = vacancyConc(homog)%p(offset) + CvDot = vacancyConcRate(homog)%p(offset) + CvEq = lattice_equilibriumvacancyConcentration(phase) + + Li = CvDot*math_I3* & + kinematics_vacancy_strain_coeff(instance)/ & + (1.0_pReal + kinematics_vacancy_strain_coeff(instance)*(Cv - CvEq)) + + dLi_dTstar3333 = 0.0_pReal + +end subroutine kinematics_vacancy_strain_LiAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the kinematic contribution to vacancy chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_vacancy_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCv, Tstar_v, Fi0, Fi, ipc, ip, el) + use material, only: & + material_phase + use math, only: & + math_inv33, & + math_mul33x33, & + math_Mandel6to33, & + math_transpose33 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v + real(pReal), intent(in), dimension(3,3) :: & + Fi0, Fi + real(pReal), intent(out) :: & + ChemPot, dChemPot_dCv + integer(pInt) :: & + phase, & + instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_vacancy_strain_instance(phase) + + ChemPot = -kinematics_vacancy_strain_coeff(instance)* & + sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & + math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) + dChemPot_dCv = 0.0_pReal + +end subroutine kinematics_vacancy_strain_ChemPotAndItsTangent + +end module kinematics_vacancy_strain diff --git a/code/plastic_disloUCLA.f90 b/code/plastic_disloUCLA.f90 new file mode 100644 index 000000000..d95a5e6a4 --- /dev/null +++ b/code/plastic_disloUCLA.f90 @@ -0,0 +1,2116 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author David Cereceda, Lawrence Livermore National Laboratory +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incoprorating dislocation and twinning physics +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module plastic_disloUCLA + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_disloUCLA_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_disloUCLA_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_disloUCLA_output !< name of each post result output + + real(pReal), parameter, private :: & + kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_disloUCLA_Noutput !< number of outputs per instance of this plasticity + + integer(pInt), dimension(:), allocatable, private :: & + plastic_disloUCLA_totalNslip, & !< total number of active slip systems for each instance + plastic_disloUCLA_totalNtwin !< total number of active twin systems for each instance + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_disloUCLA_Nslip, & !< number of active slip systems for each family and instance + plastic_disloUCLA_Ntwin !< number of active twin systems for each family and instance + + real(pReal), dimension(:), allocatable, private :: & + plastic_disloUCLA_CAtomicVolume, & !< atomic volume in Bugers vector unit + plastic_disloUCLA_D0, & !< prefactor for self-diffusion coefficient + plastic_disloUCLA_Qsd, & !< activation energy for dislocation climb + plastic_disloUCLA_GrainSize, & !< grain size + plastic_disloUCLA_MaxTwinFraction, & !< maximum allowed total twin volume fraction + plastic_disloUCLA_CEdgeDipMinDistance, & !< + plastic_disloUCLA_Cmfptwin, & !< + plastic_disloUCLA_Cthresholdtwin, & !< + plastic_disloUCLA_SolidSolutionStrength, & !< Strength due to elements in solid solution + plastic_disloUCLA_L0, & !< Length of twin nuclei in Burgers vectors + plastic_disloUCLA_xc, & !< critical distance for formation of twin nucleus + plastic_disloUCLA_VcrossSlip, & !< cross slip volume + plastic_disloUCLA_SFE_0K, & !< stacking fault energy at zero K + plastic_disloUCLA_dSFE_dT, & !< temperature dependance of stacking fault energy + plastic_disloUCLA_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful + plastic_disloUCLA_aTolRho, & !< absolute tolerance for integration of dislocation density + plastic_disloUCLA_aTolTwinFrac !< absolute tolerance for integration of twin volume fraction + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_disloUCLA_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_disloUCLA_Ctwin3333 !< twin elasticity matrix for each instance + real(pReal), dimension(:,:), allocatable, private :: & + plastic_disloUCLA_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance + plastic_disloUCLA_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance + plastic_disloUCLA_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance + plastic_disloUCLA_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance + plastic_disloUCLA_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance + plastic_disloUCLA_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance + plastic_disloUCLA_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance + plastic_disloUCLA_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance + plastic_disloUCLA_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance + plastic_disloUCLA_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance + plastic_disloUCLA_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance + plastic_disloUCLA_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance + plastic_disloUCLA_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance + plastic_disloUCLA_tau_r, & !< stress to bring partial close together for each twin system and instance + plastic_disloUCLA_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance + plastic_disloUCLA_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance + plastic_disloUCLA_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_disloUCLA_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_disloUCLA_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance + plastic_disloUCLA_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance + plastic_disloUCLA_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_disloUCLA_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance + plastic_disloUCLA_pPerSlipFamily, & !< p-exponent in glide velocity + plastic_disloUCLA_qPerSlipFamily, & !< q-exponent in glide velocity + !* mobility law parameters + plastic_disloUCLA_kinkheight, & !< height of the kink pair + plastic_disloUCLA_omega, & !< attempt frequency for kink pair nucleation + plastic_disloUCLA_kinkwidth, & !< width of the kink pair + plastic_disloUCLA_dislolength, & !< dislocation length (lamda) + plastic_disloUCLA_friction, & !< friction coeff. B (kMC) + !* + plastic_disloUCLA_rPerTwinFamily, & !< r-exponent in twin nucleation rate + plastic_disloUCLA_nonSchmidCoeff !< non-Schmid coefficients (bcc) + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_disloUCLA_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance + plastic_disloUCLA_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance + plastic_disloUCLA_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance + plastic_disloUCLA_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance + plastic_disloUCLA_forestProjectionEdge !< matrix of forest projections of edge dislocations for each instance + + enum, bind(c) + enumerator :: undefined_ID, & + edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID, & + twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_disloUCLA_outputID !< ID of each post result output + + type, private :: tDisloUCLAState + real(pReal), pointer, dimension(:,:) :: & + rhoEdge, & + rhoEdgeDip, & + accshear_slip, & + twinFraction, & + accshear_twin, & + invLambdaSlip, & + invLambdaSlipTwin, & + invLambdaTwin, & + mfp_slip, & + mfp_twin, & + threshold_stress_slip, & + threshold_stress_twin, & + twinVolume + end type + type(tDisloUCLAState ), allocatable, dimension(:), private :: & + state, & + state0, & + dotState + + public :: & + plastic_disloUCLA_init, & + plastic_disloUCLA_homogenizedC, & + plastic_disloUCLA_microstructure, & + plastic_disloUCLA_LpAndItsTangent, & + plastic_disloUCLA_dotState, & + plastic_disloUCLA_postResults + private :: & + plastic_disloUCLA_stateInit, & + plastic_disloUCLA_aTolState + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333, & + math_mul3x3 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_DISLOUCLA_label, & + PLASTICITY_DISLOUCLA_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,& + f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & + offset_slip, index_myFamily, index_otherFamily, & + startIndex, endIndex + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOUCLA_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOUCLA_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_disloUCLA_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(plastic_disloUCLA_output(maxval(phase_Noutput),maxNinstance)) + plastic_disloUCLA_output = '' + allocate(plastic_disloUCLA_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_disloUCLA_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_CAtomicVolume(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_D0(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Qsd(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_GrainSize(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_MaxTwinFraction(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Cmfptwin(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Cthresholdtwin(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_SolidSolutionStrength(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_L0(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_xc(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_VcrossSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_aTolRho(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_aTolTwinFrac(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_SFE_0K(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_dSFE_dT(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default + allocate(plastic_disloUCLA_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_kinkheight(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_omega(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_kinkwidth(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_dislolength(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_friction(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_disloUCLA_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_disloUCLA_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), source=0.0_pReal) + + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + if(allocated(tempPerTwin)) deallocate(tempPerTwin) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + allocate(tempPerTwin(Nchunks_TwinFamilies)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('edge_density') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_density_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('dipole_density') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = dipole_density_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_slip','shearrate_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('edge_dipole_distance') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_dipole_distance_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stress_exponent') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = stress_exponent_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('twin_fraction') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = twin_fraction_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_twin','shearrate_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip system families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + plastic_disloUCLA_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip',& + 'kink_height','omega','kink_width','dislolength','friction_coeff') + do j = 1_pInt, Nchunks_SlipFamilies + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('rhoedge0') + plastic_disloUCLA_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('rhoedgedip0') + plastic_disloUCLA_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('slipburgers') + plastic_disloUCLA_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('qedge') + plastic_disloUCLA_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('v0') + plastic_disloUCLA_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('clambdaslip') + plastic_disloUCLA_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau_peierls') + if (lattice_structure(phase) /= LATTICE_bcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOUCLA_label//')') + plastic_disloUCLA_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('p_slip') + plastic_disloUCLA_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('q_slip') + plastic_disloUCLA_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('kink_height') + plastic_disloUCLA_kinkheight(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('omega') + plastic_disloUCLA_omega(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('kink_width') + plastic_disloUCLA_kinkwidth(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('dislolength') + plastic_disloUCLA_dislolength(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('friction_coeff') + plastic_disloUCLA_friction(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on slip number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_disloUCLA_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ndot0','twinsize','twinburgers','r_twin') + do j = 1_pInt, Nchunks_TwinFamilies + tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('ndot0') + if (lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOUCLA_label//')') + plastic_disloUCLA_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinsize') + plastic_disloUCLA_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinburgers') + plastic_disloUCLA_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('r_twin') + plastic_disloUCLA_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip','interactionslipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_disloUCLA_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin','interactionsliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_disloUCLA_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip','interactiontwinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_disloUCLA_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin','interactiontwintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_disloUCLA_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt,Nchunks_nonSchmid + plastic_disloUCLA_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin systems + case ('grainsize') + plastic_disloUCLA_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('maxtwinfraction') + plastic_disloUCLA_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('d0') + plastic_disloUCLA_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('qsd') + plastic_disloUCLA_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_rho') + plastic_disloUCLA_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_disloUCLA_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cmfptwin') + plastic_disloUCLA_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cthresholdtwin') + plastic_disloUCLA_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('solidsolutionstrength') + plastic_disloUCLA_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('l0') + plastic_disloUCLA_L0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('xc') + plastic_disloUCLA_xc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('vcrossslip') + plastic_disloUCLA_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cedgedipmindistance') + plastic_disloUCLA_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('catomicvolume') + plastic_disloUCLA_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('sfe_0k') + plastic_disloUCLA_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dsfe_dt') + plastic_disloUCLA_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dipoleformationfactor') + plastic_disloUCLA_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then + instance = phase_plasticityInstance(phase) + if (sum(plastic_disloUCLA_Nslip(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOUCLA_label//')') + if (sum(plastic_disloUCLA_Ntwin(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOUCLA_label//')') + do f = 1_pInt,lattice_maxNslipFamily + if (plastic_disloUCLA_Nslip(f,instance) > 0_pInt) then + if (plastic_disloUCLA_rhoEdge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_rhoEdgeDip0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_v0PerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOUCLA_label//')') + endif + enddo + do f = 1_pInt,lattice_maxNtwinFamily + if (plastic_disloUCLA_Ntwin(f,instance) > 0_pInt) then + if (plastic_disloUCLA_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='ndot0 ('//PLASTICITY_DISLOUCLA_label//')') + endif + enddo + if (plastic_disloUCLA_CAtomicVolume(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_D0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_Qsd(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOUCLA_label//')') + if (sum(plastic_disloUCLA_Ntwin(:,instance)) > 0_pInt) then + if (abs(plastic_disloUCLA_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & + abs(plastic_disloUCLA_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & + lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_aTolTwinFrac(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOUCLA_label//')') + endif + if (abs(plastic_disloUCLA_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & + plastic_disloUCLA_dipoleFormationFactor(instance) /= 1.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOUCLA_label//')') + +!-------------------------------------------------------------------------------------------------- +! Determine total number of active slip or twin systems + plastic_disloUCLA_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_disloUCLA_Nslip(:,instance)) + plastic_disloUCLA_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_disloUCLA_Ntwin(:,instance)) + plastic_disloUCLA_totalNslip(instance) = sum(plastic_disloUCLA_Nslip(:,instance)) + plastic_disloUCLA_totalNtwin(instance) = sum(plastic_disloUCLA_Ntwin(:,instance)) + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + maxTotalNslip = maxval(plastic_disloUCLA_totalNslip) + maxTotalNtwin = maxval(plastic_disloUCLA_totalNtwin) + + allocate(plastic_disloUCLA_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_tau_r(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) + + allocate(plastic_disloUCLA_interactionMatrix_SlipSlip(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from slip activity + maxval(plastic_disloUCLA_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_interactionMatrix_SlipTwin(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from twin activity + maxval(plastic_disloUCLA_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_interactionMatrix_TwinSlip(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_disloUCLA_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_interactionMatrix_TwinTwin(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_disloUCLA_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & + source=0.0_pReal) + allocate(plastic_disloUCLA_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) + + allocate(state(maxNinstance)) + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + myPhase2: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then + NofMyPhase=count(material_phase==phase) + instance = phase_plasticityInstance(phase) + + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputs: do o = 1_pInt,plastic_disloUCLA_Noutput(instance) + select case(plastic_disloUCLA_outputID(o,instance)) + case(edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID & + ) + mySize = ns + case(twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID & + ) + mySize = nt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + plastic_disloUCLA_sizePostResult(o,instance) = mySize + plastic_disloUCLA_sizePostResults(instance) = plastic_disloUCLA_sizePostResults(instance) + mySize + endif + enddo outputs + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + + sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & + + int(size(['twinFraction','accsheartwin']),pInt) * nt + sizeDeltaState = 0_pInt + sizeState = sizeDotState & + + int(size(['invLambdaSlip ','invLambdaSlipTwin ',& + 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & + + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& + 'twinVolume ']),pInt) * nt + + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_disloUCLA_sizePostResults(instance) + plasticState(phase)%nSlip = plastic_disloucla_totalNslip(instance) + plasticState(phase)%nTwin = plastic_disloucla_totalNtwin(instance) + plasticState(phase)%nTrans= 0_pInt + allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + offset_slip = 2_pInt*plasticState(phase)%nSlip + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) + !* Process slip related parameters ------------------------------------------------ + + mySlipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + mySlipSystems: do j = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + + !* Burgers vector, + ! dislocation velocity prefactor, + ! mean free path prefactor, + ! and minimum dipole distance + + plastic_disloUCLA_burgersPerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_burgersPerSlipFamily(f,instance) + + plastic_disloUCLA_QedgePerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_QedgePerSlipFamily(f,instance) + + plastic_disloUCLA_v0PerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_v0PerSlipFamily(f,instance) + + plastic_disloUCLA_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_CLambdaSlipPerSlipFamily(f,instance) + + !* Calculation of forest projections for edge dislocations + !* Interaction matrices + + otherSlipFamilies: do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) + otherSlipSystems: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) + plastic_disloUCLA_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & + abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & + lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) + plastic_disloUCLA_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo otherSlipSystems; enddo otherSlipFamilies + + otherTwinFamilies: do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) + otherTwinSystems: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) + plastic_disloUCLA_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo otherTwinSystems; enddo otherTwinFamilies + + enddo mySlipSystems + enddo mySlipFamilies + + !* Process twin related parameters ------------------------------------------------ + + myTwinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(plastic_disloUCLA_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list + myTwinSystems: do j = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) + + !* Burgers vector, + ! nucleation rate prefactor, + ! and twin size + + plastic_disloUCLA_burgersPerTwinSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_burgersPerTwinFamily(f,instance) + + plastic_disloUCLA_Ndot0PerTwinSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) + + plastic_disloUCLA_twinsizePerTwinSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_twinsizePerTwinFamily(f,instance) + + !* Rotate twin elasticity matrices + index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list + do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt + do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt + plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & + plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & + lattice_C3333(p,q,r,s,instance) * & + lattice_Qtwin(l,p,index_otherFamily+j,phase) * & + lattice_Qtwin(m,q,index_otherFamily+j,phase) * & + lattice_Qtwin(n,r,index_otherFamily+j,phase) * & + lattice_Qtwin(o,s,index_otherFamily+j,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo; enddo + plastic_disloUCLA_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & + math_Mandel3333to66(plastic_disloUCLA_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) + + !* Interaction matrices + otherSlipFamilies2: do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) + otherSlipSystems2: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) + plastic_disloUCLA_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo otherSlipSystems2; enddo otherSlipFamilies2 + + otherTwinFamilies2: do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) + otherTwinSystems2: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) + plastic_disloUCLA_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo otherTwinSystems2; enddo otherTwinFamilies2 + + enddo myTwinSystems + enddo myTwinFamilies + + startIndex=1_pInt + endIndex=ns + state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+ns + state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+ns + state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+nt + state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+nt + state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+ns + state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) + + call plastic_disloUCLA_stateInit(phase,instance) + call plastic_disloUCLA_aTolState(phase,instance) + endif myPhase2 + + enddo initializeInstances + +end subroutine plastic_disloUCLA_init + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_stateInit(ph,instance) + use math, only: & + pi + use lattice, only: & + lattice_maxNslipFamily, & + lattice_mu + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + real(pReal), dimension(plasticState(ph)%sizeState) :: tempState + + integer(pInt) :: i,j,f,ns,nt, index_myFamily + real(pReal), dimension(plastic_disloUCLA_totalNslip(instance)) :: & + rhoEdge0, & + rhoEdgeDip0, & + invLambdaSlip0, & + MeanFreePathSlip0, & + tauSlipThreshold0 + real(pReal), dimension(plastic_disloUCLA_totalNtwin(instance)) :: & + MeanFreePathTwin0,TwinVolume0 + tempState = 0.0_pReal + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables + do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + rhoEdge0(index_myFamily+1_pInt: & + index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & + plastic_disloUCLA_rhoEdge0(f,instance) + rhoEdgeDip0(index_myFamily+1_pInt: & + index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & + plastic_disloUCLA_rhoEdgeDip0(f,instance) + enddo + + tempState(1_pInt:ns) = rhoEdge0 + tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent slip microstructural variables + forall (i = 1_pInt:ns) & + invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_forestProjectionEdge(1:ns,i,instance)))/ & + plastic_disloUCLA_CLambdaSlipPerSlipSystem(i,instance) + tempState(3_pInt*ns+2_pInt*nt+1:4_pInt*ns+2_pInt*nt) = invLambdaSlip0 + + forall (i = 1_pInt:ns) & + MeanFreePathSlip0(i) = & + plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_disloUCLA_GrainSize(instance)) + tempState(5_pInt*ns+3_pInt*nt+1:6_pInt*ns+3_pInt*nt) = MeanFreePathSlip0 + + forall (i = 1_pInt:ns) & + tauSlipThreshold0(i) = & + lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(i,instance) * & + sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_interactionMatrix_SlipSlip(i,1:ns,instance))) + + tempState(6_pInt*ns+4_pInt*nt+1:7_pInt*ns+4_pInt*nt) = tauSlipThreshold0 + + + +!-------------------------------------------------------------------------------------------------- +! initialize dependent twin microstructural variables + forall (j = 1_pInt:nt) & + MeanFreePathTwin0(j) = plastic_disloUCLA_GrainSize(instance) + tempState(6_pInt*ns+3_pInt*nt+1_pInt:6_pInt*ns+4_pInt*nt) = MeanFreePathTwin0 + + forall (j = 1_pInt:nt) & + TwinVolume0(j) = & + (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) + tempState(7_pInt*ns+5_pInt*nt+1_pInt:7_pInt*ns+6_pInt*nt) = TwinVolume0 + +plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) + +end subroutine plastic_disloUCLA_stateInit + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + ph, & + instance ! number specifying the current instance of the plasticity + + ! Tolerance state for dislocation densities + plasticState(ph)%aTolState(1_pInt:2_pInt*plastic_disloUCLA_totalNslip(instance)) = & + plastic_disloUCLA_aTolRho(instance) + + ! Tolerance state for accumulated shear due to slip + plasticState(ph)%aTolState(2_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & + 3_pInt*plastic_disloUCLA_totalNslip(instance))=1e6_pReal + + + ! Tolerance state for twin volume fraction + plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & + 3_pInt*plastic_disloUCLA_totalNslip(instance)+& + plastic_disloUCLA_totalNtwin(instance)) = & + plastic_disloUCLA_aTolTwinFrac(instance) + +! Tolerance state for accumulated shear due to twin + plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+ & + plastic_disloUCLA_totalNtwin(instance)+1_pInt: & + 3_pInt*plastic_disloUCLA_totalNslip(instance)+ & + 2_pInt*plastic_disloUCLA_totalNtwin(instance)) = 1e6_pReal + +end subroutine plastic_disloUCLA_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenized elasticity matrix +!-------------------------------------------------------------------------------------------------- +function plastic_disloUCLA_homogenizedC(ipc,ip,el) + use material, only: & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_C66 + + implicit none + real(pReal), dimension(6,6) :: & + plastic_disloUCLA_homogenizedC + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,i, & + ph, & + of + real(pReal) :: sumf + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + !* Homogenized elasticity matrix + plastic_disloUCLA_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) + do i=1_pInt,nt + plastic_disloUCLA_homogenizedC = plastic_disloUCLA_homogenizedC & + + state(instance)%twinFraction(i,of)*plastic_disloUCLA_Ctwin66(1:6,1:6,i,instance) + enddo + +end function plastic_disloUCLA_homogenizedC + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_microstructure(temperature,ipc,ip,el) + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + phaseAt, phasememberAt + use lattice, only: & + lattice_mu, & + lattice_nu + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + temperature !< temperature at IP + + integer(pInt) :: & + instance, & + ns,nt,s,t, & + ph, & + of + real(pReal) :: & + sumf,sfe,x0 + real(pReal), dimension(plastic_disloUCLA_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Stacking fault energy + sfe = plastic_disloUCLA_SFE_0K(instance) + & + plastic_disloUCLA_dSFE_dT(instance) * Temperature + + !* rescaled twin volume fraction for topology + forall (t = 1_pInt:nt) & + fOverStacksize(t) = & + state(instance)%twinFraction(t,of)/plastic_disloUCLA_twinsizePerTwinSystem(t,instance) + + !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation + forall (s = 1_pInt:ns) & + state(instance)%invLambdaSlip(s,of) = & + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_disloUCLA_forestProjectionEdge(1:ns,s,instance)))/ & + plastic_disloUCLA_CLambdaSlipPerSlipSystem(s,instance) + !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation + !$OMP CRITICAL (evilmatmul) + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal + if (nt > 0_pInt .and. ns > 0_pInt) & + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & + matmul(plastic_disloUCLA_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin + !$OMP CRITICAL (evilmatmul) + if (nt > 0_pInt) & + state(instance)%invLambdaTwin(1_pInt:nt,of) = & + matmul(plastic_disloUCLA_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* mean free path between 2 obstacles seen by a moving dislocation + do s = 1_pInt,ns + if (nt > 0_pInt) then + state(instance)%mfp_slip(s,of) = & + plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+plastic_disloUCLA_GrainSize(instance)*& + (state(instance)%invLambdaSlip(s,of)+state(instance)%invLambdaSlipTwin(s,of))) + else + state(instance)%mfp_slip(s,of) = & + plastic_disloUCLA_GrainSize(instance)/& + (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) + endif + enddo + + !* mean free path between 2 obstacles seen by a growing twin + forall (t = 1_pInt:nt) & + state(instance)%mfp_twin(t,of) = & + (plastic_disloUCLA_Cmfptwin(instance)*plastic_disloUCLA_GrainSize(instance))/& + (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*state(instance)%invLambdaTwin(t,of)) + + !* threshold stress for dislocation motion + forall (s = 1_pInt:ns) & + state(instance)%threshold_stress_slip(s,of) = & + lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(s,instance)*& + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_disloUCLA_interactionMatrix_SlipSlip(s,1:ns,instance))) + + !* threshold stress for growing twin + forall (t = 1_pInt:nt) & + state(instance)%threshold_stress_twin(t,of) = & + plastic_disloUCLA_Cthresholdtwin(instance)*& + (sfe/(3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance))+& + 3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& + (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(t,instance))) + + !* final twin volume after growth + forall (t = 1_pInt:nt) & + state(instance)%twinVolume(t,of) = & + (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(t,instance)*state(instance)%mfp_twin(t,of)**(2.0_pReal) + + !* equilibrium seperation of partial dislocations + do t = 1_pInt,nt + x0 = lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& + (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) + plastic_disloUCLA_tau_r(t,instance)= & + lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& + (1/(x0+plastic_disloUCLA_xc(instance))+cos(pi/3.0_pReal)/x0) !!! used where?? + enddo + +end subroutine plastic_disloUCLA_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + math_Plain3333to99, & + math_Mandel6to33, & + math_Mandel33to6, & + math_spectralDecompositionSym33, & + math_symmetric33, & + math_mul33x3 + use material, only: & + material_phase, & + phase_plasticityInstance, & + !plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily,& + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid, & + lattice_shearTwin, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + integer(pInt), intent(in) :: ipc,ip,el + real(pReal), intent(in) :: Temperature + real(pReal), dimension(6), intent(in) :: Tstar_v + real(pReal), dimension(3,3), intent(out) :: Lp + real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 + + integer(pInt) :: instance,ph,of,ns,nt,f,i,j,k,l,m,n,index_myFamily,s1,s2 + real(pReal) :: sumf,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0, & + tau_slip_pos,tau_slip_neg,vel_slip,dvel_slip,& + dgdot_dtauslip_pos,dgdot_dtauslip_neg,dgdot_dtautwin,tau_twin,gdot_twin,stressRatio + real(pReal), dimension(3,3,2) :: & + nonSchmid_tensor + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar3333 + real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip_pos,gdot_slip_neg + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Dislocation glide part + gdot_slip_pos = 0.0_pReal + gdot_slip_neg = 0.0_pReal + dgdot_dtauslip_pos = 0.0_pReal + dgdot_dtauslip_neg = 0.0_pReal + + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j+1_pInt + !* Boltzmann ratio + BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& + plastic_disloUCLA_v0PerSlipSystem(j,instance) + !* Resolved shear stress on slip system + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k, index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) + enddo nonSchmidSystems + + significantPostitiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratio + stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_pos & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_pos(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_pos) + + !* Derivatives of shear rates + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_pos & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_pos & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + dgdot_dtauslip_pos = DotGamma0 * dvel_slip + + endif significantPostitiveStress + significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratio + stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_neg & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_neg(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_neg) + + !* Derivatives of shear rates + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_neg & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_neg & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + + dgdot_dtauslip_neg = DotGamma0 * dvel_slip + + endif significantNegativeStress + !* Plastic velocity gradient for dislocation glide + Lp = Lp + (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + (dgdot_dtauslip_pos*nonSchmid_tensor(m,n,1)+& + dgdot_dtauslip_neg*nonSchmid_tensor(m,n,2))*0.5_pReal*& + lattice_Sslip(k,l,1,index_myFamily+i,ph) + enddo slipSystems + enddo slipFamilies + +!-------------------------------------------------------------------------------------------------- +! correct Lp and dLp_dTstar3333 for twinned fraction + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + Lp = Lp * (1.0_pReal - sumf) + dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf) + +!-------------------------------------------------------------------------------------------------- +! Mechanical twinning part + gdot_twin = 0.0_pReal + dgdot_dtautwin = 0.0_pReal + j = 0_pInt + twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) + j = j+1_pInt + !* Resolved shear stress on twin system + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_twin > tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then + Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive gdot_slip_pos (= gdot_slip_neg) + abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) + else + Ndot0=0.0_pReal + end if + case default + Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) + end select + gdot_twin = & + (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) + dgdot_dtautwin = ((gdot_twin*plastic_disloUCLA_rPerTwinFamily(f,instance))/tau_twin)*StressRatio_r + endif + + !* Plastic velocity gradient for mechanical twinning + Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin*& + lattice_Stwin(k,l,index_myFamily+i,ph)*& + lattice_Stwin(m,n,index_myFamily+i,ph) + enddo twinSystems + enddo twinFamilies + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + +end subroutine plastic_disloUCLA_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_dotState(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid, & + lattice_sheartwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,f,i,j,k,index_myFamily,s1,s2, & + ph, & + of + real(pReal) :: & + sumf, & + stressRatio_p,& + BoltzmannRatio,& + DotGamma0,& + stressRatio, & + EdgeDipMinDistance,& + AtomicVolume,& + VacancyDiffusion,& + StressRatio_r,& + Ndot0,& + tau_slip_pos,& + tau_slip_neg,& + DotRhoMultiplication,& + EdgeDipDistance, & + DotRhoEdgeDipAnnihilation, & + DotRhoEdgeEdgeAnnihilation, & + ClimbVelocity, & + DotRhoEdgeDipClimb, & + DotRhoDipFormation, & + tau_twin, & + vel_slip, & + gdot_slip + real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip_pos, gdot_slip_neg + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + plasticState(ph)%dotState(:,of) = 0.0_pReal + + !* Dislocation density evolution + gdot_slip_pos = 0.0_pReal + gdot_slip_neg = 0.0_pReal + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j+1_pInt + !* Boltzmann ratio + BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& + plastic_disloUCLA_v0PerSlipSystem(j,instance) + !* Resolved shear stress on slip system + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + + significantPositiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_pos & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_pos(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_pos) + endif significantPositiveStress + significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_neg & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_neg(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_neg) + endif significantNegativeStress + gdot_slip = (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal + !* Multiplication + DotRhoMultiplication = abs(gdot_slip)/& + (plastic_disloUCLA_burgersPerSlipSystem(j,instance)* & + state(instance)%mfp_slip(j,of)) + + !* Dipole formation + EdgeDipMinDistance = & + plastic_disloUCLA_CEdgeDipMinDistance(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance) + if (abs(tau_slip_pos) <= tiny(0.0_pReal)) then + DotRhoDipFormation = 0.0_pReal + else + EdgeDipDistance = & + (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(tau_slip_pos)) + if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) + if (EdgeDipDistance tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then + Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) + abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) + else + Ndot0=0.0_pReal + end if + case default + Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) + end select + + dotState(instance)%twinFraction(j, of) = & + (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*& + state(instance)%twinVolume(j, of)*Ndot0*exp(-StressRatio_r) + !* Dotstate for accumulated shear due to twin + dotState(instance)%accshear_twin(j,of) = dotState(ph)%twinFraction(j,of) * & + lattice_sheartwin(index_myfamily+i,ph) + endif + enddo twinSystems + enddo twinFamilies + +end subroutine plastic_disloUCLA_dotState + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_disloUCLA_postResults(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance,& + !plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid, & + lattice_shearTwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(plastic_disloUCLA_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_disloUCLA_postResults + + integer(pInt) :: & + instance,& + ns,nt,& + f,o,i,c,j,k,index_myFamily,& + s1,s2, & + ph, & + of + real(pReal) :: sumf,tau_twin,StressRatio_p,StressRatio_pminus1,& + BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0,stressRatio + real(pReal) :: dvel_slip, vel_slip + real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip_pos,dgdot_dtauslip_pos,tau_slip_pos,gdot_slip_neg,dgdot_dtauslip_neg,tau_slip_neg + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(ph)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Required output + c = 0_pInt + plastic_disloUCLA_postResults = 0.0_pReal + + do o = 1_pInt,plastic_disloUCLA_Noutput(instance) + select case(plastic_disloUCLA_outputID(o,instance)) + + case (edge_density_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) + c = c + ns + case (dipole_density_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) + c = c + ns + case (shear_rate_slip_ID,shear_rate_twin_ID,stress_exponent_ID) + gdot_slip_pos = 0.0_pReal + gdot_slip_neg = 0.0_pReal + dgdot_dtauslip_pos = 0.0_pReal + dgdot_dtauslip_neg = 0.0_pReal + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j + 1_pInt + !* Boltzmann ratio + BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& + plastic_disloUCLA_v0PerSlipSystem(j,instance) + !* Resolved shear stress on slip system + tau_slip_pos(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + tau_slip_neg(j) = tau_slip_pos(j) + + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + + significantPositiveTau: if((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then + !* Stress ratio + stressRatio = ((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_pos(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_pos(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_pos(j)) + !* Derivatives of shear rates + + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_pos(j) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_pos(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + + dgdot_dtauslip_pos(j) = DotGamma0 * dvel_slip + + endif significantPositiveTau + significantNegativeTau: if((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_neg(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_neg(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_neg(j)) + !* Derivatives of shear rates + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_neg(j) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_neg(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + + + dgdot_dtauslip_neg(j) = DotGamma0 * dvel_slip + + endif significantNegativeTau + enddo slipSystems + enddo slipFamilies + + if (plastic_disloUCLA_outputID(o,instance) == shear_rate_slip_ID) then + plastic_disloUCLA_postResults(c+1:c+ns) = (gdot_slip_pos + gdot_slip_neg)*0.5_pReal + c = c + ns + elseif (plastic_disloUCLA_outputID(o,instance) == shear_rate_twin_ID) then + if (nt > 0_pInt) then + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1,plastic_disloUCLA_Ntwin(f,instance) + j = j + 1_pInt + + !* Resolved shear stress on twin system + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + !* Stress ratios + StressRatio_r = (state(instance)%threshold_stress_twin(j, of)/ & + tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) + + !* Shear rates due to twin + if ( tau_twin > 0.0_pReal ) then + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then + Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) + abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_disloUCLA_L0(instance)*& + plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) + else + Ndot0=0.0_pReal + end if + + case default + Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) + end select + plastic_disloUCLA_postResults(c+j) = & + (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) + endif + enddo twinSystems1 + enddo twinFamilies1 + endif + c = c + nt + elseif(plastic_disloUCLA_outputID(o,instance) == stress_exponent_ID) then + do j = 1_pInt, ns + if (abs(gdot_slip_pos(j)+gdot_slip_neg(j))<=tiny(0.0_pReal)) then + plastic_disloUCLA_postResults(c+j) = 0.0_pReal + else + plastic_disloUCLA_postResults(c+j) = (tau_slip_pos(j)+tau_slip_neg(j))/& + (gdot_slip_pos(j)+gdot_slip_neg(j))*& + (dgdot_dtauslip_pos(j)+dgdot_dtauslip_neg(j))* 0.5_pReal + endif + enddo + c = c + ns + endif + + case (accumulated_shear_slip_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & + state(instance)%accshear_slip(1_pInt:ns, of) + c = c + ns + case (mfp_slip_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) =& + state(instance)%mfp_slip(1_pInt:ns, of) + c = c + ns + case (resolved_stress_slip_ID) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j + 1_pInt + plastic_disloUCLA_postResults(c+j) =& + dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + enddo slipSystems1; enddo slipFamilies1 + c = c + ns + case (threshold_stress_slip_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & + state(instance)%threshold_stress_slip(1_pInt:ns,of) + c = c + ns + case (edge_dipole_distance_ID) + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems2: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j + 1_pInt + plastic_disloUCLA_postResults(c+j) = & + (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) + plastic_disloUCLA_postResults(c+j)=min(plastic_disloUCLA_postResults(c+j),& + state(instance)%mfp_slip(j,of)) + enddo slipSystems2; enddo slipFamilies2 + c = c + ns + case (twin_fraction_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt, of) + c = c + nt + + case (accumulated_shear_twin_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt, of) + c = c + nt + + case (mfp_twin_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt, of) + c = c + nt + + case (resolved_stress_twin_ID) + if (nt > 0_pInt) then + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) + j = j + 1_pInt + plastic_disloUCLA_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + enddo twinSystems2; enddo twinFamilies2 + endif + c = c + nt + case (threshold_stress_twin_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt, of) + c = c + nt + end select + enddo +end function plastic_disloUCLA_postResults + +end module plastic_disloUCLA diff --git a/code/plastic_dislotwin.f90 b/code/plastic_dislotwin.f90 new file mode 100644 index 000000000..532312bfd --- /dev/null +++ b/code/plastic_dislotwin.f90 @@ -0,0 +1,2542 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incoprorating dislocation and twinning physics +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module plastic_dislotwin + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_dislotwin_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_dislotwin_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_dislotwin_output !< name of each post result output + + real(pReal), parameter, private :: & + kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_dislotwin_Noutput !< number of outputs per instance of this plasticity + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_dislotwin_totalNslip, & !< total number of active slip systems for each instance + plastic_dislotwin_totalNtwin, & !< total number of active twin systems for each instance + plastic_dislotwin_totalNtrans !< number of active transformation systems + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_dislotwin_Nslip, & !< number of active slip systems for each family and instance + plastic_dislotwin_Ntwin, & !< number of active twin systems for each family and instance + plastic_dislotwin_Ntrans !< number of active transformation systems for each family and instance + + real(pReal), dimension(:), allocatable, private :: & + plastic_dislotwin_CAtomicVolume, & !< atomic volume in Bugers vector unit + plastic_dislotwin_D0, & !< prefactor for self-diffusion coefficient + plastic_dislotwin_Qsd, & !< activation energy for dislocation climb + plastic_dislotwin_GrainSize, & !< grain size + plastic_dislotwin_pShearBand, & !< p-exponent in shearband velocity + plastic_dislotwin_qShearBand, & !< q-exponent in shearband velocity + plastic_dislotwin_MaxTwinFraction, & !< maximum allowed total twin volume fraction + plastic_dislotwin_CEdgeDipMinDistance, & !< + plastic_dislotwin_Cmfptwin, & !< + plastic_dislotwin_Cthresholdtwin, & !< + plastic_dislotwin_SolidSolutionStrength, & !< Strength due to elements in solid solution + plastic_dislotwin_L0_twin, & !< Length of twin nuclei in Burgers vectors + plastic_dislotwin_L0_trans, & !< Length of trans nuclei in Burgers vectors + plastic_dislotwin_xc_twin, & !< critical distance for formation of twin nucleus + plastic_dislotwin_xc_trans, & !< critical distance for formation of trans nucleus + plastic_dislotwin_VcrossSlip, & !< cross slip volume + plastic_dislotwin_sbResistance, & !< value for shearband resistance (might become an internal state variable at some point) + plastic_dislotwin_sbVelocity, & !< value for shearband velocity_0 + plastic_dislotwin_sbQedge, & !< value for shearband systems Qedge + plastic_dislotwin_SFE_0K, & !< stacking fault energy at zero K + plastic_dislotwin_dSFE_dT, & !< temperature dependance of stacking fault energy + plastic_dislotwin_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful + plastic_dislotwin_aTolRho, & !< absolute tolerance for integration of dislocation density + plastic_dislotwin_aTolTwinFrac, & !< absolute tolerance for integration of twin volume fraction + plastic_dislotwin_aTolTransFrac, & !< absolute tolerance for integration of trans volume fraction + plastic_dislotwin_deltaG, & !< Free energy difference between austensite and martensite + plastic_dislotwin_Cmfptrans, & !< + plastic_dislotwin_Cthresholdtrans, & !< + plastic_dislotwin_transStackHeight !< Stack height of hex nucleus + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctwin3333 !< twin elasticity matrix for each instance + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctrans66 !< trans elasticity matrix in Mandel notation for each instance + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctrans3333 !< trans elasticity matrix for each instance + real(pReal), dimension(:,:), allocatable, private :: & + plastic_dislotwin_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance + plastic_dislotwin_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance + plastic_dislotwin_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance + plastic_dislotwin_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance + plastic_dislotwin_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance + plastic_dislotwin_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance + plastic_dislotwin_burgersPerTransFamily, & !< absolute length of burgers vector [m] for each trans family and instance + plastic_dislotwin_burgersPerTransSystem, & !< absolute length of burgers vector [m] for each trans system and instance + plastic_dislotwin_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance + plastic_dislotwin_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance + plastic_dislotwin_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance + plastic_dislotwin_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance + plastic_dislotwin_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance + plastic_dislotwin_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance + plastic_dislotwin_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance + plastic_dislotwin_Ndot0PerTransFamily, & !< trans nucleation rate [1/m³s] for each trans family and instance + plastic_dislotwin_Ndot0PerTransSystem, & !< trans nucleation rate [1/m³s] for each trans system and instance + plastic_dislotwin_tau_r_twin, & !< stress to bring partial close together for each twin system and instance + plastic_dislotwin_tau_r_trans, & !< stress to bring partial close together for each trans system and instance + plastic_dislotwin_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance + plastic_dislotwin_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance + plastic_dislotwin_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_dislotwin_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_dislotwin_lamellarsizePerTransFamily, & !< martensite lamellar thickness [m] for each trans family and instance + plastic_dislotwin_lamellarsizePerTransSystem, & !< martensite lamellar thickness [m] for each trans system and instance + plastic_dislotwin_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance + plastic_dislotwin_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance + plastic_dislotwin_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_dislotwin_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance + plastic_dislotwin_interaction_SlipTrans, & !< coefficients for slip-trans interaction for each interaction type and instance + plastic_dislotwin_interaction_TransSlip, & !< coefficients for trans-slip interaction for each interaction type and instance + plastic_dislotwin_interaction_TransTrans, & !< coefficients for trans-trans interaction for each interaction type and instance + plastic_dislotwin_pPerSlipFamily, & !< p-exponent in glide velocity + plastic_dislotwin_qPerSlipFamily, & !< q-exponent in glide velocity + plastic_dislotwin_rPerTwinFamily, & !< r-exponent in twin nucleation rate + plastic_dislotwin_sPerTransFamily !< s-exponent in trans nucleation rate + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_dislotwin_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance + plastic_dislotwin_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance + plastic_dislotwin_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance + plastic_dislotwin_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance + plastic_dislotwin_interactionMatrix_SlipTrans, & !< interaction matrix of slip systems with trans systems for each instance + plastic_dislotwin_interactionMatrix_TransSlip, & !< interaction matrix of trans systems with slip systems for each instance + plastic_dislotwin_interactionMatrix_TransTrans, & !< interaction matrix of the different trans systems for each instance + plastic_dislotwin_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance + plastic_dislotwin_projectionMatrix_Trans !< matrix for projection of slip system shear on fault band (twin) systems for each instance + + real(pReal), dimension(:,:,:,:,:), allocatable, private :: & + plastic_dislotwin_sbSv + + enum, bind(c) + enumerator :: undefined_ID, & + edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID, & + twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID, & + resolved_stress_shearband_ID, & + shear_rate_shearband_ID, & + sb_eigenvalues_ID, & + sb_eigenvectors_ID, & + stress_trans_fraction_ID, & + strain_trans_fraction_ID, & + trans_fraction_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_dislotwin_outputID !< ID of each post result output + type, private :: tDislotwinState + real(pReal), pointer, dimension(:,:) :: & + rhoEdge, & + rhoEdgeDip, & + accshear_slip, & + twinFraction, & + accshear_twin, & + stressTransFraction, & + strainTransFraction , & + invLambdaSlip, & + invLambdaSlipTwin, & + invLambdaTwin, & + invLambdaSlipTrans, & + invLambdaTrans, & + mfp_slip, & + mfp_twin, & + mfp_trans, & + threshold_stress_slip, & + threshold_stress_twin, & + threshold_stress_trans, & + twinVolume, & + martensiteVolume + end type + type(tDislotwinState), allocatable, dimension(:), private :: & + state, & + state0, & + dotState + + public :: & + plastic_dislotwin_init, & + plastic_dislotwin_homogenizedC, & + plastic_dislotwin_microstructure, & + plastic_dislotwin_LpAndItsTangent, & + plastic_dislotwin_dotState, & + plastic_dislotwin_postResults + private :: & + plastic_dislotwin_stateInit, & + plastic_dislotwin_aTolState + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333, & + math_mul3x3 + use mesh, only: & + mesh_maxNips, & + mesh_NcpElems + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + homogenization_maxNgrains, & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_DISLOTWIN_label, & + PLASTICITY_DISLOTWIN_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,maxTotalNtrans,& + f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt,nr, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipTrans = 0_pInt, Nchunks_TransSlip = 0_pInt, Nchunks_TransTrans = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_TransFamilies = 0_pInt, & + offset_slip, index_myFamily, index_otherFamily, & + startIndex, endIndex + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin, tempPerTrans + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOTWIN_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOTWIN_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_dislotwin_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(plastic_dislotwin_output(maxval(phase_Noutput),maxNinstance)) + plastic_dislotwin_output = '' + allocate(plastic_dislotwin_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_dislotwin_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_totalNtrans(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_CAtomicVolume(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_D0(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Qsd(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_GrainSize(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_pShearBand(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_qShearBand(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_MaxTwinFraction(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cmfptwin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cthresholdtwin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_SolidSolutionStrength(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_L0_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_L0_trans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_xc_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_xc_trans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_VcrossSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_aTolRho(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_aTolTwinFrac(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_aTolTransFrac(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_sbResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_sbVelocity(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_sbQedge(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_SFE_0K(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_dSFE_dT(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default + allocate(plastic_dislotwin_deltaG(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cmfptrans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cthresholdtrans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_transStackHeight(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTransFamily(lattice_maxNtransFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTransFamily(lattice_maxNtransFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_SlipTrans(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TransSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TransTrans(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_sbSv(6,6,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) + allocate(plastic_dislotwin_lamellarsizePerTransFamily(lattice_maxNtransFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_sPerTransFamily(lattice_maxNtransFamily,maxNinstance),source=0.0_pReal) + + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) + Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase)> 0_pInt) + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_SlipTrans = maxval(lattice_interactionSlipTrans(:,:,phase)) + Nchunks_TransSlip = maxval(lattice_interactionTransSlip(:,:,phase)) + Nchunks_TransTrans = maxval(lattice_interactionTransTrans(:,:,phase)) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + if(allocated(tempPerTwin)) deallocate(tempPerTwin) + if(allocated(tempPerTrans)) deallocate(tempPerTrans) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + allocate(tempPerTwin(Nchunks_TwinFamilies)) + allocate(tempPerTrans(Nchunks_TransFamilies)) + endif + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('edge_density') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_density_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('dipole_density') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = dipole_density_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_slip','shearrate_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('edge_dipole_distance') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_dipole_distance_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stress_exponent') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_exponent_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('twin_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = twin_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_twin','shearrate_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_shearband') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_shearband_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_shearband','shearrate_shearband') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_shearband_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('sb_eigenvalues') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvalues_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('sb_eigenvectors') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvectors_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stress_trans_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_trans_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('strain_trans_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = strain_trans_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('trans_fraction','total_trans_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = trans_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip system families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + plastic_dislotwin_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip') + do j = 1_pInt, Nchunks_SlipFamilies + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('rhoedge0') + plastic_dislotwin_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('rhoedgedip0') + plastic_dislotwin_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('slipburgers') + plastic_dislotwin_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('qedge') + plastic_dislotwin_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('v0') + plastic_dislotwin_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('clambdaslip') + plastic_dislotwin_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau_peierls') + if (lattice_structure(phase) /= LATTICE_bcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOTWIN_label//')') + plastic_dislotwin_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('p_slip') + plastic_dislotwin_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('q_slip') + plastic_dislotwin_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on slip number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_dislotwin_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ndot0_twin','twinsize','twinburgers','r_twin') + do j = 1_pInt, Nchunks_TwinFamilies + tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('ndot0_twin') + if (lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') + plastic_dislotwin_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinsize') + plastic_dislotwin_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinburgers') + plastic_dislotwin_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('r_twin') + plastic_dislotwin_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of transformation system families + case ('ntrans') + if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & + call IO_warning(53_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + Nchunks_TransFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TransFamilies + plastic_dislotwin_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ndot0_trans','lamellarsize','transburgers','s_trans') + do j = 1_pInt, Nchunks_TransFamilies + tempPerTrans(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('ndot0_trans') + if (lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') + plastic_dislotwin_Ndot0PerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + case ('lamellarsize') + plastic_dislotwin_lamellarsizePerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + case ('transburgers') + plastic_dislotwin_burgersPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + case ('s_trans') + plastic_dislotwin_sPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip','interactionslipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_dislotwin_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin','interactionsliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_dislotwin_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip','interactiontwinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_dislotwin_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin','interactiontwintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_dislotwin_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptrans','interactionsliptrans') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTrans) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_SlipTrans + plastic_dislotwin_interaction_SlipTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_transslip','interactiontransslip') + if (chunkPos(1) < 1_pInt + Nchunks_TransSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TransSlip + plastic_dislotwin_interaction_TransSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_transtrans','interactiontranstrans') + if (chunkPos(1) < 1_pInt + Nchunks_TransTrans) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TransTrans + plastic_dislotwin_interaction_TransTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin/trans systems + case ('grainsize') + plastic_dislotwin_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('maxtwinfraction') + plastic_dislotwin_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('p_shearband') + plastic_dislotwin_pShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('q_shearband') + plastic_dislotwin_qShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('d0') + plastic_dislotwin_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('qsd') + plastic_dislotwin_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_rho') + plastic_dislotwin_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_dislotwin_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_transfrac') + plastic_dislotwin_aTolTransFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cmfptwin') + plastic_dislotwin_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cthresholdtwin') + plastic_dislotwin_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('solidsolutionstrength') + plastic_dislotwin_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('l0_twin') + plastic_dislotwin_L0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('l0_trans') + plastic_dislotwin_L0_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('xc_twin') + plastic_dislotwin_xc_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('xc_trans') + plastic_dislotwin_xc_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('vcrossslip') + plastic_dislotwin_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cedgedipmindistance') + plastic_dislotwin_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('catomicvolume') + plastic_dislotwin_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('sfe_0k') + plastic_dislotwin_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dsfe_dt') + plastic_dislotwin_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dipoleformationfactor') + plastic_dislotwin_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('shearbandresistance') + plastic_dislotwin_sbResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('shearbandvelocity') + plastic_dislotwin_sbVelocity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('qedgepersbsystem') + plastic_dislotwin_sbQedge(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('deltag') + plastic_dislotwin_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cmfptrans') + plastic_dislotwin_Cmfptrans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cthresholdtrans') + plastic_dislotwin_Cthresholdtrans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('transstackheight') + plastic_dislotwin_transStackHeight(instance) = IO_floatValue(line,chunkPos,2_pInt) + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then + instance = phase_plasticityInstance(phase) + + if (sum(plastic_dislotwin_Nslip(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOTWIN_label//')') + if (sum(plastic_dislotwin_Ntwin(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOTWIN_label//')') + if (sum(plastic_dislotwin_Ntrans(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Ntrans ('//PLASTICITY_DISLOTWIN_label//')') + do f = 1_pInt,lattice_maxNslipFamily + if (plastic_dislotwin_Nslip(f,instance) > 0_pInt) then + if (plastic_dislotwin_rhoEdge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_rhoEdgeDip0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_v0PerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOTWIN_label//')') + endif + enddo + do f = 1_pInt,lattice_maxNtwinFamily + if (plastic_dislotwin_Ntwin(f,instance) > 0_pInt) then + if (plastic_dislotwin_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='ndot0_twin ('//PLASTICITY_DISLOTWIN_label//')') + endif + enddo + if (plastic_dislotwin_CAtomicVolume(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_D0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_Qsd(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOTWIN_label//')') + if (sum(plastic_dislotwin_Ntwin(:,instance)) > 0_pInt) then + if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & + abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & + lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_aTolTwinFrac(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOTWIN_label//')') + endif + if (sum(plastic_dislotwin_Ntrans(:,instance)) > 0_pInt) then + if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & + abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & + lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_aTolTransFrac(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolTransFrac ('//PLASTICITY_DISLOTWIN_label//')') + endif + if (plastic_dislotwin_sbResistance(instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sbResistance ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_sbVelocity(instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sbVelocity ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & + plastic_dislotwin_pShearBand(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='pShearBand ('//PLASTICITY_DISLOTWIN_label//')') + if (abs(plastic_dislotwin_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & + plastic_dislotwin_dipoleFormationFactor(instance) /= 1.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & + plastic_dislotwin_qShearBand(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='qShearBand ('//PLASTICITY_DISLOTWIN_label//')') + +!-------------------------------------------------------------------------------------------------- +! Determine total number of active slip or twin systems + plastic_dislotwin_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_dislotwin_Nslip(:,instance)) + plastic_dislotwin_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_dislotwin_Ntwin(:,instance)) + plastic_dislotwin_Ntrans(:,instance)= min(lattice_NtransSystem(:,phase),plastic_dislotwin_Ntrans(:,instance)) + plastic_dislotwin_totalNslip(instance) = sum(plastic_dislotwin_Nslip(:,instance)) + plastic_dislotwin_totalNtwin(instance) = sum(plastic_dislotwin_Ntwin(:,instance)) + plastic_dislotwin_totalNtrans(instance) = sum(plastic_dislotwin_Ntrans(:,instance)) + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + maxTotalNslip = maxval(plastic_dislotwin_totalNslip) + maxTotalNtwin = maxval(plastic_dislotwin_totalNtwin) + maxTotalNtrans = maxval(plastic_dislotwin_totalNtrans) + + allocate(plastic_dislotwin_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_tau_r_twin(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_tau_r_trans(maxTotalNtrans, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_lamellarsizePerTransSystem(maxTotalNtrans, maxNinstance),source=0.0_pReal) + + allocate(plastic_dislotwin_interactionMatrix_SlipSlip(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from slip activity + maxval(plastic_dislotwin_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_SlipTwin(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from twin activity + maxval(plastic_dislotwin_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TwinSlip(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_dislotwin_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TwinTwin(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_dislotwin_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_SlipTrans(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from trans activity + maxval(plastic_dislotwin_totalNtrans),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TransSlip(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from slip activity + maxval(plastic_dislotwin_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TransTrans(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from trans activity + maxval(plastic_dislotwin_totalNtrans),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_projectionMatrix_Trans(maxTotalNtrans,maxTotalNslip,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ctrans66(6,6,maxTotalNtrans,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ctrans3333(3,3,3,3,maxTotalNtrans,maxNinstance), source=0.0_pReal) + + allocate(state(maxNinstance)) + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + myPhase2: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then + NofMyPhase=count(material_phase==phase) + instance = phase_plasticityInstance(phase) + + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_dislotwin_Noutput(instance) + select case(plastic_dislotwin_outputID(o,instance)) + case(edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID & + ) + mySize = ns + case(twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID & + ) + mySize = nt + case(resolved_stress_shearband_ID, & + shear_rate_shearband_ID & + ) + mySize = 6_pInt + case(sb_eigenvalues_ID) + mySize = 3_pInt + case(sb_eigenvectors_ID) + mySize = 9_pInt + case(stress_trans_fraction_ID, & + strain_trans_fraction_ID, & + trans_fraction_ID & + ) + mySize = nr + end select + + if (mySize > 0_pInt) then ! any meaningful output found + plastic_dislotwin_sizePostResult(o,instance) = mySize + plastic_dislotwin_sizePostResults(instance) = plastic_dislotwin_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + + sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & + + int(size(['twinFraction','accsheartwin']),pInt) * nt & + + int(size(['stressTransFraction','strainTransFraction']),pInt) * nr + sizeDeltaState = 0_pInt + sizeState = sizeDotState & + + int(size(['invLambdaSlip ','invLambdaSlipTwin ','invLambdaSlipTrans',& + 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & + + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& + 'twinVolume ']),pInt) * nt & + + int(size(['invLambdaTrans ','meanFreePathTrans','tauTransThreshold', & + 'martensiteVolume ']),pInt) * nr + + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_dislotwin_sizePostResults(instance) + plasticState(phase)%nSlip = plastic_dislotwin_totalNslip(instance) + plasticState(phase)%nTwin = plastic_dislotwin_totalNtwin(instance) + plasticState(phase)%nTrans= plastic_dislotwin_totalNtrans(instance) + allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + offset_slip = 2_pInt*plasticState(phase)%nslip + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) + + !* Process slip related parameters ------------------------------------------------ + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + slipSystemsLoop: do j = 1_pInt,plastic_dislotwin_Nslip(f,instance) + + !* Burgers vector, + ! dislocation velocity prefactor, + ! mean free path prefactor, + ! and minimum dipole distance + + plastic_dislotwin_burgersPerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_burgersPerSlipFamily(f,instance) + + plastic_dislotwin_QedgePerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_QedgePerSlipFamily(f,instance) + + plastic_dislotwin_v0PerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_v0PerSlipFamily(f,instance) + + plastic_dislotwin_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_CLambdaSlipPerSlipFamily(f,instance) + + !* Calculation of forest projections for edge dislocations + !* Interaction matrices + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_dislotwin_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & + abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & + lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) + plastic_dislotwin_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_dislotwin_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtransFamily + index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) + plastic_dislotwin_interactionMatrix_SlipTrans(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_SlipTrans(lattice_interactionSlipTrans( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo slipSystemsLoop + enddo slipFamiliesLoop + + !* Process twin related parameters ------------------------------------------------ + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(plastic_dislotwin_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list + twinSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntwin(f,instance) + + !* Burgers vector, + ! nucleation rate prefactor, + ! and twin size + + plastic_dislotwin_burgersPerTwinSystem(index_myFamily+j,instance) = & + plastic_dislotwin_burgersPerTwinFamily(f,instance) + + plastic_dislotwin_Ndot0PerTwinSystem(index_myFamily+j,instance) = & + plastic_dislotwin_Ndot0PerTwinFamily(f,instance) + + plastic_dislotwin_twinsizePerTwinSystem(index_myFamily+j,instance) = & + plastic_dislotwin_twinsizePerTwinFamily(f,instance) + + !* Rotate twin elasticity matrices + index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list + do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt + do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt + plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & + plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & + lattice_C3333(p,q,r,s,instance) * & + lattice_Qtwin(l,p,index_otherFamily+j,phase) * & + lattice_Qtwin(m,q,index_otherFamily+j,phase) * & + lattice_Qtwin(n,r,index_otherFamily+j,phase) * & + lattice_Qtwin(o,s,index_otherFamily+j,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo; enddo + plastic_dislotwin_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & + math_Mandel3333to66(plastic_dislotwin_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) + + !* Interaction matrices + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_dislotwin_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_dislotwin_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo twinSystemsLoop + enddo twinFamiliesLoop + + !* Process transformation related parameters ------------------------------------------------ + transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily + index_myFamily = sum(plastic_dislotwin_Ntrans(1:f-1_pInt,instance)) ! index in truncated trans system list + transSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntrans(f,instance) + + !* Burgers vector, + ! nucleation rate prefactor, + ! and martensite size + + plastic_dislotwin_burgersPerTransSystem(index_myFamily+j,instance) = & + plastic_dislotwin_burgersPerTransFamily(f,instance) + + plastic_dislotwin_Ndot0PerTransSystem(index_myFamily+j,instance) = & + plastic_dislotwin_Ndot0PerTransFamily(f,instance) + + plastic_dislotwin_lamellarsizePerTransSystem(index_myFamily+j,instance) = & + plastic_dislotwin_lamellarsizePerTransFamily(f,instance) + + !* Rotate trans elasticity matrices + index_otherFamily = sum(lattice_NtransSystem(1:f-1_pInt,phase)) ! index in full lattice trans list + do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt + do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt + plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) = & + plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) + & + lattice_trans_C3333(p,q,r,s,instance) * & + lattice_Qtrans(l,p,index_otherFamily+j,phase) * & + lattice_Qtrans(m,q,index_otherFamily+j,phase) * & + lattice_Qtrans(n,r,index_otherFamily+j,phase) * & + lattice_Qtrans(o,s,index_otherFamily+j,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo; enddo + plastic_dislotwin_Ctrans66(1:6,1:6,index_myFamily+j,instance) = & + math_Mandel3333to66(plastic_dislotwin_Ctrans3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) + + !* Interaction matrices + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_dislotwin_interactionMatrix_TransSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TransSlip(lattice_interactionTransSlip( & + sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtransFamily + index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) + plastic_dislotwin_interactionMatrix_TransTrans(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TransTrans(lattice_interactionTransTrans( & + sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + !* Projection matrices for shear from slip systems to fault-band (twin) systems for strain-induced martensite nucleation + select case(trans_lattice_structure(phase)) + case (LATTICE_bcc_ID) + do o = 1_pInt,lattice_maxNtransFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (trans) + plastic_dislotwin_projectionMatrix_Trans(index_myFamily+j,index_otherFamily+k,instance) = & + lattice_projectionTrans( sum(lattice_NtransSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, phase) + enddo; enddo + end select + + enddo transSystemsLoop + enddo transFamiliesLoop + + startIndex=1_pInt + endIndex=ns + state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%stressTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%stressTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%stressTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%strainTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%strainTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%strainTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlipTrans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlipTrans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%invLambdaTrans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaTrans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%mfp_trans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_trans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%threshold_stress_trans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_trans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%martensiteVolume=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%martensiteVolume=>plasticState(phase)%state0(startIndex:endIndex,:) + + call plastic_dislotwin_stateInit(phase,instance) + call plastic_dislotwin_aTolState(phase,instance) + endif myPhase2 + + enddo initializeInstances +end subroutine plastic_dislotwin_init + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_stateInit(ph,instance) + use math, only: & + pi + use lattice, only: & + lattice_maxNslipFamily, & + lattice_mu + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + real(pReal), dimension(plasticState(ph)%sizeState) :: tempState + + integer(pInt) :: i,j,f,ns,nt,nr, index_myFamily + real(pReal), dimension(plastic_dislotwin_totalNslip(instance)) :: & + rhoEdge0, & + rhoEdgeDip0, & + invLambdaSlip0, & + MeanFreePathSlip0, & + tauSlipThreshold0 + real(pReal), dimension(plastic_dislotwin_totalNtwin(instance)) :: & + MeanFreePathTwin0,TwinVolume0 + real(pReal), dimension(plastic_dislotwin_totalNtrans(instance)) :: & + MeanFreePathTrans0,MartensiteVolume0 + tempState = 0.0_pReal + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables + do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + rhoEdge0(index_myFamily+1_pInt: & + index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & + plastic_dislotwin_rhoEdge0(f,instance) + rhoEdgeDip0(index_myFamily+1_pInt: & + index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & + plastic_dislotwin_rhoEdgeDip0(f,instance) + enddo + + tempState(1_pInt:ns) = rhoEdge0 + tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent slip microstructural variables + forall (i = 1_pInt:ns) & + invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_forestProjectionEdge(1:ns,i,instance)))/ & + plastic_dislotwin_CLambdaSlipPerSlipSystem(i,instance) + tempState(3_pInt*ns+2_pInt*nt+2_pInt*nr+1:4_pInt*ns+2_pInt*nt+2_pInt*nr) = invLambdaSlip0 + + forall (i = 1_pInt:ns) & + MeanFreePathSlip0(i) = & + plastic_dislotwin_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_dislotwin_GrainSize(instance)) + tempState(6_pInt*ns+3_pInt*nt+3_pInt*nr+1:7_pInt*ns+3_pInt*nt+3_pInt*nr) = MeanFreePathSlip0 + + forall (i = 1_pInt:ns) & + tauSlipThreshold0(i) = & + lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(i,instance) * & + sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_interactionMatrix_SlipSlip(i,1:ns,instance))) + + tempState(7_pInt*ns+4_pInt*nt+4_pInt*nr+1:8_pInt*ns+4_pInt*nt+4_pInt*nr) = tauSlipThreshold0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent twin microstructural variables + forall (j = 1_pInt:nt) & + MeanFreePathTwin0(j) = plastic_dislotwin_GrainSize(instance) + tempState(7_pInt*ns+3_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+3_pInt*nr) = MeanFreePathTwin0 + + forall (j = 1_pInt:nt) & + TwinVolume0(j) = & + (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) + tempState(8_pInt*ns+5_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+5_pInt*nr) = TwinVolume0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent trans microstructural variables + forall (j = 1_pInt:nr) & + MeanFreePathTrans0(j) = plastic_dislotwin_GrainSize(instance) + tempState(7_pInt*ns+4_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+4_pInt*nr) = MeanFreePathTrans0 + + forall (j = 1_pInt:nr) & + MartensiteVolume0(j) = & + (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(j,instance)*MeanFreePathTrans0(j)**(2.0_pReal) + tempState(8_pInt*ns+6_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+6_pInt*nr) = MartensiteVolume0 + +plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) + +end subroutine plastic_dislotwin_stateInit + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + ph, & + instance ! number specifying the current instance of the plasticity + + integer(pInt) :: ns, nt, nr + + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + ! Tolerance state for dislocation densities + plasticState(ph)%aTolState(1_pInt: & + 2_pInt*ns) = plastic_dislotwin_aTolRho(instance) + + ! Tolerance state for accumulated shear due to slip + plasticState(ph)%aTolState(2_pInt*ns+1_pInt: & + 3_pInt*ns)=1.0e6_pReal + + ! Tolerance state for twin volume fraction + plasticState(ph)%aTolState(3_pInt*ns+1_pInt: & + 3_pInt*ns+nt) = plastic_dislotwin_aTolTwinFrac(instance) + + ! Tolerance state for accumulated shear due to twin + plasticState(ph)%aTolState(3_pInt*ns+nt+1_pInt: & + 3_pInt*ns+2_pInt*nt) = 1.0e6_pReal + +! Tolerance state for stress-assisted martensite volume fraction + plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+1_pInt: & + 3_pInt*ns+2_pInt*nt+nr) = plastic_dislotwin_aTolTransFrac(instance) + +! Tolerance state for strain-induced martensite volume fraction + plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+nr+1_pInt: & + 3_pInt*ns+2_pInt*nt+2_pInt*nr) = plastic_dislotwin_aTolTransFrac(instance) + +end subroutine plastic_dislotwin_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenized elasticity matrix +!-------------------------------------------------------------------------------------------------- +function plastic_dislotwin_homogenizedC(ipc,ip,el) + use material, only: & + phase_plasticityInstance, & + phaseAt, phasememberAt + use lattice, only: & + lattice_C66 + + implicit none + real(pReal), dimension(6,6) :: & + plastic_dislotwin_homogenizedC + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,nr,i, & + ph, & + of + real(pReal) :: sumf, sumftr + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + + !* Homogenized elasticity matrix + plastic_dislotwin_homogenizedC = (1.0_pReal-sumf-sumftr)*lattice_C66(1:6,1:6,ph) + do i=1_pInt,nt + plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & + + state(instance)%twinFraction(i,of)*plastic_dislotwin_Ctwin66(1:6,1:6,i,instance) + enddo + do i=1_pInt,nr + plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & + + (state(instance)%stressTransFraction(i,of) + state(instance)%strainTransFraction(i,of))*& + plastic_dislotwin_Ctrans66(1:6,1:6,i,instance) + enddo + + end function plastic_dislotwin_homogenizedC + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_microstructure(temperature,ipc,ip,el) + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + !plasticState, & !!!!delete + phaseAt, phasememberAt + use lattice, only: & + lattice_mu, & + lattice_nu + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + temperature !< temperature at IP + + integer(pInt) :: & + instance, & + ns,nt,nr,s,t,r, & + ph, & + of + real(pReal) :: & + sumf,sfe,x0,sumftr + real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize + real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + ftransOverLamellarSize + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + + !* Stacking fault energy + sfe = plastic_dislotwin_SFE_0K(instance) + & + plastic_dislotwin_dSFE_dT(instance) * Temperature + + !* rescaled twin volume fraction for topology + forall (t = 1_pInt:nt) & + fOverStacksize(t) = & + state(instance)%twinFraction(t,of)/plastic_dislotwin_twinsizePerTwinSystem(t,instance) + + !* rescaled trans volume fraction for topology + forall (r = 1_pInt:nr) & + ftransOverLamellarSize(r) = & + (state(instance)%stressTransFraction(r,of)+state(instance)%strainTransFraction(r,of))/& + plastic_dislotwin_lamellarsizePerTransSystem(r,instance) + + !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation + forall (s = 1_pInt:ns) & + state(instance)%invLambdaSlip(s,of) = & + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_dislotwin_forestProjectionEdge(1:ns,s,instance)))/ & + plastic_dislotwin_CLambdaSlipPerSlipSystem(s,instance) + + !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation + !$OMP CRITICAL (evilmatmul) + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal + if (nt > 0_pInt .and. ns > 0_pInt) & + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & + matmul(plastic_dislotwin_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin + !$OMP CRITICAL (evilmatmul) + if (nt > 0_pInt) & + state(instance)%invLambdaTwin(1_pInt:nt,of) = & + matmul(plastic_dislotwin_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* 1/mean free distance between 2 martensite lamellar from different systems seen by a moving dislocation + state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = 0.0_pReal + if (nr > 0_pInt .and. ns > 0_pInt) & + state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = & + matmul(plastic_dislotwin_interactionMatrix_SlipTrans(1:ns,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) + + !* 1/mean free distance between 2 martensite stacks from different systems seen by a growing martensite (1/lambda_trans) + if (nr > 0_pInt) & + state(instance)%invLambdaTrans(1_pInt:nr,of) = & + matmul(plastic_dislotwin_interactionMatrix_TransTrans(1:nr,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) + + !* mean free path between 2 obstacles seen by a moving dislocation + do s = 1_pInt,ns + if ((nt > 0_pInt) .or. (nr > 0_pInt)) then + state(instance)%mfp_slip(s,of) = & + plastic_dislotwin_GrainSize(instance)/(1.0_pReal+plastic_dislotwin_GrainSize(instance)*& + (state(instance)%invLambdaSlip(s,of) + & + state(instance)%invLambdaSlipTwin(s,of) + & + state(instance)%invLambdaSlipTrans(s,of))) + else + state(instance)%mfp_slip(s,of) = & + plastic_dislotwin_GrainSize(instance)/& + (1.0_pReal+plastic_dislotwin_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) !!!!!! correct? + endif + enddo + + !* mean free path between 2 obstacles seen by a growing twin + forall (t = 1_pInt:nt) & + state(instance)%mfp_twin(t,of) = & + plastic_dislotwin_Cmfptwin(instance)*plastic_dislotwin_GrainSize(instance)/& + (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(ph)%invLambdaTwin(t,of)) + + !* mean free path between 2 obstacles seen by a growing martensite + forall (r = 1_pInt:nr) & + state(instance)%mfp_trans(r,of) = & + plastic_dislotwin_Cmfptrans(instance)*plastic_dislotwin_GrainSize(instance)/& + (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(instance)%invLambdaTrans(r,of)) + + !* threshold stress for dislocation motion + forall (s = 1_pInt:ns) & + state(instance)%threshold_stress_slip(s,of) = & + lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(s,instance)*& + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_dislotwin_interactionMatrix_SlipSlip(s,1:ns,instance))) + + !* threshold stress for growing twin + forall (t = 1_pInt:nt) & + state(instance)%threshold_stress_twin(t,of) = & + plastic_dislotwin_Cthresholdtwin(instance)* & + (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)) & + + 3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& + (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(t,instance)) & + ) + + !* threshold stress for growing martensite + forall (r = 1_pInt:nr) & + state(instance)%threshold_stress_trans(r,of) = & + plastic_dislotwin_Cthresholdtrans(instance)* & + (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & + + 3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)*lattice_mu(ph)/& + (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(r,instance))& + + plastic_dislotwin_transStackHeight(instance)*plastic_dislotwin_deltaG(instance)/ & + (3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & + ) + + !* final twin volume after growth + forall (t = 1_pInt:nt) & + state(instance)%twinVolume(t,of) = & + (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(t,instance)*& + state(instance)%mfp_twin(t,of)**(2.0_pReal) + + !* final martensite volume after growth + forall (r = 1_pInt:nr) & + state(instance)%martensiteVolume(r,of) = & + (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(r,instance)*& + state(instance)%mfp_trans(r,of)**(2.0_pReal) + + !* equilibrium separation of partial dislocations (twin) + do t = 1_pInt,nt + x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& + (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) + plastic_dislotwin_tau_r_twin(t,instance)= & + lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& + (1/(x0+plastic_dislotwin_xc_twin(instance))+cos(pi/3.0_pReal)/x0) + enddo + + !* equilibrium separation of partial dislocations (trans) + do r = 1_pInt,nr + x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)**(2.0_pReal)/& + (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) + plastic_dislotwin_tau_r_trans(r,instance)= & + lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)/(2.0_pReal*pi)*& + (1/(x0+plastic_dislotwin_xc_trans(instance))+cos(pi/3.0_pReal)/x0) + enddo + +end subroutine plastic_dislotwin_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + math_Plain3333to99, & + math_Mandel6to33, & + math_Mandel33to6, & + math_spectralDecompositionSym, & + math_tensorproduct33, & + math_symmetric33, & + math_mul33x3 + use material, only: & + material_phase, & + phase_plasticityInstance, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_Strans, & + lattice_Strans_v, & + lattice_maxNslipFamily,& + lattice_maxNtwinFamily, & + lattice_maxNtransFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NtransSystem, & + lattice_shearTwin, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + integer(pInt), intent(in) :: ipc,ip,el + real(pReal), intent(in) :: Temperature + real(pReal), dimension(6), intent(in) :: Tstar_v + real(pReal), dimension(3,3), intent(out) :: Lp + real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 + + integer(pInt) :: instance,ph,of,ns,nt,nr,f,i,j,k,l,m,n,index_myFamily,s1,s2 + real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0_twin,stressRatio, & + Ndot0_trans,StressRatio_s + real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 + real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,dgdot_dtauslip,tau_slip + real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,dgdot_dtautwin,tau_twin + real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_trans,dgdot_dtautrans,tau_trans + real(pReal), dimension(6) :: gdot_sb,dgdot_dtausb,tau_sb + real(pReal), dimension(3,3) :: eigVectors, sb_Smatrix + real(pReal), dimension(3) :: eigValues, sb_s, sb_m + logical :: error + real(pReal), dimension(3,6), parameter :: & + sb_sComposition = & + reshape(real([& + 1, 0, 1, & + 1, 0,-1, & + 1, 1, 0, & + 1,-1, 0, & + 0, 1, 1, & + 0, 1,-1 & + ],pReal),[ 3,6]), & + sb_mComposition = & + reshape(real([& + 1, 0,-1, & + 1, 0,+1, & + 1,-1, 0, & + 1, 1, 0, & + 0, 1,-1, & + 0, 1, 1 & + ],pReal),[ 3,6]) + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Dislocation glide part + gdot_slip = 0.0_pReal + dgdot_dtauslip = 0.0_pReal + j = 0_pInt + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystemsLoop: do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on slip system + tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + + if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) + StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0 & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_dislotwin_qPerSlipFamily(f,instance)) & + * sign(1.0_pReal,tau_slip(j)) + + !* Derivatives of shear rates + dgdot_dtauslip(j) = & + abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& + *plastic_dislotwin_qPerSlipFamily(f,instance)/& + (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) + endif + + !* Plastic velocity gradient for dislocation glide + Lp = Lp + gdot_slip(j)*lattice_Sslip(:,:,1,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& + lattice_Sslip(k,l,1,index_myFamily+i,ph)*& + lattice_Sslip(m,n,1,index_myFamily+i,ph) + enddo slipSystemsLoop + enddo slipFamiliesLoop + +!-------------------------------------------------------------------------------------------------- +! correct Lp and dLp_dTstar3333 for twinned and transformed fraction + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + Lp = Lp * (1.0_pReal - sumf - sumftr) + dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf - sumftr) + +!-------------------------------------------------------------------------------------------------- +! Shear banding (shearband) part + if(abs(plastic_dislotwin_sbVelocity(instance)) > tiny(0.0_pReal) .and. & + abs(plastic_dislotwin_sbResistance(instance)) > tiny(0.0_pReal)) then + gdot_sb = 0.0_pReal + dgdot_dtausb = 0.0_pReal + call math_spectralDecompositionSym(math_Mandel6to33(Tstar_v),eigValues,eigVectors,error) + do j = 1_pInt,6_pInt + sb_s = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_sComposition(1:3,j)) + sb_m = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_mComposition(1:3,j)) + sb_Smatrix = math_tensorproduct33(sb_s,sb_m) + plastic_dislotwin_sbSv(1:6,j,ipc,ip,el) = math_Mandel33to6(math_symmetric33(sb_Smatrix)) + + !* Calculation of Lp + !* Resolved shear stress on shear banding system + tau_sb(j) = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) + + !* Stress ratios + if (abs(tau_sb(j)) < tol_math_check) then + StressRatio_p = 0.0_pReal + StressRatio_pminus1 = 0.0_pReal + else + StressRatio_p = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& + **plastic_dislotwin_pShearBand(instance) + StressRatio_pminus1 = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& + **(plastic_dislotwin_pShearBand(instance)-1.0_pReal) + endif + + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = plastic_dislotwin_sbVelocity(instance) + + !* Shear rates due to shearband + gdot_sb(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qShearBand(instance))*sign(1.0_pReal,tau_sb(j)) + + !* Derivatives of shear rates + dgdot_dtausb(j) = & + ((abs(gdot_sb(j))*BoltzmannRatio*& + plastic_dislotwin_pShearBand(instance)*plastic_dislotwin_qShearBand(instance))/& + plastic_dislotwin_sbResistance(instance))*& + StressRatio_pminus1*(1_pInt-StressRatio_p)**(plastic_dislotwin_qShearBand(instance)-1.0_pReal) + + !* Plastic velocity gradient for shear banding + Lp = Lp + gdot_sb(j)*sb_Smatrix + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtausb(j)*& + sb_Smatrix(k,l)*& + sb_Smatrix(m,n) + enddo + end if + +!-------------------------------------------------------------------------------------------------- +! Mechanical twinning part + gdot_twin = 0.0_pReal + dgdot_dtautwin = 0.0_pReal + j = 0_pInt + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on twin system + tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_twin(j) > tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then + Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(ph)%rhoEdgeDip(s2,of))+& !!!!! correct? + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) + else + Ndot0_twin=0.0_pReal + end if + case default + Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) + end select + gdot_twin(j) = & + (1.0_pReal-sumf-sumftr)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) + dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_dislotwin_rPerTwinFamily(f,instance))/tau_twin(j))*StressRatio_r + endif + + !* Plastic velocity gradient for mechanical twinning + Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& + lattice_Stwin(k,l,index_myFamily+i,ph)*& + lattice_Stwin(m,n,index_myFamily+i,ph) + enddo twinSystemsLoop + enddo twinFamiliesLoop + + !* Phase transformation part + gdot_trans = 0.0_pReal + dgdot_dtautrans = 0.0_pReal + j = 0_pInt + transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily + index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family + transSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) + j = j+1_pInt + + !* Resolved shear stress on transformation system + tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_trans(j) > tol_math_check) then + StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) + !* Shear rates and their derivatives due to transformation + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then + Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !!!!! correct? + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) + else + Ndot0_trans=0.0_pReal + end if + case default + Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) + end select + gdot_trans(j) = & + (1.0_pReal-sumf-sumftr)*& + state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) + dgdot_dtautrans(j) = ((gdot_trans(j)*plastic_dislotwin_sPerTransFamily(f,instance))/tau_trans(j))*StressRatio_s + endif + + !* Plastic velocity gradient for phase transformation + Lp = Lp + gdot_trans(j)*lattice_Strans(:,:,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautrans(j)*& + lattice_Strans(k,l,index_myFamily+i,ph)*& + lattice_Strans(m,n,index_myFamily+i,ph) + + enddo transSystemsLoop + enddo transFamiliesLoop + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + +end subroutine plastic_dislotwin_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_dotState(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_Strans_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_maxNtransFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NtransSystem, & + lattice_sheartwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + lattice_fccTobcc_transNucleationTwinPair, & + lattice_fccTobcc_shearCritTrans, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,nr,f,i,j,index_myFamily,s1,s2, & + ph, & + of + real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,& + EdgeDipMinDistance,AtomicVolume,VacancyDiffusion,StressRatio_r,Ndot0_twin,stressRatio,& + Ndot0_trans,StressRatio_s,EdgeDipDistance, ClimbVelocity,DotRhoEdgeDipClimb,DotRhoEdgeDipAnnihilation, & + DotRhoDipFormation,DotRhoMultiplication,DotRhoEdgeEdgeAnnihilation + real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,tau_slip + + real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + tau_twin + real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + tau_trans + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + plasticState(instance)%dotState(:,of) = 0.0_pReal + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + + !* Dislocation density evolution + gdot_slip = 0.0_pReal + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + !* Resolved shear stress on slip system + tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + + if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) + StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + plasticState(ph)%state(j, of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)** & + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau_slip(j)) + endif + !* Multiplication + DotRhoMultiplication = abs(gdot_slip(j))/& + (plastic_dislotwin_burgersPerSlipSystem(j,instance)*state(instance)%mfp_slip(j,of)) + !* Dipole formation + EdgeDipMinDistance = & + plastic_dislotwin_CEdgeDipMinDistance(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance) + if (abs(tau_slip(j)) <= tiny(0.0_pReal)) then + DotRhoDipFormation = 0.0_pReal + else + EdgeDipDistance = & + (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(tau_slip(j))) + if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) + if (EdgeDipDistance tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/& + tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then + Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) + else + Ndot0_twin=0.0_pReal + end if + case default + Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) + end select + dotState(instance)%twinFraction(j,of) = & + (1.0_pReal-sumf-sumftr)*& + state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) + !* Dotstate for accumulated shear due to twin + dotState(instance)%accshear_twin(j,of) = dotState(instance)%twinFraction(j,of) * & + lattice_sheartwin(index_myfamily+i,ph) + endif + enddo + enddo + + !* Transformation volume fraction evolution + j = 0_pInt + do f = 1_pInt,lattice_maxNtransFamily ! loop over all trans families + index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) ! process each (active) trans system in family + j = j+1_pInt + + !* Resolved shear stress on transformation system + tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_trans(j) > tol_math_check) then + StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/& + tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) + !* Shear rates and their derivatives due to transformation + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then + Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) + else + Ndot0_trans=0.0_pReal + end if + case default + Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) + end select + dotState(instance)%strainTransFraction(j,of) = & + (1.0_pReal-sumf-sumftr)*& + state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) + !* Dotstate for accumulated shear due to transformation + !dotState(instance)%accshear_trans(j,of) = dotState(instance)%strainTransFraction(j,of) * & + ! lattice_sheartrans(index_myfamily+i,ph) + endif + + enddo + enddo + +end subroutine plastic_dislotwin_dotState + + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_dislotwin_postResults(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi, & + math_Mandel6to33, & + math_eigenvaluesSym33, & + math_spectralDecompositionSym33 + use material, only: & + material_phase, & + phase_plasticityInstance,& + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_shearTwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(plastic_dislotwin_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_dislotwin_postResults + integer(pInt) :: & + instance,& + ns,nt,nr,& + f,o,i,c,j,index_myFamily,& + s1,s2, & + ph, & + of + real(pReal) :: sumf,tau,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0_twin,dgdot_dtauslip, & + stressRatio + real(preal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip + real(pReal), dimension(3,3) :: eigVectors + real(pReal), dimension (3) :: eigValues + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Required output + c = 0_pInt + plastic_dislotwin_postResults = 0.0_pReal + do o = 1_pInt,plastic_dislotwin_Noutput(instance) + select case(plastic_dislotwin_outputID(o,instance)) + + case (edge_density_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) + c = c + ns + case (dipole_density_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) + c = c + ns + case (shear_rate_slip_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt ! could be taken from state by now! + + !* Resolved shear stress on slip system + tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + !* Stress ratios + if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau)-state(ph)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) + StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + plastic_dislotwin_postResults(c+j) = & + DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) + else + plastic_dislotwin_postResults(c+j) = 0.0_pReal + endif + + enddo ; enddo + c = c + ns + case (accumulated_shear_slip_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = & + state(instance)%accshear_slip(1_pInt:ns,of) + c = c + ns + case (mfp_slip_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) =& + state(instance)%mfp_slip(1_pInt:ns,of) + c = c + ns + case (resolved_stress_slip_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + plastic_dislotwin_postResults(c+j) =& + dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + enddo; enddo + c = c + ns + case (threshold_stress_slip_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = & + state(instance)%threshold_stress_slip(1_pInt:ns,of) + c = c + ns + case (edge_dipole_distance_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + plastic_dislotwin_postResults(c+j) = & + (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) + plastic_dislotwin_postResults(c+j)=min(plastic_dislotwin_postResults(c+j),& + state(instance)%mfp_slip(j,of)) + ! plastic_dislotwin_postResults(c+j)=max(plastic_dislotwin_postResults(c+j),& + ! plasticState(ph)%state(4*ns+2*nt+2*nr+j, of)) + enddo; enddo + c = c + ns + case (resolved_stress_shearband_ID) + do j = 1_pInt,6_pInt ! loop over all shearband families + plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v, & + plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) + enddo + c = c + 6_pInt + case (shear_rate_shearband_ID) + do j = 1_pInt,6_pInt ! loop over all shearbands + !* Resolved shear stress on shearband system + tau = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) + !* Stress ratios + if (abs(tau) < tol_math_check) then + StressRatio_p = 0.0_pReal + StressRatio_pminus1 = 0.0_pReal + else + StressRatio_p = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& + plastic_dislotwin_pShearBand(instance) + StressRatio_pminus1 = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& + (plastic_dislotwin_pShearBand(instance)-1.0_pReal) + endif + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = plastic_dislotwin_sbVelocity(instance) + ! Shear rate due to shear band + plastic_dislotwin_postResults(c+j) = & + DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**plastic_dislotwin_qShearBand(instance))*& + sign(1.0_pReal,tau) + enddo + c = c + 6_pInt + case (twin_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt,of) + c = c + nt + case (shear_rate_twin_ID) + if (nt > 0_pInt) then + + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + + !* Resolved shear stress on slip system + tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + !* Stress ratios + if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) + else + gdot_slip(j) = 0.0_pReal + endif + enddo;enddo + + j = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily ! loop over all twin families + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1,plastic_dislotwin_Ntwin(f,instance) ! process each (active) twin system in family + j = j + 1_pInt + + tau = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + + !* Shear rates due to twin + if ( tau > 0.0_pReal ) then + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau < plastic_dislotwin_tau_r_twin(j,instance)) then + Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_twin(instance)*& + plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_twin(j,instance)-tau))) + else + Ndot0_twin=0.0_pReal + end if + case default + Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) + end select + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau) & + **plastic_dislotwin_rPerTwinFamily(f,instance) + plastic_dislotwin_postResults(c+j) = & + (plastic_dislotwin_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) + endif + + enddo ; enddo + endif + c = c + nt + case (accumulated_shear_twin_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt,of) + c = c + nt + case (mfp_twin_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt,of) + c = c + nt + case (resolved_stress_twin_ID) + if (nt > 0_pInt) then + j = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily ! loop over all slip families + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + enddo; enddo + endif + c = c + nt + case (threshold_stress_twin_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt,of) + c = c + nt + case (stress_exponent_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + + !* Resolved shear stress on slip system + tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) + + !* Derivatives of shear rates + dgdot_dtauslip = & + abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& + *plastic_dislotwin_qPerSlipFamily(f,instance)/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) + + else + gdot_slip(j) = 0.0_pReal + dgdot_dtauslip = 0.0_pReal + endif + + !* Stress exponent + if (abs(gdot_slip(j))<=tiny(0.0_pReal)) then + plastic_dislotwin_postResults(c+j) = 0.0_pReal + else + plastic_dislotwin_postResults(c+j) = (tau/gdot_slip(j))*dgdot_dtauslip + endif + enddo ; enddo + c = c + ns + case (sb_eigenvalues_ID) + plastic_dislotwin_postResults(c+1_pInt:c+3_pInt) = math_eigenvaluesSym33(math_Mandel6to33(Tstar_v)) + c = c + 3_pInt + case (sb_eigenvectors_ID) + call math_spectralDecompositionSym33(math_Mandel6to33(Tstar_v),eigValues,eigVectors) + plastic_dislotwin_postResults(c+1_pInt:c+9_pInt) = reshape(eigVectors,[9]) + c = c + 9_pInt + case (stress_trans_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nr) = & + state(instance)%stressTransFraction(1_pInt:nr,of) + c = c + nr + case (strain_trans_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nr) = & + state(instance)%strainTransFraction(1_pInt:nr,of) + c = c + nr + case (trans_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nr) = & + state(instance)%stressTransFraction(1_pInt:nr,of) + & + state(instance)%strainTransFraction(1_pInt:nr,of) + c = c + nr + end select + enddo +end function plastic_dislotwin_postResults + +end module plastic_dislotwin \ No newline at end of file diff --git a/code/plastic_isotropic.f90 b/code/plastic_isotropic.f90 new file mode 100644 index 000000000..13481b9a7 --- /dev/null +++ b/code/plastic_isotropic.f90 @@ -0,0 +1,678 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for isotropic (ISOTROPIC) plasticity +!> @details Isotropic (ISOTROPIC) Plasticity which resembles the phenopowerlaw plasticity without +!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an +!! untextured polycrystal +!-------------------------------------------------------------------------------------------------- +module plastic_isotropic +#ifdef HDF + use hdf5, only: & + HID_T +#endif + + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_isotropic_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_isotropic_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_isotropic_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_isotropic_Noutput !< number of outputs per instance + + enum, bind(c) + enumerator :: undefined_ID, & + flowstress_ID, & + strainrate_ID + end enum + + type, private :: tParameters !< container type for internal constitutive parameters + integer(kind(undefined_ID)), allocatable, dimension(:) :: & + outputID + real(pReal) :: & + fTaylor, & + tau0, & + gdot0, & + n, & + h0, & + h0_slopeLnRate, & + tausat, & + a, & + aTolFlowstress, & + aTolShear , & + tausat_SinhFitA, & + tausat_SinhFitB, & + tausat_SinhFitC, & + tausat_SinhFitD + logical :: & + dilatation + end type + + type(tParameters), dimension(:), allocatable, private :: param !< containers of constitutive parameters (len Ninstance) + + type, private :: tIsotropicState !< internal state aliases + real(pReal), pointer, dimension(:) :: & ! scalars along NipcMyInstance + flowstress, & + accumulatedShear + end type + type, private :: tIsotropicAbsTol !< internal alias for abs tolerance in state + real(pReal), pointer :: & ! scalars along NipcMyInstance + flowstress, & + accumulatedShear + end type + type(tIsotropicState), allocatable, dimension(:), private :: & !< state aliases per instance + state, & + state0, & + dotState + type(tIsotropicAbsTol), allocatable, dimension(:), private :: & !< state aliases per instance + stateAbsTol + + public :: & + plastic_isotropic_init, & + plastic_isotropic_LpAndItsTangent, & + plastic_isotropic_LiAndItsTangent, & + plastic_isotropic_dotState, & + plastic_isotropic_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic + use numerics, only: & + analyticJaco, & + worldrank, & + numerics_integrator + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_ISOTROPIC_label, & + PLASTICITY_ISOTROPIC_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + + use lattice + + implicit none + integer(pInt), intent(in) :: fileUnit + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + o, & + phase, & + instance, & + maxNinstance, & + mySize, & + sizeDotState, & + sizeState, & + sizeDeltaState + character(len=65536) :: & + tag = '', & + outputtag = '', & + line = '', & + extmsg = '' + integer(pInt) :: NipcMyPhase + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_ISOTROPIC_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_ISOTROPIC_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_isotropic_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_isotropic_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) + allocate(plastic_isotropic_output(maxval(phase_Noutput), maxNinstance)) + plastic_isotropic_output = '' + allocate(plastic_isotropic_Noutput(maxNinstance), source=0_pInt) + + allocate(param(maxNinstance)) ! one container of parameters per instance + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + phase = phase + 1_pInt ! advance section counter + if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then + instance = phase_plasticityInstance(phase) + + endif + cycle ! skip to next line + endif + if (phase > 0_pInt) then; if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + allocate(param(instance)%outputID(phase_Noutput(phase))) ! allocate space for IDs of every requested output + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + extmsg = trim(tag)//' ('//PLASTICITY_ISOTROPIC_label//')' ! prepare error message identifier + + select case(tag) + case ('(output)') + outputtag = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + select case(outputtag) + case ('flowstress') + plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt + param(instance)%outputID (plastic_isotropic_Noutput(instance)) = flowstress_ID + plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag + case ('strainrate') + plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt + param(instance)%outputID (plastic_isotropic_Noutput(instance)) = strainrate_ID + plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag + + end select + + case ('/dilatation/') + param(instance)%dilatation = .true. + + case ('tau0') + param(instance)%tau0 = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%tau0 < 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('gdot0') + param(instance)%gdot0 = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%gdot0 <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('n') + param(instance)%n = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%n <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('h0') + param(instance)%h0 = IO_floatValue(line,chunkPos,2_pInt) + + case ('h0_slope','slopelnrate') + param(instance)%h0_slopeLnRate = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat') + param(instance)%tausat = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%tausat <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('tausat_sinhfita') + param(instance)%tausat_SinhFitA = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat_sinhfitb') + param(instance)%tausat_SinhFitB = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat_sinhfitc') + param(instance)%tausat_SinhFitC = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat_sinhfitd') + param(instance)%tausat_SinhFitD = IO_floatValue(line,chunkPos,2_pInt) + + case ('a', 'w0') + param(instance)%a = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%a <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('taylorfactor') + param(instance)%fTaylor = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%fTaylor <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('atol_flowstress') + param(instance)%aTolFlowstress = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%aTolFlowstress <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('atol_shear') + param(instance)%aTolShear = IO_floatValue(line,chunkPos,2_pInt) + + case default + + end select + endif; endif + enddo parsingFile + + allocate(state(maxNinstance)) ! internal state aliases + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + allocate(stateAbsTol(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop over every plasticity + myPhase: if (phase_plasticity(phase) == PLASTICITY_isotropic_ID) then ! isolate instances of own constitutive description + NipcMyPhase = count(material_phase == phase) ! number of own material points (including point components ipc) + instance = phase_plasticityInstance(phase) +!-------------------------------------------------------------------------------------------------- +! sanity checks + if (param(instance)%aTolShear <= 0.0_pReal) & + param(instance)%aTolShear = 1.0e-6_pReal ! default absolute tolerance 1e-6 + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) + select case(param(instance)%outputID(o)) + case(flowstress_ID,strainrate_ID) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_isotropic_sizePostResult(o,instance) = mySize + plastic_isotropic_sizePostResults(instance) = & + plastic_isotropic_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = 2_pInt ! flowstress, accumulated_shear + sizeDotState = sizeState ! both evolve + sizeDeltaState = 0_pInt ! no sudden jumps in state + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_isotropic_sizePostResults(instance) + plasticState(phase)%nSlip = 1 + plasticState(phase)%nTwin = 0 + plasticState(phase)%nTrans= 0 + allocate(plasticState(phase)%aTolState ( sizeState)) + + allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase),source=0.0_pReal) + + allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase),source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase),source=0.0_pReal) + +!-------------------------------------------------------------------------------------------------- +! globally required state aliases + plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NipcMyPhase) + plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NipcMyPhase) + +!-------------------------------------------------------------------------------------------------- +! locally defined state aliases + state(instance)%flowstress => plasticState(phase)%state (1,1:NipcMyPhase) + state0(instance)%flowstress => plasticState(phase)%state0 (1,1:NipcMyPhase) + dotState(instance)%flowstress => plasticState(phase)%dotState (1,1:NipcMyPhase) + stateAbsTol(instance)%flowstress => plasticState(phase)%aTolState(1) + + state(instance)%accumulatedShear => plasticState(phase)%state (2,1:NipcMyPhase) + state0(instance)%accumulatedShear => plasticState(phase)%state0 (2,1:NipcMyPhase) + dotState(instance)%accumulatedShear => plasticState(phase)%dotState (2,1:NipcMyPhase) + stateAbsTol(instance)%accumulatedShear => plasticState(phase)%aTolState(2) + +!-------------------------------------------------------------------------------------------------- +! init state + state0(instance)%flowstress = param(instance)%tau0 + state0(instance)%accumulatedShear = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! init absolute state tolerances + stateAbsTol(instance)%flowstress = param(instance)%aTolFlowstress + stateAbsTol(instance)%accumulatedShear = param(instance)%aTolShear + + endif myPhase + enddo initializeInstances + +end subroutine plastic_isotropic_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_g + use math, only: & + math_mul6x6, & + math_Mandel6to33, & + math_Plain3333to99, & + math_deviatoric33, & + math_mul33xx33, & + math_transpose33 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(3,3) :: & + Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal) :: & + gamma_dot, & !< strainrate + norm_Tstar_dev, & !< euclidean norm of Tstar_dev + squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev + integer(pInt) :: & + instance, of, & + k, l, m, n + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + + Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress + squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) + norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) + + if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero + Lp = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + else + gamma_dot = param(instance)%gdot0 & + * ( sqrt(1.5_pReal) * norm_Tstar_dev / param(instance)%fTaylor / state(instance)%flowstress(of) ) & + **param(instance)%n + + Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/param(instance)%fTaylor + + if (iand(debug_level(debug_constitutive), debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i8,1x,i2,1x,i3)') '<< CONST isotropic >> at el ip g ',el,ip,ipc + write(6,'(/,a,/,3(12x,3(f12.4,1x)/))') '<< CONST isotropic >> Tstar (dev) / MPa', & + math_transpose33(Tstar_dev_33(1:3,1:3))*1.0e-6_pReal + write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> norm Tstar / MPa', norm_Tstar_dev*1.0e-6_pReal + write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> gdot', gamma_dot + end if +!-------------------------------------------------------------------------------------------------- +! Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & + Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal + forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & + dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal + dLp_dTstar99 = math_Plain3333to99(gamma_dot / param(instance)%fTaylor * & + dLp_dTstar_3333 / norm_Tstar_dev) + end if +end subroutine plastic_isotropic_LpAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_LiAndItsTangent(Li,dLi_dTstar_3333,Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6, & + math_Mandel6to33, & + math_Plain3333to99, & + math_spherical33, & + math_mul33xx33 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Li !< plastic velocity gradient + + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(3,3) :: & + Tstar_sph_33 !< sphiatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor + real(pReal), dimension(3,3,3,3), intent(out) :: & + dLi_dTstar_3333 !< derivative of Li with respect to Tstar as 4th order tensor + real(pReal) :: & + gamma_dot, & !< strainrate + norm_Tstar_sph, & !< euclidean norm of Tstar_sph + squarenorm_Tstar_sph !< square of the euclidean norm of Tstar_sph + integer(pInt) :: & + instance, of, & + k, l, m, n + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + + Tstar_sph_33 = math_spherical33(math_Mandel6to33(Tstar_v)) ! spherical part of 2nd Piola-Kirchhoff stress + squarenorm_Tstar_sph = math_mul33xx33(Tstar_sph_33,Tstar_sph_33) + norm_Tstar_sph = sqrt(squarenorm_Tstar_sph) + + if (param(instance)%dilatation) then + if (norm_Tstar_sph <= 0.0_pReal) then ! Tstar == 0 --> both Li and dLi_dTstar are zero + Li = 0.0_pReal + dLi_dTstar_3333 = 0.0_pReal + else + gamma_dot = param(instance)%gdot0 & + * (sqrt(1.5_pReal) * norm_Tstar_sph / param(instance)%fTaylor / state(instance)%flowstress(of) ) & + **param(instance)%n + + Li = Tstar_sph_33/norm_Tstar_sph * gamma_dot/param(instance)%fTaylor + + !-------------------------------------------------------------------------------------------------- + ! Calculation of the tangent of Li + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLi_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & + Tstar_sph_33(k,l)*Tstar_sph_33(m,n) / squarenorm_Tstar_sph + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLi_dTstar_3333(k,l,k,l) = dLi_dTstar_3333(k,l,k,l) + 1.0_pReal + + dLi_dTstar_3333 = gamma_dot / param(instance)%fTaylor * & + dLi_dTstar_3333 / norm_Tstar_sph + endif + endif + +end subroutine plastic_isotropic_LiAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_dotState(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6) :: & + Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + gamma_dot, & !< strainrate + hardening, & !< hardening coefficient + saturation, & !< saturation flowstress + norm_Tstar_v !< euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of !< shortcut notation for offset position in state array + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + +!-------------------------------------------------------------------------------------------------- +! norm of (deviatoric) 2nd Piola-Kirchhoff stress + if (param(instance)%dilatation) then + norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) + else + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + end if +!-------------------------------------------------------------------------------------------------- +! strain rate + gamma_dot = param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & + / &!----------------------------------------------------------------------------------- + (param(instance)%fTaylor*state(instance)%flowstress(of) ))**param(instance)%n + +!-------------------------------------------------------------------------------------------------- +! hardening coefficient + if (abs(gamma_dot) > 1e-12_pReal) then + if (abs(param(instance)%tausat_SinhFitA) <= tiny(0.0_pReal)) then + saturation = param(instance)%tausat + else + saturation = ( param(instance)%tausat & + + ( log( ( gamma_dot / param(instance)%tausat_SinhFitA& + )**(1.0_pReal / param(instance)%tausat_SinhFitD)& + + sqrt( ( gamma_dot / param(instance)%tausat_SinhFitA & + )**(2.0_pReal / param(instance)%tausat_SinhFitD) & + + 1.0_pReal ) & + ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) + )**(1.0_pReal / param(instance)%tausat_SinhFitC) & + / ( param(instance)%tausat_SinhFitB & + * (gamma_dot / param(instance)%gdot0)**(1.0_pReal / param(instance)%n) & + ) & + ) + endif + hardening = ( param(instance)%h0 + param(instance)%h0_slopeLnRate * log(gamma_dot) ) & + * abs( 1.0_pReal - state(instance)%flowstress(of)/saturation )**param(instance)%a & + * sign(1.0_pReal, 1.0_pReal - state(instance)%flowstress(of)/saturation) + else + hardening = 0.0_pReal + endif + + dotState(instance)%flowstress (of) = hardening * gamma_dot + dotState(instance)%accumulatedShear(of) = gamma_dot + +end subroutine plastic_isotropic_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_isotropic_postResults(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(plastic_isotropic_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_isotropic_postResults + + real(pReal), dimension(6) :: & + Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + norm_Tstar_v ! euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of, & !< shortcut notation for offset position in state array + c, & + o + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + +!-------------------------------------------------------------------------------------------------- +! norm of (deviatoric) 2nd Piola-Kirchhoff stress + if (param(instance)%dilatation) then + norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) + else + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + end if + + c = 0_pInt + plastic_isotropic_postResults = 0.0_pReal + + outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) + select case(param(instance)%outputID(o)) + case (flowstress_ID) + plastic_isotropic_postResults(c+1_pInt) = state(instance)%flowstress(of) + c = c + 1_pInt + case (strainrate_ID) + plastic_isotropic_postResults(c+1_pInt) = & + param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & + / &!---------------------------------------------------------------------------------- + (param(instance)%fTaylor * state(instance)%flowstress(of)) ) ** param(instance)%n + c = c + 1_pInt + end select + enddo outputsLoop + +end function plastic_isotropic_postResults + + +end module plastic_isotropic diff --git a/code/plastic_j2.f90 b/code/plastic_j2.f90 new file mode 100644 index 000000000..89c022cc9 --- /dev/null +++ b/code/plastic_j2.f90 @@ -0,0 +1,579 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for isotropic (J2) plasticity +!> @details Isotropic (J2) Plasticity which resembles the phenopowerlaw plasticity without +!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an +!! untextured polycrystal +!-------------------------------------------------------------------------------------------------- +module plastic_j2 +#ifdef HDF + use hdf5, only: & + HID_T +#endif + + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_j2_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_j2_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_j2_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_j2_Noutput !< number of outputs per instance + real(pReal), dimension(:), allocatable, private :: & + plastic_j2_fTaylor, & !< Taylor factor + plastic_j2_tau0, & !< initial plastic stress + plastic_j2_gdot0, & !< reference velocity + plastic_j2_n, & !< Visco-plastic parameter +!-------------------------------------------------------------------------------------------------- +! h0 as function of h0 = A + B log (gammadot) + plastic_j2_h0, & + plastic_j2_h0_slopeLnRate, & + plastic_j2_tausat, & !< final plastic stress + plastic_j2_a, & + plastic_j2_aTolResistance, & + plastic_j2_aTolShear, & +!-------------------------------------------------------------------------------------------------- +! tausat += (asinh((gammadot / SinhFitA)**(1 / SinhFitD)))**(1 / SinhFitC) / (SinhFitB * (gammadot / gammadot0)**(1/n)) + plastic_j2_tausat_SinhFitA, & !< fitting parameter for normalized strain rate vs. stress function + plastic_j2_tausat_SinhFitB, & !< fitting parameter for normalized strain rate vs. stress function + plastic_j2_tausat_SinhFitC, & !< fitting parameter for normalized strain rate vs. stress function + plastic_j2_tausat_SinhFitD !< fitting parameter for normalized strain rate vs. stress function + + enum, bind(c) + enumerator :: undefined_ID, & + flowstress_ID, & + strainrate_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_j2_outputID !< ID of each post result output + + +#ifdef HDF + type plastic_j2_tOutput + real(pReal), dimension(:), allocatable, private :: & + flowstress, & + strainrate + logical :: flowstressActive = .false., strainrateActive = .false. ! if we can write the output block wise, this is not needed anymore because we can do an if(allocated(xxx)) + end type plastic_j2_tOutput + type(plastic_j2_tOutput), allocatable, dimension(:) :: plastic_j2_Output2 +integer(HID_T), allocatable, dimension(:) :: outID +#endif + + + public :: & + plastic_j2_init, & + plastic_j2_LpAndItsTangent, & + plastic_j2_dotState, & + plastic_j2_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_j2_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) +#ifdef HDF + use hdf5 +#endif + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic + use numerics, only: & + analyticJaco, & + worldrank, & + numerics_integrator + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_error, & + IO_timeStamp, & +#ifdef HDF + tempResults, & + HDF5_addGroup, & + HDF5_addScalarDataset,& +#endif + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_J2_label, & + PLASTICITY_J2_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + + use lattice + + implicit none + integer(pInt), intent(in) :: fileUnit + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + o, & + phase, & + maxNinstance, & + instance, & + mySize, & + sizeDotState, & + sizeState, & + sizeDeltaState + character(len=65536) :: & + tag = '', & + line = '' + integer(pInt) :: NofMyPhase + +#ifdef HDF + character(len=5) :: & + str1 + integer(HID_T) :: ID,ID2,ID4 +#endif + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_J2_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_J2_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + +#ifdef HDF + allocate(plastic_j2_Output2(maxNinstance)) + allocate(outID(maxNinstance)) +#endif + + allocate(plastic_j2_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_j2_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) + allocate(plastic_j2_output(maxval(phase_Noutput), maxNinstance)) + plastic_j2_output = '' + allocate(plastic_j2_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_j2_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_j2_fTaylor(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tau0(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_gdot0(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_n(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_h0(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_h0_slopeLnRate(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_a(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_aTolResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_aTolShear (maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitA(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitB(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitC(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitD(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + phase = phase + 1_pInt ! advance section counter + if (phase_plasticity(phase) == PLASTICITY_J2_ID) then + instance = phase_plasticityInstance(phase) +#ifdef HDF + outID(instance)=HDF5_addGroup(str1,tempResults) +#endif + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_J2_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('flowstress') + plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt + plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = flowstress_ID + plastic_j2_output(plastic_j2_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) +#ifdef HDF + call HDF5_addScalarDataset(outID(instance),myConstituents,'flowstress','MPa') + allocate(plastic_j2_Output2(instance)%flowstress(myConstituents)) + plastic_j2_Output2(instance)%flowstressActive = .true. +#endif + case ('strainrate') + plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt + plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = strainrate_ID + plastic_j2_output(plastic_j2_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) +#ifdef HDF + call HDF5_addScalarDataset(outID(instance),myConstituents,'strainrate','1/s') + allocate(plastic_j2_Output2(instance)%strainrate(myConstituents)) + plastic_j2_Output2(instance)%strainrateActive = .true. +#endif + case default + + end select + case ('tau0') + plastic_j2_tau0(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_tau0(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('gdot0') + plastic_j2_gdot0(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_gdot0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('n') + plastic_j2_n(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_n(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('h0') + plastic_j2_h0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_slope','slopelnrate') + plastic_j2_h0_slopeLnRate(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat') + plastic_j2_tausat(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_tausat(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('tausat_sinhfita') + plastic_j2_tausat_SinhFitA(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat_sinhfitb') + plastic_j2_tausat_SinhFitB(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat_sinhfitc') + plastic_j2_tausat_SinhFitC(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat_sinhfitd') + plastic_j2_tausat_SinhFitD(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('a', 'w0') + plastic_j2_a(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_a(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('taylorfactor') + plastic_j2_fTaylor(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_fTaylor(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('atol_resistance') + plastic_j2_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_aTolResistance(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('atol_shear') + plastic_j2_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case default + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_j2_ID) then + NofMyPhase=count(material_phase==phase) + instance = phase_plasticityInstance(phase) +!-------------------------------------------------------------------------------------------------- +! sanity checks + if (plastic_j2_aTolShear(instance) <= 0.0_pReal) & + plastic_j2_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) + select case(plastic_j2_outputID(o,instance)) + case(flowstress_ID,strainrate_ID) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_j2_sizePostResult(o,instance) = mySize + plastic_j2_sizePostResults(instance) = & + plastic_j2_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = 2_pInt + sizeDotState = sizeState + sizeDeltaState = 0_pInt + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_j2_sizePostResults(instance) + plasticState(phase)%nSlip = 1 + plasticState(phase)%nTwin = 0 + plasticState(phase)%nTrans= 0 + allocate(plasticState(phase)%aTolState ( sizeState)) + plasticState(phase)%aTolState(1) = plastic_j2_aTolResistance(instance) + plasticState(phase)%aTolState(2) = plastic_j2_aTolShear(instance) + allocate(plasticState(phase)%state0 ( sizeState,NofMyPhase)) + plasticState(phase)%state0(1,1:NofMyPhase) = plastic_j2_tau0(instance) + plasticState(phase)%state0(2,1:NofMyPhase) = 0.0_pReal + allocate(plasticState(phase)%partionedState0 ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase),source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase),source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NofMyPhase) + endif myPhase + enddo initializeInstances + +end subroutine plastic_j2_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_j2_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6, & + math_Mandel6to33, & + math_Plain3333to99, & + math_deviatoric33, & + math_mul33xx33 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(3,3) :: & + Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal) :: & + gamma_dot, & !< strainrate + norm_Tstar_dev, & !< euclidean norm of Tstar_dev + squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & + k, l, m, n + + instance = phase_plasticityInstance(material_phase(ipc,ip,el)) + Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress + squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) + norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) + + if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero + Lp = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + else + gamma_dot = plastic_j2_gdot0(instance) & + * (sqrt(1.5_pReal) * norm_Tstar_dev / (plastic_j2_fTaylor(instance) * & + plasticState(phaseAt(ipc,ip,el))%state(1,phasememberAt(ipc,ip,el)))) & + **plastic_j2_n(instance) + + Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/plastic_j2_fTaylor(instance) + +!-------------------------------------------------------------------------------------------------- +! Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,m,n) = (plastic_j2_n(instance)-1.0_pReal) * & + Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal + forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & + dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal + dLp_dTstar99 = math_Plain3333to99(gamma_dot / plastic_j2_fTaylor(instance) * & + dLp_dTstar_3333 / norm_Tstar_dev) + end if +end subroutine plastic_j2_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_j2_dotState(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6) :: & + Tstar_dev_v !< deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + gamma_dot, & !< strainrate + hardening, & !< hardening coefficient + saturation, & !< saturation resistance + norm_Tstar_dev !< euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of, & !< shortcut notation for offset position in state array + ph !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(material_phase(ipc,ip,el)) + +!-------------------------------------------------------------------------------------------------- +! norm of deviatoric part of 2nd Piola-Kirchhoff stress + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + +!-------------------------------------------------------------------------------------------------- +! strain rate + gamma_dot = plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & + / &!----------------------------------------------------------------------------------- + (plastic_j2_fTaylor(instance)*plasticState(ph)%state(1,of)) )**plastic_j2_n(instance) + +!-------------------------------------------------------------------------------------------------- +! hardening coefficient + if (abs(gamma_dot) > 1e-12_pReal) then + if (abs(plastic_j2_tausat_SinhFitA(instance)) <= tiny(0.0_pReal)) then + saturation = plastic_j2_tausat(instance) + else + saturation = ( plastic_j2_tausat(instance) & + + ( log( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance)& + )**(1.0_pReal / plastic_j2_tausat_SinhFitD(instance))& + + sqrt( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance) & + )**(2.0_pReal / plastic_j2_tausat_SinhFitD(instance)) & + + 1.0_pReal ) & + ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) + )**(1.0_pReal / plastic_j2_tausat_SinhFitC(instance)) & + / ( plastic_j2_tausat_SinhFitB(instance) & + * (gamma_dot / plastic_j2_gdot0(instance))**(1.0_pReal / plastic_j2_n(instance)) & + ) & + ) + endif + hardening = ( plastic_j2_h0(instance) + plastic_j2_h0_slopeLnRate(instance) * log(gamma_dot) ) & + * abs( 1.0_pReal - plasticState(ph)%state(1,of)/saturation )**plastic_j2_a(instance) & + * sign(1.0_pReal, 1.0_pReal - plasticState(ph)%state(1,of)/saturation) + else + hardening = 0.0_pReal + endif + + plasticState(ph)%dotState(1,of) = hardening * gamma_dot + plasticState(ph)%dotState(2,of) = gamma_dot + +end subroutine plastic_j2_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_j2_postResults(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(plastic_j2_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_j2_postResults + + real(pReal), dimension(6) :: & + Tstar_dev_v ! deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + norm_Tstar_dev ! euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of, & !< shortcut notation for offset position in state array + ph, & !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) + c, & + o + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(material_phase(ipc,ip,el)) + +!-------------------------------------------------------------------------------------------------- +! calculate deviatoric part of 2nd Piola-Kirchhoff stress and its norm + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + + c = 0_pInt + plastic_j2_postResults = 0.0_pReal + + outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) + select case(plastic_j2_outputID(o,instance)) + case (flowstress_ID) + plastic_j2_postResults(c+1_pInt) = plasticState(ph)%state(1,of) + c = c + 1_pInt + case (strainrate_ID) + plastic_j2_postResults(c+1_pInt) = & + plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & + / &!---------------------------------------------------------------------------------- + (plastic_j2_fTaylor(instance) * plasticState(ph)%state(1,of)) ) ** plastic_j2_n(instance) + c = c + 1_pInt + end select + enddo outputsLoop + +end function plastic_j2_postResults + + +end module plastic_j2 diff --git a/code/plastic_none.f90 b/code/plastic_none.f90 new file mode 100644 index 000000000..f624a80a2 --- /dev/null +++ b/code/plastic_none.f90 @@ -0,0 +1,109 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for purely elastic material +!-------------------------------------------------------------------------------------------------- +module plastic_none + use prec, only: & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_none_sizePostResults + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_none_sizePostResult !< size of each post result output + + public :: & + plastic_none_init + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_none_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic + use IO, only: & + IO_timeStamp + use numerics, only: & + worldrank, & + numerics_integrator + use material, only: & + phase_plasticity, & + PLASTICITY_NONE_label, & + material_phase, & + plasticState, & + PLASTICITY_none_ID + + implicit none + + integer(pInt) :: & + maxNinstance, & + phase, & + NofMyPhase, & + sizeState, & + sizeDotState, & + sizeDeltaState + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONE_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_none_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + if (phase_plasticity(phase) == PLASTICITY_none_ID) then + NofMyPhase=count(material_phase==phase) + + sizeState = 0_pInt + plasticState(phase)%sizeState = sizeState + sizeDotState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + sizeDeltaState = 0_pInt + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = 0_pInt + plasticState(phase)%nSlip = 0_pInt + plasticState(phase)%nTwin = 0_pInt + plasticState(phase)%nTrans = 0_pInt + allocate(plasticState(phase)%aTolState (sizeState)) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase)) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase)) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase)) + allocate(plasticState(phase)%state (sizeState,NofMyPhase)) + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase)) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase)) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase)) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase)) + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase)) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase)) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase)) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase)) + endif + enddo initializeInstances + + allocate(plastic_none_sizePostResults(maxNinstance), source=0_pInt) + +end subroutine plastic_none_init + +end module plastic_none diff --git a/code/plastic_nonlocal.f90 b/code/plastic_nonlocal.f90 new file mode 100644 index 000000000..1922c08e2 --- /dev/null +++ b/code/plastic_nonlocal.f90 @@ -0,0 +1,4031 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Christoph Kords, 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 +!> @brief material subroutine for plasticity including dislocation flux +!-------------------------------------------------------------------------------------------------- +module plastic_nonlocal + use prec, only: & + pReal, & + pInt + + implicit none + private + character(len=22), dimension(11), parameter, private :: & + BASICSTATES = ['rhoSglEdgePosMobile ', & + 'rhoSglEdgeNegMobile ', & + 'rhoSglScrewPosMobile ', & + 'rhoSglScrewNegMobile ', & + 'rhoSglEdgePosImmobile ', & + 'rhoSglEdgeNegImmobile ', & + 'rhoSglScrewPosImmobile', & + 'rhoSglScrewNegImmobile', & + 'rhoDipEdge ', & + 'rhoDipScrew ', & + 'accumulatedshear ' ] !< list of "basic" microstructural state variables that are independent from other state variables + + character(len=16), dimension(3), parameter, private :: & + DEPENDENTSTATES = ['rhoForest ', & + 'tauThreshold ', & + 'tauBack ' ] !< list of microstructural state variables that depend on other state variables + + character(len=20), dimension(6), parameter, private :: & + OTHERSTATES = ['velocityEdgePos ', & + 'velocityEdgeNeg ', & + 'velocityScrewPos ', & + 'velocityScrewNeg ', & + 'maxDipoleHeightEdge ', & + 'maxDipoleHeightScrew' ] !< list of other dependent state variables that are not updated by microstructure + + real(pReal), parameter, private :: & + KB = 1.38e-23_pReal !< Physical parameter, Boltzmann constant in J/Kelvin + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_nonlocal_sizeDotState, & !< number of dotStates = number of basic state variables + plastic_nonlocal_sizeDependentState, & !< number of dependent state variables + plastic_nonlocal_sizeState, & !< total number of state variables + plastic_nonlocal_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_nonlocal_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_nonlocal_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_nonlocal_Noutput !< number of outputs per instance of this plasticity + + integer(pInt), dimension(:,:), allocatable, private :: & + iGamma, & !< state indices for accumulated shear + iRhoF, & !< state indices for forest density + iTauF, & !< state indices for critical resolved shear stress + iTauB !< state indices for backstress + integer(pInt), dimension(:,:,:), allocatable, private :: & + iRhoU, & !< state indices for unblocked density + iRhoB, & !< state indices for blocked density + iRhoD, & !< state indices for dipole density + iV, & !< state indices for dislcation velocities + iD !< state indices for stable dipole height + + integer(pInt), dimension(:), allocatable, public, protected :: & + totalNslip !< total number of active slip systems for each instance + + integer(pInt), dimension(:,:), allocatable, private :: & + Nslip, & !< number of active slip systems for each family and instance + slipFamily, & !< lookup table relating active slip system to slip family for each instance + slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance + colinearSystem !< colinear system to the active slip system (only valid for fcc!) + + real(pReal), dimension(:), allocatable, private :: & + atomicVolume, & !< atomic volume + Dsd0, & !< prefactor for self-diffusion coefficient + selfDiffusionEnergy, & !< activation enthalpy for diffusion + aTolRho, & !< absolute tolerance for dislocation density in state integration + aTolShear, & !< absolute tolerance for accumulated shear in state integration + significantRho, & !< density considered significant + significantN, & !< number of dislocations considered significant + cutoffRadius, & !< cutoff radius for dislocation stress + doublekinkwidth, & !< width of a doubkle kink in multiples of the burgers vector length b + solidSolutionEnergy, & !< activation energy for solid solution in J + solidSolutionSize, & !< solid solution obstacle size in multiples of the burgers vector length + solidSolutionConcentration, & !< concentration of solid solution in atomic parts + pParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) + qParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) + viscosity, & !< viscosity for dislocation glide in Pa s + fattack, & !< attack frequency in Hz + rhoSglScatter, & !< standard deviation of scatter in initial dislocation density + surfaceTransmissivity, & !< transmissivity at free surface + grainboundaryTransmissivity, & !< transmissivity at grain boundary (identified by different texture) + CFLfactor, & !< safety factor for CFL flux condition + fEdgeMultiplication, & !< factor that determines how much edge dislocations contribute to multiplication (0...1) + rhoSglRandom, & + rhoSglRandomBinning, & + linetensionEffect, & + edgeJogFactor + + real(pReal), dimension(:,:), allocatable, private :: & + rhoSglEdgePos0, & !< initial edge_pos dislocation density per slip system for each family and instance + rhoSglEdgeNeg0, & !< initial edge_neg dislocation density per slip system for each family and instance + rhoSglScrewPos0, & !< initial screw_pos dislocation density per slip system for each family and instance + rhoSglScrewNeg0, & !< initial screw_neg dislocation density per slip system for each family and instance + rhoDipEdge0, & !< initial edge dipole dislocation density per slip system for each family and instance + rhoDipScrew0, & !< initial screw dipole dislocation density per slip system for each family and instance + lambda0PerSlipFamily, & !< mean free path prefactor for each family and instance + lambda0, & !< mean free path prefactor for each slip system and instance + burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each family and instance + burgers, & !< absolute length of burgers vector [m] for each slip system and instance + interactionSlipSlip !< coefficients for slip-slip interaction for each interaction type and instance + + real(pReal), dimension(:,:,:), allocatable, private :: & + minDipoleHeightPerSlipFamily, & !< minimum stable edge/screw dipole height for each family and instance + minDipoleHeight, & !< minimum stable edge/screw dipole height for each slip system and instance + peierlsStressPerSlipFamily, & !< Peierls stress (edge and screw) + peierlsStress, & !< Peierls stress (edge and screw) + forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance + forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance + interactionMatrixSlipSlip !< interaction matrix of the different slip systems for each instance + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + lattice2slip, & !< orthogonal transformation matrix from lattice coordinate system to slip coordinate system (passive rotation !!!) + rhoDotEdgeJogsOutput, & + sourceProbability + + real(pReal), dimension(:,:,:,:,:), allocatable, private :: & + rhoDotFluxOutput, & + rhoDotMultiplicationOutput, & + rhoDotSingle2DipoleGlideOutput, & + rhoDotAthermalAnnihilationOutput, & + rhoDotThermalAnnihilationOutput, & + nonSchmidProjection !< combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) + + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + compatibility !< slip system compatibility between me and my neighbors + + real(pReal), dimension(:,:), allocatable, private :: & + nonSchmidCoeff + + logical, dimension(:), allocatable, private :: & + shortRangeStressCorrection, & !< flag indicating the use of the short range stress correction by a excess density gradient term + probabilisticMultiplication + + enum, bind(c) + enumerator :: undefined_ID, & + rho_ID, & + delta_ID, & + rho_edge_ID, & + rho_screw_ID, & + rho_sgl_ID, & + delta_sgl_ID, & + rho_sgl_edge_ID, & + rho_sgl_edge_pos_ID, & + rho_sgl_edge_neg_ID, & + rho_sgl_screw_ID, & + rho_sgl_screw_pos_ID, & + rho_sgl_screw_neg_ID, & + rho_sgl_mobile_ID, & + rho_sgl_edge_mobile_ID, & + rho_sgl_edge_pos_mobile_ID, & + rho_sgl_edge_neg_mobile_ID, & + rho_sgl_screw_mobile_ID, & + rho_sgl_screw_pos_mobile_ID, & + rho_sgl_screw_neg_mobile_ID, & + rho_sgl_immobile_ID, & + rho_sgl_edge_immobile_ID, & + rho_sgl_edge_pos_immobile_ID, & + rho_sgl_edge_neg_immobile_ID, & + rho_sgl_screw_immobile_ID, & + rho_sgl_screw_pos_immobile_ID, & + rho_sgl_screw_neg_immobile_ID, & + rho_dip_ID, & + delta_dip_ID, & + rho_dip_edge_ID, & + rho_dip_screw_ID, & + excess_rho_ID, & + excess_rho_edge_ID, & + excess_rho_screw_ID, & + rho_forest_ID, & + shearrate_ID, & + resolvedstress_ID, & + resolvedstress_external_ID, & + resolvedstress_back_ID, & + resistance_ID, & + rho_dot_ID, & + rho_dot_sgl_ID, & + rho_dot_sgl_mobile_ID, & + rho_dot_dip_ID, & + rho_dot_gen_ID, & + rho_dot_gen_edge_ID, & + rho_dot_gen_screw_ID, & + rho_dot_sgl2dip_ID, & + rho_dot_sgl2dip_edge_ID, & + rho_dot_sgl2dip_screw_ID, & + rho_dot_ann_ath_ID, & + rho_dot_ann_the_ID, & + rho_dot_ann_the_edge_ID, & + rho_dot_ann_the_screw_ID, & + rho_dot_edgejogs_ID, & + rho_dot_flux_ID, & + rho_dot_flux_mobile_ID, & + rho_dot_flux_edge_ID, & + rho_dot_flux_screw_ID, & + velocity_edge_pos_ID, & + velocity_edge_neg_ID, & + velocity_screw_pos_ID, & + velocity_screw_neg_ID, & + slipdirectionx_ID, & + slipdirectiony_ID, & + slipdirectionz_ID, & + slipnormalx_ID, & + slipnormaly_ID, & + slipnormalz_ID, & + fluxdensity_edge_posx_ID, & + fluxdensity_edge_posy_ID, & + fluxdensity_edge_posz_ID, & + fluxdensity_edge_negx_ID, & + fluxdensity_edge_negy_ID, & + fluxdensity_edge_negz_ID, & + fluxdensity_screw_posx_ID, & + fluxdensity_screw_posy_ID, & + fluxdensity_screw_posz_ID, & + fluxdensity_screw_negx_ID, & + fluxdensity_screw_negy_ID, & + fluxdensity_screw_negz_ID, & + maximumdipoleheight_edge_ID, & + maximumdipoleheight_screw_ID, & + accumulatedshear_ID, & + dislocationstress_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_nonlocal_outputID !< ID of each post result output + + public :: & + plastic_nonlocal_init, & + plastic_nonlocal_stateInit, & + plastic_nonlocal_aTolState, & + plastic_nonlocal_microstructure, & + plastic_nonlocal_LpAndItsTangent, & + plastic_nonlocal_dotState, & + plastic_nonlocal_deltaState, & + plastic_nonlocal_updateCompatibility, & + plastic_nonlocal_postResults + + private :: & + plastic_nonlocal_kinetics, & + plastic_nonlocal_dislocationstress + + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_init(fileUnit) +use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) +use math, only: math_Mandel3333to66, & + math_Voigt66to3333, & + math_mul3x3, & + math_transpose33 +use IO, only: IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF +use debug, only: debug_level, & + debug_constitutive, & + debug_levelBasic +use mesh, only: mesh_NcpElems, & + mesh_maxNips, & + mesh_maxNipNeighbors +use material, only: phase_plasticity, & + homogenization_maxNgrains, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_NONLOCAL_label, & + PLASTICITY_NONLOCAL_ID, & + plasticState, & + MATERIAL_partPhase ,& + material_phase +use lattice +use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + +implicit none +integer(pInt), intent(in) :: fileUnit + +!*** local variables +integer(pInt), allocatable, dimension(:) :: chunkPos +integer(pInt) :: phase, & + maxNinstances, & + maxTotalNslip, & + f, & ! index of my slip family + instance, & ! index of my instance of this plasticity + l, & + ns, & ! short notation for total number of active slip systems for the current instance + o, & ! index of my output + s, & ! index of my slip system + s1, & ! index of my slip system + s2, & ! index of my slip system + it, & ! index of my interaction type + t, & ! index of dislocation type + c, & ! index of dislocation character + Nchunks_SlipSlip = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, & + Nchunks_nonSchmid = 0_pInt, & + mySize = 0_pInt ! to suppress warnings, safe as init is called only once + character(len=65536) :: & + tag = '', & + line = '' + + integer(pInt) :: sizeState, sizeDotState,sizeDependentState, sizeDeltaState + + + integer(pInt) :: NofMyPhase + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONLOCAL_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) + if (maxNinstances == 0) return ! we don't have to do anything if there's no instance for this constitutive law + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstances + +!*** memory allocation for global variables + +allocate(plastic_nonlocal_sizeDotState(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizeDependentState(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizeState(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizePostResults(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizePostResult(maxval(phase_Noutput), maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_Noutput(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_output(maxval(phase_Noutput), maxNinstances)) + plastic_nonlocal_output = '' +allocate(plastic_nonlocal_outputID(maxval(phase_Noutput), maxNinstances), source=undefined_ID) +allocate(Nslip(lattice_maxNslipFamily,maxNinstances), source=0_pInt) +allocate(slipFamily(lattice_maxNslip,maxNinstances), source=0_pInt) +allocate(slipSystemLattice(lattice_maxNslip,maxNinstances), source=0_pInt) +allocate(totalNslip(maxNinstances), source=0_pInt) +allocate(atomicVolume(maxNinstances), source=0.0_pReal) +allocate(Dsd0(maxNinstances), source=-1.0_pReal) +allocate(selfDiffusionEnergy(maxNinstances), source=0.0_pReal) +allocate(aTolRho(maxNinstances), source=0.0_pReal) +allocate(aTolShear(maxNinstances), source=0.0_pReal) +allocate(significantRho(maxNinstances), source=0.0_pReal) +allocate(significantN(maxNinstances), source=0.0_pReal) +allocate(cutoffRadius(maxNinstances), source=-1.0_pReal) +allocate(doublekinkwidth(maxNinstances), source=0.0_pReal) +allocate(solidSolutionEnergy(maxNinstances), source=0.0_pReal) +allocate(solidSolutionSize(maxNinstances), source=0.0_pReal) +allocate(solidSolutionConcentration(maxNinstances), source=0.0_pReal) +allocate(pParam(maxNinstances), source=1.0_pReal) +allocate(qParam(maxNinstances), source=1.0_pReal) +allocate(viscosity(maxNinstances), source=0.0_pReal) +allocate(fattack(maxNinstances), source=0.0_pReal) +allocate(rhoSglScatter(maxNinstances), source=0.0_pReal) +allocate(rhoSglRandom(maxNinstances), source=0.0_pReal) +allocate(rhoSglRandomBinning(maxNinstances), source=1.0_pReal) +allocate(surfaceTransmissivity(maxNinstances), source=1.0_pReal) +allocate(grainboundaryTransmissivity(maxNinstances), source=-1.0_pReal) +allocate(CFLfactor(maxNinstances), source=2.0_pReal) +allocate(fEdgeMultiplication(maxNinstances), source=0.0_pReal) +allocate(linetensionEffect(maxNinstances), source=0.0_pReal) +allocate(edgeJogFactor(maxNinstances), source=1.0_pReal) +allocate(shortRangeStressCorrection(maxNinstances), source=.false.) +allocate(probabilisticMultiplication(maxNinstances), source=.false.) + +allocate(rhoSglEdgePos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoSglEdgeNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoSglScrewPos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoSglScrewNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoDipEdge0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoDipScrew0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) +allocate(lambda0PerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) +allocate(interactionSlipSlip(lattice_maxNinteraction,maxNinstances), source=0.0_pReal) +allocate(minDipoleHeightPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=-1.0_pReal) +allocate(peierlsStressPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=0.0_pReal) +allocate(nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstances), source=0.0_pReal) + + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through phases of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_SlipSlip = maxval(lattice_InteractionSlipSlip(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + endif + cycle + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then ! one of my phases. do not short-circuit here (.and. with next if statement). It's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('rho') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('delta') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('delta_sgl') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_sgl_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_pos_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_neg_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_pos_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_neg_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_pos_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_neg_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_pos_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_neg_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('delta_dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dip_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dip_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('excess_rho') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('excess_rho_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('excess_rho_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_forest') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_forest_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = shearrate_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_external') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_external_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_back') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_back_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resistance_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_gen') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_gen_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_gen_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl2dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl2dip_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl2dip_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_ath') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_ath_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_the') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_the_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_the_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_edgejogs') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_edgejogs_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_edge_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_edge_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_screw_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_screw_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipdirection.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipdirection.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectiony_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipdirection.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipnormal.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipnormal.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormaly_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipnormal.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_pos.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_pos.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_pos.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_neg.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_neg.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_neg.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_pos.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_pos.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_pos.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_neg.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_neg.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_neg.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('maximumdipoleheight_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('maximumdipoleheight_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear','accumulated_shear') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = accumulatedshear_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('dislocationstress') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = dislocationstress_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + case ('nslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do f = 1_pInt, Nchunks_SlipFamilies + Nslip(f,instance) = IO_intValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosgledgepos0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglEdgePos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosgledgeneg0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglEdgeNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosglscrewpos0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglScrewPos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosglscrewneg0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglScrewNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhodipedge0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoDipEdge0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhodipscrew0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoDipScrew0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('lambda0') + do f = 1_pInt, Nchunks_SlipFamilies + lambda0PerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('burgers') + do f = 1_pInt, Nchunks_SlipFamilies + burgersPerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('cutoffradius','r') + cutoffRadius(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('minimumdipoleheightedge','ddipminedge') + do f = 1_pInt, Nchunks_SlipFamilies + minDipoleHeightPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('minimumdipoleheightscrew','ddipminscrew') + do f = 1_pInt, Nchunks_SlipFamilies + minDipoleHeightPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('atomicvolume') + atomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('selfdiffusionprefactor','dsd0') + Dsd0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('selfdiffusionenergy','qsd') + selfDiffusionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('atol_rho','atol_density','absolutetolerancedensity','absolutetolerance_density') + aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('atol_shear','atol_plasticshear','atol_accumulatedshear','absolutetoleranceshear','absolutetolerance_shear') + aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('significantrho','significant_rho','significantdensity','significant_density') + significantRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('significantn','significant_n','significantdislocations','significant_dislcations') + significantN(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('interaction_slipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') + do it = 1_pInt,Nchunks_SlipSlip + interactionSlipSlip(it,instance) = IO_floatValue(line,chunkPos,1_pInt+it) + enddo + case('linetension','linetensioneffect','linetension_effect') + linetensionEffect(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('edgejog','edgejogs','edgejogeffect','edgejog_effect') + edgeJogFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('peierlsstressedge','peierlsstress_edge') + do f = 1_pInt, Nchunks_SlipFamilies + peierlsStressPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('peierlsstressscrew','peierlsstress_screw') + do f = 1_pInt, Nchunks_SlipFamilies + peierlsStressPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('doublekinkwidth') + doublekinkwidth(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('solidsolutionenergy') + solidSolutionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('solidsolutionsize') + solidSolutionSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('solidsolutionconcentration') + solidSolutionConcentration(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('p') + pParam(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('q') + qParam(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('viscosity','glideviscosity') + viscosity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('attackfrequency','fattack') + fattack(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('rhosglscatter') + rhoSglScatter(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('rhosglrandom') + rhoSglRandom(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('rhosglrandombinning') + rhoSglRandomBinning(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('surfacetransmissivity') + surfaceTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('grainboundarytransmissivity') + grainboundaryTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('cflfactor') + CFLfactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('fedgemultiplication','edgemultiplicationfactor','edgemultiplication') + fEdgeMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('shortrangestresscorrection') + shortRangeStressCorrection(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_label//')') + do f = 1_pInt,Nchunks_nonSchmid + nonSchmidCoeff(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('probabilisticmultiplication','randomsources','randommultiplication','discretesources') + probabilisticMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then + instance = phase_plasticityInstance(phase) + if (sum(Nslip(:,instance)) <= 0_pInt) & + call IO_error(211_pInt,ext_msg='Nslip ('//PLASTICITY_NONLOCAL_label//')') + do o = 1_pInt,maxval(phase_Noutput) + if(len(plastic_nonlocal_output(o,instance)) > 64_pInt) & + call IO_error(666_pInt) + enddo + do f = 1_pInt,lattice_maxNslipFamily + if (Nslip(f,instance) > 0_pInt) then + if (rhoSglEdgePos0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglEdgePos0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglEdgeNeg0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglEdgeNeg0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglScrewPos0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglScrewPos0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglScrewNeg0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglScrewNeg0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoDipEdge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoDipEdge0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoDipScrew0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoDipScrew0 ('//PLASTICITY_NONLOCAL_label//')') + if (burgersPerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='Burgers ('//PLASTICITY_NONLOCAL_label//')') + if (lambda0PerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='lambda0 ('//PLASTICITY_NONLOCAL_label//')') + if (minDipoleHeightPerSlipFamily(f,1,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='minimumDipoleHeightEdge ('//PLASTICITY_NONLOCAL_label//')') + if (minDipoleHeightPerSlipFamily(f,2,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='minimumDipoleHeightScrew ('//PLASTICITY_NONLOCAL_label//')') + if (peierlsStressPerSlipFamily(f,1,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='peierlsStressEdge ('//PLASTICITY_NONLOCAL_label//')') + if (peierlsStressPerSlipFamily(f,2,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='peierlsStressScrew ('//PLASTICITY_NONLOCAL_label//')') + endif + enddo + if (any(interactionSlipSlip(1:maxval(lattice_interactionSlipSlip(:,:,phase)),instance) < 0.0_pReal)) & + call IO_error(211_pInt,ext_msg='interaction_SlipSlip ('//PLASTICITY_NONLOCAL_label//')') + if (linetensionEffect(instance) < 0.0_pReal .or. linetensionEffect(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='linetension ('//PLASTICITY_NONLOCAL_label//')') + if (edgeJogFactor(instance) < 0.0_pReal .or. edgeJogFactor(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='edgejog ('//PLASTICITY_NONLOCAL_label//')') + if (cutoffRadius(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='r ('//PLASTICITY_NONLOCAL_label//')') + if (atomicVolume(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='atomicVolume ('//PLASTICITY_NONLOCAL_label//')') + if (Dsd0(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='selfDiffusionPrefactor ('//PLASTICITY_NONLOCAL_label//')') + if (selfDiffusionEnergy(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='selfDiffusionEnergy ('//PLASTICITY_NONLOCAL_label//')') + if (aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='aTol_rho ('//PLASTICITY_NONLOCAL_label//')') + if (aTolShear(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='aTol_shear ('//PLASTICITY_NONLOCAL_label//')') + if (significantRho(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='significantRho ('//PLASTICITY_NONLOCAL_label//')') + if (significantN(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='significantN ('//PLASTICITY_NONLOCAL_label//')') + if (doublekinkwidth(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='doublekinkwidth ('//PLASTICITY_NONLOCAL_label//')') + if (solidSolutionEnergy(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='solidSolutionEnergy ('//PLASTICITY_NONLOCAL_label//')') + if (solidSolutionSize(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='solidSolutionSize ('//PLASTICITY_NONLOCAL_label//')') + if (solidSolutionConcentration(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='solidSolutionConcentration ('//PLASTICITY_NONLOCAL_label//')') + if (pParam(instance) <= 0.0_pReal .or. pParam(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='p ('//PLASTICITY_NONLOCAL_label//')') + if (qParam(instance) < 1.0_pReal .or. qParam(instance) > 2.0_pReal) & + call IO_error(211_pInt,ext_msg='q ('//PLASTICITY_NONLOCAL_label//')') + if (viscosity(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='viscosity ('//PLASTICITY_NONLOCAL_label//')') + if (fattack(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='attackFrequency ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglScatter(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglScatter ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglRandom(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglRandom ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglRandomBinning(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglRandomBinning ('//PLASTICITY_NONLOCAL_label//')') + if (surfaceTransmissivity(instance) < 0.0_pReal .or. surfaceTransmissivity(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='surfaceTransmissivity ('//PLASTICITY_NONLOCAL_label//')') + if (grainboundaryTransmissivity(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='grainboundaryTransmissivity ('//PLASTICITY_NONLOCAL_label//')') + if (CFLfactor(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='CFLfactor ('//PLASTICITY_NONLOCAL_label//')') + if (fEdgeMultiplication(instance) < 0.0_pReal .or. fEdgeMultiplication(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='edgemultiplicationfactor ('//PLASTICITY_NONLOCAL_label//')') + + + !*** determine total number of active slip systems + Nslip(1:lattice_maxNslipFamily,instance) = min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase), & + Nslip(1:lattice_maxNslipFamily,instance) ) ! we can't use more slip systems per family than specified in lattice + totalNslip(instance) = sum(Nslip(1:lattice_maxNslipFamily,instance)) + endif myPhase +enddo sanityChecks + + +!*** allocation of variables whose size depends on the total number of active slip systems + +maxTotalNslip = maxval(totalNslip) + +allocate(iRhoU(maxTotalNslip,4,maxNinstances), source=0_pInt) +allocate(iRhoB(maxTotalNslip,4,maxNinstances), source=0_pInt) +allocate(iRhoD(maxTotalNslip,2,maxNinstances), source=0_pInt) +allocate(iV(maxTotalNslip,4,maxNinstances), source=0_pInt) +allocate(iD(maxTotalNslip,2,maxNinstances), source=0_pInt) +allocate(iGamma(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(iRhoF(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(iTauF(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(iTauB(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(burgers(maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(lambda0(maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(minDipoleHeight(maxTotalNslip,2,maxNinstances), source=-1.0_pReal) +allocate(forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(lattice2slip(1:3, 1:3, maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(sourceProbability(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=2.0_pReal) + +allocate(rhoDotFluxOutput(maxTotalNslip,8,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotMultiplicationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotSingle2DipoleGlideOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotAthermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotThermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotEdgeJogsOutput(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) + +allocate(compatibility(2,maxTotalNslip,maxTotalNslip,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(peierlsStress(maxTotalNslip,2,maxNinstances), source=0.0_pReal) +allocate(colinearSystem(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + NofMyPhase=count(material_phase==phase) + myPhase2: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID .and. NofMyPhase/=0) then + instance = phase_plasticityInstance(phase) + !*** Inverse lookup of my slip system family and the slip system in lattice + + l = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily + do s = 1_pInt,Nslip(f,instance) + l = l + 1_pInt + slipFamily(l,instance) = f + slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt, phase)) + s + enddo; enddo + + + !*** determine size of state array + + ns = totalNslip(instance) + + sizeDotState = int(size(BASICSTATES),pInt) * ns + sizeDependentState = int(size(DEPENDENTSTATES),pInt) * ns + sizeState = sizeDotState + sizeDependentState & + + int(size(OTHERSTATES),pInt) * ns + sizeDeltaState = sizeDotState + + !*** determine indices to state array + + l = 0_pInt + do t = 1_pInt,4_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iRhoU(s,t,instance) = l + enddo + enddo + do t = 1_pInt,4_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iRhoB(s,t,instance) = l + enddo + enddo + do c = 1_pInt,2_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iRhoD(s,c,instance) = l + enddo + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iGamma(s,instance) = l + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iRhoF(s,instance) = l + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iTauF(s,instance) = l + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iTauB(s,instance) = l + enddo + do t = 1_pInt,4_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iV(s,t,instance) = l + enddo + enddo + do c = 1_pInt,2_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iD(s,c,instance) = l + enddo + enddo + if (iD(ns,2,instance) /= sizeState) & ! check if last index is equal to size of state + call IO_error(0_pInt, ext_msg = 'state indices not properly set ('//PLASTICITY_NONLOCAL_label//')') + + + !*** determine size of postResults array + + outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) + select case(plastic_nonlocal_outputID(o,instance)) + case( rho_ID, & + delta_ID, & + rho_edge_ID, & + rho_screw_ID, & + rho_sgl_ID, & + delta_sgl_ID, & + rho_sgl_edge_ID, & + rho_sgl_edge_pos_ID, & + rho_sgl_edge_neg_ID, & + rho_sgl_screw_ID, & + rho_sgl_screw_pos_ID, & + rho_sgl_screw_neg_ID, & + rho_sgl_mobile_ID, & + rho_sgl_edge_mobile_ID, & + rho_sgl_edge_pos_mobile_ID, & + rho_sgl_edge_neg_mobile_ID, & + rho_sgl_screw_mobile_ID, & + rho_sgl_screw_pos_mobile_ID, & + rho_sgl_screw_neg_mobile_ID, & + rho_sgl_immobile_ID, & + rho_sgl_edge_immobile_ID, & + rho_sgl_edge_pos_immobile_ID, & + rho_sgl_edge_neg_immobile_ID, & + rho_sgl_screw_immobile_ID, & + rho_sgl_screw_pos_immobile_ID, & + rho_sgl_screw_neg_immobile_ID, & + rho_dip_ID, & + delta_dip_ID, & + rho_dip_edge_ID, & + rho_dip_screw_ID, & + excess_rho_ID, & + excess_rho_edge_ID, & + excess_rho_screw_ID, & + rho_forest_ID, & + shearrate_ID, & + resolvedstress_ID, & + resolvedstress_external_ID, & + resolvedstress_back_ID, & + resistance_ID, & + rho_dot_ID, & + rho_dot_sgl_ID, & + rho_dot_sgl_mobile_ID, & + rho_dot_dip_ID, & + rho_dot_gen_ID, & + rho_dot_gen_edge_ID, & + rho_dot_gen_screw_ID, & + rho_dot_sgl2dip_ID, & + rho_dot_sgl2dip_edge_ID, & + rho_dot_sgl2dip_screw_ID, & + rho_dot_ann_ath_ID, & + rho_dot_ann_the_ID, & + rho_dot_ann_the_edge_ID, & + rho_dot_ann_the_screw_ID, & + rho_dot_edgejogs_ID, & + rho_dot_flux_ID, & + rho_dot_flux_mobile_ID, & + rho_dot_flux_edge_ID, & + rho_dot_flux_screw_ID, & + velocity_edge_pos_ID, & + velocity_edge_neg_ID, & + velocity_screw_pos_ID, & + velocity_screw_neg_ID, & + slipdirectionx_ID, & + slipdirectiony_ID, & + slipdirectionz_ID, & + slipnormalx_ID, & + slipnormaly_ID, & + slipnormalz_ID, & + fluxdensity_edge_posx_ID, & + fluxdensity_edge_posy_ID, & + fluxdensity_edge_posz_ID, & + fluxdensity_edge_negx_ID, & + fluxdensity_edge_negy_ID, & + fluxdensity_edge_negz_ID, & + fluxdensity_screw_posx_ID, & + fluxdensity_screw_posy_ID, & + fluxdensity_screw_posz_ID, & + fluxdensity_screw_negx_ID, & + fluxdensity_screw_negy_ID, & + fluxdensity_screw_negz_ID, & + maximumdipoleheight_edge_ID, & + maximumdipoleheight_screw_ID, & + accumulatedshear_ID ) + mySize = totalNslip(instance) + case(dislocationstress_ID) + mySize = 6_pInt + case default + end select + + if (mySize > 0_pInt) then ! any meaningful output found + plastic_nonlocal_sizePostResult(o,instance) = mySize + plastic_nonlocal_sizePostResults(instance) = plastic_nonlocal_sizePostResults(instance) + mySize + endif + enddo outputsLoop + + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_nonlocal_sizePostResults(instance) + plasticState(phase)%nonlocal = .true. + plasticState(phase)%nSlip = totalNslip(instance) + plasticState(phase)%nTwin = 0_pInt + plasticState(phase)%nTrans= 0_pInt + allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) + + do s1 = 1_pInt,ns + f = slipFamily(s1,instance) + + !*** burgers vector, mean free path prefactor and minimum dipole distance for each slip system + + burgers(s1,instance) = burgersPerSlipFamily(f,instance) + lambda0(s1,instance) = lambda0PerSlipFamily(f,instance) + minDipoleHeight(s1,1:2,instance) = minDipoleHeightPerSlipFamily(f,1:2,instance) + peierlsStress(s1,1:2,instance) = peierlsStressPerSlipFamily(f,1:2,instance) + + do s2 = 1_pInt,ns + + !*** calculation of forest projections for edge and screw dislocations. s2 acts as forest for s1 + + forestProjectionEdge(s1,s2,instance) & + = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & + lattice_st(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of edge dislocations is the projection of (t = b x n) onto the slip normal of the respective slip plane + + forestProjectionScrew(s1,s2,instance) & + = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & + lattice_sd(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of screw dislocations is the projection of b onto the slip normal of the respective splip plane + + !*** calculation of interaction matrices + + interactionMatrixSlipSlip(s1,s2,instance) & + = interactionSlipSlip(lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & + slipSystemLattice(s2,instance), & + phase), instance) + + !*** colinear slip system (only makes sense for fcc like it is defined here) + + if (lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & + slipSystemLattice(s2,instance), & + phase) == 3_pInt) then + colinearSystem(s1,instance) = s2 + endif + + enddo + + !*** rotation matrix from lattice configuration to slip system + + lattice2slip(1:3,1:3,s1,instance) & + = math_transpose33( reshape([ lattice_sd(1:3, slipSystemLattice(s1,instance), phase), & + -lattice_st(1:3, slipSystemLattice(s1,instance), phase), & + lattice_sn(1:3, slipSystemLattice(s1,instance), phase)], [3,3])) + enddo + + + !*** combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) + !* four types t: + !* 1) positive screw at positive resolved stress + !* 2) positive screw at negative resolved stress + !* 3) negative screw at positive resolved stress + !* 4) negative screw at negative resolved stress + + do s = 1_pInt,ns + do l = 1_pInt,lattice_NnonSchmid(phase) + nonSchmidProjection(1:3,1:3,1,s,instance) = nonSchmidProjection(1:3,1:3,1,s,instance) & + + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l,slipSystemLattice(s,instance),phase) + nonSchmidProjection(1:3,1:3,2,s,instance) = nonSchmidProjection(1:3,1:3,2,s,instance) & + + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l+1,slipSystemLattice(s,instance),phase) + enddo + nonSchmidProjection(1:3,1:3,3,s,instance) = -nonSchmidProjection(1:3,1:3,2,s,instance) + nonSchmidProjection(1:3,1:3,4,s,instance) = -nonSchmidProjection(1:3,1:3,1,s,instance) + forall (t = 1:4) & + nonSchmidProjection(1:3,1:3,t,s,instance) = nonSchmidProjection(1:3,1:3,t,s,instance) & + + lattice_Sslip(1:3,1:3,1,slipSystemLattice(s,instance),phase) + enddo + + call plastic_nonlocal_aTolState(phase,instance) + endif myPhase2 + + enddo initializeInstances + +end subroutine plastic_nonlocal_init + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- + +subroutine plastic_nonlocal_stateInit() +use IO, only: IO_error +use lattice, only: lattice_maxNslipFamily +use math, only: math_sampleGaussVar +use mesh, only: mesh_ipVolume, & + mesh_NcpElems, & + mesh_element, & + FE_Nips, & + FE_geomtype +use material, only: material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticity ,& + PLASTICITY_NONLOCAL_ID +implicit none + +integer(pInt) :: e, & + i, & + ns, & ! short notation for total number of active slip systems + f, & ! index of lattice family + from, & + upto, & + s, & ! index of slip system + t, & + j, & + instance, & + maxNinstances +real(pReal), dimension(2) :: noise +real(pReal), dimension(4) :: rnd +real(pReal) meanDensity, & + totalVolume, & + densityBinning, & + minimumIpVolume + +maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) + +do instance = 1_pInt,maxNinstances + ns = totalNslip(instance) + + ! randomly distribute dislocation segments on random slip system and of random type in the volume + if (rhoSglRandom(instance) > 0.0_pReal) then + + ! get the total volume of the instance + + minimumIpVolume = huge(1.0_pReal) + totalVolume = 0.0_pReal + do e = 1_pInt,mesh_NcpElems + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & + .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then + totalVolume = totalVolume + mesh_ipVolume(i,e) + minimumIpVolume = min(minimumIpVolume, mesh_ipVolume(i,e)) + endif + enddo + enddo + densityBinning = rhoSglRandomBinning(instance) / minimumIpVolume ** (2.0_pReal / 3.0_pReal) + + ! subsequently fill random ips with dislocation segments until we reach the desired overall density + + meanDensity = 0.0_pReal + do while(meanDensity < rhoSglRandom(instance)) + call random_number(rnd) + e = nint(rnd(1)*real(mesh_NcpElems,pReal)+0.5_pReal,pInt) + i = nint(rnd(2)*real(FE_Nips(FE_geomtype(mesh_element(2,e))),pReal)+0.5_pReal,pInt) + if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & + .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then + s = nint(rnd(3)*real(ns,pReal)+0.5_pReal,pInt) + t = nint(rnd(4)*4.0_pReal+0.5_pReal,pInt) + meanDensity = meanDensity + densityBinning * mesh_ipVolume(i,e) / totalVolume + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) = & + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) & + + densityBinning + endif + enddo + ! homogeneous distribution of density with some noise + else + do e = 1_pInt,mesh_NcpElems + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & + .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then + do f = 1_pInt,lattice_maxNslipFamily + from = 1_pInt + sum(Nslip(1:f-1_pInt,instance)) + upto = sum(Nslip(1:f,instance)) + do s = from,upto + do j = 1_pInt,2_pInt + noise(j) = math_sampleGaussVar(0.0_pReal, rhoSglScatter(instance)) + enddo + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,1,instance),phasememberAt(1,i,e)) = & + rhoSglEdgePos0(f,instance) + noise(1) + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,2,instance),phasememberAt(1,i,e)) = & + rhoSglEdgeNeg0(f,instance) + noise(1) + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,3,instance),phasememberAt(1,i,e)) = & + rhoSglScrewPos0(f,instance) + noise(2) + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,4,instance),phasememberAt(1,i,e)) = & + rhoSglScrewNeg0(f,instance) + noise(2) + enddo + plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,1,instance),phasememberAt(1,i,e)) = & + rhoDipEdge0(f,instance) + plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,2,instance),phasememberAt(1,i,e)) = & + rhoDipScrew0(f,instance) + enddo + endif + enddo + enddo + endif +enddo + +end subroutine plastic_nonlocal_stateInit + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + integer(pInt) :: & + ns, & + t, c + + ns = totalNslip(instance) + forall (t = 1_pInt:4_pInt) + plasticState(ph)%aTolState(iRhoU(1:ns,t,instance)) = aTolRho(instance) + plasticState(ph)%aTolState(iRhoB(1:ns,t,instance)) = aTolRho(instance) + end forall + forall (c = 1_pInt:2_pInt) & + plasticState(ph)%aTolState(iRhoD(1:ns,c,instance)) = aTolRho(instance) + + plasticState(ph)%aTolState(iGamma(1:ns,instance)) = aTolShear(instance) + +end subroutine plastic_nonlocal_aTolState + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates quantities characterizing the microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_microstructure(Fe, Fp, ip, el) +use IO, only: & + IO_error +use math, only: & + pi, & + math_mul33x3, & + math_mul3x3, & + math_inv33, & + math_transpose33 +use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use mesh, only: & + mesh_element, & + mesh_ipNeighborhood, & + mesh_ipCoordinates, & + mesh_ipVolume, & + mesh_ipAreaNormal, & + mesh_ipArea, & + FE_NipNeighbors, & + mesh_maxNipNeighbors, & + FE_geomtype, & + FE_celltype +use material, only: & + material_phase, & + phase_localPlasticity, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance +use lattice, only: & + lattice_sd, & + lattice_st, & + lattice_mu, & + lattice_nu, & + lattice_structure, & + LATTICE_bcc_ID, & + LATTICE_fcc_ID + +implicit none + +integer(pInt), intent(in) :: ip, & ! current integration point + el ! current element +real(pReal), dimension(3,3), intent(in) :: & + Fe, & ! elastic deformation gradient + Fp ! elastic deformation gradient + + integer(pInt) :: & + ph, & !< phase + of, & !< offset + np, & !< neighbor phase + no !< nieghbor offset + +integer(pInt) neighbor_el, & ! element number of neighboring material point + neighbor_ip, & ! integration point of neighboring material point + instance, & ! my instance of this plasticity + neighbor_instance, & ! instance of this plasticity of neighboring material point + neighbor_phase, & + ns, & ! total number of active slip systems at my material point + neighbor_ns, & ! total number of active slip systems at neighboring material point + c, & ! index of dilsocation character (edge, screw) + s, & ! slip system index + t, & ! index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) + dir, & + n, & + nRealNeighbors ! number of really existing neighbors +integer(pInt), dimension(2) :: neighbors +real(pReal) FVsize, & + correction, & + myRhoForest +real(pReal), dimension(2) :: rhoExcessGradient, & + rhoExcessGradient_over_rho, & + rhoTotal +real(pReal), dimension(3) :: rhoExcessDifferences, & + normal_latticeConf +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoForest, & ! forest dislocation density + tauBack, & ! back stress from pileup on same slip system + tauThreshold ! threshold shear stress +real(pReal), dimension(3,3) :: invFe, & ! inverse of elastic deformation gradient + invFp, & ! inverse of plastic deformation gradient + connections, & + invConnections +real(pReal), dimension(3,mesh_maxNipNeighbors) :: & + connection_latticeConf +real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoExcess +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + rhoDip ! dipole dislocation density (edge, screw) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))), & + totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + myInteractionMatrix ! corrected slip interaction matrix +real(pReal), dimension(2,maxval(totalNslip),mesh_maxNipNeighbors) :: & + neighbor_rhoExcess, & ! excess density at neighboring material point + neighbor_rhoTotal ! total density at neighboring material point +real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + m ! direction of dislocation motion + +ph = phaseAt(1,ip,el) +of = phasememberAt(1,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + +!*** get basic states + + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & + rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities + +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal +where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoDip) < significantRho(instance)) & + rhoDip = 0.0_pReal + +!*** calculate the forest dislocation density +!*** (= projection of screw and edge dislocations) + +forall (s = 1_pInt:ns) & + rhoForest(s) = dot_product((sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1)), & + forestProjectionEdge(s,1:ns,instance)) & + + dot_product((sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2)), & + forestProjectionScrew(s,1:ns,instance)) + + +!*** calculate the threshold shear stress for dislocation slip +!*** coefficients are corrected for the line tension effect +!*** (see Kubin,Devincre,Hoc; 2008; Modeling dislocation storage rates and mean free paths in face-centered cubic crystals) + +myInteractionMatrix = 0.0_pReal +myInteractionMatrix(1:ns,1:ns) = interactionMatrixSlipSlip(1:ns,1:ns,instance) +if (lattice_structure(ph) == LATTICE_bcc_ID .or. lattice_structure(ph) == LATTICE_fcc_ID) then ! only fcc and bcc + do s = 1_pInt,ns + myRhoForest = max(rhoForest(s),significantRho(instance)) + correction = ( 1.0_pReal - linetensionEffect(instance) & + + linetensionEffect(instance) & + * log(0.35_pReal * burgers(s,instance) * sqrt(myRhoForest)) & + / log(0.35_pReal * burgers(s,instance) * 1e6_pReal)) ** 2.0_pReal + myInteractionMatrix(s,1:ns) = correction * myInteractionMatrix(s,1:ns) + enddo +endif +forall (s = 1_pInt:ns) & + tauThreshold(s) = lattice_mu(ph) * burgers(s,instance) & + * sqrt(dot_product((sum(abs(rhoSgl),2) + sum(abs(rhoDip),2)), myInteractionMatrix(s,1:ns))) + + +!*** calculate the dislocation stress of the neighboring excess dislocation densities +!*** zero for material points of local plasticity + +tauBack = 0.0_pReal + +if (.not. phase_localPlasticity(ph) .and. shortRangeStressCorrection(instance)) then + invFe = math_inv33(Fe) + invFp = math_inv33(Fp) + rhoExcess(1,1:ns) = rhoSgl(1:ns,1) - rhoSgl(1:ns,2) + rhoExcess(2,1:ns) = rhoSgl(1:ns,3) - rhoSgl(1:ns,4) + FVsize = mesh_ipVolume(ip,el) ** (1.0_pReal/3.0_pReal) + + !* loop through my neighborhood and get the connection vectors (in lattice frame) and the excess densities + + nRealNeighbors = 0_pInt + neighbor_rhoTotal = 0.0_pReal + do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) + neighbor_el = mesh_ipNeighborhood(1,n,ip,el) + neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) + np = phaseAt(1,neighbor_ip,neighbor_el) + no = phasememberAt(1,neighbor_ip,neighbor_el) + if (neighbor_el > 0 .and. neighbor_ip > 0) then + neighbor_phase = material_phase(1,neighbor_ip,neighbor_el) + neighbor_instance = phase_plasticityInstance(neighbor_phase) + neighbor_ns = totalNslip(neighbor_instance) + if (.not. phase_localPlasticity(neighbor_phase) & + .and. neighbor_instance == instance) then ! same instance should be same structure + if (neighbor_ns == ns) then + nRealNeighbors = nRealNeighbors + 1_pInt + forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + + neighbor_rhoExcess(c,s,n) = & + max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles + - max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) ! negative mobiles + neighbor_rhoTotal(c,s,n) = & + max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles + + max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) & ! negative mobiles + + abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads + + abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance), no)) & ! negative deads + + max(plasticState(np)%state(iRhoD(s,c,neighbor_instance), no), 0.0_pReal) ! dipoles + + endforall + connection_latticeConf(1:3,n) = & + math_mul33x3(invFe, mesh_ipCoordinates(1:3,neighbor_ip,neighbor_el) & + - mesh_ipCoordinates(1:3,ip,el)) + normal_latticeConf = math_mul33x3(math_transpose33(invFp), mesh_ipAreaNormal(1:3,n,ip,el)) + if (math_mul3x3(normal_latticeConf,connection_latticeConf(1:3,n)) < 0.0_pReal) then ! neighboring connection points in opposite direction to face normal: must be periodic image + connection_latticeConf(1:3,n) = normal_latticeConf * mesh_ipVolume(ip,el) & + / mesh_ipArea(n,ip,el) ! instead take the surface normal scaled with the diameter of the cell + endif + else + ! different number of active slip systems + call IO_error(-1_pInt,ext_msg='different number of active slip systems in neighboring IPs of same crystal structure') + endif + else + ! local neighbor or different lattice structure or different constitution instance -> use central values instead + connection_latticeConf(1:3,n) = 0.0_pReal + neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess + endif + else + ! free surface -> use central values instead + connection_latticeConf(1:3,n) = 0.0_pReal + neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess + endif + enddo + + + !* loop through the slip systems and calculate the dislocation gradient by + !* 1. interpolation of the excess density in the neighorhood + !* 2. interpolation of the dead dislocation density in the central volume + + m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) + m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) + + do s = 1_pInt,ns + + !* gradient from interpolation of neighboring excess density + + do c = 1_pInt,2_pInt + do dir = 1_pInt,3_pInt + neighbors(1) = 2_pInt * dir - 1_pInt + neighbors(2) = 2_pInt * dir + connections(dir,1:3) = connection_latticeConf(1:3,neighbors(1)) & + - connection_latticeConf(1:3,neighbors(2)) + rhoExcessDifferences(dir) = neighbor_rhoExcess(c,s,neighbors(1)) & + - neighbor_rhoExcess(c,s,neighbors(2)) + enddo + invConnections = math_inv33(connections) + if (all(abs(invConnections) <= tiny(0.0_pReal))) & ! check for failed in version (math_inv33 returns 0) and avoid floating point equality comparison + call IO_error(-1_pInt,ext_msg='back stress calculation: inversion error') + rhoExcessGradient(c) = math_mul3x3(m(1:3,s,c), & + math_mul33x3(invConnections,rhoExcessDifferences)) + enddo + + !* plus gradient from deads + + do t = 1_pInt,4_pInt + c = (t - 1_pInt) / 2_pInt + 1_pInt + rhoExcessGradient(c) = rhoExcessGradient(c) + rhoSgl(s,t+4_pInt) / FVsize + enddo + + !* normalized with the total density + + rhoExcessGradient_over_rho = 0.0_pReal + forall (c = 1_pInt:2_pInt) & + rhoTotal(c) = (sum(abs(rhoSgl(s,[2*c-1,2*c,2*c+3,2*c+4]))) + rhoDip(s,c) & + + sum(neighbor_rhoTotal(c,s,:))) / real(1_pInt + nRealNeighbors,pReal) + forall (c = 1_pInt:2_pInt, rhoTotal(c) > 0.0_pReal) & + rhoExcessGradient_over_rho(c) = rhoExcessGradient(c) / rhoTotal(c) + + !* gives the local stress correction when multiplied with a factor + + tauBack(s) = - lattice_mu(ph) * burgers(s,instance) / (2.0_pReal * pi) & + * (rhoExcessGradient_over_rho(1) / (1.0_pReal - lattice_nu(ph)) & + + rhoExcessGradient_over_rho(2)) + + enddo +endif + + +!*** set dependent states +plasticState(ph)%state(iRhoF(1:ns,instance),of) = rhoForest +plasticState(ph)%state(iTauF(1:ns,instance),of) = tauThreshold +plasticState(ph)%state(iTauB(1:ns,instance),of) = tauBack + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_microstructure at el ip ',el,ip + write(6,'(a,/,12x,12(e10.3,1x))') '<< CONST >> rhoForest', rhoForest + write(6,'(a,/,12x,12(f10.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold/1e6 + write(6,'(a,/,12x,12(f10.5,1x),/)') '<< CONST >> tauBack / MPa', tauBack/1e6 + endif +#endif + +end subroutine plastic_nonlocal_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates kinetics +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_kinetics(v, dv_dtau, dv_dtauNS, tau, tauNS, & + tauThreshold, c, Temperature, ip, el) + +use debug, only: debug_level, & + debug_constitutive, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use material, only: material_phase, & + phase_plasticityInstance + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el, & !< current element number + c !< dislocation character (1:edge, 2:screw) +real(pReal), intent(in) :: Temperature !< temperature +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & + intent(in) :: tau, & !< resolved external shear stress (without non Schmid effects) + tauNS, & !< resolved external shear stress (including non Schmid effects) + tauThreshold !< threshold shear stress + +!*** output variables +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & + intent(out) :: v, & !< velocity + dv_dtau, & !< velocity derivative with respect to resolved shear stress (without non Schmid contributions) + dv_dtauNS !< velocity derivative with respect to resolved shear stress (including non Schmid contributions) + +!*** local variables +integer(pInt) :: instance, & !< current instance of this plasticity + ns, & !< short notation for the total number of active slip systems + s !< index of my current slip system +real(pReal) tauRel_P, & + tauRel_S, & + tauEff, & !< effective shear stress + tPeierls, & !< waiting time in front of a peierls barriers + tSolidSolution, & !< waiting time in front of a solid solution obstacle + vViscous, & !< viscous glide velocity + dtPeierls_dtau, & !< derivative with respect to resolved shear stress + dtSolidSolution_dtau, & !< derivative with respect to resolved shear stress + meanfreepath_S, & !< mean free travel distance for dislocations between two solid solution obstacles + meanfreepath_P, & !< mean free travel distance for dislocations between two Peierls barriers + jumpWidth_P, & !< depth of activated area + jumpWidth_S, & !< depth of activated area + activationLength_P, & !< length of activated dislocation line + activationLength_S, & !< length of activated dislocation line + activationVolume_P, & !< volume that needs to be activated to overcome barrier + activationVolume_S, & !< volume that needs to be activated to overcome barrier + activationEnergy_P, & !< energy that is needed to overcome barrier + activationEnergy_S, & !< energy that is needed to overcome barrier + criticalStress_P, & !< maximum obstacle strength + criticalStress_S, & !< maximum obstacle strength + mobility !< dislocation mobility + + +instance = phase_plasticityInstance(material_phase(1_pInt,ip,el)) +ns = totalNslip(instance) + +v = 0.0_pReal +dv_dtau = 0.0_pReal +dv_dtauNS = 0.0_pReal + + +if (Temperature > 0.0_pReal) then + do s = 1_pInt,ns + if (abs(tau(s)) > tauThreshold(s)) then + + !* Peierls contribution + !* Effective stress includes non Schmid constributions + !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity + + tauEff = max(0.0_pReal, abs(tauNS(s)) - tauThreshold(s)) ! ensure that the effective stress is positive + meanfreepath_P = burgers(s,instance) + jumpWidth_P = burgers(s,instance) + activationLength_P = doublekinkwidth(instance) * burgers(s,instance) + activationVolume_P = activationLength_P * jumpWidth_P * burgers(s,instance) + criticalStress_P = peierlsStress(s,c,instance) + activationEnergy_P = criticalStress_P * activationVolume_P + tauRel_P = min(1.0_pReal, tauEff / criticalStress_P) ! ensure that the activation probability cannot become greater than one + tPeierls = 1.0_pReal / fattack(instance) & + * exp(activationEnergy_P / (KB * Temperature) & + * (1.0_pReal - tauRel_P**pParam(instance))**qParam(instance)) + if (tauEff < criticalStress_P) then + dtPeierls_dtau = tPeierls * pParam(instance) * qParam(instance) * activationVolume_P / (KB * Temperature) & + * (1.0_pReal - tauRel_P**pParam(instance))**(qParam(instance)-1.0_pReal) & + * tauRel_P**(pParam(instance)-1.0_pReal) + else + dtPeierls_dtau = 0.0_pReal + endif + + + !* Contribution from solid solution strengthening + !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity + + tauEff = abs(tau(s)) - tauThreshold(s) + meanfreepath_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) + jumpWidth_S = solidSolutionSize(instance) * burgers(s,instance) + activationLength_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) + activationVolume_S = activationLength_S * jumpWidth_S * burgers(s,instance) + activationEnergy_S = solidSolutionEnergy(instance) + criticalStress_S = activationEnergy_S / activationVolume_S + tauRel_S = min(1.0_pReal, tauEff / criticalStress_S) ! ensure that the activation probability cannot become greater than one + tSolidSolution = 1.0_pReal / fattack(instance) & + * exp(activationEnergy_S / (KB * Temperature) & + * (1.0_pReal - tauRel_S**pParam(instance))**qParam(instance)) + if (tauEff < criticalStress_S) then + dtSolidSolution_dtau = tSolidSolution * pParam(instance) * qParam(instance) & + * activationVolume_S / (KB * Temperature) & + * (1.0_pReal - tauRel_S**pParam(instance))**(qParam(instance)-1.0_pReal) & + * tauRel_S**(pParam(instance)-1.0_pReal) + else + dtSolidSolution_dtau = 0.0_pReal + endif + + + !* viscous glide velocity + + tauEff = abs(tau(s)) - tauThreshold(s) + mobility = burgers(s,instance) / viscosity(instance) + vViscous = mobility * tauEff + + + !* Mean velocity results from waiting time at peierls barriers and solid solution obstacles with respective meanfreepath of + !* free flight at glide velocity in between. + !* adopt sign from resolved stress + + v(s) = sign(1.0_pReal,tau(s)) & + / (tPeierls / meanfreepath_P + tSolidSolution / meanfreepath_S + 1.0_pReal / vViscous) + dv_dtau(s) = v(s) * v(s) * (dtSolidSolution_dtau / meanfreepath_S & + + mobility / (vViscous * vViscous)) + dv_dtauNS(s) = v(s) * v(s) * dtPeierls_dtau / meanfreepath_P + endif + enddo +endif + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_kinetics at el ip',el,ip + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold / 1e6_pReal + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tau / MPa', tau / 1e6_pReal + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauNS / MPa', tauNS / 1e6_pReal + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> v / 1e-3m/s', v * 1e3 + write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtau', dv_dtau + write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtauNS', dv_dtauNS + endif +#endif + +end subroutine plastic_nonlocal_kinetics + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_LpAndItsTangent(Lp, dLp_dTstar99, Tstar_v, Temperature, ip, el) + +use math, only: math_Plain3333to99, & + math_mul6x6, & + math_mul33xx33, & + math_Mandel6to33 +use debug, only: debug_level, & + debug_constitutive, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use material, only: material_phase, & + plasticState, & + phaseAt, phasememberAt,& + phase_plasticityInstance +use lattice, only: lattice_Sslip, & + lattice_Sslip_v, & + lattice_NnonSchmid +use mesh, only: mesh_ipVolume + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el !< current element number +real(pReal), intent(in) :: Temperature !< temperature +real(pReal), dimension(6), intent(in) :: Tstar_v !< 2nd Piola-Kirchhoff stress in Mandel notation + + +!*** output variables +real(pReal), dimension(3,3), intent(out) :: Lp !< plastic velocity gradient +real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 !< derivative of Lp with respect to Tstar (9x9 matrix) + +!*** local variables +integer(pInt) instance, & !< current instance of this plasticity + ns, & !< short notation for the total number of active slip systems + i, & + j, & + k, & + l, & + ph, & !phase number + of, & !offset + t, & !< dislocation type + s, & !< index of my current slip system + sLattice !< index of my current slip system according to lattice order +real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 !< derivative of Lp with respect to Tstar (3x3x3x3 matrix) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl !< single dislocation densities (including blocked) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + v, & !< velocity + tauNS, & !< resolved shear stress including non Schmid and backstress terms + dv_dtau, & !< velocity derivative with respect to the shear stress + dv_dtauNS !< velocity derivative with respect to the shear stress +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + tau, & !< resolved shear stress including backstress terms + gdotTotal, & !< shear rate + tauBack, & !< back stress from dislocation gradients on same slip system + tauThreshold !< threshold shear stress +!*** shortcut for mapping +ph = phaseAt(1_pInt,ip,el) +of = phasememberAt(1_pInt,ip,el) + +!*** initialize local variables + +Lp = 0.0_pReal +dLp_dTstar3333 = 0.0_pReal + +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + + +!*** shortcut to state variables + + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + + rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) +endforall +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal + +tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) +tauThreshold = plasticState(ph)%state(iTauF(1:ns,instance),of) + + +!*** get resolved shear stress +!*** for screws possible non-schmid contributions are also taken into account + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauNS(s,1) = tau(s) + tauNS(s,2) = tau(s) + if (tau(s) > 0.0_pReal) then + tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,1,s,instance)) + tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,3,s,instance)) + else + tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,2,s,instance)) + tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,4,s,instance)) + endif +enddo +forall (t = 1_pInt:4_pInt) & + tauNS(1:ns,t) = tauNS(1:ns,t) + tauBack ! add backstress +tau = tau + tauBack ! add backstress + + +!*** get dislocation velocity and its tangent and store the velocity in the state array + +! edges +call plastic_nonlocal_kinetics(v(1:ns,1), dv_dtau(1:ns,1), dv_dtauNS(1:ns,1), & + tau(1:ns), tauNS(1:ns,1), tauThreshold(1:ns), & + 1_pInt, Temperature, ip, el) +v(1:ns,2) = v(1:ns,1) +dv_dtau(1:ns,2) = dv_dtau(1:ns,1) +dv_dtauNS(1:ns,2) = dv_dtauNS(1:ns,1) + +!screws +if (lattice_NnonSchmid(ph) == 0_pInt) then ! no non-Schmid contributions + forall(t = 3_pInt:4_pInt) + v(1:ns,t) = v(1:ns,1) + dv_dtau(1:ns,t) = dv_dtau(1:ns,1) + dv_dtauNS(1:ns,t) = dv_dtauNS(1:ns,1) + endforall +else ! take non-Schmid contributions into account + do t = 3_pInt,4_pInt + call plastic_nonlocal_kinetics(v(1:ns,t), dv_dtau(1:ns,t), dv_dtauNS(1:ns,t), & + tau(1:ns), tauNS(1:ns,t), tauThreshold(1:ns), & + 2_pInt , Temperature, ip, el) + enddo +endif + + +!*** store velocity in state + +forall (t = 1_pInt:4_pInt) & + plasticState(ph)%state(iV(1:ns,t,instance),of) = v(1:ns,t) +!*** Bauschinger effect + +forall (s = 1_pInt:ns, t = 5_pInt:8_pInt, rhoSgl(s,t) * v(s,t-4_pInt) < 0.0_pReal) & + rhoSgl(s,t-4_pInt) = rhoSgl(s,t-4_pInt) + abs(rhoSgl(s,t)) + + +!*** Calculation of Lp and its tangent + +gdotTotal = sum(rhoSgl(1:ns,1:4) * v, 2) * burgers(1:ns,instance) + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + Lp = Lp + gdotTotal(s) * lattice_Sslip(1:3,1:3,1,sLattice,ph) + + ! Schmid contributions to tangent + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + + lattice_Sslip(i,j,1,sLattice,ph) * lattice_Sslip(k,l,1,sLattice,ph) & + * sum(rhoSgl(s,1:4) * dv_dtau(s,1:4)) * burgers(s,instance) + + ! non Schmid contributions to tangent + if (tau(s) > 0.0_pReal) then + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + + lattice_Sslip(i,j,1,sLattice,ph) & + * ( nonSchmidProjection(k,l,1,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & + + nonSchmidProjection(k,l,3,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & + * burgers(s,instance) + else + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + + lattice_Sslip(i,j,1,sLattice,ph) & + * ( nonSchmidProjection(k,l,2,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & + + nonSchmidProjection(k,l,4,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & + * burgers(s,instance) + endif +enddo +dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_LpandItsTangent at el ip',el,ip + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> gdot total / 1e-3',gdotTotal*1e3_pReal + write(6,'(a,/,3(12x,3(f12.7,1x),/))') '<< CONST >> Lp',transpose(Lp) + endif +#endif + +end subroutine plastic_nonlocal_LpAndItsTangent + + + +!-------------------------------------------------------------------------------------------------- +!> @brief (instantaneous) incremental change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_deltaState(Tstar_v,ip,el) +use debug, only: debug_level, & + debug_constitutive, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use math, only: pi, & + math_mul6x6 +use lattice, only: lattice_Sslip_v ,& + lattice_mu, & + lattice_nu +use mesh, only: mesh_ipVolume +use material, only: material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + +implicit none +integer(pInt), intent(in) :: ip, & ! current grain number + el ! current element number +real(pReal), dimension(6), intent(in) :: Tstar_v ! current 2nd Piola-Kirchhoff stress in Mandel notation + + + integer(pInt) :: & + ph, & !< phase + of !< offset + +integer(pInt) ::instance, & ! current instance of this plasticity + ns, & ! short notation for the total number of active slip systems + c, & ! character of dislocation + t, & ! type of dislocation + s, & ! index of my current slip system + sLattice ! index of my current slip system according to lattice order +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),10) :: & + deltaRho, & ! density increment + deltaRhoRemobilization, & ! density increment by remobilization + deltaRhoDipole2SingleStress ! density increment by dipole dissociation (by stress change) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),8) :: & + rhoSgl ! current single dislocation densities (positive/negative screw and edge without dipoles) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),4) :: & + v ! dislocation glide velocity +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + tau, & ! current resolved shear stress + tauBack ! current back stress from pileups on same slip system +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),2) :: & + rhoDip, & ! current dipole dislocation densities (screw and edge dipoles) + dLower, & ! minimum stable dipole distance for edges and screws + dUpper, & ! current maximum stable dipole distance for edges and screws + dUpperOld, & ! old maximum stable dipole distance for edges and screws + deltaDUpper ! change in maximum stable dipole distance for edges and screws + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_deltaState at el ip ',el,ip +#endif + + ph = phaseAt(1,ip,el) + of = phasememberAt(1,ip,el) + instance = phase_plasticityInstance(ph) + ns = totalNslip(instance) + + +!*** shortcut to state variables + + forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) + v(s,t) = plasticState(ph)%state(iV(s,t,instance),of) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities + dUpperOld(s,c) = plasticState(ph)%state(iD(s,c,instance),of) +endforall + tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) + +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal +where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoDip) < significantRho(instance)) & + rhoDip = 0.0_pReal + + + + +!**************************************************************************** +!*** dislocation remobilization (bauschinger effect) + +deltaRhoRemobilization = 0.0_pReal +do t = 1_pInt,4_pInt + do s = 1_pInt,ns + if (rhoSgl(s,t+4_pInt) * v(s,t) < 0.0_pReal) then + deltaRhoRemobilization(s,t) = abs(rhoSgl(s,t+4_pInt)) + rhoSgl(s,t) = rhoSgl(s,t) + abs(rhoSgl(s,t+4_pInt)) + deltaRhoRemobilization(s,t+4_pInt) = - rhoSgl(s,t+4_pInt) + rhoSgl(s,t+4_pInt) = 0.0_pReal + endif + enddo +enddo + + + +!**************************************************************************** +!*** calculate dipole formation and dissociation by stress change + +!*** calculate limits for stable dipole height + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) + if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal +enddo +dLower = minDipoleHeight(1:ns,1:2,instance) +dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & + / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) +dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) / (4.0_pReal * pi * abs(tau)) + + +forall (c = 1_pInt:2_pInt) + where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& + abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & + dUpper(1:ns,c)) +end forall +dUpper = max(dUpper,dLower) +deltaDUpper = dUpper - dUpperOld + + +!*** dissociation by stress increase +deltaRhoDipole2SingleStress = 0.0_pReal +forall (c=1_pInt:2_pInt, s=1_pInt:ns, deltaDUpper(s,c) < 0.0_pReal .and. & + abs(dUpperOld(s,c) - dLower(s,c)) > tiny(0.0_pReal)) & + deltaRhoDipole2SingleStress(s,8_pInt+c) = rhoDip(s,c) * deltaDUpper(s,c) & + / (dUpperOld(s,c) - dLower(s,c)) + +forall (t=1_pInt:4_pInt) & + deltaRhoDipole2SingleStress(1_pInt:ns,t) = -0.5_pReal & + * deltaRhoDipole2SingleStress(1_pInt:ns,(t-1_pInt)/2_pInt+9_pInt) + + +!*** store new maximum dipole height in state + +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & + plasticState(ph)%state(iD(s,c,instance),of) = dUpper(s,c) + + + +!**************************************************************************** +!*** assign the changes in the dislocation densities to deltaState + +deltaRho = deltaRhoRemobilization & + + deltaRhoDipole2SingleStress +plasticState(ph)%deltaState(:,of) = 0.0_pReal +forall (s = 1:ns, t = 1_pInt:4_pInt) + plasticState(ph)%deltaState(iRhoU(s,t,instance),of)= deltaRho(s,t) + plasticState(ph)%deltaState(iRhoB(s,t,instance),of) = deltaRho(s,t+4_pInt) +endforall +forall (s = 1:ns, c = 1_pInt:2_pInt) & + plasticState(ph)%deltaState(iRhoD(s,c,instance),of) = deltaRho(s,c+8_pInt) + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation remobilization', deltaRhoRemobilization(1:ns,1:8) + write(6,'(a,/,10(12x,12(e12.5,1x),/),/)') '<< CONST >> dipole dissociation by stress increase', deltaRhoDipole2SingleStress + endif +#endif + +end subroutine plastic_nonlocal_deltaState + +!--------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!--------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_dotState(Tstar_v, Fe, Fp, Temperature, & + timestep,subfrac, ip,el) + +use prec, only: DAMASK_NaN +use numerics, only: numerics_integrationMode, & + numerics_timeSyncing +use IO, only: IO_error +use debug, only: debug_level, & + debug_constitutive, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_g, & + debug_i, & + debug_e +use math, only: math_mul6x6, & + math_mul3x3, & + math_mul33x3, & + math_mul33x33, & + math_inv33, & + math_det33, & + math_transpose33, & + pi +use mesh, only: mesh_NcpElems, & + mesh_maxNips, & + mesh_element, & + mesh_ipNeighborhood, & + mesh_ipVolume, & + mesh_ipArea, & + mesh_ipAreaNormal, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype +use material, only: homogenization_maxNgrains, & + material_phase, & + phase_plasticityInstance, & + phase_localPlasticity, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticity ,& + PLASTICITY_NONLOCAL_ID +use lattice, only: lattice_Sslip_v, & + lattice_sd, & + lattice_st ,& + lattice_mu, & + lattice_nu, & + lattice_structure, & + LATTICE_bcc_ID, & + LATTICE_fcc_ID + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el !< current element number +real(pReal), intent(in) :: Temperature, & !< temperature + timestep !< substepped crystallite time increment +real(pReal), dimension(6), intent(in) :: Tstar_v !< current 2nd Piola-Kirchhoff stress in Mandel notation +real(pReal), dimension(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + subfrac !< fraction of timestep at the beginning of the substepped crystallite time increment +real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + Fe, & !< elastic deformation gradient + Fp !< plastic deformation gradient + + +!*** local variables +integer(pInt) :: ph, & + instance, & !< current instance of this plasticity + neighbor_instance, & !< instance of my neighbor's plasticity + ns, & !< short notation for the total number of active slip systems + c, & !< character of dislocation + n, & !< index of my current neighbor + neighbor_el, & !< element number of my neighbor + neighbor_ip, & !< integration point of my neighbor + neighbor_n, & !< neighbor index pointing to me when looking from my neighbor + opposite_neighbor, & !< index of my opposite neighbor + opposite_ip, & !< ip of my opposite neighbor + opposite_el, & !< element index of my opposite neighbor + opposite_n, & !< neighbor index pointing to me when looking from my opposite neighbor + t, & !< type of dislocation + o,& !< offset shortcut + no,& !< neighbour offset shortcut + p,& !< phase shortcut + np,& !< neighbour phase shortcut + topp, & !< type of dislocation with opposite sign to t + s, & !< index of my current slip system + sLattice !< index of my current slip system according to lattice order +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),10) :: & + rhoDot, & !< density evolution + rhoDotMultiplication, & !< density evolution by multiplication + rhoDotFlux, & !< density evolution by flux + rhoDotSingle2DipoleGlide, & !< density evolution by dipole formation (by glide) + rhoDotAthermalAnnihilation, & !< density evolution by athermal annihilation + rhoDotThermalAnnihilation !< density evolution by thermal annihilation +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) + rhoSglOriginal, & + neighbor_rhoSgl, & !< current single dislocation densities of neighboring ip (positive/negative screw and edge without dipoles) + rhoSgl0, & !< single dislocation densities at start of cryst inc (positive/negative screw and edge without dipoles) + my_rhoSgl !< single dislocation densities of central ip (positive/negative screw and edge without dipoles) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + v, & !< current dislocation glide velocity + v0, & !< dislocation glide velocity at start of cryst inc + my_v, & !< dislocation glide velocity of central ip + neighbor_v, & !< dislocation glide velocity of enighboring ip + gdot !< shear rates +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoForest, & !< forest dislocation density + tauThreshold, & !< threshold shear stress + tau, & !< current resolved shear stress + tauBack, & !< current back stress from pileups on same slip system + vClimb, & !< climb velocity of edge dipoles + nSources +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) + rhoDipOriginal, & + dLower, & !< minimum stable dipole distance for edges and screws + dUpper !< current maximum stable dipole distance for edges and screws +real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + m !< direction of dislocation motion +real(pReal), dimension(3,3) :: my_F, & !< my total deformation gradient + neighbor_F, & !< total deformation gradient of my neighbor + my_Fe, & !< my elastic deformation gradient + neighbor_Fe, & !< elastic deformation gradient of my neighbor + Favg !< average total deformation gradient of me and my neighbor +real(pReal), dimension(3) :: normal_neighbor2me, & !< interface normal pointing from my neighbor to me in neighbor's lattice configuration + normal_neighbor2me_defConf, & !< interface normal pointing from my neighbor to me in shared deformed configuration + normal_me2neighbor, & !< interface normal pointing from me to my neighbor in my lattice configuration + normal_me2neighbor_defConf !< interface normal pointing from me to my neighbor in shared deformed configuration +real(pReal) area, & !< area of the current interface + transmissivity, & !< overall transmissivity of dislocation flux to neighboring material point + lineLength, & !< dislocation line length leaving the current interface + selfDiffusion, & !< self diffusion + rnd, & + meshlength +logical considerEnteringFlux, & + considerLeavingFlux + + + p = phaseAt(1,ip,el) + o = phasememberAt(1,ip,el) + + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_dotState at el ip ',el,ip +#endif + +ph = material_phase(1_pInt,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + +tau = 0.0_pReal +gdot = 0.0_pReal + + +!*** shortcut to state variables + + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) + v(s,t) = plasticState(p)%state(iV (s,t,instance),o) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + rhoDip(s,c) = max(plasticState(p)%state(iRhoD(s,c,instance),o), 0.0_pReal) ! ensure positive dipole densities +endforall +rhoForest = plasticState(p)%state(iRhoF(1:ns,instance),o) +tauThreshold = plasticState(p)%state(iTauF(1:ns,instance),o) +tauBack = plasticState(p)%state(iTauB(1:ns,instance),o) + +rhoSglOriginal = rhoSgl +rhoDipOriginal = rhoDip +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal +where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoDip) < significantRho(instance)) & + rhoDip = 0.0_pReal + +if (numerics_timeSyncing) then + forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl0(s,t) = max(plasticState(p)%state0(iRhoU(s,t,instance),o), 0.0_pReal) + rhoSgl0(s,t+4_pInt) = plasticState(p)%state0(iRhoB(s,t,instance),o) + v0(s,t) = plasticState(p)%state0(iV (s,t,instance),o) + endforall + where (abs(rhoSgl0) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl0) < significantRho(instance)) & + rhoSgl0 = 0.0_pReal +endif + + + +!*** sanity check for timestep + +if (timestep <= 0.0_pReal) then ! if illegal timestep... Why here and not on function entry?? + plasticState(p)%dotState = 0.0_pReal ! ...return without doing anything (-> zero dotState) + return +endif + + + +!**************************************************************************** +!*** Calculate shear rate + +forall (t = 1_pInt:4_pInt) & + gdot(1_pInt:ns,t) = rhoSgl(1_pInt:ns,t) * burgers(1:ns,instance) * v(1:ns,t) + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> rho / 1/m^2', rhoSgl, rhoDip + write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> gdot / 1/s',gdot + endif +#endif + + + +!**************************************************************************** +!*** calculate limits for stable dipole height + +do s = 1_pInt,ns ! loop over slip systems + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) + if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal +enddo + +dLower = minDipoleHeight(1:ns,1:2,instance) +dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & + / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) +dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & + / (4.0_pReal * pi * abs(tau)) +forall (c = 1_pInt:2_pInt) + where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& + abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & + dUpper(1:ns,c)) +end forall +dUpper = max(dUpper,dLower) + +!**************************************************************************** +!*** calculate dislocation multiplication + +rhoDotMultiplication = 0.0_pReal +if (lattice_structure(ph) == LATTICE_bcc_ID) then ! BCC + forall (s = 1:ns, sum(abs(v(s,1:4))) > 0.0_pReal) + rhoDotMultiplication(s,1:2) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication + * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path + ! * 2.0_pReal * sum(abs(v(s,3:4))) / sum(abs(v(s,1:4))) ! ratio of screw to overall velocity determines edge generation + rhoDotMultiplication(s,3:4) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication + * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path + ! * 2.0_pReal * sum(abs(v(s,1:2))) / sum(abs(v(s,1:4))) ! ratio of edge to overall velocity determines screw generation + endforall + +else ! ALL OTHER STRUCTURES + if (probabilisticMultiplication(instance)) then + meshlength = mesh_ipVolume(ip,el)**0.333_pReal + where(sum(rhoSgl(1:ns,1:4),2) > 0.0_pReal) + nSources = (sum(rhoSgl(1:ns,1:2),2) * fEdgeMultiplication(instance) + sum(rhoSgl(1:ns,3:4),2)) & + / sum(rhoSgl(1:ns,1:4),2) * meshlength / lambda0(1:ns,instance)*sqrt(rhoForest(1:ns)) + elsewhere + nSources = meshlength / lambda0(1:ns,instance) * sqrt(rhoForest(1:ns)) + endwhere + do s = 1_pInt,ns + if (nSources(s) < 1.0_pReal) then + if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal) then + call random_number(rnd) + sourceProbability(s,1_pInt,ip,el) = rnd + !$OMP FLUSH(sourceProbability) + endif + if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal - nSources(s)) then + rhoDotMultiplication(s,1:4) = sum(rhoSglOriginal(s,1:4) * abs(v(s,1:4))) / meshlength + endif + else + sourceProbability(s,1_pInt,ip,el) = 2.0_pReal + rhoDotMultiplication(s,1:4) = & + (sum(abs(gdot(s,1:2))) * fEdgeMultiplication(instance) + sum(abs(gdot(s,3:4)))) & + / burgers(s,instance) * sqrt(rhoForest(s)) / lambda0(s,instance) + endif + enddo +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) & + write(6,'(a,/,4(12x,12(f12.5,1x),/,/))') '<< CONST >> sources', nSources +#endif + else + rhoDotMultiplication(1:ns,1:4) = spread( & + (sum(abs(gdot(1:ns,1:2)),2) * fEdgeMultiplication(instance) + sum(abs(gdot(1:ns,3:4)),2)) & + * sqrt(rhoForest(1:ns)) / lambda0(1:ns,instance) / burgers(1:ns,instance), 2, 4) + endif +endif + + + +!**************************************************************************** +!*** calculate dislocation fluxes (only for nonlocal plasticity) + +rhoDotFlux = 0.0_pReal +!? why needed here +if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then ! only for nonlocal plasticity + + !*** check CFL (Courant-Friedrichs-Lewy) condition for flux + + if (any( abs(gdot) > 0.0_pReal & ! any active slip system ... + .and. CFLfactor(instance) * abs(v) * timestep & + > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el)))) then ! ...with velocity above critical value (we use the reference volume and area for simplicity here) +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then + write(6,'(a,i5,a,i2)') '<< CONST >> CFL condition not fullfilled at el ',el,' ip ',ip + write(6,'(a,e10.3,a,e10.3)') '<< CONST >> velocity is at ', & + maxval(abs(v), abs(gdot) > 0.0_pReal & + .and. CFLfactor(instance) * abs(v) * timestep & + > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el))), & + ' at a timestep of ',timestep + write(6,'(a)') '<< CONST >> enforcing cutback !!!' + endif +#endif + plasticState(p)%dotState = DAMASK_NaN ! -> return NaN and, hence, enforce cutback + return + endif + + + !*** be aware of the definition of lattice_st = lattice_sd x lattice_sn !!! + !*** opposite sign to our p vector in the (s,p,n) triplet !!! + + m(1:3,1:ns,1) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) + m(1:3,1:ns,2) = -lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) + m(1:3,1:ns,3) = -lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) + m(1:3,1:ns,4) = lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) + + my_Fe = Fe(1:3,1:3,1_pInt,ip,el) + my_F = math_mul33x33(my_Fe, Fp(1:3,1:3,1_pInt,ip,el)) + + do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) ! loop through my neighbors +! write(6,*) 'c' + neighbor_el = mesh_ipNeighborhood(1,n,ip,el) + neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) + neighbor_n = mesh_ipNeighborhood(3,n,ip,el) + np = phaseAt(1,neighbor_ip,neighbor_el) + no = phasememberAt(1,neighbor_ip,neighbor_el) + + opposite_neighbor = n + mod(n,2_pInt) - mod(n+1_pInt,2_pInt) + opposite_el = mesh_ipNeighborhood(1,opposite_neighbor,ip,el) + opposite_ip = mesh_ipNeighborhood(2,opposite_neighbor,ip,el) + opposite_n = mesh_ipNeighborhood(3,opposite_neighbor,ip,el) + + if (neighbor_n > 0_pInt) then ! if neighbor exists, average deformation gradient + neighbor_instance = phase_plasticityInstance(material_phase(1_pInt,neighbor_ip,neighbor_el)) + neighbor_Fe = Fe(1:3,1:3,1_pInt,neighbor_ip,neighbor_el) + neighbor_F = math_mul33x33(neighbor_Fe, Fp(1:3,1:3,1_pInt,neighbor_ip,neighbor_el)) + Favg = 0.5_pReal * (my_F + neighbor_F) + else ! if no neighbor, take my value as average + Favg = my_F + endif + + + !* FLUX FROM MY NEIGHBOR TO ME + !* This is only considered, if I have a neighbor of nonlocal plasticity + !* (also nonlocal constitutive law with local properties) that is at least a little bit + !* compatible. + !* If it's not at all compatible, no flux is arriving, because everything is dammed in front of + !* my neighbor's interface. + !* The entering flux from my neighbor will be distributed on my slip systems according to the + !*compatibility + + considerEnteringFlux = .false. + neighbor_v = 0.0_pReal ! needed for check of sign change in flux density below + neighbor_rhoSgl = 0.0_pReal + if (neighbor_n > 0_pInt) then + if (phase_plasticity(material_phase(1,neighbor_ip,neighbor_el)) == PLASTICITY_NONLOCAL_ID & + .and. any(compatibility(:,:,:,n,ip,el) > 0.0_pReal)) & + considerEnteringFlux = .true. + endif + + if (considerEnteringFlux) then + if(numerics_timeSyncing .and. (subfrac(1_pInt,neighbor_ip,neighbor_el) /= subfrac(1_pInt,ip,el))) & + then ! for timesyncing: in case of a timestep at the interface we have to use "state0" to make sure that fluxes n both sides are equal + forall (s = 1:ns, t = 1_pInt:4_pInt) + + neighbor_v(s,t) = plasticState(np)%state0(iV (s,t,neighbor_instance),no) + neighbor_rhoSgl(s,t) = max(plasticState(np)%state0(iRhoU(s,t,neighbor_instance),no),0.0_pReal) + + endforall + else + forall (s = 1:ns, t = 1_pInt:4_pInt) + neighbor_v(s,t) = plasticState(np)%state(iV (s,t,neighbor_instance),no) + neighbor_rhoSgl(s,t) = max(plasticState(np)%state(iRhoU(s,t,neighbor_instance),no), & + 0.0_pReal) + endforall + endif + + where (neighbor_rhoSgl * mesh_ipVolume(neighbor_ip,neighbor_el) ** 0.667_pReal < significantN(instance) & + .or. neighbor_rhoSgl < significantRho(instance)) & + neighbor_rhoSgl = 0.0_pReal + normal_neighbor2me_defConf = math_det33(Favg) * math_mul33x3(math_inv33(transpose(Favg)), & + mesh_ipAreaNormal(1:3,neighbor_n,neighbor_ip,neighbor_el)) ! calculate the normal of the interface in (average) deformed configuration (now pointing from my neighbor to me!!!) + normal_neighbor2me = math_mul33x3(transpose(neighbor_Fe), normal_neighbor2me_defConf) & + / math_det33(neighbor_Fe) ! interface normal in the lattice configuration of my neighbor + area = mesh_ipArea(neighbor_n,neighbor_ip,neighbor_el) * norm2(normal_neighbor2me) + normal_neighbor2me = normal_neighbor2me / norm2(normal_neighbor2me) ! normalize the surface normal to unit length + do s = 1_pInt,ns + do t = 1_pInt,4_pInt + c = (t + 1_pInt) / 2 + topp = t + mod(t,2_pInt) - mod(t+1_pInt,2_pInt) + if (neighbor_v(s,t) * math_mul3x3(m(1:3,s,t), normal_neighbor2me) > 0.0_pReal & ! flux from my neighbor to me == entering flux for me + .and. v(s,t) * neighbor_v(s,t) >= 0.0_pReal ) then ! ... only if no sign change in flux density + lineLength = neighbor_rhoSgl(s,t) * neighbor_v(s,t) & + * math_mul3x3(m(1:3,s,t), normal_neighbor2me) * area ! positive line length that wants to enter through this interface + where (compatibility(c,1_pInt:ns,s,n,ip,el) > 0.0_pReal) & ! positive compatibility... + rhoDotFlux(1_pInt:ns,t) = rhoDotFlux(1_pInt:ns,t) & + + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to equally signed mobile dislocation type + * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal + where (compatibility(c,1_pInt:ns,s,n,ip,el) < 0.0_pReal) & ! ..negative compatibility... + rhoDotFlux(1_pInt:ns,topp) = rhoDotFlux(1_pInt:ns,topp) & + + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to opposite signed mobile dislocation type + * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal + endif + enddo + enddo + endif + + + !* FLUX FROM ME TO MY NEIGHBOR + !* This is not considered, if my opposite neighbor has a different constitutive law than nonlocal (still considered for nonlocal law with lcal properties). + !* Then, we assume, that the opposite(!) neighbor sends an equal amount of dislocations to me. + !* So the net flux in the direction of my neighbor is equal to zero: + !* leaving flux to neighbor == entering flux from opposite neighbor + !* In case of reduced transmissivity, part of the leaving flux is stored as dead dislocation density. + !* That means for an interface of zero transmissivity the leaving flux is fully converted to dead dislocations. + + considerLeavingFlux = .true. + if (opposite_n > 0_pInt) then + if (phase_plasticity(material_phase(1,opposite_ip,opposite_el)) /= PLASTICITY_NONLOCAL_ID) & + considerLeavingFlux = .false. + endif + + if (considerLeavingFlux) then + + !* timeSyncing mode: If the central ip has zero subfraction, always use "state0". This is needed in case of + !* a synchronization step for the central ip, because then "state" contains the values at the end of the + !* previously converged full time step. Also, if either me or my neighbor has zero subfraction, we have to + !* use "state0" to make sure that fluxes on both sides of the (potential) timestep are equal. + my_rhoSgl = rhoSgl + my_v = v + if(numerics_timeSyncing) then + if (abs(subfrac(1_pInt,ip,el))<= tiny(0.0_pReal)) then + my_rhoSgl = rhoSgl0 + my_v = v0 + elseif (neighbor_n > 0_pInt) then + if (abs(subfrac(1_pInt,neighbor_ip,neighbor_el))<= tiny(0.0_pReal)) then + my_rhoSgl = rhoSgl0 + my_v = v0 + endif + endif + endif + + normal_me2neighbor_defConf = math_det33(Favg) & + * math_mul33x3(math_inv33(math_transpose33(Favg)), & + mesh_ipAreaNormal(1:3,n,ip,el)) ! calculate the normal of the interface in (average) deformed configuration (pointing from me to my neighbor!!!) + normal_me2neighbor = math_mul33x3(math_transpose33(my_Fe), normal_me2neighbor_defConf) & + / math_det33(my_Fe) ! interface normal in my lattice configuration + area = mesh_ipArea(n,ip,el) * norm2(normal_me2neighbor) + normal_me2neighbor = normal_me2neighbor / norm2(normal_me2neighbor) ! normalize the surface normal to unit length + do s = 1_pInt,ns + do t = 1_pInt,4_pInt + c = (t + 1_pInt) / 2_pInt + if (my_v(s,t) * math_mul3x3(m(1:3,s,t), normal_me2neighbor) > 0.0_pReal ) then ! flux from me to my neighbor == leaving flux for me (might also be a pure flux from my mobile density to dead density if interface not at all transmissive) + if (my_v(s,t) * neighbor_v(s,t) >= 0.0_pReal) then ! no sign change in flux density + transmissivity = sum(compatibility(c,1_pInt:ns,s,n,ip,el)**2.0_pReal) ! overall transmissivity from this slip system to my neighbor + else ! sign change in flux density means sign change in stress which does not allow for dislocations to arive at the neighbor + transmissivity = 0.0_pReal + endif + lineLength = my_rhoSgl(s,t) * my_v(s,t) & + * math_mul3x3(m(1:3,s,t), normal_me2neighbor) * area ! positive line length of mobiles that wants to leave through this interface + rhoDotFlux(s,t) = rhoDotFlux(s,t) - lineLength / mesh_ipVolume(ip,el) ! subtract dislocation flux from current type + rhoDotFlux(s,t+4_pInt) = rhoDotFlux(s,t+4_pInt) & + + lineLength / mesh_ipVolume(ip,el) * (1.0_pReal - transmissivity) & + * sign(1.0_pReal, my_v(s,t)) ! dislocation flux that is not able to leave through interface (because of low transmissivity) will remain as immobile single density at the material point + endif + enddo + enddo + endif + + enddo ! neighbor loop +endif + + + +!**************************************************************************** +!*** calculate dipole formation and annihilation + +!*** formation by glide + +do c = 1_pInt,2_pInt + rhoDotSingle2DipoleGlide(1:ns,2*c-1) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile + + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile + + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) ! positive mobile --> negative immobile + + rhoDotSingle2DipoleGlide(1:ns,2*c) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile + + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile + + abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c))) ! negative mobile --> positive immobile + + rhoDotSingle2DipoleGlide(1:ns,2*c+3) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * rhoSgl(1:ns,2*c+3) * abs(gdot(1:ns,2*c)) ! negative mobile --> positive immobile + + rhoDotSingle2DipoleGlide(1:ns,2*c+4) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * rhoSgl(1:ns,2*c+4) * abs(gdot(1:ns,2*c-1)) ! positive mobile --> negative immobile + + rhoDotSingle2DipoleGlide(1:ns,c+8) = - rhoDotSingle2DipoleGlide(1:ns,2*c-1) & + - rhoDotSingle2DipoleGlide(1:ns,2*c) & + + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+3)) & + + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+4)) +enddo + + +!*** athermal annihilation + +rhoDotAthermalAnnihilation = 0.0_pReal + +forall (c=1_pInt:2_pInt) & + rhoDotAthermalAnnihilation(1:ns,c+8_pInt) = -2.0_pReal * dLower(1:ns,c) / burgers(1:ns,instance) & + * ( 2.0_pReal * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1))) & ! was single hitting single + + 2.0_pReal * (abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c)) + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) & ! was single hitting immobile single or was immobile single hit by single + + rhoDip(1:ns,c) * (abs(gdot(1:ns,2*c-1)) + abs(gdot(1:ns,2*c)))) ! single knocks dipole constituent +! annihilated screw dipoles leave edge jogs behind on the colinear system +if (lattice_structure(ph) == LATTICE_fcc_ID) & ! only fcc + forall (s = 1:ns, colinearSystem(s,instance) > 0_pInt) & + rhoDotAthermalAnnihilation(colinearSystem(s,instance),1:2) = - rhoDotAthermalAnnihilation(s,10) & + * 0.25_pReal * sqrt(rhoForest(s)) * (dUpper(s,2) + dLower(s,2)) * edgeJogFactor(instance) + + + +!*** thermally activated annihilation of edge dipoles by climb + +rhoDotThermalAnnihilation = 0.0_pReal +selfDiffusion = Dsd0(instance) * exp(-selfDiffusionEnergy(instance) / (KB * Temperature)) +vClimb = atomicVolume(instance) * selfDiffusion / ( KB * Temperature ) & + * lattice_mu(ph) / ( 2.0_pReal * PI * (1.0_pReal-lattice_nu(ph)) ) & + * 2.0_pReal / ( dUpper(1:ns,1) + dLower(1:ns,1) ) +forall (s = 1_pInt:ns, dUpper(s,1) > dLower(s,1)) & + rhoDotThermalAnnihilation(s,9) = max(- 4.0_pReal * rhoDip(s,1) * vClimb(s) / (dUpper(s,1) - dLower(s,1)), & + - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & + - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have + + + +!**************************************************************************** +!*** assign the rates of dislocation densities to my dotState +!*** if evolution rates lead to negative densities, a cutback is enforced + +rhoDot = 0.0_pReal +rhoDot = rhoDotFlux & + + rhoDotMultiplication & + + rhoDotSingle2DipoleGlide & + + rhoDotAthermalAnnihilation & + + rhoDotThermalAnnihilation + +if (numerics_integrationMode == 1_pInt) then ! save rates for output if in central integration mode + rhoDotFluxOutput(1:ns,1:8,1_pInt,ip,el) = rhoDotFlux(1:ns,1:8) + rhoDotMultiplicationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotMultiplication(1:ns,[1,3]) + rhoDotSingle2DipoleGlideOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotSingle2DipoleGlide(1:ns,9:10) + rhoDotAthermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotAthermalAnnihilation(1:ns,9:10) + rhoDotThermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotThermalAnnihilation(1:ns,9:10) + rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) = 2.0_pReal * rhoDotThermalAnnihilation(1:ns,1) +endif + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip .and. debug_g == 1_pInt)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> dislocation multiplication', & + rhoDotMultiplication(1:ns,1:4) * timestep + write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation flux', & + rhoDotFlux(1:ns,1:8) * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> dipole formation by glide', & + rhoDotSingle2DipoleGlide * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> athermal dipole annihilation', & + rhoDotAthermalAnnihilation * timestep + write(6,'(a,/,2(12x,12(e12.5,1x),/))') '<< CONST >> thermally activated dipole annihilation', & + rhoDotThermalAnnihilation(1:ns,9:10) * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> total density change', & + rhoDot * timestep + write(6,'(a,/,10(12x,12(f12.5,1x),/))') '<< CONST >> relative density change', & + rhoDot(1:ns,1:8) * timestep / (abs(rhoSglOriginal)+1.0e-10), & + rhoDot(1:ns,9:10) * timestep / (rhoDipOriginal+1.0e-10) + write(6,*) + endif +#endif + + +if ( any(rhoSglOriginal(1:ns,1:4) + rhoDot(1:ns,1:4) * timestep < -aTolRho(instance)) & + .or. any(rhoDipOriginal(1:ns,1:2) + rhoDot(1:ns,9:10) * timestep < -aTolRho(instance))) then +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then + write(6,'(a,i5,a,i2)') '<< CONST >> evolution rate leads to negative density at el ',el,' ip ',ip + write(6,'(a)') '<< CONST >> enforcing cutback !!!' + endif +#endif + plasticState(p)%dotState = DAMASK_NaN + return +else + forall (s = 1:ns, t = 1_pInt:4_pInt) + plasticState(p)%dotState(iRhoU(s,t,instance),o) = rhoDot(s,t) + plasticState(p)%dotState(iRhoB(s,t,instance),o) = rhoDot(s,t+4_pInt) + endforall + forall (s = 1:ns, c = 1_pInt:2_pInt) & + plasticState(p)%dotState(iRhoD(s,c,instance),o) = rhoDot(s,c+8_pInt) + forall (s = 1:ns) & + plasticState(p)%dotState(iGamma(s,instance),o) = sum(gdot(s,1:4)) +endif + +end subroutine plastic_nonlocal_dotState + + +!********************************************************************* +!* COMPATIBILITY UPDATE * +!* Compatibility is defined as normalized product of signed cosine * +!* of the angle between the slip plane normals and signed cosine of * +!* the angle between the slip directions. Only the largest values * +!* that sum up to a total of 1 are considered, all others are set to * +!* zero. * +!********************************************************************* +subroutine plastic_nonlocal_updateCompatibility(orientation,i,e) + +use math, only: math_mul3x3, & + math_qRot +use material, only: material_phase, & + material_texture, & + phase_localPlasticity, & + phase_plasticityInstance, & + homogenization_maxNgrains +use mesh, only: mesh_element, & + mesh_ipNeighborhood, & + mesh_maxNips, & + mesh_NcpElems, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype +use lattice, only: lattice_sn, & + lattice_sd, & + lattice_qDisorientation + +implicit none + +!* input variables +integer(pInt), intent(in) :: i, & ! ip index + e ! element index +real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + orientation ! crystal orientation in quaternions + +!* local variables +integer(pInt) Nneighbors, & ! number of neighbors + n, & ! neighbor index + neighbor_e, & ! element index of my neighbor + neighbor_i, & ! integration point index of my neighbor + ph, & + neighbor_phase, & + textureID, & + neighbor_textureID, & + instance, & ! instance of plasticity + ns, & ! number of active slip systems + s1, & ! slip system index (me) + s2 ! slip system index (my neighbor) +real(pReal), dimension(4) :: absoluteMisorientation ! absolute misorientation (without symmetry) between me and my neighbor +real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& + totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& + FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e))))) :: & + my_compatibility ! my_compatibility for current element and ip +real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & + slipNormal, & + slipDirection +real(pReal) my_compatibilitySum, & + thresholdValue, & + nThresholdValues +logical, dimension(totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & + belowThreshold + + +Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) +ph = material_phase(1,i,e) +textureID = material_texture(1,i,e) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) +slipNormal(1:3,1:ns) = lattice_sn(1:3, slipSystemLattice(1:ns,instance), ph) +slipDirection(1:3,1:ns) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) + + +!*** start out fully compatible + +my_compatibility = 0.0_pReal +forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,1:Nneighbors) = 1.0_pReal + + +!*** Loop thrugh neighbors and check whether there is any my_compatibility. + +do n = 1_pInt,Nneighbors + neighbor_e = mesh_ipNeighborhood(1,n,i,e) + neighbor_i = mesh_ipNeighborhood(2,n,i,e) + + + !* FREE SURFACE + !* Set surface transmissivity to the value specified in the material.config + + if (neighbor_e <= 0_pInt .or. neighbor_i <= 0_pInt) then + forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,n) = sqrt(surfaceTransmissivity(instance)) + cycle + endif + + + !* PHASE BOUNDARY + !* If we encounter a different nonlocal "cpfem" phase at the neighbor, + !* we consider this to be a real "physical" phase boundary, so completely incompatible. + !* If one of the two "CPFEM" phases has a local plasticity law, + !* we do not consider this to be a phase boundary, so completely compatible. + + neighbor_phase = material_phase(1,neighbor_i,neighbor_e) + if (neighbor_phase /= ph) then + if (.not. phase_localPlasticity(neighbor_phase) .and. .not. phase_localPlasticity(ph)) then + forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,n) = 0.0_pReal ! = sqrt(0.0) + endif + cycle + endif + + + !* GRAIN BOUNDARY ! + !* fixed transmissivity for adjacent ips with different texture (only if explicitly given in material.config) + + if (grainboundaryTransmissivity(instance) >= 0.0_pReal) then + neighbor_textureID = material_texture(1,neighbor_i,neighbor_e) + if (neighbor_textureID /= textureID) then + if (.not. phase_localPlasticity(neighbor_phase)) then + forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,n) = sqrt(grainboundaryTransmissivity(instance)) + endif + cycle + endif + + + !* GRAIN BOUNDARY ? + !* Compatibility defined by relative orientation of slip systems: + !* The my_compatibility value is defined as the product of the slip normal projection and the slip direction projection. + !* Its sign is always positive for screws, for edges it has the same sign as the slip normal projection. + !* Since the sum for each slip system can easily exceed one (which would result in a transmissivity larger than one), + !* only values above or equal to a certain threshold value are considered. This threshold value is chosen, such that + !* the number of compatible slip systems is minimized with the sum of the original my_compatibility values exceeding one. + !* Finally the smallest my_compatibility value is decreased until the sum is exactly equal to one. + !* All values below the threshold are set to zero. + else + absoluteMisorientation = lattice_qDisorientation(orientation(1:4,1,i,e), & + orientation(1:4,1,neighbor_i,neighbor_e)) ! no symmetry + do s1 = 1_pInt,ns ! my slip systems + do s2 = 1_pInt,ns ! my neighbor's slip systems + my_compatibility(1,s2,s1,n) = math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2))) & + * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) + my_compatibility(2,s2,s1,n) = abs(math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2)))) & + * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) + enddo + + my_compatibilitySum = 0.0_pReal + belowThreshold = .true. + do while (my_compatibilitySum < 1.0_pReal .and. any(belowThreshold(1:ns))) + thresholdValue = maxval(my_compatibility(2,1:ns,s1,n), belowThreshold(1:ns)) ! screws always positive + nThresholdValues = real(count(my_compatibility(2,1:ns,s1,n) == thresholdValue),pReal) + where (my_compatibility(2,1:ns,s1,n) >= thresholdValue) & + belowThreshold(1:ns) = .false. + if (my_compatibilitySum + thresholdValue * nThresholdValues > 1.0_pReal) & + where (abs(my_compatibility(1:2,1:ns,s1,n)) == thresholdValue) & ! MD: rather check below threshold? + my_compatibility(1:2,1:ns,s1,n) = sign((1.0_pReal - my_compatibilitySum) & + / nThresholdValues, my_compatibility(1:2,1:ns,s1,n)) + my_compatibilitySum = my_compatibilitySum + nThresholdValues * thresholdValue + enddo + where (belowThreshold(1:ns)) my_compatibility(1,1:ns,s1,n) = 0.0_pReal + where (belowThreshold(1:ns)) my_compatibility(2,1:ns,s1,n) = 0.0_pReal + enddo ! my slip systems cycle + endif + +enddo ! neighbor cycle + +compatibility(1:2,1:ns,1:ns,1:Nneighbors,i,e) = my_compatibility + +end subroutine plastic_nonlocal_updateCompatibility + +!********************************************************************* +!* calculates quantities characterizing the microstructure * +!********************************************************************* +function plastic_nonlocal_dislocationstress(Fe, ip, el) +use math, only: math_mul33x33, & + math_mul33x3, & + math_inv33, & + math_transpose33, & + pi +use mesh, only: mesh_NcpElems, & + mesh_maxNips, & + mesh_element, & + mesh_node0, & + mesh_cellCenterCoordinates, & + mesh_ipVolume, & + mesh_periodicSurface, & + FE_Nips, & + FE_geomtype +use material, only: homogenization_maxNgrains, & + material_phase, & + plasticState, & + phaseAt, phasememberAt,& + phase_localPlasticity, & + phase_plasticityInstance +use lattice, only: lattice_mu, & + lattice_nu + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el !< current element +real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + Fe !< elastic deformation gradient + +!*** output variables +real(pReal), dimension(3,3) :: plastic_nonlocal_dislocationstress + +!*** local variables +integer(pInt) neighbor_el, & !< element number of neighbor material point + neighbor_ip, & !< integration point of neighbor material point + instance, & !< my instance of this plasticity + neighbor_instance, & !< instance of this plasticity of neighbor material point + ph, & + neighbor_phase, & + ns, & !< total number of active slip systems at my material point + neighbor_ns, & !< total number of active slip systems at neighbor material point + c, & !< index of dilsocation character (edge, screw) + s, & !< slip system index + o,& !< offset shortcut + no,& !< neighbour offset shortcut + p,& !< phase shortcut + np,& !< neighbour phase shortcut + t, & !< index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) + dir, & + deltaX, deltaY, deltaZ, & + side, & + j +integer(pInt), dimension(2,3) :: periodicImages +real(pReal) x, y, z, & !< coordinates of connection vector in neighbor lattice frame + xsquare, ysquare, zsquare, & !< squares of respective coordinates + distance, & !< length of connection vector + segmentLength, & !< segment length of dislocations + lambda, & + R, Rsquare, Rcube, & + denominator, & + flipSign, & + neighbor_ipVolumeSideLength +real(pReal), dimension(3) :: connection, & !< connection vector between me and my neighbor in the deformed configuration + connection_neighborLattice, & !< connection vector between me and my neighbor in the lattice configuration of my neighbor + connection_neighborSlip, & !< connection vector between me and my neighbor in the slip system frame of my neighbor + maxCoord, minCoord, & + meshSize, & + coords, & !< x,y,z coordinates of cell center of ip volume + neighbor_coords !< x,y,z coordinates of cell center of neighbor ip volume +real(pReal), dimension(3,3) :: sigma, & !< dislocation stress for one slip system in neighbor material point's slip system frame + Tdislo_neighborLattice, & !< dislocation stress as 2nd Piola-Kirchhoff stress at neighbor material point + invFe, & !< inverse of my elastic deformation gradient + neighbor_invFe, & + neighborLattice2myLattice !< mapping from neighbor MPs lattice configuration to my lattice configuration +real(pReal), dimension(2,2,maxval(totalNslip)) :: & + neighbor_rhoExcess !< excess density at neighbor material point (edge/screw,mobile/dead,slipsystem) +real(pReal), dimension(2,maxval(totalNslip)) :: & + rhoExcessDead +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) + +ph = material_phase(1_pInt,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) +p = phaseAt(1,ip,el) +o = phasememberAt(1,ip,el) + +!*** get basic states + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) +endforall + + + +!*** calculate the dislocation stress of the neighboring excess dislocation densities +!*** zero for material points of local plasticity + +plastic_nonlocal_dislocationstress = 0.0_pReal + +if (.not. phase_localPlasticity(ph)) then + invFe = math_inv33(Fe(1:3,1:3,1_pInt,ip,el)) + + !* in case of periodic surfaces we have to find out how many periodic images in each direction we need + + do dir = 1_pInt,3_pInt + maxCoord(dir) = maxval(mesh_node0(dir,:)) + minCoord(dir) = minval(mesh_node0(dir,:)) + enddo + meshSize = maxCoord - minCoord + coords = mesh_cellCenterCoordinates(ip,el) + periodicImages = 0_pInt + do dir = 1_pInt,3_pInt + if (mesh_periodicSurface(dir)) then + periodicImages(1,dir) = floor((coords(dir) - cutoffRadius(instance) - minCoord(dir)) / meshSize(dir), pInt) + periodicImages(2,dir) = ceiling((coords(dir) + cutoffRadius(instance) - maxCoord(dir)) / meshSize(dir), pInt) + endif + enddo + + + !* loop through all material points (also through their periodic images if present), + !* but only consider nonlocal neighbors within a certain cutoff radius R + + do neighbor_el = 1_pInt,mesh_NcpElems + ipLoop: do neighbor_ip = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,neighbor_el))) + neighbor_phase = material_phase(1_pInt,neighbor_ip,neighbor_el) + np = phaseAt(1,neighbor_ip,neighbor_el) + no = phasememberAt(1,neighbor_ip,neighbor_el) + + if (phase_localPlasticity(neighbor_phase)) cycle + neighbor_instance = phase_plasticityInstance(neighbor_phase) + neighbor_ns = totalNslip(neighbor_instance) + neighbor_invFe = math_inv33(Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) + neighbor_ipVolumeSideLength = mesh_ipVolume(neighbor_ip,neighbor_el) ** (1.0_pReal/3.0_pReal) ! reference volume used here + + forall (s = 1_pInt:neighbor_ns, c = 1_pInt:2_pInt) + neighbor_rhoExcess(c,1,s) = plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no) & ! positive mobiles + - plasticState(np)%state(iRhoU(s,2*c,neighbor_instance),no) ! negative mobiles + neighbor_rhoExcess(c,2,s) = abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads + - abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance),no)) ! negative deads + + endforall + Tdislo_neighborLattice = 0.0_pReal + do deltaX = periodicImages(1,1),periodicImages(2,1) + do deltaY = periodicImages(1,2),periodicImages(2,2) + do deltaZ = periodicImages(1,3),periodicImages(2,3) + + + !* regular case + + if (neighbor_el /= el .or. neighbor_ip /= ip & + .or. deltaX /= 0_pInt .or. deltaY /= 0_pInt .or. deltaZ /= 0_pInt) then + + neighbor_coords = mesh_cellCenterCoordinates(neighbor_ip,neighbor_el) & + + [real(deltaX,pReal), real(deltaY,pReal), real(deltaZ,pReal)] * meshSize + connection = neighbor_coords - coords + distance = sqrt(sum(connection * connection)) + if (distance > cutoffRadius(instance)) cycle + + + !* the segment length is the minimum of the third root of the control volume and the ip distance + !* this ensures, that the central MP never sits on a neighbor dislocation segment + + connection_neighborLattice = math_mul33x3(neighbor_invFe, connection) + segmentLength = min(neighbor_ipVolumeSideLength, distance) + + + !* loop through all slip systems of the neighbor material point + !* and add up the stress contributions from egde and screw excess on these slip systems (if significant) + + do s = 1_pInt,neighbor_ns + if (all(abs(neighbor_rhoExcess(:,:,s)) < significantRho(instance))) cycle ! not significant + + + !* map the connection vector from the lattice into the slip system frame + + connection_neighborSlip = math_mul33x3(lattice2slip(1:3,1:3,s,neighbor_instance), & + connection_neighborLattice) + + + !* edge contribution to stress + sigma = 0.0_pReal + + x = connection_neighborSlip(1) + y = connection_neighborSlip(2) + z = connection_neighborSlip(3) + xsquare = x * x + ysquare = y * y + zsquare = z * z + + do j = 1_pInt,2_pInt + if (abs(neighbor_rhoExcess(1,j,s)) < significantRho(instance)) then + cycle + elseif (j > 1_pInt) then + x = connection_neighborSlip(1) & + + sign(0.5_pReal * segmentLength, & + plasticState(np)%state(iRhoB(s,1,neighbor_instance),no) & + - plasticState(np)%state(iRhoB(s,2,neighbor_instance),no)) + + xsquare = x * x + endif + + flipSign = sign(1.0_pReal, -y) + do side = 1_pInt,-1_pInt,-2_pInt + lambda = real(side,pReal) * 0.5_pReal * segmentLength - y + R = sqrt(xsquare + zsquare + lambda * lambda) + Rsquare = R * R + Rcube = Rsquare * R + denominator = R * (R + flipSign * lambda) + if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop + + sigma(1,1) = sigma(1,1) - real(side,pReal) & + * flipSign * z / denominator & + * (1.0_pReal + xsquare / Rsquare + xsquare / denominator) & + * neighbor_rhoExcess(1,j,s) + sigma(2,2) = sigma(2,2) - real(side,pReal) & + * (flipSign * 2.0_pReal * lattice_nu(ph) * z / denominator + z * lambda / Rcube) & + * neighbor_rhoExcess(1,j,s) + sigma(3,3) = sigma(3,3) + real(side,pReal) & + * flipSign * z / denominator & + * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & + * neighbor_rhoExcess(1,j,s) + sigma(1,2) = sigma(1,2) + real(side,pReal) & + * x * z / Rcube * neighbor_rhoExcess(1,j,s) + sigma(1,3) = sigma(1,3) + real(side,pReal) & + * flipSign * x / denominator & + * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & + * neighbor_rhoExcess(1,j,s) + sigma(2,3) = sigma(2,3) - real(side,pReal) & + * (lattice_nu(ph) / R - zsquare / Rcube) * neighbor_rhoExcess(1,j,s) + enddo + enddo + + !* screw contribution to stress + + x = connection_neighborSlip(1) ! have to restore this value, because position might have been adapted for edge deads before + do j = 1_pInt,2_pInt + if (abs(neighbor_rhoExcess(2,j,s)) < significantRho(instance)) then + cycle + elseif (j > 1_pInt) then + y = connection_neighborSlip(2) & + + sign(0.5_pReal * segmentLength, & + plasticState(np)%state(iRhoB(s,3,neighbor_instance),no) & + - plasticState(np)%state(iRhoB(s,4,neighbor_instance),no)) + ysquare = y * y + endif + + flipSign = sign(1.0_pReal, x) + do side = 1_pInt,-1_pInt,-2_pInt + lambda = x + real(side,pReal) * 0.5_pReal * segmentLength + R = sqrt(ysquare + zsquare + lambda * lambda) + Rsquare = R * R + Rcube = Rsquare * R + denominator = R * (R + flipSign * lambda) + if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop + + sigma(1,2) = sigma(1,2) - real(side,pReal) * flipSign * z & + * (1.0_pReal - lattice_nu(ph)) / denominator & + * neighbor_rhoExcess(2,j,s) + sigma(1,3) = sigma(1,3) + real(side,pReal) * flipSign * y & + * (1.0_pReal - lattice_nu(ph)) / denominator & + * neighbor_rhoExcess(2,j,s) + enddo + enddo + + if (all(abs(sigma) < 1.0e-10_pReal)) cycle ! SIGMA IS NOT A REAL STRESS, THATS WHY WE NEED A REALLY SMALL VALUE HERE + + !* copy symmetric parts + + sigma(2,1) = sigma(1,2) + sigma(3,1) = sigma(1,3) + sigma(3,2) = sigma(2,3) + + + !* scale stresses and map them into the neighbor material point's lattice configuration + + sigma = sigma * lattice_mu(neighbor_phase) * burgers(s,neighbor_instance) & + / (4.0_pReal * pi * (1.0_pReal - lattice_nu(neighbor_phase))) & + * mesh_ipVolume(neighbor_ip,neighbor_el) / segmentLength ! reference volume is used here (according to the segment length calculation) + Tdislo_neighborLattice = Tdislo_neighborLattice & + + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,neighbor_instance)), & + math_mul33x33(sigma, lattice2slip(1:3,1:3,s,neighbor_instance))) + + enddo ! slip system loop + + + !* special case of central ip volume + !* only consider dead dislocations + !* we assume that they all sit at a distance equal to half the third root of V + !* in direction of the according slip direction + + else + + forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & + + rhoExcessDead(c,s) = plasticState(p)%state(iRhoB(s,2*c-1,instance),o) & ! positive deads (here we use symmetry: if this has negative sign it is + !treated as negative density at positive position instead of positive + !density at negative position) + + plasticState(p)%state(iRhoB(s,2*c,instance),o) ! negative deads (here we use symmetry: if this has negative sign it is + !treated as positive density at positive position instead of negative + !density at negative position) + do s = 1_pInt,ns + if (all(abs(rhoExcessDead(:,s)) < significantRho(instance))) cycle ! not significant + sigma = 0.0_pReal ! all components except for sigma13 are zero + sigma(1,3) = - (rhoExcessDead(1,s) + rhoExcessDead(2,s) * (1.0_pReal - lattice_nu(ph))) & + * neighbor_ipVolumeSideLength * lattice_mu(ph) * burgers(s,instance) & + / (sqrt(2.0_pReal) * pi * (1.0_pReal - lattice_nu(ph))) + sigma(3,1) = sigma(1,3) + + Tdislo_neighborLattice = Tdislo_neighborLattice & + + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,instance)), & + math_mul33x33(sigma, lattice2slip(1:3,1:3,s,instance))) + + enddo ! slip system loop + + endif + + enddo ! deltaZ loop + enddo ! deltaY loop + enddo ! deltaX loop + + + !* map the stress from the neighbor MP's lattice configuration into the deformed configuration + !* and back into my lattice configuration + + neighborLattice2myLattice = math_mul33x33(invFe, Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) + plastic_nonlocal_dislocationstress = plastic_nonlocal_dislocationstress & + + math_mul33x33(neighborLattice2myLattice, & + math_mul33x33(Tdislo_neighborLattice, & + math_transpose33(neighborLattice2myLattice))) + + enddo ipLoop + enddo ! element loop + +endif + +end function plastic_nonlocal_dislocationstress + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_nonlocal_postResults(Tstar_v,Fe,ip,el) + use math, only: & + math_mul6x6, & + math_mul33x3, & + math_mul33x33, & + pi + use mesh, only: & + mesh_NcpElems, & + mesh_maxNips + use material, only: & + homogenization_maxNgrains, & + material_phase, & + phaseAt, phasememberAt, & + plasticState, & + phase_plasticityInstance + use lattice, only: & + lattice_Sslip_v, & + lattice_sd, & + lattice_st, & + lattice_sn, & + lattice_mu, & + lattice_nu + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + Fe !< elastic deformation gradient + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + + real(pReal), dimension(plastic_nonlocal_sizePostResults(& + phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + plastic_nonlocal_postResults + + integer(pInt) :: & + ph, & + instance, & !< current instance of this plasticity + ns, & !< short notation for the total number of active slip systems + c, & !< character of dislocation + cs, & !< constitutive result index + o, & !< index of current output + of,& !< offset shortcut + t, & !< type of dislocation + s, & !< index of my current slip system + sLattice !< index of my current slip system according to lattice order + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) + rhoDotSgl !< evolution rate of single dislocation densities (positive/negative screw and edge without dipoles) + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + gdot, & !< shear rates + v !< velocities + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoForest, & !< forest dislocation density + tauThreshold, & !< threshold shear stress + tau, & !< current resolved shear stress + tauBack !< back stress from pileups on same slip system + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) + rhoDotDip, & !< evolution rate of dipole dislocation densities (screw and edge dipoles) + dLower, & !< minimum stable dipole distance for edges and screws + dUpper !< current maximum stable dipole distance for edges and screws + real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + m, & !< direction of dislocation motion for edge and screw (unit vector) + m_currentconf !< direction of dislocation motion for edge and screw (unit vector) in current configuration + real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + n_currentconf !< slip system normal (unit vector) in current configuration + real(pReal), dimension(3,3) :: & + sigma + +ph = phaseAt(1,ip,el) +of = phasememberAt(1,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + +cs = 0_pInt +plastic_nonlocal_postResults = 0.0_pReal + + +!* short hand notations for state variables + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = plasticState(ph)%State(iRhoU(s,t,instance),of) + rhoSgl(s,t+4_pInt) = plasticState(ph)%State(iRhoB(s,t,instance),of) + v(s,t) = plasticState(ph)%State(iV(s,t,instance),of) + rhoDotSgl(s,t) = plasticState(ph)%dotState(iRhoU(s,t,instance),of) + rhoDotSgl(s,t+4_pInt) = plasticState(ph)%dotState(iRhoB(s,t,instance),of) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + rhoDip(s,c) = plasticState(ph)%State(iRhoD(s,c,instance),of) + rhoDotDip(s,c) = plasticState(ph)%dotState(iRhoD(s,c,instance),of) +endforall +rhoForest = plasticState(ph)%State(iRhoF(1:ns,instance),of) +tauThreshold = plasticState(ph)%State(iTauF(1:ns,instance),of) +tauBack = plasticState(ph)%State(iTauB(1:ns,instance),of) + +!* Calculate shear rate + +forall (t = 1_pInt:4_pInt) & + gdot(1:ns,t) = rhoSgl(1:ns,t) * burgers(1:ns,instance) * v(1:ns,t) + + +!* calculate limits for stable dipole height + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) + if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal +enddo + +dLower = minDipoleHeight(1:ns,1:2,instance) +dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & + / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) +dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & + / (4.0_pReal * pi * abs(tau)) +forall (c = 1_pInt:2_pInt) + where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& + abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & + dUpper(1:ns,c)) +end forall +dUpper = max(dUpper,dLower) + + +!*** dislocation motion + +m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) +m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) +forall (c = 1_pInt:2_pInt, s = 1_pInt:ns) & + m_currentconf(1:3,s,c) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), m(1:3,s,c)) +forall (s = 1_pInt:ns) & + n_currentconf(1:3,s) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), & + lattice_sn(1:3,slipSystemLattice(s,instance),ph)) + + +outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) + select case(plastic_nonlocal_outputID(o,instance)) + case (rho_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) + sum(rhoDip,2) + cs = cs + ns + + case (rho_sgl_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) + cs = cs + ns + + case (rho_sgl_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,1:4)),2) + cs = cs + ns + + case (rho_sgl_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:8),2) + cs = cs + ns + + case (rho_dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDip,2) + cs = cs + ns + + case (rho_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1) + cs = cs + ns + + case (rho_sgl_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + cs = cs + ns + + case (rho_sgl_edge_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,1:2),2) + cs = cs + ns + + case (rho_sgl_edge_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:6),2) + cs = cs + ns + + case (rho_sgl_edge_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5)) + cs = cs + ns + + case (rho_sgl_edge_pos_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) + cs = cs + ns + + case (rho_sgl_edge_pos_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,5) + cs = cs + ns + + case (rho_sgl_edge_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6)) + cs = cs + ns + + case (rho_sgl_edge_neg_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) + cs = cs + ns + + case (rho_sgl_edge_neg_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,6) + cs = cs + ns + + case (rho_dip_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,1) + cs = cs + ns + + case (rho_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2) + cs = cs + ns + + case (rho_sgl_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + cs = cs + ns + + case (rho_sgl_screw_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,3:4),2) + cs = cs + ns + + case (rho_sgl_screw_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,7:8),2) + cs = cs + ns + + case (rho_sgl_screw_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7)) + cs = cs + ns + + case (rho_sgl_screw_pos_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) + cs = cs + ns + + case (rho_sgl_screw_pos_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,7) + cs = cs + ns + + case (rho_sgl_screw_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8)) + cs = cs + ns + + case (rho_sgl_screw_neg_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) + cs = cs + ns + + case (rho_sgl_screw_neg_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,8) + cs = cs + ns + + case (rho_dip_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,2) + cs = cs + ns + + case (excess_rho_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & + - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) & + + (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & + - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) + cs = cs + ns + + case (excess_rho_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & + - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) + cs = cs + ns + + case (excess_rho_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & + - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) + cs = cs + ns + + case (rho_forest_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoForest + cs = cs + ns + + case (delta_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2) + sum(rhoDip,2)) + cs = cs + ns + + case (delta_sgl_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2)) + cs = cs + ns + + case (delta_dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(rhoDip,2)) + cs = cs + ns + + case (shearrate_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(gdot,2) + cs = cs + ns + + case (resolvedstress_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tau + cs = cs + ns + + case (resolvedstress_back_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauBack + cs = cs + ns + + case (resolvedstress_external_ID) + do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + plastic_nonlocal_postResults(cs+s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + enddo + cs = cs + ns + + case (resistance_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauThreshold + cs = cs + ns + + case (rho_dot_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & + + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) & + + sum(rhoDotDip,2) + cs = cs + ns + + case (rho_dot_sgl_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & + + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) + cs = cs + ns + + case (rho_dot_sgl_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) + cs = cs + ns + + case (rho_dot_dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotDip,2) + cs = cs + ns + + case (rho_dot_gen_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_gen_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_gen_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_sgl2dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_sgl2dip_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_sgl2dip_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_ath_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotAthermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotAthermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_the_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_the_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_the_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_edgejogs_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_flux_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) + cs = cs + ns + + case (rho_dot_flux_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) & + + sum(rhoDotFluxOutput(1:ns,5:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) + cs = cs + ns + + case (rho_dot_flux_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:2,1_pInt,ip,el),2) & + + sum(rhoDotFluxOutput(1:ns,5:6,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:6)),2) + cs = cs + ns + + case (rho_dot_flux_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,3:4,1_pInt,ip,el),2) & + + sum(rhoDotFluxOutput(1:ns,7:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,7:8)),2) + cs = cs + ns + + case (velocity_edge_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,1) + cs = cs + ns + + case (velocity_edge_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,2) + cs = cs + ns + + case (velocity_screw_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,3) + cs = cs + ns + + case (velocity_screw_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,4) + cs = cs + ns + + case (slipdirectionx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(1,1:ns,1) + cs = cs + ns + + case (slipdirectiony_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(2,1:ns,1) + cs = cs + ns + + case (slipdirectionz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(3,1:ns,1) + cs = cs + ns + + case (slipnormalx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(1,1:ns) + cs = cs + ns + + case (slipnormaly_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(2,1:ns) + cs = cs + ns + + case (slipnormalz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(3,1:ns) + cs = cs + ns + + case (fluxdensity_edge_posx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(1,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_posy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(2,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_posz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(3,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_negx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(1,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_negy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(2,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_negz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(3,1:ns,1) + cs = cs + ns + + case (fluxdensity_screw_posx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(1,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_posy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(2,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_posz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(3,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_negx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(1,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_negy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(2,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_negz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(3,1:ns,2) + cs = cs + ns + + case (maximumdipoleheight_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,1) + cs = cs + ns + + case (maximumdipoleheight_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,2) + cs = cs + ns + + case(dislocationstress_ID) + sigma = plastic_nonlocal_dislocationstress(Fe, ip, el) + plastic_nonlocal_postResults(cs+1_pInt) = sigma(1,1) + plastic_nonlocal_postResults(cs+2_pInt) = sigma(2,2) + plastic_nonlocal_postResults(cs+3_pInt) = sigma(3,3) + plastic_nonlocal_postResults(cs+4_pInt) = sigma(1,2) + plastic_nonlocal_postResults(cs+5_pInt) = sigma(2,3) + plastic_nonlocal_postResults(cs+6_pInt) = sigma(3,1) + cs = cs + 6_pInt + + case(accumulatedshear_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = plasticState(ph)%state(iGamma(1:ns,instance),of) + cs = cs + ns + + end select +enddo outputsLoop + +end function plastic_nonlocal_postResults + +end module plastic_nonlocal diff --git a/code/plastic_phenoplus.f90 b/code/plastic_phenoplus.f90 new file mode 100644 index 000000000..0a40edd84 --- /dev/null +++ b/code/plastic_phenoplus.f90 @@ -0,0 +1,1419 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Chen Zhang, Michigan State University +!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw +!... fitting +!-------------------------------------------------------------------------------------------------- +module plastic_phenoplus + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenoplus_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_phenoplus_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_phenoplus_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_phenoplus_Noutput !< number of outputs per instance of this constitution + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenoplus_totalNslip, & !< no. of slip system used in simulation + plastic_phenoplus_totalNtwin, & !< no. of twin system used in simulation + plastic_phenoplus_totalNtrans !< no. of trans system used in simulation + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_phenoplus_Nslip, & !< active number of slip systems per family (input parameter, per family) + plastic_phenoplus_Ntwin, & !< active number of twin systems per family (input parameter, per family) + plastic_phenoplus_Ntrans !< active number of trans systems per family (input parameter, per family) + + real(pReal), dimension(:), allocatable, private :: & + plastic_phenoplus_gdot0_slip, & !< reference shear strain rate for slip (input parameter) + plastic_phenoplus_gdot0_twin, & !< reference shear strain rate for twin (input parameter) + plastic_phenoplus_n_slip, & !< stress exponent for slip (input parameter) + plastic_phenoplus_n_twin, & !< stress exponent for twin (input parameter) + plastic_phenoplus_spr, & !< push-up factor for slip saturation due to twinning + plastic_phenoplus_twinB, & + plastic_phenoplus_twinC, & + plastic_phenoplus_twinD, & + plastic_phenoplus_twinE, & + plastic_phenoplus_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) + plastic_phenoplus_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) + plastic_phenoplus_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) + plastic_phenoplus_a_slip, & + plastic_phenoplus_aTolResistance, & + plastic_phenoplus_aTolShear, & + plastic_phenoplus_aTolTwinfrac, & + plastic_phenoplus_aTolTransfrac, & + plastic_phenoplus_Cnuc, & !< coefficient for strain-induced martensite nucleation + plastic_phenoplus_Cdwp, & !< coefficient for double well potential + plastic_phenoplus_Cgro, & !< coefficient for stress-assisted martensite growth + plastic_phenoplus_deltaG, & !< free energy difference between austensite and martensite [MPa] + plastic_phenoplus_kappa_max !< capped kappa for each slip system + + real(pReal), dimension(:,:), allocatable, private :: & + plastic_phenoplus_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) + plastic_phenoplus_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) + plastic_phenoplus_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) + plastic_phenoplus_nonSchmidCoeff, & + + plastic_phenoplus_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) + plastic_phenoplus_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) + plastic_phenoplus_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) + plastic_phenoplus_interaction_TwinTwin !< interaction factors twin - twin (input parameter) + + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_phenoplus_hardeningMatrix_SlipSlip, & + plastic_phenoplus_hardeningMatrix_SlipTwin, & + plastic_phenoplus_hardeningMatrix_TwinSlip, & + plastic_phenoplus_hardeningMatrix_TwinTwin + + enum, bind(c) + enumerator :: undefined_ID, & + resistance_slip_ID, & + accumulatedshear_slip_ID, & + shearrate_slip_ID, & + resolvedstress_slip_ID, & + kappa_slip_ID, & + totalshear_ID, & + resistance_twin_ID, & + accumulatedshear_twin_ID, & + shearrate_twin_ID, & + resolvedstress_twin_ID, & + totalvolfrac_twin_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_phenoplus_outputID !< ID of each post result output + + public :: & + plastic_phenoplus_init, & + plastic_phenoplus_microstructure, & + plastic_phenoplus_LpAndItsTangent, & + plastic_phenoplus_dotState, & + plastic_phenoplus_postResults + private :: & + plastic_phenoplus_aTolState, & + plastic_phenoplus_stateInit + + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_PHENOPLUS_label, & + PLASTICITY_PHENOPLUS_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + maxNinstance, & + instance,phase,j,k, f,o, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & + Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & + NipcMyPhase, & + offset_slip, index_myFamily, index_otherFamily, & + mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPLUS_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPLUS_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_phenoplus_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_sizePostResult(maxval(phase_Noutput),maxNinstance), & + source=0_pInt) + allocate(plastic_phenoplus_output(maxval(phase_Noutput),maxNinstance)) + plastic_phenoplus_output = '' + allocate(plastic_phenoplus_outputID(maxval(phase_Noutput),maxNinstance),source=undefined_ID) + allocate(plastic_phenoplus_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_Ntrans(lattice_maxNtransFamily,maxNinstance),source=0_pInt) + allocate(plastic_phenoplus_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_totalNtrans(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_gdot0_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_n_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_tau0_slip(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_tausat_slip(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_gdot0_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_n_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_tau0_twin(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_spr(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinB(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinC(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinD(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinE(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_h0_SlipSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_h0_TwinSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_h0_TwinTwin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_a_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolShear(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolTwinfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolTransfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_Cnuc(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_Cdwp(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_Cgro(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_deltaG(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_kappa_max(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase + Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('resistance_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_slip','accumulated_shear_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('kappa_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = kappa_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalshear') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalshear_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_twin','accumulated_shear_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalvolfrac_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalvolfrac_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case default + + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) + do j = 1_pInt, Nchunks_SlipFamilies + plastic_phenoplus_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tausat_slip','tau0_slip') + tempPerSlip = 0.0_pReal + do j = 1_pInt, Nchunks_SlipFamilies + if (plastic_phenoplus_Nslip(j,instance) > 0_pInt) & + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('tausat_slip') + plastic_phenoplus_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau0_slip') + plastic_phenoplus_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_phenoplus_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0_twin') + do j = 1_pInt, Nchunks_TwinFamilies + if (plastic_phenoplus_Ntwin(j,instance) > 0_pInt) & + plastic_phenoplus_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of transformation families + case ('ntrans') + if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + Nchunks_TransFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TransFamilies + plastic_phenoplus_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_phenoplus_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_phenoplus_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_phenoplus_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_phenoplus_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt,Nchunks_nonSchmid + plastic_phenoplus_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin systems + case ('gdot0_slip') + plastic_phenoplus_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_slip') + plastic_phenoplus_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('a_slip', 'w0_slip') + plastic_phenoplus_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('gdot0_twin') + plastic_phenoplus_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_twin') + plastic_phenoplus_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('s_pr') + plastic_phenoplus_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_b') + plastic_phenoplus_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_c') + plastic_phenoplus_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_d') + plastic_phenoplus_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_e') + plastic_phenoplus_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_slipslip') + plastic_phenoplus_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twinslip') + plastic_phenoplus_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twintwin') + plastic_phenoplus_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_resistance') + plastic_phenoplus_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_shear') + plastic_phenoplus_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_phenoplus_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_transfrac') + plastic_phenoplus_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('kappa_max') + plastic_phenoplus_kappa_max(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cnuc') + plastic_phenoplus_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cdwp') + plastic_phenoplus_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cgro') + plastic_phenoplus_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('deltag') + plastic_phenoplus_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) + case default + + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then + instance = phase_plasticityInstance(phase) + plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested + plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance)) + plastic_phenoplus_Ntwin(1:lattice_maxNtwinFamily,instance) = & + min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested + plastic_phenoplus_Ntwin(:,instance)) + plastic_phenoplus_totalNslip(instance) = sum(plastic_phenoplus_Nslip(:,instance)) ! how many slip systems altogether + plastic_phenoplus_totalNtwin(instance) = sum(plastic_phenoplus_Ntwin(:,instance)) ! how many twin systems altogether + plastic_phenoplus_totalNtrans(instance) = sum(plastic_phenoplus_Ntrans(:,instance)) ! how many trans systems altogether + + if (any(plastic_phenoplus_tau0_slip(:,instance) < 0.0_pReal .and. & + plastic_phenoplus_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (plastic_phenoplus_gdot0_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (plastic_phenoplus_n_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (any(plastic_phenoplus_tausat_slip(:,instance) <= 0.0_pReal .and. & + plastic_phenoplus_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (any(abs(plastic_phenoplus_a_slip(instance)) <= tiny(0.0_pReal) .and. & + plastic_phenoplus_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (any(plastic_phenoplus_tau0_twin(:,instance) < 0.0_pReal .and. & + plastic_phenoplus_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPLUS_label//')') + if ( plastic_phenoplus_gdot0_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenoplus_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPLUS_label//')') + if ( plastic_phenoplus_n_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenoplus_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPLUS_label//')') + if (plastic_phenoplus_aTolResistance(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa + if (plastic_phenoplus_aTolShear(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenoplus_aTolTwinfrac(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenoplus_aTolTransfrac(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + allocate(plastic_phenoplus_hardeningMatrix_SlipSlip(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from slip activity + maxval(plastic_phenoplus_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_hardeningMatrix_SlipTwin(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from twin activity + maxval(plastic_phenoplus_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_hardeningMatrix_TwinSlip(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_phenoplus_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_hardeningMatrix_TwinTwin(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_phenoplus_totalNtwin),& + maxNinstance), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config + myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then ! only consider my phase + NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase + instance = phase_plasticityInstance(phase) ! which instance of my phase + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) + select case(plastic_phenoplus_outputID(o,instance)) + case(resistance_slip_ID, & + shearrate_slip_ID, & + accumulatedshear_slip_ID, & + resolvedstress_slip_ID, & + kappa_slip_ID & + ) + mySize = plastic_phenoplus_totalNslip(instance) + case(resistance_twin_ID, & + shearrate_twin_ID, & + accumulatedshear_twin_ID, & + resolvedstress_twin_ID & + ) + mySize = plastic_phenoplus_totalNtwin(instance) + case(totalshear_ID, & + totalvolfrac_twin_ID & + ) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_phenoplus_sizePostResult(o,instance) = mySize + plastic_phenoplus_sizePostResults(instance) = plastic_phenoplus_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = plastic_phenoplus_totalNslip(instance) & ! s_slip + + plastic_phenoplus_totalNtwin(instance) & ! s_twin + + 2_pInt & ! sum(gamma) + sum(f) + + plastic_phenoplus_totalNslip(instance) & ! accshear_slip + + plastic_phenoplus_totalNtwin(instance) & ! accshear_twin + + plastic_phenoplus_totalNslip(instance) ! kappa + + !sizeDotState = sizeState ! same as sizeState + !QUICK FIX: the dotState cannot have redundancy, which could cause unknown error + ! explicitly specify the size of the dotState to avoid this potential + ! memory leak issue. + sizeDotState = plastic_phenoplus_totalNslip(instance) & ! s_slip + + plastic_phenoplus_totalNtwin(instance) & ! s_twin + + 2_pInt & ! sum(gamma) + sum(f) + + plastic_phenoplus_totalNslip(instance) & ! accshear_slip + + plastic_phenoplus_totalNtwin(instance) ! accshear_twin + + sizeDeltaState = 0_pInt + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_phenoplus_sizePostResults(instance) + plasticState(phase)%nSlip =plastic_phenoplus_totalNslip(instance) + plasticState(phase)%nTwin =plastic_phenoplus_totalNtwin(instance) + plasticState(phase)%nTrans=plastic_phenoplus_totalNtrans(instance) + allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) + + offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + + do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X + index_myFamily = sum(plastic_phenoplus_Nslip(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenoplus_Nslip(f,instance) ! loop over (active) systems in my family (slip) + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenoplus_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenoplus_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + + do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X + index_myFamily = sum(plastic_phenoplus_Ntwin(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenoplus_Ntwin(f,instance) ! loop over (active) systems in my family (twin) + + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenoplus_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenoplus_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + + call plastic_phenoplus_stateInit(phase,instance) + call plastic_phenoplus_aTolState(phase,instance) + endif myPhase2 + enddo initializeInstances + +end subroutine plastic_phenoplus_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_stateInit(ph,instance) + use lattice, only: & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + integer(pInt) :: & + i + real(pReal), dimension(plasticState(ph)%sizeState) :: & + tempState + + tempState = 0.0_pReal + do i = 1_pInt,lattice_maxNslipFamily + tempState(1+sum(plastic_phenoplus_Nslip(1:i-1,instance)) : & + sum(plastic_phenoplus_Nslip(1:i ,instance))) = & + plastic_phenoplus_tau0_slip(i,instance) + enddo + + do i = 1_pInt,lattice_maxNtwinFamily + tempState(1+sum(plastic_phenoplus_Nslip(:,instance))+& + sum(plastic_phenoplus_Ntwin(1:i-1,instance)) : & + sum(plastic_phenoplus_Nslip(:,instance))+& + sum(plastic_phenoplus_Ntwin(1:i ,instance))) = & + plastic_phenoplus_tau0_twin(i,instance) + enddo + + plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array + 2, & ! along dimension 2 + size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) + +end subroutine plastic_phenoplus_stateInit + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + plasticState(ph)%aTolState(1:plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance)) = & + plastic_phenoplus_aTolResistance(instance) + plasticState(ph)%aTolState(1+plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance)) = & + plastic_phenoplus_aTolShear(instance) + plasticState(ph)%aTolState(2+plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance)) = & + plastic_phenoplus_aTolTwinFrac(instance) + plasticState(ph)%aTolState(3+plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance): & + 2+2*(plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance))) = & + plastic_phenoplus_aTolShear(instance) + +end subroutine plastic_phenoplus_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate push-up factors (kappa) for each voxel based on its neighbors +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el) + use math, only: pi, & + math_mul33x33, & + math_mul3x3, & + math_transpose33, & + math_qDot, & + math_qRot, & + indeg + + use mesh, only: mesh_element, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype, & + mesh_maxNips, & + mesh_NcpElems, & + mesh_ipNeighborhood + + use material, only: material_phase, & + material_texture, & + phase_plasticityInstance, & + phaseAt, phasememberAt, & + homogenization_maxNgrains, & + plasticState + + use lattice, only: lattice_sn, & + lattice_sd, & + lattice_qDisorientation + + !***input variables + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + orientation ! crystal orientation in quaternions + + !***local variables + integer(pInt) instance, & !my instance of this plasticity + ph, & !my phase + of, & !my spatial position in memory (offset) + textureID, & !my texture + Nneighbors, & !number of neighbors (<= 6) + vld_Nneighbors, & !number of my valid neighbors + n, & !neighbor index (for iterating through all neighbors) + ns, & !number of slip system + nt, & !number of twin system + me_slip, & !my slip system index + neighbor_el, & !element number of neighboring material point + neighbor_ip, & !integration point of neighboring material point + neighbor_n, & !I have no idea what is this + neighbor_of, & !spatial position in memory for this neighbor (offset) + neighbor_ph, & !neighbor's phase + neighbor_tex, & !neighbor's texture ID + ne_slip_ac, & !loop to find neighbor shear + ne_slip, & !slip system index for neighbor + index_kappa, & !index of pushup factors in plasticState + offset_acshear_slip, & !offset in PlasticState for the accumulative shear + j !quickly loop through slip families + + real(pReal) kappa_max, & ! + tmp_myshear_slip, & !temp storage for accumulative shear for me + mprime_cut, & !m' cutoff to consider neighboring effect + avg_acshear_ne, & !the average accumulative shear from my neighbor + tmp_mprime, & !temp holder for m' value + tmp_acshear !temp holder for accumulative shear for m' + + + real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + m_primes, & !m' between me_alpha(one) and neighbor beta(all) + me_acshear, & !temp storage for ac_shear of one particular system for me + ne_acshear !temp storage for ac_shear of one particular system for one of my neighbor + + real(pReal), dimension(3,plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + slipNormal, & + slipDirect + + real(pReal), dimension(4) :: my_orientation, & !store my orientation + neighbor_orientation, & !store my neighbor orientation + absMisorientation + + real(pReal), dimension(FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) :: & + ne_mprimes !m' between each neighbor + + !***Get my properties + Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) + ph = phaseAt(ipc,ip,el) !get my phase + of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory + textureID = material_texture(1,ip,el) !get my texture ID + instance = phase_plasticityInstance(ph) !get my instance based on phase ID + ns = plastic_phenoplus_totalNslip(instance) + nt = plastic_phenoplus_totalNtwin(instance) + offset_acshear_slip = ns + nt + 2_pInt + index_kappa = ns + nt + 2_pInt + ns + nt !location of kappa in plasticState + mprime_cut = 0.7_pReal !set by Dr.Bieler + + !***gather my accumulative shear from palsticState + FINDMYSHEAR: do j = 1_pInt,ns + me_acshear(j) = plasticState(ph)%state(offset_acshear_slip+j, of) + enddo FINDMYSHEAR + + !***gather my orientation and slip systems + my_orientation = orientation(1:4, ipc, ip, el) + slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) + slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) + kappa_max = plastic_phenoplus_kappa_max(instance) !maximum pushups allowed (READIN) + + !***calculate kappa between me and all my neighbors + LOOPMYSLIP: DO me_slip=1_pInt,ns + vld_Nneighbors = Nneighbors + tmp_myshear_slip = me_acshear(me_slip) + tmp_mprime = 0.0_pReal !highest m' from all neighbors + tmp_acshear = 0.0_pReal !accumulative shear from highest m' + + !***go through my neighbors to find highest m' + LOOPNEIGHBORS: DO n=1_pInt,Nneighbors + neighbor_el = mesh_ipNeighborhood(1,n,ip,el) + neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) + neighbor_n = 1 !It is ipc + neighbor_of = phasememberAt( neighbor_n, neighbor_ip, neighbor_el) + neighbor_ph = phaseAt( neighbor_n, neighbor_ip, neighbor_el) + neighbor_tex = material_texture(1,neighbor_ip,neighbor_el) + neighbor_orientation = orientation(1:4, neighbor_n, neighbor_ip, neighbor_el) !ipc is always 1. + absMisorientation = lattice_qDisorientation(my_orientation, & + neighbor_orientation, & + 0_pInt) !no need for explicit calculation of symmetry + + !***find the accumulative shear for this neighbor + LOOPFINDNEISHEAR: DO ne_slip_ac=1_pInt, ns + ne_acshear(ne_slip_ac) = plasticState(ph)%state(offset_acshear_slip+ne_slip_ac, & + neighbor_of) + ENDDO LOOPFINDNEISHEAR + + !***calculate the average accumulative shear and use it as cutoff + avg_acshear_ne = SUM(ne_acshear)/ns + + !*** + IF (ph==neighbor_ph) THEN + !***walk through all the + LOOPNEIGHBORSLIP: DO ne_slip=1_pInt,ns + !***only consider slip system that is active (above average accumulative shear) + IF (ne_acshear(ne_slip) > avg_acshear_ne) THEN + m_primes(ne_slip) = abs(math_mul3x3(slipNormal(1:3,me_slip), & + math_qRot(absMisorientation, slipNormal(1:3,ne_slip)))) & + *abs(math_mul3x3(slipDirect(1:3,me_slip), & + math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) + !***find the highest m' and corresponding accumulative shear + IF (m_primes(ne_slip) > tmp_mprime) THEN + tmp_mprime = m_primes(ne_slip) + tmp_acshear = ne_acshear(ne_slip) + ENDIF + ENDIF + ENDDO LOOPNEIGHBORSLIP + + ELSE + ne_mprimes(n) = 0.0_pReal + vld_Nneighbors = vld_Nneighbors - 1_pInt + ENDIF + + ENDDO LOOPNEIGHBORS + + !***check if this element close to rim + IF (vld_Nneighbors < Nneighbors) THEN + !***rim voxel, no modification allowed + plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal + ELSE + !***patch voxel, started to calculate push up factor for gamma_dot + IF ((tmp_mprime > mprime_cut) .AND. (tmp_acshear > tmp_myshear_slip)) THEN + plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal / tmp_mprime + ELSE + !***minimum damping factor is 0.5 + plasticState(ph)%state(index_kappa+me_slip, of) = 0.5_pReal + tmp_mprime * 0.5_pReal + ENDIF + ENDIF + + ENDDO LOOPMYSLIP + +end subroutine plastic_phenoplus_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use math, only: & + math_Plain3333to99, & + math_Mandel6to33 + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + use material, only: & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + + integer(pInt) :: & + instance, & + nSlip, & + nTwin,index_Gamma,index_F,index_myFamily, index_kappa, & + f,i,j,k,l,m,n, & + of, & + ph + real(pReal) :: & + tau_slip_pos,tau_slip_neg, & + gdot_slip_pos,gdot_slip_neg, & + dgdot_dtauslip_pos,dgdot_dtauslip_neg, & + gdot_twin,dgdot_dtautwin,tau_twin + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal), dimension(3,3,2) :: & + nonSchmid_tensor + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + nSlip = plastic_phenoplus_totalNslip(instance) + nTwin = plastic_phenoplus_totalNtwin(instance) + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + index_kappa = nSlip + nTwin + 2_pInt +nSlip + nTwin + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Slip part + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) + enddo + + !***insert non-local effect here by modify gdot with kappa in plastic state + !***this implementation will most likely cause convergence issue + ! gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ! ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of)* & + ! plasticState(ph)%state(j+index_kappa, of))) & !in-place modification of gdot + ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) + + ! gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ! ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of)* & + ! plasticState(ph)%state(j+index_kappa, of))) & !?should we make it direction aware + ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) + + !***original calculation + gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of))) & !in-place modification of gdot + **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) + + gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of))) & !?should we make it direction aware + **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) + + !***MAGIC HERE***! + !***directly modify the amount of shear happens considering neighborhood + gdot_slip_pos = gdot_slip_pos * plasticState(ph)%state(j+index_kappa, of) + gdot_slip_neg = gdot_slip_neg * plasticState(ph)%state(j+index_kappa, of) + + Lp = Lp + (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then + dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenoplus_n_slip(instance)/tau_slip_pos + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,1) + endif + + if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then + dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenoplus_n_slip(instance)/tau_slip_neg + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,2) + endif + enddo slipSystems + enddo slipFamilies + +!-------------------------------------------------------------------------------------------------- +! Twinning part + j = 0_pInt + twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenoplus_gdot0_twin(instance)*& + (abs(tau_twin)/plasticState(ph)%state(nSlip+j,of))**& + plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_twin) > tiny(0.0_pReal)) then + dgdot_dtautwin = gdot_twin*plastic_phenoplus_n_twin(instance)/tau_twin + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & + lattice_Stwin(m,n,index_myFamily+i,ph) + endif + enddo twinSystems + enddo twinFamilies + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + + +end subroutine plastic_phenoplus_LpAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_dotState(Tstar_v,ipc,ip,el) + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_shearTwin, & + lattice_NnonSchmid + use material, only: & + material_phase, & + phaseAt, phasememberAt, & + plasticState, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + integer(pInt) :: & + instance,ph, & + nSlip,nTwin, & + f,i,j,k, & + index_Gamma,index_F,index_myFamily,& + offset_accshear_slip,offset_accshear_twin, offset_kappa, & + of + real(pReal) :: & + c_SlipSlip,c_TwinSlip,c_TwinTwin, & + ssat_offset, & + tau_slip_pos,tau_slip_neg,tau_twin + + real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip + real(pReal), dimension(plastic_phenoplus_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenoplus_totalNslip(instance) + nTwin = plastic_phenoplus_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + offset_accshear_slip = nSlip + nTwin + 2_pInt + offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + offset_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin + plasticState(ph)%dotState(:,of) = 0.0_pReal + + +!-------------------------------------------------------------------------------------------------- +! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices + c_SlipSlip = plastic_phenoplus_h0_SlipSlip(instance)*& + (1.0_pReal + plastic_phenoplus_twinC(instance)*plasticState(ph)%state(index_F,of)**& + plastic_phenoplus_twinB(instance)) + c_TwinSlip = plastic_phenoplus_h0_TwinSlip(instance)*& + plasticState(ph)%state(index_Gamma,of)**plastic_phenoplus_twinE(instance) + c_TwinTwin = plastic_phenoplus_h0_TwinTwin(instance)*& + plasticState(ph)%state(index_F,of)**plastic_phenoplus_twinD(instance) + +!-------------------------------------------------------------------------------------------------- +! calculate left and right vectors and calculate dot gammas + ssat_offset = plastic_phenoplus_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j+1_pInt + left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part + left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part + !***original implementation + right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & + **plastic_phenoplus_a_slip(instance)& + *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) + !***modify a_slip to get nonlocal effect + ! right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & + ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & + ! **(plastic_phenoplus_a_slip(instance)*plasticState(ph)%state(j+offset_kappa, of))& + ! *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & + ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) + right_TwinSlip(j) = 1.0_pReal ! no system-dependent part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot gamma + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + gdot_slip(j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance) & + +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + enddo slipSystems1 + enddo slipFamilies1 + + + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j+1_pInt + left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part + left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part + right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part + right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot vol frac + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenoplus_gdot0_twin(instance)*& + (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& + plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + enddo twinSystems1 + enddo twinFamilies1 + +!-------------------------------------------------------------------------------------------------- +! calculate the overall hardening based on above + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j + c_SlipSlip * left_SlipSlip(j) * & + dot_product(plastic_phenoplus_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & + right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + dot_product(plastic_phenoplus_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & + right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & + abs(gdot_slip(j)) + plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) + enddo slipSystems2 + enddo slipFamilies2 + + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j + c_TwinSlip * left_TwinSlip(j) * & + dot_product(plastic_phenoplus_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & + right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + c_TwinTwin * left_TwinTwin(j) * & + dot_product(plastic_phenoplus_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & + right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 + plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & + gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) + plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) + enddo twinSystems2 + enddo twinFamilies2 + + +end subroutine plastic_phenoplus_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_phenoplus_postResults(Tstar_v,ipc,ip,el) + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + real(pReal), dimension(plastic_phenoplus_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_phenoplus_postResults + + integer(pInt) :: & + instance,ph, of, & + nSlip,nTwin, & + o,f,i,c,j,k, & + index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily,index_kappa + real(pReal) :: & + tau_slip_pos,tau_slip_neg,tau + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenoplus_totalNslip(instance) + nTwin = plastic_phenoplus_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + index_accshear_slip = nSlip + nTwin + 2_pInt + 1_pInt + index_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + 1_pInt + index_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin + 1_pInt + + plastic_phenoplus_postResults = 0.0_pReal + c = 0_pInt + + outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) + select case(plastic_phenoplus_outputID(o,instance)) + case (resistance_slip_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) + c = c + nSlip + + case (accumulatedshear_slip_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& + index_accshear_slip+nSlip-1_pInt,of) + c = c + nSlip + + case (shearrate_slip_ID) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j + 1_pInt + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo + plastic_phenoplus_postResults(c+j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance) & + +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + + enddo slipSystems1 + enddo slipFamilies1 + c = c + nSlip + + case (resolvedstress_slip_ID) + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j + 1_pInt + plastic_phenoplus_postResults(c+j) = & + dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + enddo slipSystems2 + enddo slipFamilies2 + c = c + nSlip + + case (kappa_slip_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = & + plasticState(ph)%state(index_kappa:index_kappa+nSlip-1_pInt,of) + c = c + nSlip + + case (totalshear_ID) + plastic_phenoplus_postResults(c+1_pInt) = & + plasticState(ph)%state(index_Gamma,of) + c = c + 1_pInt + + case (resistance_twin_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) + c = c + nTwin + + case (accumulatedshear_twin_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) + c = c + nTwin + + case (shearrate_twin_ID) + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j + 1_pInt + tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + plastic_phenoplus_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenoplus_gdot0_twin(instance)*& + (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& + plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) + enddo twinSystems1 + enddo twinFamilies1 + c = c + nTwin + + case (resolvedstress_twin_ID) + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j + 1_pInt + plastic_phenoplus_postResults(c+j) = & + dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + enddo twinSystems2 + enddo twinFamilies2 + c = c + nTwin + + case (totalvolfrac_twin_ID) + plastic_phenoplus_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) + c = c + 1_pInt + + end select + enddo outputsLoop + +end function plastic_phenoplus_postResults + +end module plastic_phenoplus diff --git a/code/plastic_phenopowerlaw.f90 b/code/plastic_phenopowerlaw.f90 new file mode 100644 index 000000000..1f8e16250 --- /dev/null +++ b/code/plastic_phenopowerlaw.f90 @@ -0,0 +1,1226 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw +!! fitting +!-------------------------------------------------------------------------------------------------- +module plastic_phenopowerlaw + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenopowerlaw_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_phenopowerlaw_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_phenopowerlaw_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_phenopowerlaw_Noutput !< number of outputs per instance of this constitution + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenopowerlaw_totalNslip, & !< no. of slip system used in simulation + plastic_phenopowerlaw_totalNtwin, & !< no. of twin system used in simulation + plastic_phenopowerlaw_totalNtrans !< no. of trans system used in simulation + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_phenopowerlaw_Nslip, & !< active number of slip systems per family (input parameter, per family) + plastic_phenopowerlaw_Ntwin, & !< active number of twin systems per family (input parameter, per family) + plastic_phenopowerlaw_Ntrans !< active number of trans systems per family (input parameter, per family) + + real(pReal), dimension(:), allocatable, private :: & + plastic_phenopowerlaw_gdot0_slip, & !< reference shear strain rate for slip (input parameter) + plastic_phenopowerlaw_gdot0_twin, & !< reference shear strain rate for twin (input parameter) + plastic_phenopowerlaw_n_slip, & !< stress exponent for slip (input parameter) + plastic_phenopowerlaw_n_twin, & !< stress exponent for twin (input parameter) + plastic_phenopowerlaw_spr, & !< push-up factor for slip saturation due to twinning + plastic_phenopowerlaw_twinB, & + plastic_phenopowerlaw_twinC, & + plastic_phenopowerlaw_twinD, & + plastic_phenopowerlaw_twinE, & + plastic_phenopowerlaw_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) + plastic_phenopowerlaw_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) + plastic_phenopowerlaw_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) + plastic_phenopowerlaw_a_slip, & + plastic_phenopowerlaw_aTolResistance, & + plastic_phenopowerlaw_aTolShear, & + plastic_phenopowerlaw_aTolTwinfrac, & + plastic_phenopowerlaw_aTolTransfrac, & + plastic_phenopowerlaw_Cnuc, & !< coefficient for strain-induced martensite nucleation + plastic_phenopowerlaw_Cdwp, & !< coefficient for double well potential + plastic_phenopowerlaw_Cgro, & !< coefficient for stress-assisted martensite growth + plastic_phenopowerlaw_deltaG !< free energy difference between austensite and martensite [MPa] + + real(pReal), dimension(:,:), allocatable, private :: & + plastic_phenopowerlaw_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) + plastic_phenopowerlaw_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) + plastic_phenopowerlaw_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) + plastic_phenopowerlaw_nonSchmidCoeff, & + + plastic_phenopowerlaw_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) + plastic_phenopowerlaw_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) + plastic_phenopowerlaw_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) + plastic_phenopowerlaw_interaction_TwinTwin !< interaction factors twin - twin (input parameter) + + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_phenopowerlaw_hardeningMatrix_SlipSlip, & + plastic_phenopowerlaw_hardeningMatrix_SlipTwin, & + plastic_phenopowerlaw_hardeningMatrix_TwinSlip, & + plastic_phenopowerlaw_hardeningMatrix_TwinTwin + + enum, bind(c) + enumerator :: undefined_ID, & + resistance_slip_ID, & + accumulatedshear_slip_ID, & + shearrate_slip_ID, & + resolvedstress_slip_ID, & + totalshear_ID, & + resistance_twin_ID, & + accumulatedshear_twin_ID, & + shearrate_twin_ID, & + resolvedstress_twin_ID, & + totalvolfrac_twin_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_phenopowerlaw_outputID !< ID of each post result output + + type, private :: tPhenopowerlawState + real(pReal), pointer, dimension(:,:) :: & + s_slip, & + s_twin, & + accshear_slip, & + accshear_twin + real(pReal), pointer, dimension(:) :: & + sumGamma, & + sumF + end type + + type(tPhenopowerlawState), allocatable, dimension(:), private :: & + dotState, & + state, & + state0 + + public :: & + plastic_phenopowerlaw_init, & + plastic_phenopowerlaw_LpAndItsTangent, & + plastic_phenopowerlaw_dotState, & + plastic_phenopowerlaw_postResults + private :: & + plastic_phenopowerlaw_aTolState, & + plastic_phenopowerlaw_stateInit + + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_PHENOPOWERLAW_label, & + PLASTICITY_PHENOPOWERLAW_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + maxNinstance, & + instance,phase,j,k, f,o, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & + Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & + NipcMyPhase, & + offset_slip, index_myFamily, index_otherFamily, & + mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState, & + startIndex, endIndex + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPOWERLAW_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPOWERLAW_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + + allocate(plastic_phenopowerlaw_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_sizePostResult(maxval(phase_Noutput),maxNinstance), & + source=0_pInt) + allocate(plastic_phenopowerlaw_output(maxval(phase_Noutput),maxNinstance)) + plastic_phenopowerlaw_output = '' + allocate(plastic_phenopowerlaw_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_phenopowerlaw_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_totalNtrans(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_gdot0_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_n_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_tau0_slip(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_tausat_slip(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_phenopowerlaw_gdot0_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_n_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_tau0_twin(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_spr(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinB(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinC(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinD(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinE(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_h0_SlipSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_h0_TwinSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_h0_TwinTwin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_a_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolShear(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolTwinfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolTransfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_Cnuc(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_Cdwp(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_Cgro(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_deltaG(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase + Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('resistance_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_slip','accumulated_shear_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalshear') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalshear_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_twin','accumulated_shear_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalvolfrac_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalvolfrac_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case default + + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) + do j = 1_pInt, Nchunks_SlipFamilies + plastic_phenopowerlaw_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tausat_slip','tau0_slip') + tempPerSlip = 0.0_pReal + do j = 1_pInt, Nchunks_SlipFamilies + if (plastic_phenopowerlaw_Nslip(j,instance) > 0_pInt) & + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('tausat_slip') + plastic_phenopowerlaw_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau0_slip') + plastic_phenopowerlaw_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_phenopowerlaw_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0_twin') + do j = 1_pInt, Nchunks_TwinFamilies + if (plastic_phenopowerlaw_Ntwin(j,instance) > 0_pInt) & + plastic_phenopowerlaw_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of transformation families + case ('ntrans') + if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + Nchunks_TransFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TransFamilies + plastic_phenopowerlaw_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_phenopowerlaw_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_phenopowerlaw_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_phenopowerlaw_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_phenopowerlaw_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt,Nchunks_nonSchmid + plastic_phenopowerlaw_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin systems + case ('gdot0_slip') + plastic_phenopowerlaw_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_slip') + plastic_phenopowerlaw_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('a_slip', 'w0_slip') + plastic_phenopowerlaw_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('gdot0_twin') + plastic_phenopowerlaw_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_twin') + plastic_phenopowerlaw_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('s_pr') + plastic_phenopowerlaw_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_b') + plastic_phenopowerlaw_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_c') + plastic_phenopowerlaw_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_d') + plastic_phenopowerlaw_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_e') + plastic_phenopowerlaw_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_slipslip') + plastic_phenopowerlaw_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twinslip') + plastic_phenopowerlaw_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twintwin') + plastic_phenopowerlaw_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_resistance') + plastic_phenopowerlaw_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_shear') + plastic_phenopowerlaw_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_phenopowerlaw_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_transfrac') + plastic_phenopowerlaw_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cnuc') + plastic_phenopowerlaw_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cdwp') + plastic_phenopowerlaw_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cgro') + plastic_phenopowerlaw_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('deltag') + plastic_phenopowerlaw_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) + case default + + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then + instance = phase_plasticityInstance(phase) + plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested + plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance)) + plastic_phenopowerlaw_Ntwin(1:lattice_maxNtwinFamily,instance) = & + min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested + plastic_phenopowerlaw_Ntwin(:,instance)) + plastic_phenopowerlaw_totalNslip(instance) = sum(plastic_phenopowerlaw_Nslip(:,instance)) ! how many slip systems altogether + plastic_phenopowerlaw_totalNtwin(instance) = sum(plastic_phenopowerlaw_Ntwin(:,instance)) ! how many twin systems altogether + plastic_phenopowerlaw_totalNtrans(instance) = sum(plastic_phenopowerlaw_Ntrans(:,instance)) ! how many trans systems altogether + + if (any(plastic_phenopowerlaw_tau0_slip(:,instance) < 0.0_pReal .and. & + plastic_phenopowerlaw_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (plastic_phenopowerlaw_gdot0_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (plastic_phenopowerlaw_n_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (any(plastic_phenopowerlaw_tausat_slip(:,instance) <= 0.0_pReal .and. & + plastic_phenopowerlaw_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (any(abs(plastic_phenopowerlaw_a_slip(instance)) <= tiny(0.0_pReal) .and. & + plastic_phenopowerlaw_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (any(plastic_phenopowerlaw_tau0_twin(:,instance) < 0.0_pReal .and. & + plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') + if ( plastic_phenopowerlaw_gdot0_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') + if ( plastic_phenopowerlaw_n_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (plastic_phenopowerlaw_aTolResistance(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa + if (plastic_phenopowerlaw_aTolShear(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenopowerlaw_aTolTwinfrac(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenopowerlaw_aTolTransfrac(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + allocate(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from slip activity + maxval(plastic_phenopowerlaw_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from twin activity + maxval(plastic_phenopowerlaw_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_phenopowerlaw_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_phenopowerlaw_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(state(maxNinstance)) + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config + myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then ! only consider my phase + NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase + instance = phase_plasticityInstance(phase) ! which instance of my phase + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) + select case(plastic_phenopowerlaw_outputID(o,instance)) + case(resistance_slip_ID, & + shearrate_slip_ID, & + accumulatedshear_slip_ID, & + resolvedstress_slip_ID & + ) + mySize = plastic_phenopowerlaw_totalNslip(instance) + case(resistance_twin_ID, & + shearrate_twin_ID, & + accumulatedshear_twin_ID, & + resolvedstress_twin_ID & + ) + mySize = plastic_phenopowerlaw_totalNtwin(instance) + case(totalshear_ID, & + totalvolfrac_twin_ID & + ) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_phenopowerlaw_sizePostResult(o,instance) = mySize + plastic_phenopowerlaw_sizePostResults(instance) = plastic_phenopowerlaw_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = plastic_phenopowerlaw_totalNslip(instance) & ! s_slip + + plastic_phenopowerlaw_totalNtwin(instance) & ! s_twin + + 2_pInt & ! sum(gamma) + sum(f) + + plastic_phenopowerlaw_totalNslip(instance) & ! accshear_slip + + plastic_phenopowerlaw_totalNtwin(instance) ! accshear_twin + + sizeDotState = sizeState + sizeDeltaState = 0_pInt + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_phenopowerlaw_sizePostResults(instance) + plasticState(phase)%nSlip =plastic_phenopowerlaw_totalNslip(instance) + plasticState(phase)%nTwin =plastic_phenopowerlaw_totalNtwin(instance) + plasticState(phase)%nTrans=plastic_phenopowerlaw_totalNtrans(instance) + allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) + + offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + + do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X + index_myFamily = sum(plastic_phenopowerlaw_Nslip(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) ! loop over (active) systems in my family (slip) + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenopowerlaw_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenopowerlaw_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + + do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X + index_myFamily = sum(plastic_phenopowerlaw_Ntwin(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) ! loop over (active) systems in my family (twin) + + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenopowerlaw_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenopowerlaw_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + startIndex = 1_pInt + endIndex = plastic_phenopowerlaw_totalNslip(instance) + state (instance)%s_slip=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%s_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%s_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex + plastic_phenopowerlaw_totalNtwin(instance) + state (instance)%s_twin=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%s_twin=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%s_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex + 1_pInt + state (instance)%sumGamma=>plasticState(phase)%state (startIndex,:) + state0 (instance)%sumGamma=>plasticState(phase)%state0 (startIndex,:) + dotState(instance)%sumGamma=>plasticState(phase)%dotState(startIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex + 1_pInt + state (instance)%sumF=>plasticState(phase)%state (startIndex,:) + state0 (instance)%sumF=>plasticState(phase)%state0 (startIndex,:) + dotState(instance)%sumF=>plasticState(phase)%dotState(startIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex +plastic_phenopowerlaw_totalNslip(instance) + state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex +plastic_phenopowerlaw_totalNtwin(instance) + state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + + call plastic_phenopowerlaw_stateInit(phase,instance) + call plastic_phenopowerlaw_aTolState(phase,instance) + endif myPhase2 + enddo initializeInstances + +end subroutine plastic_phenopowerlaw_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_stateInit(ph,instance) + use lattice, only: & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + integer(pInt) :: & + i + real(pReal), dimension(plasticState(ph)%sizeState) :: & + tempState + + tempState = 0.0_pReal + do i = 1_pInt,lattice_maxNslipFamily + tempState(1+sum(plastic_phenopowerlaw_Nslip(1:i-1,instance)) : & + sum(plastic_phenopowerlaw_Nslip(1:i ,instance))) = & + plastic_phenopowerlaw_tau0_slip(i,instance) + enddo + + do i = 1_pInt,lattice_maxNtwinFamily + tempState(1+sum(plastic_phenopowerlaw_Nslip(:,instance))+& + sum(plastic_phenopowerlaw_Ntwin(1:i-1,instance)) : & + sum(plastic_phenopowerlaw_Nslip(:,instance))+& + sum(plastic_phenopowerlaw_Ntwin(1:i ,instance))) = & + plastic_phenopowerlaw_tau0_twin(i,instance) + enddo + + plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array + 2, & ! along dimension 2 + size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) + +end subroutine plastic_phenopowerlaw_stateInit + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + plasticState(ph)%aTolState(1:plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance)) = & + plastic_phenopowerlaw_aTolResistance(instance) + plasticState(ph)%aTolState(1+plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance)) = & + plastic_phenopowerlaw_aTolShear(instance) + plasticState(ph)%aTolState(2+plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance)) = & + plastic_phenopowerlaw_aTolTwinFrac(instance) + plasticState(ph)%aTolState(3+plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance): & + 2+2*(plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance))) = & + plastic_phenopowerlaw_aTolShear(instance) + +end subroutine plastic_phenopowerlaw_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use math, only: & + math_Plain3333to99, & + math_Mandel6to33 + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + use material, only: & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + + integer(pInt) :: & + instance, & + index_myFamily, & + f,i,j,k,l,m,n, & + of, & + ph + real(pReal) :: & + tau_slip_pos,tau_slip_neg, & + gdot_slip_pos,gdot_slip_neg, & + dgdot_dtauslip_pos,dgdot_dtauslip_neg, & + gdot_twin,dgdot_dtautwin,tau_twin + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal), dimension(3,3,2) :: & + nonSchmid_tensor + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Slip part + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) + enddo + gdot_slip_pos = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & + ((abs(tau_slip_pos)/(state(instance)%s_slip(j,of))) & + **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) + + gdot_slip_neg = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & + ((abs(tau_slip_neg)/(state(instance)%s_slip(j,of))) & + **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) + + Lp = Lp + (1.0_pReal-state(instance)%sumF(of))*& ! 1-F + (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then + dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenopowerlaw_n_slip(instance)/tau_slip_pos + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,1) + endif + + if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then + dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenopowerlaw_n_slip(instance)/tau_slip_neg + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,2) + endif + enddo slipSystems + enddo slipFamilies + +!-------------------------------------------------------------------------------------------------- +! Twinning part + j = 0_pInt + twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin = (1.0_pReal-state(instance)%sumF(of))*& ! 1-F + plastic_phenopowerlaw_gdot0_twin(instance)*& + (abs(tau_twin)/state(instance)%s_twin(j,of))**& + plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_twin) > tiny(0.0_pReal)) then + dgdot_dtautwin = gdot_twin*plastic_phenopowerlaw_n_twin(instance)/tau_twin + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & + lattice_Stwin(m,n,index_myFamily+i,ph) + endif + enddo twinSystems + enddo twinFamilies + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + + +end subroutine plastic_phenopowerlaw_LpAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_dotState(Tstar_v,ipc,ip,el) + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_shearTwin, & + lattice_NnonSchmid + use material, only: & + material_phase, & + phaseAt, phasememberAt, & + plasticState, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + integer(pInt) :: & + instance,ph, & + nSlip,nTwin, & + f,i,j,k, & + index_Gamma,index_F,index_myFamily, & + offset_accshear_slip,offset_accshear_twin, & + of + real(pReal) :: & + c_SlipSlip,c_TwinSlip,c_TwinTwin, & + ssat_offset, & + tau_slip_pos,tau_slip_neg,tau_twin + + real(pReal), dimension(plastic_phenopowerlaw_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip + real(pReal), dimension(plastic_phenopowerlaw_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenopowerlaw_totalNslip(instance) + nTwin = plastic_phenopowerlaw_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + offset_accshear_slip = nSlip + nTwin + 2_pInt + offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + plasticState(ph)%dotState(:,of) = 0.0_pReal + + +!-------------------------------------------------------------------------------------------------- +! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices + c_SlipSlip = plastic_phenopowerlaw_h0_SlipSlip(instance)*& + (1.0_pReal + plastic_phenopowerlaw_twinC(instance)*plasticState(ph)%state(index_F,of)**& + plastic_phenopowerlaw_twinB(instance)) + c_TwinSlip = plastic_phenopowerlaw_h0_TwinSlip(instance)*& + plasticState(ph)%state(index_Gamma,of)**plastic_phenopowerlaw_twinE(instance) + c_TwinTwin = plastic_phenopowerlaw_h0_TwinTwin(instance)*& + plasticState(ph)%state(index_F,of)**plastic_phenopowerlaw_twinD(instance) + +!-------------------------------------------------------------------------------------------------- +! calculate left and right vectors and calculate dot gammas + ssat_offset = plastic_phenopowerlaw_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j+1_pInt + left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part + left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part + right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) & + **plastic_phenopowerlaw_a_slip(instance)& + *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) + right_TwinSlip(j) = 1.0_pReal ! no system-dependent part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot gamma + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + gdot_slip(j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance) & + +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + enddo slipSystems1 + enddo slipFamilies1 + + + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j+1_pInt + left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part + left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part + right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part + right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot vol frac + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenopowerlaw_gdot0_twin(instance)*& + (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& + plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + enddo twinSystems1 + enddo twinFamilies1 + +!-------------------------------------------------------------------------------------------------- +! calculate the overall hardening based on above + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j + c_SlipSlip * left_SlipSlip(j) * & + dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & + right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & + right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & + abs(gdot_slip(j)) + plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) + enddo slipSystems2 + enddo slipFamilies2 + + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j + c_TwinSlip * left_TwinSlip(j) * & + dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & + right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + c_TwinTwin * left_TwinTwin(j) * & + dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & + right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 + plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & + gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) + plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) + enddo twinSystems2 + enddo twinFamilies2 + + +end subroutine plastic_phenopowerlaw_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_phenopowerlaw_postResults(Tstar_v,ipc,ip,el) + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + real(pReal), dimension(plastic_phenopowerlaw_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_phenopowerlaw_postResults + + integer(pInt) :: & + instance,ph, of, & + nSlip,nTwin, & + o,f,i,c,j,k, & + index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily + real(pReal) :: & + tau_slip_pos,tau_slip_neg,tau + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenopowerlaw_totalNslip(instance) + nTwin = plastic_phenopowerlaw_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + index_accshear_slip = nSlip + nTwin + 3_pInt + index_accshear_twin = nSlip + nTwin + 3_pInt + nSlip + + plastic_phenopowerlaw_postResults = 0.0_pReal + c = 0_pInt + + outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) + select case(plastic_phenopowerlaw_outputID(o,instance)) + case (resistance_slip_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) + c = c + nSlip + + case (accumulatedshear_slip_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& + index_accshear_slip+nSlip-1_pInt,of) + c = c + nSlip + + case (shearrate_slip_ID) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j + 1_pInt + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo + plastic_phenopowerlaw_postResults(c+j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance) & + +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + + enddo slipSystems1 + enddo slipFamilies1 + c = c + nSlip + + case (resolvedstress_slip_ID) + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j + 1_pInt + plastic_phenopowerlaw_postResults(c+j) = & + dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + enddo slipSystems2 + enddo slipFamilies2 + c = c + nSlip + + case (totalshear_ID) + plastic_phenopowerlaw_postResults(c+1_pInt) = & + plasticState(ph)%state(index_Gamma,of) + c = c + 1_pInt + + case (resistance_twin_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) + c = c + nTwin + + case (accumulatedshear_twin_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) + c = c + nTwin + case (shearrate_twin_ID) + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j + 1_pInt + tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + plastic_phenopowerlaw_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenopowerlaw_gdot0_twin(instance)*& + (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& + plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) + enddo twinSystems1 + enddo twinFamilies1 + c = c + nTwin + + case (resolvedstress_twin_ID) + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j + 1_pInt + plastic_phenopowerlaw_postResults(c+j) = & + dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + enddo twinSystems2 + enddo twinFamilies2 + c = c + nTwin + + case (totalvolfrac_twin_ID) + plastic_phenopowerlaw_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) + c = c + 1_pInt + + end select + enddo outputsLoop + +end function plastic_phenopowerlaw_postResults + +end module plastic_phenopowerlaw diff --git a/code/plastic_titanmod.f90 b/code/plastic_titanmod.f90 new file mode 100644 index 000000000..abc6d661b --- /dev/null +++ b/code/plastic_titanmod.f90 @@ -0,0 +1,1913 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Alankar Alankar, 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 +!> @brief material subroutine for titanium +!-------------------------------------------------------------------------------------------------- +module plastic_titanmod + use prec, only: & + pReal, & + pInt + + implicit none + private + character(len=18), dimension(3), parameter, private :: & + plastic_titanmod_listBasicSlipStates = & + ['rho_edge ', 'rho_screw ', 'shear_system'] + character(len=18), dimension(1), parameter, private :: & + plastic_titanmod_listBasicTwinStates = ['gdot_twin'] + character(len=19), dimension(11), parameter, private :: & + plastic_titanmod_listDependentSlipStates = & + ['segment_edge ', 'segment_screw ', & + 'resistance_edge ', 'resistance_screw ', & + 'tau_slip ', & + 'velocity_edge ', 'velocity_screw ', & + 'gdot_slip_edge ', 'gdot_slip_screw ', & + 'stressratio_edge_p ', 'stressratio_screw_p' ] + character(len=18), dimension(2), parameter, private :: & + plastic_titanmod_listDependentTwinStates = & + ['twin_fraction', 'tau_twin '] + real(pReal), parameter, private :: & + kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin + + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_titanmod_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_titanmod_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_titanmod_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_titanmod_Noutput !< number of outputs per instance of this plasticity !< ID of the lattice structure + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_titanmod_totalNslip, & !< total number of active slip systems for each instance + plastic_titanmod_totalNtwin !< total number of active twin systems for each instance + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_titanmod_Nslip, & !< number of active slip systems for each family and instance + plastic_titanmod_Ntwin, & !< number of active twin systems for each family and instance + plastic_titanmod_slipFamily, & !< lookup table relating active slip system to slip family for each instance + plastic_titanmod_twinFamily, & !< lookup table relating active twin system to twin family for each instance + plastic_titanmod_slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance + plastic_titanmod_twinSystemLattice !< lookup table relating active twin system index to lattice twin system index for each instance + + real(pReal), dimension(:), allocatable, private :: & + plastic_titanmod_debyefrequency, & !< Debye frequency + plastic_titanmod_kinkf0, & !< + plastic_titanmod_CAtomicVolume, & !< atomic volume in Bugers vector unit + plastic_titanmod_dc, & !< prefactor for self-diffusion coefficient + plastic_titanmod_twinhpconstant, & !< activation energy for dislocation climb + plastic_titanmod_GrainSize, & !< grain size - Not being used + plastic_titanmod_MaxTwinFraction, & !< maximum allowed total twin volume fraction + plastic_titanmod_r, & !< r-exponent in twin nucleation rate + plastic_titanmod_CEdgeDipMinDistance, & !< Not being used + plastic_titanmod_Cmfptwin, & !< Not being used + plastic_titanmod_Cthresholdtwin, & !< Not being used + plastic_titanmod_aTolRho !< absolute tolerance for integration of dislocation density + + real(pReal), dimension(:,:), allocatable, private :: & + plastic_titanmod_rho_edge0, & !< initial edge dislocation density per slip system for each family and instance + plastic_titanmod_rho_screw0, & !< initial screw dislocation density per slip system for each family and instance + plastic_titanmod_shear_system0, & !< accumulated shear on each system + plastic_titanmod_burgersPerSlipFam, & !< absolute length of burgers vector [m] for each slip family and instance + plastic_titanmod_burgersPerSlipSys, & !< absolute length of burgers vector [m] for each slip system and instance + plastic_titanmod_burgersPerTwinFam, & !< absolute length of burgers vector [m] for each twin family and instance + plastic_titanmod_burgersPerTwinSys, & !< absolute length of burgers vector [m] for each twin system and instance + plastic_titanmod_f0_PerSlipFam, & !< activation energy for glide [J] for each slip family and instance + plastic_titanmod_f0_PerSlipSys, & !< activation energy for glide [J] for each slip system and instance + plastic_titanmod_twinf0_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance + plastic_titanmod_twinf0_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance + plastic_titanmod_twinshearconstant_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance + plastic_titanmod_twinshearconstant_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance + plastic_titanmod_tau0e_PerSlipFam, & !< Initial yield stress for edge dislocations per slip family + plastic_titanmod_tau0e_PerSlipSys, & !< Initial yield stress for edge dislocations per slip system + plastic_titanmod_tau0s_PerSlipFam, & !< Initial yield stress for screw dislocations per slip family + plastic_titanmod_tau0s_PerSlipSys, & !< Initial yield stress for screw dislocations per slip system + plastic_titanmod_twintau0_PerTwinFam, & !< Initial yield stress for edge dislocations per twin family + plastic_titanmod_twintau0_PerTwinSys, & !< Initial yield stress for edge dislocations per twin system + plastic_titanmod_capre_PerSlipFam, & !< Capture radii for edge dislocations per slip family + plastic_titanmod_capre_PerSlipSys, & !< Capture radii for edge dislocations per slip system + plastic_titanmod_caprs_PerSlipFam, & !< Capture radii for screw dislocations per slip family + plastic_titanmod_caprs_PerSlipSys, & !< Capture radii for screw dislocations per slip system + plastic_titanmod_pe_PerSlipFam, & !< p-exponent in glide velocity + plastic_titanmod_ps_PerSlipFam, & !< p-exponent in glide velocity + plastic_titanmod_qe_PerSlipFam, & !< q-exponent in glide velocity + plastic_titanmod_qs_PerSlipFam, & !< q-exponent in glide velocity + plastic_titanmod_pe_PerSlipSys, & !< p-exponent in glide velocity + plastic_titanmod_ps_PerSlipSys, & !< p-exponent in glide velocity + plastic_titanmod_qe_PerSlipSys, & !< q-exponent in glide velocity + plastic_titanmod_qs_PerSlipSys, & !< q-exponent in glide velocity + plastic_titanmod_twinp_PerTwinFam, & !< p-exponent in glide velocity + plastic_titanmod_twinq_PerTwinFam, & !< q-exponent in glide velocity + plastic_titanmod_twinp_PerTwinSys, & !< p-exponent in glide velocity + plastic_titanmod_twinq_PerTwinSys, & !< p-exponent in glide velocity + plastic_titanmod_v0e_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance + plastic_titanmod_v0e_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance + plastic_titanmod_v0s_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance + plastic_titanmod_v0s_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance + plastic_titanmod_twingamma0_PerTwinFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance + plastic_titanmod_twingamma0_PerTwinSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance + plastic_titanmod_kinkcriticallength_PerSlipFam, & !< screw dislocation mobility prefactor for kink-pairs per slip family + plastic_titanmod_kinkcriticallength_PerSlipSys, & !< screw dislocation mobility prefactor for kink-pairs per slip system + plastic_titanmod_twinsizePerTwinFam, & !< twin thickness [m] for each twin family and instance + plastic_titanmod_twinsizePerTwinSys, & !< twin thickness [m] for each twin system and instance + plastic_titanmod_CeLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_titanmod_CeLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_titanmod_CsLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_titanmod_CsLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_titanmod_twinLambdaSlipPerTwinFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_titanmod_twinLambdaSlipPerTwinSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_titanmod_interactionSlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance + plastic_titanmod_interaction_ee, & !< coefficients for e-e interaction for each interaction type and instance + plastic_titanmod_interaction_ss, & !< coefficients for s-s interaction for each interaction type and instance + plastic_titanmod_interaction_es, & !< coefficients for e-s-twin interaction for each interaction type and instance + plastic_titanmod_interactionSlipTwin, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_titanmod_interactionTwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_titanmod_interactionTwinTwin !< coefficients for twin-twin interaction for each interaction type and instance + + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_titanmod_interactionMatrixSlipSlip, & !< interaction matrix of the different slip systems for each instance + plastic_titanmod_interactionMatrix_ee, & !< interaction matrix of e-e for each instance + plastic_titanmod_interactionMatrix_ss, & !< interaction matrix of s-s for each instance + plastic_titanmod_interactionMatrix_es, & !< interaction matrix of e-s for each instance + plastic_titanmod_interactionMatrixSlipTwin, & !< interaction matrix of slip systems with twin systems for each instance + plastic_titanmod_interactionMatrixTwinSlip, & !< interaction matrix of twin systems with slip systems for each instance + plastic_titanmod_interactionMatrixTwinTwin, & !< interaction matrix of the different twin systems for each instance + plastic_titanmod_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance + plastic_titanmod_forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance + plastic_titanmod_TwinforestProjectionEdge, & !< matrix of forest projections of edge dislocations in twin system for each instance + plastic_titanmod_TwinforestProjectionScrew !< matrix of forest projections of screw dislocations in twin system for each instance + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_titanmod_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance + + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_titanmod_Ctwin3333 !< twin elasticity matrix for each instance + + enum, bind(c) + enumerator :: undefined_ID, & + rhoedge_ID, rhoscrew_ID, & + segment_edge_ID, segment_screw_ID, & + resistance_edge_ID, resistance_screw_ID, & + velocity_edge_ID, velocity_screw_ID, & + tau_slip_ID, & + gdot_slip_edge_ID, gdot_slip_screw_ID, & + gdot_slip_ID, & + stressratio_edge_p_ID, stressratio_screw_p_ID, & + shear_system_ID, & + twin_fraction_ID, & + shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & + rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & + rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & + shear_total_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_titanmod_outputID !< ID of each post result output + + public :: & + plastic_titanmod_microstructure, & + plastic_titanmod_stateInit, & + plastic_titanmod_init, & + plastic_titanmod_LpAndItsTangent, & + plastic_titanmod_dotState, & + plastic_titanmod_postResults, & + plastic_titanmod_homogenizedC + + contains + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66,& + math_Voigt66to3333,& + math_mul3x3 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_TITANMOD_label, & + PLASTICITY_TITANMOD_ID, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + phase, & + instance, j, k, l, m, n, p, q, r, & + f, o, & + s, s1, s2, & + t, t1, t2, & + ns, nt, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & + offset_slip, mySize, & + maxTotalNslip,maxTotalNtwin, maxNinstance + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase = 0_pInt + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_TITANMOD_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_TITANMOD_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_titanmod_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_titanmod_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) + allocate(plastic_titanmod_output(maxval(phase_Noutput),maxNinstance)) + plastic_titanmod_output = '' + allocate(plastic_titanmod_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_titanmod_Noutput(maxNinstance), source=0_pInt) + + allocate(plastic_titanmod_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_slipFamily(lattice_maxNslip,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_twinFamily(lattice_maxNtwin,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_slipSystemLattice(lattice_maxNslip,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_twinSystemLattice(lattice_maxNtwin,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_titanmod_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_titanmod_debyefrequency(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_kinkf0(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CAtomicVolume(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_dc(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinhpconstant(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_GrainSize(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_MaxTwinFraction(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_r(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Cmfptwin(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Cthresholdtwin(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_aTolRho(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_rho_edge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_rho_screw0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_shear_system0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_burgersPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_burgersPerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_f0_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_capre_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_caprs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_pe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_ps_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_kinkcriticallength_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinsizePerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CeLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CsLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_twinf0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinshearconstant_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twintau0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinp_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinq_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twingamma0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinLambdaSlipPerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_interactionSlipSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interaction_ee(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interaction_ss(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interaction_es(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionSlipTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionTwinSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionTwinTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + phase = phase + 1_pInt ! advance section counter + if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then ! one of my sections. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('rhoedge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('segment_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('segment_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('tau_slip') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = tau_slip_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('gdot_slip_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('gdot_slip_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('gdot_slip') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stressratio_edge_p') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_edge_p_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stressratio_screw_p') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_screw_p_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_system') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_system_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('twin_fraction') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = twin_fraction_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_basal') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_basal_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_prism') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_prism_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_pyra') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyra_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_pyrca') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyrca_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_basal') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_basal_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_prism') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_prism_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_pyra') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyra_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_pyrca') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyrca_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_basal') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_basal_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_prism') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_prism_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_pyra') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyra_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_pyrca') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyrca_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_total') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_total_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + case ('debyefrequency') + plastic_titanmod_debyefrequency(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('kinkf0') + plastic_titanmod_kinkf0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('nslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ntwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinFamilies) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('rho_edge0') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_rho_edge0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('rho_screw0') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_rho_screw0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('slipburgers') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_burgersPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinburgers') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_burgersPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('f0') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_f0_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinf0') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinf0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0e') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_tau0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twintau0') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twintau0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0s') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_tau0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('capre') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_capre_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('caprs') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_caprs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('v0e') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_v0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twingamma0') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twingamma0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('v0s') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_v0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('kinkcriticallength') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_kinkcriticallength_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinsize') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinsizePerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('celambdaslip') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_CeLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinlambdaslip') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinlambdaslipPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('cslambdaslip') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_CsLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('grainsize') + plastic_titanmod_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('maxtwinfraction') + plastic_titanmod_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('pe') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_pe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinp') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinp_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('ps') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_ps_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('qe') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_qe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinq') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinq_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('qs') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_qs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinshearconstant') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinshearconstant_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('dc') + plastic_titanmod_dc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twinhpconstant') + plastic_titanmod_twinhpconstant(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_rho') + plastic_titanmod_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('interactionee') + do j = 1_pInt, lattice_maxNinteraction + plastic_titanmod_interaction_ee(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interactionss') + do j = 1_pInt, lattice_maxNinteraction + plastic_titanmod_interaction_ss(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interactiones') + do j = 1_pInt, lattice_maxNinteraction + plastic_titanmod_interaction_es(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_slipslip','interactionslipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_titanmod_interactionSlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin','interactionsliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_titanmod_interactionSlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip','interactiontwinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_titanmod_interactionTwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin','interactiontwintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_titanmod_interactionTwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then + instance = phase_plasticityInstance(phase) + if (sum(plastic_titanmod_Nslip(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='nslip ('//PLASTICITY_TITANMOD_label//')') + if (sum(plastic_titanmod_Ntwin(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='ntwin ('//PLASTICITY_TITANMOD_label//')') + do f = 1_pInt,lattice_maxNslipFamily + if (plastic_titanmod_Nslip(f,instance) > 0_pInt) then + if (plastic_titanmod_rho_edge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rho_edge0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_rho_screw0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rho_screw0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_burgersPerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='slipburgers ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_f0_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='f0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_tau0e_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau0e ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_tau0s_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau0s ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_capre_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='capre ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_caprs_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='caprs ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_v0e_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0e ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_v0s_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0s ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='kinkCriticalLength ('//PLASTICITY_TITANMOD_label//')') + endif + enddo + do f = 1_pInt,lattice_maxNtwinFamily + if (plastic_titanmod_Ntwin(f,instance) > 0_pInt) then + if (plastic_titanmod_burgersPerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twinf0_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinf0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinshearconstant ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twintau0_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twintau0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twingamma0_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twingamma0 ('//PLASTICITY_TITANMOD_label//')') + endif + enddo + if (plastic_titanmod_dc(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='dc ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twinhpconstant(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinhpconstant ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTol_rho ('//PLASTICITY_TITANMOD_label//')') + +!-------------------------------------------------------------------------------------------------- +! determine total number of active slip or twin systems + plastic_titanmod_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_titanmod_Nslip(:,instance)) + plastic_titanmod_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_titanmod_Ntwin(:,instance)) + plastic_titanmod_totalNslip(instance) = sum(plastic_titanmod_Nslip(:,instance)) + plastic_titanmod_totalNtwin(instance) = sum(plastic_titanmod_Ntwin(:,instance)) + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + maxTotalNslip = maxval(plastic_titanmod_totalNslip) + maxTotalNtwin = maxval(plastic_titanmod_totalNtwin) + + allocate(plastic_titanmod_burgersPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_f0_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_capre_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_caprs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_pe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_ps_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_kinkcriticallength_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CeLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CsLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_burgersPerTwinSys(maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinf0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinshearconstant_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twintau0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinp_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinq_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twingamma0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinsizePerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinLambdaSlipPerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Ctwin66 (6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Ctwin3333 (3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrix_ee(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrix_ss(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrix_es(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrixSlipTwin(maxTotalNslip,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrixTwinSlip(maxTotalNtwin,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrixTwinTwin(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_TwinforestProjectionEdge(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_TwinforestProjectionScrew(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then + instance = phase_plasticityInstance(phase) + +!-------------------------------------------------------------------------------------------------- +! inverse lookup of slip system family + l = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily + do s = 1_pInt,plastic_titanmod_Nslip(f,instance) + l = l + 1_pInt + plastic_titanmod_slipFamily(l,instance) = f + plastic_titanmod_slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt,phase)) + s + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! inverse lookup of twin system family + l = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily + do t = 1_pInt,plastic_titanmod_Ntwin(f,instance) + l = l + 1_pInt + plastic_titanmod_twinFamily(l,instance) = f + plastic_titanmod_twinSystemLattice(l,instance) = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) + t + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! determine size of state array + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + sizeDotState = & + size(plastic_titanmod_listBasicSlipStates)*ns + & + size(plastic_titanmod_listBasicTwinStates)*nt + sizeState = sizeDotState+ & + size(plastic_titanmod_listDependentSlipStates)*ns + & + size(plastic_titanmod_listDependentTwinStates)*nt + sizeDeltaState = 0_pInt + +!-------------------------------------------------------------------------------------------------- +! determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_titanmod_Noutput(instance) + mySize = 0_pInt + select case(plastic_titanmod_outputID(o,instance)) + case(rhoedge_ID, rhoscrew_ID, & + segment_edge_ID, segment_screw_ID, & + resistance_edge_ID, resistance_screw_ID, & + velocity_edge_ID, velocity_screw_ID, & + tau_slip_ID, & + gdot_slip_edge_ID, gdot_slip_screw_ID, & + gdot_slip_ID, & + stressratio_edge_p_ID, stressratio_screw_p_ID, & + shear_system_ID) + mySize = plastic_titanmod_totalNslip(instance) + case(twin_fraction_ID) + mySize = plastic_titanmod_totalNtwin(instance) + case(shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & ! use only if all 4 slip families in hex are considered + rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & + rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & + shear_total_ID) + mySize = 1_pInt + case default + call IO_error(105_pInt,ext_msg=plastic_titanmod_output(o,instance)// & + ' ('//PLASTICITY_TITANMOD_label//')') + end select + + outputFound: if (mySize > 0_pInt) then + plastic_titanmod_sizePostResult(o,instance) = mySize + plastic_titanmod_sizePostResults(instance) = plastic_titanmod_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop +! Determine size of state array + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_titanmod_sizePostResults(instance) + plasticState(phase)%nSlip =plastic_titanmod_totalNslip(instance) + plasticState(phase)%nTwin = 0_pInt + plasticState(phase)%nTrans= 0_pInt + allocate(plasticState(phase)%aTolState (sizeState), source=plastic_titanmod_aTolRho(instance)) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + offset_slip = 2_pInt*plasticState(phase)%nSlip+1 + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) +!-------------------------------------------------------------------------------------------------- +! construction of the twin elasticity matrices + do j=1_pInt,lattice_maxNtwinFamily + do k=1_pInt,plastic_titanmod_Ntwin(j,instance) + do l=1_pInt,3_pInt ; do m=1_pInt,3_pInt ; do n=1_pInt,3_pInt ; do o=1_pInt,3_pInt + do p=1_pInt,3_pInt ; do q=1_pInt,3_pInt ; do r=1_pInt,3_pInt ; do s=1_pInt,3_pInt + plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) = & + plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) + & + lattice_C3333(p,q,r,s,phase)*& + lattice_Qtwin(l,p,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & + lattice_Qtwin(m,q,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & + lattice_Qtwin(n,r,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & + lattice_Qtwin(o,s,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo ; enddo + plastic_titanmod_Ctwin66(1:6,1:6,k,instance) = & + math_Mandel3333to66(plastic_titanmod_Ctwin3333(1:3,1:3,1:3,1:3,k,instance)) + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! Burgers vector, dislocation velocity prefactor for each slip system + do s = 1_pInt,plastic_titanmod_totalNslip(instance) + f = plastic_titanmod_slipFamily(s,instance) + + plastic_titanmod_burgersPerSlipSys(s,instance) = & + plastic_titanmod_burgersPerSlipFam(f,instance) + + plastic_titanmod_f0_PerSlipSys(s,instance) = & + plastic_titanmod_f0_PerSlipFam(f,instance) + + plastic_titanmod_tau0e_PerSlipSys(s,instance) = & + plastic_titanmod_tau0e_PerSlipFam(f,instance) + + plastic_titanmod_tau0s_PerSlipSys(s,instance) = & + plastic_titanmod_tau0s_PerSlipFam(f,instance) + + plastic_titanmod_capre_PerSlipSys(s,instance) = & + plastic_titanmod_capre_PerSlipFam(f,instance) + + plastic_titanmod_caprs_PerSlipSys(s,instance) = & + plastic_titanmod_caprs_PerSlipFam(f,instance) + + plastic_titanmod_v0e_PerSlipSys(s,instance) = & + plastic_titanmod_v0e_PerSlipFam(f,instance) + + plastic_titanmod_v0s_PerSlipSys(s,instance) = & + plastic_titanmod_v0s_PerSlipFam(f,instance) + + plastic_titanmod_kinkcriticallength_PerSlipSys(s,instance) = & + plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) + + plastic_titanmod_pe_PerSlipSys(s,instance) = & + plastic_titanmod_pe_PerSlipFam(f,instance) + + plastic_titanmod_ps_PerSlipSys(s,instance) = & + plastic_titanmod_ps_PerSlipFam(f,instance) + + plastic_titanmod_qe_PerSlipSys(s,instance) = & + plastic_titanmod_qe_PerSlipFam(f,instance) + + plastic_titanmod_qs_PerSlipSys(s,instance) = & + plastic_titanmod_qs_PerSlipFam(f,instance) + + plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance) = & + plastic_titanmod_CeLambdaSlipPerSlipFam(f,instance) + + plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance) = & + plastic_titanmod_CsLambdaSlipPerSlipFam(f,instance) + enddo + +!-------------------------------------------------------------------------------------------------- +! Burgers vector, nucleation rate prefactor and twin size for each twin system + do t = 1_pInt,plastic_titanmod_totalNtwin(instance) + f = plastic_titanmod_twinFamily(t,instance) + + plastic_titanmod_burgersPerTwinSys(t,instance) = & + plastic_titanmod_burgersPerTwinFam(f,instance) + + plastic_titanmod_twinsizePerTwinSys(t,instance) = & + plastic_titanmod_twinsizePerTwinFam(f,instance) + + plastic_titanmod_twinf0_PerTwinSys(t,instance) = & + plastic_titanmod_twinf0_PerTwinFam(f,instance) + + plastic_titanmod_twinshearconstant_PerTwinSys(t,instance) = & + plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) + + plastic_titanmod_twintau0_PerTwinSys(t,instance) = & + plastic_titanmod_twintau0_PerTwinFam(f,instance) + + plastic_titanmod_twingamma0_PerTwinSys(t,instance) = & + plastic_titanmod_twingamma0_PerTwinFam(f,instance) + + plastic_titanmod_twinp_PerTwinSys(t,instance) = & + plastic_titanmod_twinp_PerTwinFam(f,instance) + + plastic_titanmod_twinq_PerTwinSys(t,instance) = & + plastic_titanmod_twinq_PerTwinFam(f,instance) + + plastic_titanmod_twinLambdaSlipPerTwinSys(t,instance) = & + plastic_titanmod_twinLambdaSlipPerTwinFam(f,instance) + enddo + +!-------------------------------------------------------------------------------------------------- +! Construction of interaction matrices + do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) + do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) + plastic_titanmod_interactionMatrixSlipSlip(s1,s2,instance) = & + plastic_titanmod_interactionSlipSlip(lattice_interactionSlipSlip( & + plastic_titanmod_slipSystemLattice(s1,instance),& + plastic_titanmod_slipSystemLattice(s2,instance),phase),instance) + + plastic_titanmod_interactionMatrix_ee(s1,s2,instance) = & + plastic_titanmod_interaction_ee(lattice_interactionSlipSlip ( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + + plastic_titanmod_interactionMatrix_ss(s1,s2,instance) = & + plastic_titanmod_interaction_ss(lattice_interactionSlipSlip( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + + plastic_titanmod_interactionMatrix_es(s1,s2,instance) = & + plastic_titanmod_interaction_es(lattice_interactionSlipSlip( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + enddo; enddo + + do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) + do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) + plastic_titanmod_interactionMatrixSlipTwin(s1,t2,instance) = & + plastic_titanmod_interactionSlipTwin(lattice_interactionSlipTwin( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) + enddo; enddo + + do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) + do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) + plastic_titanmod_interactionMatrixTwinSlip(t1,s2,instance) = & + plastic_titanmod_interactionTwinSlip(lattice_interactionTwinSlip( & + plastic_titanmod_twinSystemLattice(t1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + enddo; enddo + + do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) + do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) + plastic_titanmod_interactionMatrixTwinTwin(t1,t2,instance) = & + plastic_titanmod_interactionTwinTwin(lattice_interactionTwinTwin( & + plastic_titanmod_twinSystemLattice(t1,instance), & + plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) + enddo; enddo + + do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) + do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for edge dislocations + plastic_titanmod_forestProjectionEdge(s1,s2,instance) = & + abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & + lattice_st(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) + +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for screw dislocations + plastic_titanmod_forestProjectionScrew(s1,s2,instance) = & + abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & + lattice_sd(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for edge dislocations in twin system + do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) + do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) + plastic_titanmod_TwinforestProjectionEdge(t1,t2,instance) = & + abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & + lattice_tt(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) + +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for screw dislocations in twin system + plastic_titanmod_TwinforestProjectionScrew(t1,t2,instance) = & + abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & + lattice_td(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) + enddo; enddo + call plastic_titanmod_stateInit(phase,instance) + endif + enddo initializeInstances + +end subroutine plastic_titanmod_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_stateInit(ph,instance) + use lattice, only: & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_mu + + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: instance !< number specifying the instance of the plasticity + integer(pInt), intent(in) :: ph !< number specifying the phase of the plasticity + + + integer(pInt) :: & + s,s0,s1, & + t,t0,t1, & + ns,nt,f + real(pReal), dimension(plastic_titanmod_totalNslip(instance)) :: & + rho_edge0, & + rho_screw0, & + shear_system0, & + segment_edge0, & + segment_screw0, & + resistance_edge0, & + resistance_screw0 + real(pReal), dimension(plastic_titanmod_totalNtwin(instance)) :: & + twingamma_dot0, & + resistance_twin0 + real(pReal), dimension(plasticState(ph)%sizeState) :: tempState !!!!!!!!!????????? check + + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + tempState = 0.0_pReal +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables for slip + s1 = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily + s0 = s1 + 1_pInt + s1 = s0 + plastic_titanmod_Nslip(f,instance) - 1_pInt + do s = s0,s1 + rho_edge0(s) = plastic_titanmod_rho_edge0(f,instance) + rho_screw0(s) = plastic_titanmod_rho_screw0(f,instance) + shear_system0(s) = 0.0_pReal + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables for twin + t1 = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily + t0 = t1 + 1_pInt + t1 = t0 + plastic_titanmod_Ntwin(f,instance) - 1_pInt + do t = t0,t1 + twingamma_dot0(t)=0.0_pReal + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! initialize dependent slip microstructural variables + forall (s = 1_pInt:ns) + segment_edge0(s) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) + segment_screw0(s) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) + resistance_edge0(s) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & + sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & + dot_product((rho_screw0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) + resistance_screw0(s) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & + sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & + dot_product((rho_screw0), plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) + end forall + + forall (t = 1_pInt:nt) & + resistance_twin0(t) = 0.0_pReal + +tempState = 0.0_pReal +tempState (1:ns) = rho_edge0 +tempState (1_pInt*ns+1_pInt:2_pInt*ns) = rho_screw0 +tempState (2_pInt*ns+1_pInt:3_pInt*ns) = shear_system0 +tempState (3_pInt*ns+1_pInt:3_pInt*ns+nt) = twingamma_dot0 +tempState (3_pInt*ns+nt+1_pInt:4_pInt*ns+nt) = segment_edge0 +tempState (4_pInt*ns+nt+1_pInt:5_pInt*ns+nt) = segment_screw0 +tempState (5_pInt*ns+nt+1_pInt:6_pInt*ns+nt) = resistance_edge0 +tempState (6_pInt*ns+nt+1_pInt:7_pInt*ns+nt) = resistance_screw0 +tempState (7_pInt*ns+nt+1_pInt:7_pInt*ns+2_pInt*nt)=resistance_twin0 + +plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) +end subroutine plastic_titanmod_stateInit + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenized elasticity matrix +!-------------------------------------------------------------------------------------------------- +function plastic_titanmod_homogenizedC(ipc,ip,el) + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_C66 + +implicit none + real(pReal), dimension(6,6) :: & + plastic_titanmod_homogenizedC + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element +real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + volumefraction_PerTwinSys + integer(pInt) :: & + ph, & + of, & + instance, & + ns, nt, & + i + real(pReal) :: & + sumf + +!-------------------------------------------------------------------------------------------------- +! shortened notation +! ph = material_phase(ipc,ip,el) + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! total twin volume fraction + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + enddo + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + +!-------------------------------------------------------------------------------------------------- +! homogenized elasticity matrix + plastic_titanmod_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) + do i=1_pInt,nt + plastic_titanmod_homogenizedC = plastic_titanmod_homogenizedC & + + volumefraction_PerTwinSys(i)*& + plastic_titanmod_Ctwin66(1:6,1:6,i,instance) + enddo + +end function plastic_titanmod_homogenizedC + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_microstructure(temperature,ipc,ip,el) + + use material, only: & + material_phase,& + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_mu + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + temperature !< temperature at IP + integer(pInt) :: & + instance, & + ns, nt, s, t, & + i, & + ph, & + of + real(pReal) :: & + sumf, & + sfe ! stacking fault energy + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + volumefraction_PerTwinSys + +!-------------------------------------------------------------------------------------------------- + +!Shortened notation + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! total twin volume fraction + forall (i = 1_pInt:nt) & + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + + sfe = 0.0002_pReal*Temperature-0.0396_pReal + +!-------------------------------------------------------------------------------------------------- +! average segment length for edge dislocations in matrix + forall (s = 1_pInt:ns) & + plasticState(ph)%state(3_pInt*ns+nt+s, of) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product(plasticState(ph)%state(1:ns, of), & + plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & + plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! average segment length for screw dislocations in matrix + forall (s = 1_pInt:ns) & + plasticState(ph)%state(4_pInt*ns+nt+s, of) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product(plasticState(ph)%state(1:ns, of), & + plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & + plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! threshold stress or slip resistance for edge dislocation motion + forall (s = 1_pInt:ns) & + plasticState(ph)%state(5_pInt*ns+nt+s, of) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& + sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& + plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & + dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& + plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! threshold stress or slip resistance for screw dislocation motion + forall (s = 1_pInt:ns) & + plasticState(ph)%state(6_pInt*ns+nt+s, of) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& + sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& + plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & + dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& + plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! threshold stress or slip resistance for dislocation motion in twin + forall (t = 1_pInt:nt) & + plasticState(ph)%state(7_pInt*ns+nt+t, of) = & + lattice_mu(ph)*plastic_titanmod_burgersPerTwinSys(t,instance)*& + (dot_product((abs(plasticState(ph)%state(2_pInt*ns+1_pInt:2_pInt*ns+nt, of))),& + plastic_titanmod_interactionMatrixTwinTwin(1:nt,t,instance))) + +! state=tempState + +end subroutine plastic_titanmod_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,temperature,ipc,ip,el) + use math, only: & + math_Plain3333to99, & + math_Mandel6to33 + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_structure, & + LATTICE_hex_ID + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at IP + integer(pInt) :: & + index_myFamily, instance, & + ns,nt, & + f,i,j,k,l,m,n, & + ph, & + of + real(pReal) :: sumf, & + StressRatio_edge_p, minusStressRatio_edge_p, StressRatio_edge_pminus1, BoltzmannRatioedge, & + StressRatio_screw_p, minusStressRatio_screw_p, StressRatio_screw_pminus1, BoltzmannRatioscrew, & + twinStressRatio_p, twinminusStressRatio_p, twinStressRatio_pminus1, BoltzmannRatiotwin, & + twinDotGamma0, bottomstress_edge, bottomstress_screw, screwvelocity_prefactor + real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 + real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,dgdot_dtauslip,tau_slip, & + edge_velocity, screw_velocity, & + gdot_slip_edge, gdot_slip_screw + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,dgdot_dtautwin,tau_twin, volumefraction_PerTwinSys + +! tempState=state + + + +!-------------------------------------------------------------------------------------------------- +! shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + + enddo + + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + + !* Dislocation glide part + gdot_slip = 0.0_pReal + gdot_slip_edge = 0.0_pReal + gdot_slip_screw = 0.0_pReal + dgdot_dtauslip = 0.0_pReal + j = 0_pInt + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on slip system + tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + if(lattice_structure(ph)==LATTICE_hex_ID) then ! only for prismatic and pyr systems in hex + screwvelocity_prefactor=plastic_titanmod_debyefrequency(instance)* & + plasticState(ph)%state(4_pInt*ns+nt+j, of)*(plastic_titanmod_burgersPerSlipSys(j,instance)/ & + plastic_titanmod_kinkcriticallength_PerSlipSys(j,instance))**2 + + !* Stress ratio for screw ! No slip resistance for screw dislocations, only Peierls stress + bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) + StressRatio_screw_p = ((abs(tau_slip(j)))/ & + ( bottomstress_screw) & + )**plastic_titanmod_ps_PerSlipSys(j,instance) + + if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then + minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p + else + minusStressRatio_screw_p=0.001_pReal + endif + + bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) + StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/ & + ( bottomstress_screw) & + )**(plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio for screw + BoltzmannRatioscrew = plastic_titanmod_kinkf0(instance)/(kB*Temperature) + + else ! if the structure is not hex or the slip family is basal + screwvelocity_prefactor=plastic_titanmod_v0s_PerSlipSys(j,instance) + bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance)+ & + plasticState(ph)%state(6*ns+nt+j, of) + StressRatio_screw_p = ((abs(tau_slip(j)))/( bottomstress_screw ))**plastic_titanmod_ps_PerSlipSys(j,instance) + + if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then + minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p + else + minusStressRatio_screw_p=0.001_pReal + endif + + StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/( bottomstress_screw))** & + (plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio for screw + BoltzmannRatioscrew = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) + + endif + + !* Stress ratio for edge + bottomstress_edge=plastic_titanmod_tau0e_PerSlipSys(j,instance)+ & + plasticState(ph)%state(5*ns+nt+j, of) + StressRatio_edge_p = ((abs(tau_slip(j)))/ & + ( bottomstress_edge) & + )**plastic_titanmod_pe_PerSlipSys(j,instance) + + if((1.0_pReal-StressRatio_edge_p)>0.001_pReal) then + minusStressRatio_edge_p=1.0_pReal-StressRatio_edge_p + else + minusStressRatio_edge_p=0.001_pReal + endif + + StressRatio_edge_pminus1 = ((abs(tau_slip(j)))/( bottomstress_edge))** & + (plastic_titanmod_pe_PerSlipSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio for edge. For screws it is defined above + BoltzmannRatioedge = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) + + screw_velocity(j) =screwvelocity_prefactor * & ! there is no v0 for screw now because it is included in the prefactor + exp(-BoltzmannRatioscrew*(minusStressRatio_screw_p)** & + plastic_titanmod_qs_PerSlipSys(j,instance)) + + edge_velocity(j) =plastic_titanmod_v0e_PerSlipSys(j,instance)*exp(-BoltzmannRatioedge* & + (minusStressRatio_edge_p)** & + plastic_titanmod_qe_PerSlipSys(j,instance)) + + !* Shear rates due to edge slip + gdot_slip_edge(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(j, of)* & + edge_velocity(j))* sign(1.0_pReal,tau_slip(j)) + !* Shear rates due to screw slip + gdot_slip_screw(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(ns+j, of) * & + screw_velocity(j))* sign(1.0_pReal,tau_slip(j)) + !Total shear rate + + gdot_slip(j) = gdot_slip_edge(j) + gdot_slip_screw(j) + + plasticState(ph)%state( 7*ns+2*nt+j, of)= edge_velocity(j) + plasticState(ph)%state( 8*ns+2*nt+j, of)= screw_velocity(j) + plasticState(ph)%state( 9*ns+2*nt+j, of)= tau_slip(j) + plasticState(ph)%state(10*ns+2*nt+j, of)= gdot_slip_edge(j) + plasticState(ph)%state(11*ns+2*nt+j, of)= gdot_slip_screw(j) + plasticState(ph)%state(12*ns+2*nt+j, of)= StressRatio_edge_p + plasticState(ph)%state(13*ns+2*nt+j, of)= StressRatio_screw_p + + !* Derivatives of shear rates + dgdot_dtauslip(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(( & + ( & + ( & + ( & + (edge_velocity(j)*plasticState(ph)%state(j, of))) * & + BoltzmannRatioedge*& + plastic_titanmod_pe_PerSlipSys(j,instance)* & + plastic_titanmod_qe_PerSlipSys(j,instance) & + )/ & + bottomstress_edge & + )*& + StressRatio_edge_pminus1*(minusStressRatio_edge_p)** & + (plastic_titanmod_qe_PerSlipSys(j,instance)-1.0_pReal) & + ) + & + ( & + ( & + ( & + (plasticState(ph)%state(ns+j, of) * screw_velocity(j)) * & + BoltzmannRatioscrew* & + plastic_titanmod_ps_PerSlipSys(j,instance)* & + plastic_titanmod_qs_PerSlipSys(j,instance) & + )/ & + bottomstress_screw & + )*& + StressRatio_screw_pminus1*(minusStressRatio_screw_p)**(plastic_titanmod_qs_PerSlipSys(j,instance)-1.0_pReal) & + ) & + ) !* sign(1.0_pReal,tau_slip(j)) + + + +!************************************************* +!sumf=0.0_pReal + !* Plastic velocity gradient for dislocation glide + Lp = Lp + (1.0_pReal - sumf)*gdot_slip(j)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& + lattice_Sslip(k,l,1,index_myFamily+i,ph)*& + lattice_Sslip(m,n,1,index_myFamily+i,ph) + enddo + enddo slipFamiliesLoop + +!* Mechanical twinning part + gdot_twin = 0.0_pReal + dgdot_dtautwin = 0.0_pReal + j = 0_pInt + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on twin system + tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + +!************************************************************************************** + !* Stress ratios +! StressRatio_r = (plasticState(ph)%state6*ns+3*nt+j, of)/tau_twin(j))**plastic_titanmod_r(instance) + + !* Shear rates and their derivatives due to twin +! if ( tau_twin(j) > 0.0_pReal ) !then +! gdot_twin(j) = 0.0_pReal!& +! (plastic_titanmod_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& +! plasticState(ph)%state(6*ns+4*nt+j, of)*plastic_titanmod_Ndot0PerTwinSys(f,instance)*exp(-StressRatio_r) +! dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_titanmod_r(instance))/tau_twin(j))*StressRatio_r +! endif +!************************************************************************************** + + !* Stress ratio for edge + twinStressRatio_p = ((abs(tau_twin(j)))/ & + ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & + )**plastic_titanmod_twinp_PerTwinSys(j,instance) + + if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then + twinminusStressRatio_p=1.0_pReal-twinStressRatio_p + else + twinminusStressRatio_p=0.001_pReal + endif + + twinStressRatio_pminus1 = ((abs(tau_twin(j)))/ & + ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & + )**(plastic_titanmod_twinp_PerTwinSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio + BoltzmannRatiotwin = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) + + !* Initial twin shear rates + TwinDotGamma0 = & + plastic_titanmod_twingamma0_PerTwinSys(j,instance) + + !* Shear rates due to twin + gdot_twin(j) =sign(1.0_pReal,tau_twin(j))*plastic_titanmod_twingamma0_PerTwinSys(j,instance)* & + exp(-BoltzmannRatiotwin*(twinminusStressRatio_p)**plastic_titanmod_twinq_PerTwinSys(j,instance)) + + + !* Derivatives of shear rates in twin + dgdot_dtautwin(j) = ( & + ( & + ( & + (abs(gdot_twin(j))) * & + BoltzmannRatiotwin*& + plastic_titanmod_twinp_PerTwinSys(j,instance)* & + plastic_titanmod_twinq_PerTwinSys(j,instance) & + )/ & + plastic_titanmod_twintau0_PerTwinSys(j,instance) & + )*& + twinStressRatio_pminus1*(twinminusStressRatio_p)** & + (plastic_titanmod_twinq_PerTwinSys(j,instance)-1.0_pReal) & + ) !* sign(1.0_pReal,tau_slip(j)) + + !* Plastic velocity gradient for mechanical twinning +! Lp = Lp + sumf*gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) + Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& + lattice_Stwin(k,l,index_myFamily+i,ph)*& + lattice_Stwin(m,n,index_myFamily+i,ph) + enddo + enddo twinFamiliesLoop + +dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) +! tempState=state + + +end subroutine plastic_titanmod_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_dotState(Tstar_v,temperature,ipc,ip,el) + use lattice, only: & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + +implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: & + index_myFamily, instance, & + ns,nt,& + f,i,j, & + ph, & + of + real(pReal) :: & + sumf,BoltzmannRatio, & + twinStressRatio_p,twinminusStressRatio_p + real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + DotRhoEdgeGeneration, & + DotRhoEdgeAnnihilation, & + DotRhoScrewGeneration, & + DotRhoScrewAnnihilation + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin, & + tau_twin, & + volumefraction_PerTwinSys + +!-------------------------------------------------------------------------------------------------- +! shortened notation + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + + enddo + + sumf = sum(abs(volumefraction_PerTwinSys(1_pInt:nt))) ! safe for nt == 0 + + plasticState(ph)%dotState(:,of) = 0.0_pReal + j = 0_pInt + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + DotRhoEdgeGeneration(j) = & ! multiplication of edge dislocations + plasticState(ph)%state(ns+j, of)*plasticState(ph)%state(8*ns+2*nt+j, of)/plasticState(ph)%state(4*ns+nt+j, of) + DotRhoScrewGeneration(j) = & ! multiplication of screw dislocations + plasticState(ph)%state(j, of)*plasticState(ph)%state(7*ns+2*nt+j, of)/plasticState(ph)%state(3*ns+nt+j, of) + DotRhoEdgeAnnihilation(j) = -((plasticState(ph)%state(j, of))**2)* & ! annihilation of edge dislocations + plastic_titanmod_capre_PerSlipSys(j,instance)*plasticState(ph)%state(7*ns+2*nt+j, of)*0.5_pReal + DotRhoScrewAnnihilation(j) = -((plasticState(ph)%state(ns+j, of))**2)* & ! annihilation of screw dislocations + plastic_titanmod_caprs_PerSlipSys(j,instance)*plasticState(ph)%state(8*ns+2*nt+j, of)*0.5_pReal + plasticState(ph)%dotState(j, of) = & ! edge dislocation density rate of change + DotRhoEdgeGeneration(j)+DotRhoEdgeAnnihilation(j) + + plasticState(ph)%dotState(ns+j, of) = & ! screw dislocation density rate of change + DotRhoScrewGeneration(j)+DotRhoScrewAnnihilation(j) + + plasticState(ph)%dotState(2*ns+j, of) = & ! sum of shear due to edge and screw + plasticState(ph)%state(10*ns+2*nt+j, of)+plasticState(ph)%state(11*ns+2*nt+j, of) + enddo + enddo slipFamiliesLoop + +!* Twin fraction evolution + j = 0_pInt + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) twin system in family + j = j+1_pInt + + !* Resolved shear stress on twin system + tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + !* Stress ratio for edge + twinStressRatio_p = ((abs(tau_twin(j)))/ & + ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & + )**(plastic_titanmod_twinp_PerTwinSys(j,instance)) + + + if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then + twinminusStressRatio_p=1.0_pReal-twinStressRatio_p + else + twinminusStressRatio_p=0.001_pReal + endif + + BoltzmannRatio = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) + + gdot_twin(j) =plastic_titanmod_twingamma0_PerTwinSys(j,instance)*exp(-BoltzmannRatio* & + (twinminusStressRatio_p)** & + plastic_titanmod_twinq_PerTwinSys(j,instance))*sign(1.0_pReal,tau_twin(j)) + + plasticState(ph)%dotState(3*ns+j, of)=gdot_twin(j) + + enddo + enddo twinFamiliesLoop + +end subroutine plastic_titanmod_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_titanmod_postResults(ipc,ip,el) + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(plastic_titanmod_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_titanmod_postResults + + integer(pInt) :: & + instance, & + ns,nt,& + o,i,c, & + ph, & + of + real(pReal) :: sumf + + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + volumefraction_PerTwinSys + +!-------------------------------------------------------------------------------------------------- +! shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + enddo + + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + + +!-------------------------------------------------------------------------------------------------- +! required output + c = 0_pInt + plastic_titanmod_postResults = 0.0_pReal + + do o = 1_pInt,plastic_titanmod_Noutput(instance) + select case(plastic_titanmod_outputID(o,instance)) + case (rhoedge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(1_pInt:ns, of) + c = c + ns + case (rhoscrew_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of) + c = c + ns + case (segment_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(3_pInt*ns+nt+1_pInt:4_pInt*ns+nt, of) + c = c + ns + case (segment_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(4_pInt*ns+nt+1_pInt:5_pInt*ns+nt, of) + c = c + ns + case (resistance_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(5_pInt*ns+nt+1_pInt:6_pInt*ns+nt, of) + c = c + ns + case (resistance_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(6_pInt*ns+nt+1_pInt:7_pInt*ns+nt, of) + c = c + ns + case (velocity_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(7*ns+2*nt+1:8*ns+2*nt, of) + c = c + ns + case (velocity_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(8*ns+2*nt+1:9*ns+2*nt, of) + c = c + ns + case (tau_slip_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(9*ns+2*nt+1:10*ns+2*nt, of)) + c = c + ns + case (gdot_slip_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) + c = c + ns + case (gdot_slip_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) + c = c + ns + case (gdot_slip_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) + & + abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) + c = c + ns + case (stressratio_edge_p_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(12*ns+2*nt+1:13*ns+2*nt, of)) + c = c + ns + case (stressratio_screw_p_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(13*ns+2*nt+1:14*ns+2*nt, of)) + c = c + ns + case (shear_system_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(2*ns+1:3*ns, of)) + c = c + ns + case (shear_basal_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:2*ns+3, of))) + c = c + 1_pInt + case (shear_prism_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+4:2*ns+6, of))) + c = c + 1_pInt + case (shear_pyra_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+7:2*ns+12, of))) + c = c + 1_pInt + case (shear_pyrca_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+13:2*ns+24, of))) + c = c + 1_pInt + + case (rhoedge_basal_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(1:3, of)) + c = c + 1_pInt + case (rhoedge_prism_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(4:6, of)) + c = c + 1_pInt + case (rhoedge_pyra_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(7:12,of)) + c = c + 1_pInt + case (rhoedge_pyrca_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(13:24, of)) + c = c + 1_pInt + + case (rhoscrew_basal_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+1:ns+3, of)) + c = c + 1_pInt + case (rhoscrew_prism_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+4:ns+6, of)) + c = c + 1_pInt + case (rhoscrew_pyra_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+7:ns+12, of)) + c = c + 1_pInt + case (rhoscrew_pyrca_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+13:ns+24, of)) + c = c + 1_pInt + case (shear_total_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:3*ns, of))) + c = c + 1_pInt + case (twin_fraction_ID) + plastic_titanmod_postResults(c+1_pInt:c+nt) = abs(volumefraction_PerTwinSys(1:nt)) + c = c + nt + end select + enddo + +end function plastic_titanmod_postResults + +end module plastic_titanmod diff --git a/code/source_damage_anisoBrittle.f90 b/code/source_damage_anisoBrittle.f90 new file mode 100644 index 000000000..a751eefdc --- /dev/null +++ b/code/source_damage_anisoBrittle.f90 @@ -0,0 +1,425 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @brief material subroutine incorporating anisotropic brittle damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_anisoBrittle + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_anisoBrittle_sizePostResults, & !< cumulative size of post results + source_damage_anisoBrittle_offset, & !< which source is my current source mechanism? + source_damage_anisoBrittle_instance !< instance of source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_anisoBrittle_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_anisoBrittle_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_anisoBrittle_Noutput !< number of outputs per instance of this source + + integer(pInt), dimension(:), allocatable, private :: & + source_damage_anisoBrittle_totalNcleavage !< total number of cleavage systems + + integer(pInt), dimension(:,:), allocatable, private :: & + source_damage_anisoBrittle_Ncleavage !< number of cleavage systems per family + + real(pReal), dimension(:), allocatable, private :: & + source_damage_anisoBrittle_aTol, & + source_damage_anisoBrittle_sdot_0, & + source_damage_anisoBrittle_N + + real(pReal), dimension(:,:), allocatable, private :: & + source_damage_anisoBrittle_critDisp, & + source_damage_anisoBrittle_critLoad + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_anisoBrittle_outputID !< ID of each post result output + + + public :: & + source_damage_anisoBrittle_init, & + source_damage_anisoBrittle_dotState, & + source_damage_anisobrittle_getRateAndItsTangent, & + source_damage_anisoBrittle_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoBrittle_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_anisoBrittle_label, & + SOURCE_damage_anisoBrittle_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + use lattice, only: & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoBrittle_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_anisoBrittle_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_anisoBrittle_offset(material_Nphase), source=0_pInt) + allocate(source_damage_anisoBrittle_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_anisoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoBrittle_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_anisoBrittle_ID) & + source_damage_anisoBrittle_offset(phase) = source + enddo + enddo + + allocate(source_damage_anisoBrittle_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_output(maxval(phase_Noutput),maxNinstance)) + source_damage_anisoBrittle_output = '' + allocate(source_damage_anisoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_anisoBrittle_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_totalNcleavage(maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_aTol(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_sdot_0(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_N(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_anisoBrittle_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('anisobrittle_drivingforce') + source_damage_anisoBrittle_Noutput(instance) = source_damage_anisoBrittle_Noutput(instance) + 1_pInt + source_damage_anisoBrittle_outputID(source_damage_anisoBrittle_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_anisoBrittle_output(source_damage_anisoBrittle_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('anisobrittle_atol') + source_damage_anisoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisobrittle_sdot0') + source_damage_anisoBrittle_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisobrittle_ratesensitivity') + source_damage_anisoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('ncleavage') ! + Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_CleavageFamilies + source_damage_anisoBrittle_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticaldisplacement') + do j = 1_pInt, Nchunks_CleavageFamilies + source_damage_anisoBrittle_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticalload') + do j = 1_pInt, Nchunks_CleavageFamilies + source_damage_anisoBrittle_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then + instance = source_damage_anisoBrittle_instance(phase) + source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & + min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested + source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance)) + source_damage_anisoBrittle_totalNcleavage(instance) = sum(source_damage_anisoBrittle_Ncleavage(:,instance)) ! how many cleavage systems altogether + if (source_damage_anisoBrittle_aTol(instance) < 0.0_pReal) & + source_damage_anisoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_anisoBrittle_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoBrittle_LABEL//')') + if (any(source_damage_anisoBrittle_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//SOURCE_damage_anisoBrittle_LABEL//')') + if (any(source_damage_anisoBrittle_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//SOURCE_damage_anisoBrittle_LABEL//')') + if (source_damage_anisoBrittle_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoBrittle_LABEL//')') + endif myPhase + enddo sanityChecks + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_anisoBrittle_instance(phase) + sourceOffset = source_damage_anisoBrittle_offset(phase) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) + select case(source_damage_anisoBrittle_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_anisoBrittle_sizePostResult(o,instance) = mySize + source_damage_anisoBrittle_sizePostResults(instance) = source_damage_anisoBrittle_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoBrittle_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_anisoBrittle_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_anisoBrittle_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoBrittle_dotState(Tstar_v, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState, & + material_homog, & + damage, & + damageMapping + use lattice, only: & + lattice_Scleavage_v, & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) + integer(pInt) :: & + phase, & + constituent, & + instance, & + sourceOffset, & + damageOffset, & + homog, & + f, i, index_myFamily + real(pReal) :: & + traction_d, traction_t, traction_n, traction_crit + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoBrittle_instance(phase) + sourceOffset = source_damage_anisoBrittle_offset(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal + do f = 1_pInt,lattice_maxNcleavageFamily + index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family + do i = 1_pInt,source_damage_anisoBrittle_Ncleavage(f,instance) ! process each (active) cleavage system in family + traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) + traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) + traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) + + traction_crit = source_damage_anisoBrittle_critLoad(f,instance)* & + damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & + source_damage_anisoBrittle_sdot_0(instance)* & + ((max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & + (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & + (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance))/ & + source_damage_anisoBrittle_critDisp(f,instance) + + enddo + enddo + +end subroutine source_damage_anisoBrittle_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_damage_anisoBrittle_offset(phase) + + localphiDot = 1.0_pReal - & + sourceState(phase)%p(sourceOffset)%state(1,constituent)*phi + + dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_anisobrittle_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_anisoBrittle_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_anisoBrittle_sizePostResults( & + source_damage_anisoBrittle_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_anisoBrittle_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoBrittle_instance(phase) + sourceOffset = source_damage_anisoBrittle_offset(phase) + + c = 0_pInt + source_damage_anisoBrittle_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) + select case(source_damage_anisoBrittle_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_anisoBrittle_postResults(c+1_pInt) = & + sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1_pInt + + end select + enddo +end function source_damage_anisoBrittle_postResults + +end module source_damage_anisoBrittle diff --git a/code/source_damage_anisoDuctile.f90 b/code/source_damage_anisoDuctile.f90 new file mode 100644 index 000000000..028fd479a --- /dev/null +++ b/code/source_damage_anisoDuctile.f90 @@ -0,0 +1,415 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating anisotropic ductile damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_anisoDuctile + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_anisoDuctile_sizePostResults, & !< cumulative size of post results + source_damage_anisoDuctile_offset, & !< which source is my current damage mechanism? + source_damage_anisoDuctile_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_anisoDuctile_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_anisoDuctile_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_anisoDuctile_Noutput !< number of outputs per instance of this damage + + integer(pInt), dimension(:), allocatable, private :: & + source_damage_anisoDuctile_totalNslip !< total number of slip systems + + integer(pInt), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_Nslip !< number of slip systems per family + + real(pReal), dimension(:), allocatable, private :: & + source_damage_anisoDuctile_aTol + + real(pReal), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_critPlasticStrain + + real(pReal), dimension(:), allocatable, private :: & + source_damage_anisoDuctile_sdot_0, & + source_damage_anisoDuctile_N + + real(pReal), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_critLoad + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_outputID !< ID of each post result output + + + public :: & + source_damage_anisoDuctile_init, & + source_damage_anisoDuctile_dotState, & + source_damage_anisoDuctile_getRateAndItsTangent, & + source_damage_anisoDuctile_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoDuctile_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_anisoDuctile_label, & + SOURCE_damage_anisoDuctile_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + use lattice, only: & + lattice_maxNslipFamily, & + lattice_NslipSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoDuctile_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_anisoDuctile_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_anisoDuctile_offset(material_Nphase), source=0_pInt) + allocate(source_damage_anisoDuctile_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_anisoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoDuctile_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_anisoDuctile_ID) & + source_damage_anisoDuctile_offset(phase) = source + enddo + enddo + + allocate(source_damage_anisoDuctile_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_damage_anisoDuctile_output(maxval(phase_Noutput),maxNinstance)) + source_damage_anisoDuctile_output = '' + allocate(source_damage_anisoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_anisoDuctile_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoDuctile_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(source_damage_anisoDuctile_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_totalNslip(maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_N(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoDuctile_sdot_0(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoDuctile_aTol(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_anisoDuctile_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('anisoductile_drivingforce') + source_damage_anisoDuctile_Noutput(instance) = source_damage_anisoDuctile_Noutput(instance) + 1_pInt + source_damage_anisoDuctile_outputID(source_damage_anisoDuctile_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_anisoDuctile_output(source_damage_anisoDuctile_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('anisoductile_atol') + source_damage_anisoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('nslip') ! + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + source_damage_anisoDuctile_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_sdot0') + source_damage_anisoDuctile_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalplasticstrain') + do j = 1_pInt, Nchunks_SlipFamilies + source_damage_anisoDuctile_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_ratesensitivity') + source_damage_anisoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalload') + do j = 1_pInt, Nchunks_SlipFamilies + source_damage_anisoDuctile_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, size(phase_source) + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then + instance = source_damage_anisoDuctile_instance(phase) + source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested + source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance)) + source_damage_anisoDuctile_totalNslip(instance) = sum(source_damage_anisoDuctile_Nslip(:,instance)) + if (source_damage_anisoDuctile_aTol(instance) < 0.0_pReal) & + source_damage_anisoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_anisoDuctile_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoDuctile_LABEL//')') + if (any(source_damage_anisoDuctile_critPlasticStrain(:,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//SOURCE_damage_anisoDuctile_LABEL//')') + if (source_damage_anisoDuctile_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoDuctile_LABEL//')') + endif myPhase + enddo sanityChecks + + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_anisoDuctile_instance(phase) + sourceOffset = source_damage_anisoDuctile_offset(phase) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) + select case(source_damage_anisoDuctile_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_anisoDuctile_sizePostResult(o,instance) = mySize + source_damage_anisoDuctile_sizePostResults(instance) = source_damage_anisoDuctile_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoDuctile_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_anisoDuctile_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_anisoDuctile_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoDuctile_dotState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + sourceState, & + material_homog, & + damage, & + damageMapping + use lattice, only: & + lattice_maxNslipFamily + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, & + constituent, & + sourceOffset, & + homog, damageOffset, & + instance, & + index, f, i + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoDuctile_instance(phase) + sourceOffset = source_damage_anisoDuctile_offset(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + index = 1_pInt + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal + do f = 1_pInt,lattice_maxNslipFamily + do i = 1_pInt,source_damage_anisoDuctile_Nslip(f,instance) ! process each (active) slip system in family + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & + plasticState(phase)%slipRate(index,constituent)/ & + ((damage(homog)%p(damageOffset))**source_damage_anisoDuctile_N(instance))/ & + source_damage_anisoDuctile_critPlasticStrain(f,instance) + + index = index + 1_pInt + enddo + enddo + +end subroutine source_damage_anisoDuctile_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_damage_anisoDuctile_offset(phase) + + localphiDot = 1.0_pReal - & + sourceState(phase)%p(sourceOffset)%state(1,constituent)* & + phi + + dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_anisoDuctile_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_anisoDuctile_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_anisoDuctile_sizePostResults( & + source_damage_anisoDuctile_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_anisoDuctile_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoDuctile_instance(phase) + sourceOffset = source_damage_anisoDuctile_offset(phase) + + c = 0_pInt + source_damage_anisoDuctile_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) + select case(source_damage_anisoDuctile_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_anisoDuctile_postResults(c+1_pInt) = & + sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1_pInt + + end select + enddo +end function source_damage_anisoDuctile_postResults + +end module source_damage_anisoDuctile diff --git a/code/source_damage_isoBrittle.f90 b/code/source_damage_isoBrittle.f90 new file mode 100644 index 000000000..c063ae86f --- /dev/null +++ b/code/source_damage_isoBrittle.f90 @@ -0,0 +1,383 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incoprorating isotropic brittle damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_isoBrittle + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_isoBrittle_sizePostResults, & !< cumulative size of post results + source_damage_isoBrittle_offset, & !< which source is my current damage mechanism? + source_damage_isoBrittle_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_isoBrittle_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_isoBrittle_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_isoBrittle_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_damage_isoBrittle_aTol, & + source_damage_isoBrittle_N, & + source_damage_isoBrittle_critStrainEnergy + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_isoBrittle_outputID !< ID of each post result output + + + public :: & + source_damage_isoBrittle_init, & + source_damage_isoBrittle_deltaState, & + source_damage_isoBrittle_getRateAndItsTangent, & + source_damage_isoBrittle_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoBrittle_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_isoBrittle_label, & + SOURCE_damage_isoBrittle_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoBrittle_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_isoBrittle_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_isoBrittle_offset(material_Nphase), source=0_pInt) + allocate(source_damage_isoBrittle_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_isoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoBrittle_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_isoBrittle_ID) & + source_damage_isoBrittle_offset(phase) = source + enddo + enddo + + allocate(source_damage_isoBrittle_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_isoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_damage_isoBrittle_output(maxval(phase_Noutput),maxNinstance)) + source_damage_isoBrittle_output = '' + allocate(source_damage_isoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_isoBrittle_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_isoBrittle_critStrainEnergy(maxNinstance), source=0.0_pReal) + allocate(source_damage_isoBrittle_N(maxNinstance), source=1.0_pReal) + allocate(source_damage_isoBrittle_aTol(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_isoBrittle_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('isobrittle_drivingforce') + source_damage_isoBrittle_Noutput(instance) = source_damage_isoBrittle_Noutput(instance) + 1_pInt + source_damage_isoBrittle_outputID(source_damage_isoBrittle_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_isoBrittle_output(source_damage_isoBrittle_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('isobrittle_criticalstrainenergy') + source_damage_isoBrittle_critStrainEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isobrittle_n') + source_damage_isoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isobrittle_atol') + source_damage_isoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then + instance = source_damage_isoBrittle_instance(phase) + if (source_damage_isoBrittle_aTol(instance) < 0.0_pReal) & + source_damage_isoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_isoBrittle_critStrainEnergy(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='criticalStrainEnergy ('//SOURCE_damage_isoBrittle_LABEL//')') + endif myPhase + enddo sanityChecks + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_isoBrittle_instance(phase) + sourceOffset = source_damage_isoBrittle_offset(phase) +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) + select case(source_damage_isoBrittle_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_isoBrittle_sizePostResult(o,instance) = mySize + source_damage_isoBrittle_sizePostResults(instance) = source_damage_isoBrittle_sizePostResults(instance) + mySize + endif + enddo outputsLoop +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 1_pInt + sizeState = 1_pInt + + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoBrittle_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_isoBrittle_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_isoBrittle_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoBrittle_deltaState(C, Fe, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState, & + material_homog, & + phase_NstiffnessDegradations, & + phase_stiffnessDegradation, & + porosity, & + porosityMapping, & + STIFFNESS_DEGRADATION_porosity_ID + use math, only : & + math_mul33x33, & + math_mul66x6, & + math_Mandel33to6, & + math_transpose33, & + math_I3 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(3,3) :: & + Fe + real(pReal), intent(in), dimension(6,6) :: & + C + integer(pInt) :: & + phase, constituent, instance, sourceOffset, mech + real(pReal) :: & + strain(6), & + stiffness(6,6), & + strainenergy + + phase = phaseAt(ipc,ip,el) !< phase ID at ipc,ip,el + constituent = phasememberAt(ipc,ip,el) !< state array offset for phase ID at ipc,ip,el + ! ToDo: capability for multiple instances of SAME source within given phase. Needs Ninstance loop from here on! + instance = source_damage_isoBrittle_instance(phase) !< instance of damage_isoBrittle source + sourceOffset = source_damage_isoBrittle_offset(phase) + + stiffness = C + do mech = 1_pInt, phase_NstiffnessDegradations(phase) + select case(phase_stiffnessDegradation(mech,phase)) + case (STIFFNESS_DEGRADATION_porosity_ID) + stiffness = porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & + porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & + stiffness + end select + enddo + strain = 0.5_pReal*math_Mandel33to6(math_mul33x33(math_transpose33(Fe),Fe)-math_I3) + + strainenergy = 2.0_pReal*sum(strain*math_mul66x6(stiffness,strain))/ & + source_damage_isoBrittle_critStrainEnergy(instance) + if (strainenergy > sourceState(phase)%p(sourceOffset)%subState0(1,constituent)) then + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + strainenergy - sourceState(phase)%p(sourceOffset)%state(1,constituent) + else + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + sourceState(phase)%p(sourceOffset)%subState0(1,constituent) - & + sourceState(phase)%p(sourceOffset)%state(1,constituent) + endif + +end subroutine source_damage_isoBrittle_deltaState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoBrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, instance, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoBrittle_instance(phase) + sourceOffset = source_damage_isoBrittle_offset(phase) + + localphiDot = (1.0_pReal - phi)**(source_damage_isoBrittle_N(instance) - 1.0_pReal) - & + phi*sourceState(phase)%p(sourceOffset)%state(1,constituent) + dLocalphiDot_dPhi = - (source_damage_isoBrittle_N(instance) - 1.0_pReal)* & + (1.0_pReal - phi)**max(0.0_pReal,source_damage_isoBrittle_N(instance) - 2.0_pReal) & + - sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_isoBrittle_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_isoBrittle_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_isoBrittle_sizePostResults( & + source_damage_isoBrittle_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_isoBrittle_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoBrittle_instance(phase) + sourceOffset = source_damage_isoBrittle_offset(phase) + + c = 0_pInt + source_damage_isoBrittle_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) + select case(source_damage_isoBrittle_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_isoBrittle_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1 + + end select + enddo +end function source_damage_isoBrittle_postResults + +end module source_damage_isoBrittle diff --git a/code/source_damage_isoDuctile.f90 b/code/source_damage_isoDuctile.f90 new file mode 100644 index 000000000..b0290264c --- /dev/null +++ b/code/source_damage_isoDuctile.f90 @@ -0,0 +1,350 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @brief material subroutine incoprorating isotropic ductile damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_isoDuctile + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_isoDuctile_sizePostResults, & !< cumulative size of post results + source_damage_isoDuctile_offset, & !< which source is my current damage mechanism? + source_damage_isoDuctile_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_isoDuctile_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_isoDuctile_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_isoDuctile_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_damage_isoDuctile_aTol, & + source_damage_isoDuctile_critPlasticStrain, & + source_damage_isoDuctile_N + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_isoDuctile_outputID !< ID of each post result output + + + public :: & + source_damage_isoDuctile_init, & + source_damage_isoDuctile_dotState, & + source_damage_isoDuctile_getRateAndItsTangent, & + source_damage_isoDuctile_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoDuctile_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_isoDuctile_label, & + SOURCE_damage_isoDuctile_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoDuctile_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_isoDuctile_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_isoDuctile_offset(material_Nphase), source=0_pInt) + allocate(source_damage_isoDuctile_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_isoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoDuctile_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_isoDuctile_ID) & + source_damage_isoDuctile_offset(phase) = source + enddo + enddo + + allocate(source_damage_isoDuctile_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_isoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_damage_isoDuctile_output(maxval(phase_Noutput),maxNinstance)) + source_damage_isoDuctile_output = '' + allocate(source_damage_isoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_isoDuctile_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_isoDuctile_critPlasticStrain(maxNinstance), source=0.0_pReal) + allocate(source_damage_isoDuctile_N(maxNinstance), source=0.0_pReal) + allocate(source_damage_isoDuctile_aTol(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_isoDuctile_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('isoductile_drivingforce') + source_damage_isoDuctile_Noutput(instance) = source_damage_isoDuctile_Noutput(instance) + 1_pInt + source_damage_isoDuctile_outputID(source_damage_isoDuctile_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_isoDuctile_output(source_damage_isoDuctile_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('isoductile_criticalplasticstrain') + source_damage_isoDuctile_critPlasticStrain(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isoductile_ratesensitivity') + source_damage_isoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isoductile_atol') + source_damage_isoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then + instance = source_damage_isoDuctile_instance(phase) + if (source_damage_isoDuctile_aTol(instance) < 0.0_pReal) & + source_damage_isoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_isoDuctile_critPlasticStrain(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='critical plastic strain ('//SOURCE_damage_isoDuctile_LABEL//')') + endif myPhase + enddo sanityChecks + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_isoDuctile_instance(phase) + sourceOffset = source_damage_isoDuctile_offset(phase) +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) + select case(source_damage_isoDuctile_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_isoDuctile_sizePostResult(o,instance) = mySize + source_damage_isoDuctile_sizePostResults(instance) = source_damage_isoDuctile_sizePostResults(instance) + mySize + endif + enddo outputsLoop +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoDuctile_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_isoDuctile_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_isoDuctile_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoDuctile_dotState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + sourceState, & + material_homog, & + damage, & + damageMapping + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, constituent, instance, homog, sourceOffset, damageOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoDuctile_instance(phase) + sourceOffset = source_damage_isoDuctile_offset(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & + sum(plasticState(phase)%slipRate(:,constituent))/ & + ((damage(homog)%p(damageOffset))**source_damage_isoDuctile_N(instance))/ & + source_damage_isoDuctile_critPlasticStrain(instance) + +end subroutine source_damage_isoDuctile_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_damage_isoDuctile_offset(phase) + + localphiDot = 1.0_pReal - & + sourceState(phase)%p(sourceOffset)%state(1,constituent)* & + phi + + dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_isoDuctile_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_isoDuctile_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_isoDuctile_sizePostResults( & + source_damage_isoDuctile_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_isoDuctile_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoDuctile_instance(phase) + sourceOffset = source_damage_isoDuctile_offset(phase) + + c = 0_pInt + source_damage_isoDuctile_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) + select case(source_damage_isoDuctile_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_isoDuctile_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1 + + end select + enddo +end function source_damage_isoDuctile_postResults + +end module source_damage_isoDuctile diff --git a/code/source_thermal_dissipation.f90 b/code/source_thermal_dissipation.f90 new file mode 100644 index 000000000..83ad85167 --- /dev/null +++ b/code/source_thermal_dissipation.f90 @@ -0,0 +1,220 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for thermal source due to plastic dissipation +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_thermal_dissipation + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_thermal_dissipation_sizePostResults, & !< cumulative size of post results + source_thermal_dissipation_offset, & !< which source is my current thermal dissipation mechanism? + source_thermal_dissipation_instance !< instance of thermal dissipation source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_thermal_dissipation_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_thermal_dissipation_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_thermal_dissipation_Noutput !< number of outputs per instance of this source + + real(pReal), dimension(:), allocatable, private :: & + source_thermal_dissipation_coldworkCoeff + + public :: & + source_thermal_dissipation_init, & + source_thermal_dissipation_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_dissipation_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_thermal_dissipation_label, & + SOURCE_thermal_dissipation_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_dissipation_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_thermal_dissipation_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_thermal_dissipation_offset(material_Nphase), source=0_pInt) + allocate(source_thermal_dissipation_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_thermal_dissipation_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_dissipation_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == SOURCE_thermal_dissipation_ID) & + source_thermal_dissipation_offset(phase) = source + enddo + enddo + + allocate(source_thermal_dissipation_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_thermal_dissipation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_thermal_dissipation_output (maxval(phase_Noutput),maxNinstance)) + source_thermal_dissipation_output = '' + allocate(source_thermal_dissipation_Noutput(maxNinstance), source=0_pInt) + allocate(source_thermal_dissipation_coldworkCoeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_thermal_dissipation_instance(phase) ! which instance of my source is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('dissipation_coldworkcoeff') + source_thermal_dissipation_coldworkCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_thermal_dissipation_instance(phase) + sourceOffset = source_thermal_dissipation_offset(phase) + + sizeDotState = 0_pInt + sizeDeltaState = 0_pInt + sizeState = 0_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_dissipation_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_thermal_dissipation_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_dissipation_getRateAndItsTangent(TDot, dTDOT_dT, Tstar_v, Lp, ipc, ip, el) + use math, only: & + math_Mandel6to33 + use material, only: & + phaseAt, phasememberAt + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) + real(pReal), intent(in), dimension(3,3) :: & + Lp + real(pReal), intent(out) :: & + TDot, & + dTDOT_dT + integer(pInt) :: & + instance, phase, constituent + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_thermal_dissipation_instance(phase) + + TDot = source_thermal_dissipation_coldworkCoeff(instance)* & + sum(abs(math_Mandel6to33(Tstar_v)*Lp)) + dTDOT_dT = 0.0_pReal + +end subroutine source_thermal_dissipation_getRateAndItsTangent + +end module source_thermal_dissipation diff --git a/code/source_thermal_externalheat.f90 b/code/source_thermal_externalheat.f90 new file mode 100644 index 000000000..257012c06 --- /dev/null +++ b/code/source_thermal_externalheat.f90 @@ -0,0 +1,277 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for thermal source due to plastic dissipation +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_thermal_externalheat + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_thermal_externalheat_sizePostResults, & !< cumulative size of post results + source_thermal_externalheat_offset, & !< which source is my current thermal dissipation mechanism? + source_thermal_externalheat_instance !< instance of thermal dissipation source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_thermal_externalheat_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_thermal_externalheat_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_thermal_externalheat_Noutput !< number of outputs per instance of this source + + integer(pInt), dimension(:), allocatable, private :: & + source_thermal_externalheat_nIntervals + + real(pReal), dimension(:,:), allocatable, private :: & + source_thermal_externalheat_time, & + source_thermal_externalheat_rate + + public :: & + source_thermal_externalheat_init, & + source_thermal_externalheat_dotState, & + source_thermal_externalheat_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_externalheat_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_thermal_externalheat_label, & + SOURCE_thermal_externalheat_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase,interval + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), allocatable, dimension(:,:) :: temp_time, temp_rate + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_externalheat_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_thermal_externalheat_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_thermal_externalheat_offset(material_Nphase), source=0_pInt) + allocate(source_thermal_externalheat_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_thermal_externalheat_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_externalheat_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == SOURCE_thermal_externalheat_ID) & + source_thermal_externalheat_offset(phase) = source + enddo + enddo + + allocate(source_thermal_externalheat_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_thermal_externalheat_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_thermal_externalheat_output (maxval(phase_Noutput),maxNinstance)) + source_thermal_externalheat_output = '' + allocate(source_thermal_externalheat_Noutput(maxNinstance), source=0_pInt) + allocate(source_thermal_externalheat_nIntervals(maxNinstance), source=0_pInt) + + allocate(temp_time(maxNinstance,1000), source=0.0_pReal) + allocate(temp_rate(maxNinstance,1000), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_thermal_externalheat_instance(phase) ! which instance of my source is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('externalheat_time') + if (chunkPos(1) <= 2_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//SOURCE_thermal_externalheat_label//')') + source_thermal_externalheat_nIntervals(instance) = chunkPos(1) - 2_pInt + do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt + temp_time(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) + enddo + + case ('externalheat_rate') + do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt + temp_rate(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) + enddo + + end select + endif; endif + enddo parsingFile + + allocate(source_thermal_externalheat_time(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) + allocate(source_thermal_externalheat_rate(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_thermal_externalheat_instance(phase) + sourceOffset = source_thermal_externalheat_offset(phase) + source_thermal_externalheat_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & + temp_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) + source_thermal_externalheat_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & + temp_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) + + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_externalheat_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.00001_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_thermal_externalheat_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_externalheat_dotState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, & + constituent, & + sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_thermal_externalheat_offset(phase) + + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 1.0_pReal + +end subroutine source_thermal_externalheat_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_externalheat_getRateAndItsTangent(TDot, dTDot_dT, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + TDot, & + dTDot_dT + integer(pInt) :: & + instance, phase, constituent, sourceOffset, interval + real(pReal) :: & + norm_time + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_thermal_externalheat_instance(phase) + sourceOffset = source_thermal_externalheat_offset(phase) + + do interval = 1, source_thermal_externalheat_nIntervals(instance) + norm_time = (sourceState(phase)%p(sourceOffset)%state(1,constituent) - & + source_thermal_externalheat_time(instance,interval)) / & + (source_thermal_externalheat_time(instance,interval+1) - & + source_thermal_externalheat_time(instance,interval)) + if (norm_time >= 0.0_pReal .and. norm_time < 1.0_pReal) & + TDot = source_thermal_externalheat_rate(instance,interval ) * (1.0_pReal - norm_time) + & + source_thermal_externalheat_rate(instance,interval+1) * norm_time + enddo + dTDot_dT = 0.0 + +end subroutine source_thermal_externalheat_getRateAndItsTangent + +end module source_thermal_externalheat diff --git a/code/source_vacancy_irradiation.f90 b/code/source_vacancy_irradiation.f90 new file mode 100644 index 000000000..c4bcfba04 --- /dev/null +++ b/code/source_vacancy_irradiation.f90 @@ -0,0 +1,253 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for vacancy generation due to irradiation +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_vacancy_irradiation + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_vacancy_irradiation_sizePostResults, & !< cumulative size of post results + source_vacancy_irradiation_offset, & !< which source is my current damage mechanism? + source_vacancy_irradiation_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_vacancy_irradiation_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_vacancy_irradiation_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_vacancy_irradiation_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_vacancy_irradiation_cascadeProb, & + source_vacancy_irradiation_cascadeVolume + + public :: & + source_vacancy_irradiation_init, & + source_vacancy_irradiation_deltaState, & + source_vacancy_irradiation_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_irradiation_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_vacancy_irradiation_label, & + SOURCE_vacancy_irradiation_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_irradiation_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_vacancy_irradiation_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_vacancy_irradiation_offset(material_Nphase), source=0_pInt) + allocate(source_vacancy_irradiation_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_vacancy_irradiation_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_irradiation_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_vacancy_irradiation_ID) & + source_vacancy_irradiation_offset(phase) = source + enddo + enddo + + allocate(source_vacancy_irradiation_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_vacancy_irradiation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_vacancy_irradiation_output(maxval(phase_Noutput),maxNinstance)) + source_vacancy_irradiation_output = '' + allocate(source_vacancy_irradiation_Noutput(maxNinstance), source=0_pInt) + allocate(source_vacancy_irradiation_cascadeProb(maxNinstance), source=0.0_pReal) + allocate(source_vacancy_irradiation_cascadeVolume(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_vacancy_irradiation_instance(phase) ! which instance of my vacancy is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('irradiation_cascadeprobability') + source_vacancy_irradiation_cascadeProb(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('irradiation_cascadevolume') + source_vacancy_irradiation_cascadeVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_vacancy_irradiation_instance(phase) + sourceOffset = source_vacancy_irradiation_offset(phase) + + sizeDotState = 2_pInt + sizeDeltaState = 2_pInt + sizeState = 2_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_irradiation_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_vacancy_irradiation_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_irradiation_deltaState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, constituent, sourceOffset + real(pReal) :: & + randNo + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_vacancy_irradiation_offset(phase) + + call random_number(randNo) + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + randNo - sourceState(phase)%p(sourceOffset)%state(1,constituent) + call random_number(randNo) + sourceState(phase)%p(sourceOffset)%deltaState(2,constituent) = & + randNo - sourceState(phase)%p(sourceOffset)%state(2,constituent) + +end subroutine source_vacancy_irradiation_deltaState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_irradiation_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + CvDot, dCvDot_dCv + integer(pInt) :: & + instance, phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_vacancy_irradiation_instance(phase) + sourceOffset = source_vacancy_irradiation_offset(phase) + + CvDot = 0.0_pReal + dCvDot_dCv = 0.0_pReal + if (sourceState(phase)%p(sourceOffset)%state0(1,constituent) < source_vacancy_irradiation_cascadeProb(instance)) & + CvDot = sourceState(phase)%p(sourceOffset)%state0(2,constituent)*source_vacancy_irradiation_cascadeVolume(instance) + +end subroutine source_vacancy_irradiation_getRateAndItsTangent + +end module source_vacancy_irradiation diff --git a/code/source_vacancy_phenoplasticity.f90 b/code/source_vacancy_phenoplasticity.f90 new file mode 100644 index 000000000..f9e766b2c --- /dev/null +++ b/code/source_vacancy_phenoplasticity.f90 @@ -0,0 +1,215 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for vacancy generation due to plasticity +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_vacancy_phenoplasticity + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_vacancy_phenoplasticity_sizePostResults, & !< cumulative size of post results + source_vacancy_phenoplasticity_offset, & !< which source is my current damage mechanism? + source_vacancy_phenoplasticity_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_vacancy_phenoplasticity_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_vacancy_phenoplasticity_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_vacancy_phenoplasticity_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_vacancy_phenoplasticity_rateCoeff + + public :: & + source_vacancy_phenoplasticity_init, & + source_vacancy_phenoplasticity_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_phenoplasticity_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_vacancy_phenoplasticity_label, & + SOURCE_vacancy_phenoplasticity_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_phenoplasticity_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_vacancy_phenoplasticity_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_vacancy_phenoplasticity_offset(material_Nphase), source=0_pInt) + allocate(source_vacancy_phenoplasticity_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_vacancy_phenoplasticity_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_phenoplasticity_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_vacancy_phenoplasticity_ID) & + source_vacancy_phenoplasticity_offset(phase) = source + enddo + enddo + + allocate(source_vacancy_phenoplasticity_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_vacancy_phenoplasticity_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_vacancy_phenoplasticity_output(maxval(phase_Noutput),maxNinstance)) + source_vacancy_phenoplasticity_output = '' + allocate(source_vacancy_phenoplasticity_Noutput(maxNinstance), source=0_pInt) + allocate(source_vacancy_phenoplasticity_rateCoeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_vacancy_phenoplasticity_instance(phase) ! which instance of my vacancy is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('phenoplasticity_ratecoeff') + source_vacancy_phenoplasticity_rateCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_vacancy_phenoplasticity_instance(phase) + sourceOffset = source_vacancy_phenoplasticity_offset(phase) + + sizeDotState = 0_pInt + sizeDeltaState = 0_pInt + sizeState = 0_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_phenoplasticity_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_vacancy_phenoplasticity_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_phenoplasticity_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + plasticState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + CvDot, dCvDot_dCv + integer(pInt) :: & + instance, phase, constituent + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_vacancy_phenoplasticity_instance(phase) + + CvDot = & + source_vacancy_phenoplasticity_rateCoeff(instance)* & + sum(plasticState(phase)%slipRate(:,constituent)) + dCvDot_dCv = 0.0_pReal + +end subroutine source_vacancy_phenoplasticity_getRateAndItsTangent + +end module source_vacancy_phenoplasticity diff --git a/code/source_vacancy_thermalfluc.f90 b/code/source_vacancy_thermalfluc.f90 new file mode 100644 index 000000000..c86406430 --- /dev/null +++ b/code/source_vacancy_thermalfluc.f90 @@ -0,0 +1,255 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for vacancy generation due to thermal fluctuations +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_vacancy_thermalfluc + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_vacancy_thermalfluc_sizePostResults, & !< cumulative size of post results + source_vacancy_thermalfluc_offset, & !< which source is my current damage mechanism? + source_vacancy_thermalfluc_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_vacancy_thermalfluc_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_vacancy_thermalfluc_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_vacancy_thermalfluc_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_vacancy_thermalfluc_amplitude, & + source_vacancy_thermalfluc_normVacancyEnergy + + public :: & + source_vacancy_thermalfluc_init, & + source_vacancy_thermalfluc_deltaState, & + source_vacancy_thermalfluc_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_thermalfluc_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use lattice, only: & + lattice_vacancyFormationEnergy + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_vacancy_thermalfluc_label, & + SOURCE_vacancy_thermalfluc_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_thermalfluc_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_vacancy_thermalfluc_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_vacancy_thermalfluc_offset(material_Nphase), source=0_pInt) + allocate(source_vacancy_thermalfluc_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_vacancy_thermalfluc_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_thermalfluc_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_vacancy_thermalfluc_ID) & + source_vacancy_thermalfluc_offset(phase) = source + enddo + enddo + + allocate(source_vacancy_thermalfluc_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_vacancy_thermalfluc_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_vacancy_thermalfluc_output(maxval(phase_Noutput),maxNinstance)) + source_vacancy_thermalfluc_output = '' + allocate(source_vacancy_thermalfluc_Noutput(maxNinstance), source=0_pInt) + allocate(source_vacancy_thermalfluc_amplitude(maxNinstance), source=0.0_pReal) + allocate(source_vacancy_thermalfluc_normVacancyEnergy(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_vacancy_thermalfluc_instance(phase) ! which instance of my vacancy is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('thermalfluctuation_amplitude') + source_vacancy_thermalfluc_amplitude(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_vacancy_thermalfluc_instance(phase) + source_vacancy_thermalfluc_normVacancyEnergy(instance) = & + lattice_vacancyFormationEnergy(phase)/1.3806488e-23_pReal + sourceOffset = source_vacancy_thermalfluc_offset(phase) + + sizeDotState = 1_pInt + sizeDeltaState = 1_pInt + sizeState = 1_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_thermalfluc_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_vacancy_thermalfluc_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_thermalfluc_deltaState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, constituent, sourceOffset + real(pReal) :: & + randNo + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_vacancy_thermalfluc_offset(phase) + + call random_number(randNo) + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + randNo - 0.5_pReal - sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_vacancy_thermalfluc_deltaState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_thermalfluc_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + material_homog, & + temperature, & + thermalMapping, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + CvDot, dCvDot_dCv + integer(pInt) :: & + instance, phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_vacancy_thermalfluc_instance(phase) + sourceOffset = source_vacancy_thermalfluc_offset(phase) + + CvDot = source_vacancy_thermalfluc_amplitude(instance)* & + sourceState(phase)%p(sourceOffset)%state0(2,constituent)* & + exp(-source_vacancy_thermalfluc_normVacancyEnergy(instance)/ & + temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))) + dCvDot_dCv = 0.0_pReal + +end subroutine source_vacancy_thermalfluc_getRateAndItsTangent + +end module source_vacancy_thermalfluc diff --git a/compile.log b/compile.log new file mode 100644 index 000000000..c998f5ad4 --- /dev/null +++ b/compile.log @@ -0,0 +1,3 @@ +make DAMASK_spectral.exe -C code +make[1]: Entering directory `/mnt/research/CMM/DAMASK/zhangc43_git/code' +make[1]: Leaving directory `/mnt/research/CMM/DAMASK/zhangc43_git/code' From 97c51bf44b02acc95d492f4ae428426787a63486 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 29 Feb 2016 14:22:15 -0500 Subject: [PATCH 019/183] no need to keep track of compliation log --- compile.log | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 compile.log diff --git a/compile.log b/compile.log deleted file mode 100644 index c998f5ad4..000000000 --- a/compile.log +++ /dev/null @@ -1,3 +0,0 @@ -make DAMASK_spectral.exe -C code -make[1]: Entering directory `/mnt/research/CMM/DAMASK/zhangc43_git/code' -make[1]: Leaving directory `/mnt/research/CMM/DAMASK/zhangc43_git/code' From 9d3ca6c2e6379bb237f90ed6bd5b2afda5e29e96 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 29 Feb 2016 14:50:21 -0500 Subject: [PATCH 020/183] move everything back to single level --- code/CMakeLists.txt | 68 ++++++++++++++++++- code/damage/CMakeLists.txt | 15 ---- code/{damage => }/damage_local.f90 | 0 code/{damage => }/damage_none.f90 | 0 code/{damage => }/damage_nonlocal.f90 | 0 code/{homogenization => }/homogenization.f90 | 0 code/homogenization/CMakeLists.txt | 16 ----- .../homogenization_RGC.f90 | 0 .../homogenization_isostrain.f90 | 0 .../homogenization_none.f90 | 0 code/hydrogenflux/CMakeLists.txt | 14 ---- .../hydrogenflux_cahnhilliard.f90 | 0 .../hydrogenflux_isoconc.f90 | 0 code/porosity/CMakeLists.txt | 14 ---- code/{porosity => }/porosity_none.f90 | 0 code/{porosity => }/porosity_phasefield.f90 | 0 code/spectral/CMakeLists.txt | 18 ----- code/{spectral => }/spectral_damage.f90 | 0 code/{spectral => }/spectral_mech_AL.f90 | 0 code/{spectral => }/spectral_mech_Basic.f90 | 0 .../spectral_mech_Polarisation.f90 | 0 code/{spectral => }/spectral_thermal.f90 | 0 code/{spectral => }/spectral_utilities.f90 | 0 code/thermal/CMakeLists.txt | 15 ---- code/{thermal => }/thermal_adiabatic.f90 | 0 code/{thermal => }/thermal_conduction.f90 | 0 code/{thermal => }/thermal_isothermal.f90 | 0 code/vacancyflux/CMakeLists.txt | 15 ---- .../vacancyflux_cahnhilliard.f90 | 0 .../vacancyflux_isochempot.f90 | 0 .../{vacancyflux => }/vacancyflux_isoconc.f90 | 0 31 files changed, 65 insertions(+), 110 deletions(-) delete mode 100644 code/damage/CMakeLists.txt rename code/{damage => }/damage_local.f90 (100%) rename code/{damage => }/damage_none.f90 (100%) rename code/{damage => }/damage_nonlocal.f90 (100%) rename code/{homogenization => }/homogenization.f90 (100%) delete mode 100644 code/homogenization/CMakeLists.txt rename code/{homogenization => }/homogenization_RGC.f90 (100%) rename code/{homogenization => }/homogenization_isostrain.f90 (100%) rename code/{homogenization => }/homogenization_none.f90 (100%) delete mode 100644 code/hydrogenflux/CMakeLists.txt rename code/{hydrogenflux => }/hydrogenflux_cahnhilliard.f90 (100%) rename code/{hydrogenflux => }/hydrogenflux_isoconc.f90 (100%) delete mode 100644 code/porosity/CMakeLists.txt rename code/{porosity => }/porosity_none.f90 (100%) rename code/{porosity => }/porosity_phasefield.f90 (100%) delete mode 100644 code/spectral/CMakeLists.txt rename code/{spectral => }/spectral_damage.f90 (100%) rename code/{spectral => }/spectral_mech_AL.f90 (100%) rename code/{spectral => }/spectral_mech_Basic.f90 (100%) rename code/{spectral => }/spectral_mech_Polarisation.f90 (100%) rename code/{spectral => }/spectral_thermal.f90 (100%) rename code/{spectral => }/spectral_utilities.f90 (100%) delete mode 100644 code/thermal/CMakeLists.txt rename code/{thermal => }/thermal_adiabatic.f90 (100%) rename code/{thermal => }/thermal_conduction.f90 (100%) rename code/{thermal => }/thermal_isothermal.f90 (100%) delete mode 100644 code/vacancyflux/CMakeLists.txt rename code/{vacancyflux => }/vacancyflux_cahnhilliard.f90 (100%) rename code/{vacancyflux => }/vacancyflux_isochempot.f90 (100%) rename code/{vacancyflux => }/vacancyflux_isoconc.f90 (100%) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 33208a6ed..e4ea0b01c 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -78,6 +78,68 @@ target_link_libraries(DAMASK_SOURCE DAMASK_DRIVERS) add_library(DAMASK_CONSTITUTIVE "constitutive.f90") target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_PLASTIC DAMASK_KINEMATICS DAMASK_SOURCE) -# compile spectral solver -add_executable(DAMASKSpectral.exe DAMASK_spectral.f90) -target_link_libraries (DAMASKSpectral.exe DAMASK_CONSTITUTIVE) \ No newline at end of file +add_library(DAMASK_CRYSTALLITE "crystallite.f90") +target_link_libraries(DAMASK_CRYSTALLITE DAMASK_CONSTITUTIVE) + +add_library(DAMASK_HOMOGENIZATION "homogenization.f90" + "homogenization_RGC.f90" + "homogenization_isostrain.f90" + "homogenization_none.f90") +target_link_libraries(DAMASK_HOMOGENIZATION DAMASK_CRYSTALLITE) + +add_library(DAMASK_HYDROGENFLUX "hydrogenflux_isoconc.f90" + "hydrogenflux_cahnhilliard.f90") +target_link_libraries(DAMASK_HYDROGENFLUX DAMASK_CRYSTALLITE) + +add_library(DAMASK_POROSITY "porosity_none.f90" + "porosity_phasefield.f90") +target_link_libraries(DAMASK_POROSITY DAMASK_CRYSTALLITE) + +add_library(DAMASK_VACANCYFLUX "vacancyflux_isoconc.f90" + "vacancyflux_isochempot.f90" + "vacancyflux_cahnhilliard.f90") +target_link_libraries(DAMASK_VACANCYFLUX DAMASK_CRYSTALLITE) + +add_library(DAMASK_DAMAGE "damage_none.f90" + "damage_local.f90" + "damage_nonlocal.f90") +target_link_libraries(DAMASK_DAMAGE DAMASK_CRYSTALLITE) + +add_library(DAMASK_THERMAL "thermal_isothermal.f90" + "thermal_adiabatic.f90" + "thermal_conduction.f90") +target_link_libraries(DAMASK_THERMAL DAMASK_CRYSTALLITE) + +add_library(DAMASK_ENGINE "homogenization.f90") +target_link_libraries(DAMASK_ENGINE DAMASK_THERMAL + DAMASK_DAMAGE + DAMASK_VACANCYFLUX + DAMASK_POROSITY + DAMASK_HYDROGENFLUX + DAMASK_HOMOGENIZATION) + +add_library(DAMASK_CPFE "CPFEM.f90" + "CPFEM2.f90") +target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) + +if (FEM) + message("special treatment for FEM code") +endif(FEM) + +if (SPECTRAL) + add_library(DAMASK_SPECTRAL_UTILITY spectral_utilities.f90) + target_link_libraries(DAMASK_SPECTRAL_UTILITY DAMASK_CPFE2) + + add_library(DAMASK_SPECTRAL_BASE "spectral_thermal.f90" + "spectral_damage.f90") + target_link_libraries(DAMASK_SPECTRAL_BASE DAMASK_SPECTRAL_UTILITY) + + add_library(DAMASK_SPECTRAL_MECH "spectral_mech_AL.f90" + "spectral_mech_Polarisation.f90" + "spectral_mech_Basic.f90") + target_link_libraries(DAMASK_SPECTRAL_MECH DAMASK_SPECTRAL_UTILITY) + + add_executable(DAMASKSpectral.exe DAMASK_spectral.f90) + target_link_libraries(DAMASKSpectral.exe DAMASK_SPECTRAL_BASE + DAMASK_SPECTRAL_MECH) +endif(SPECTRAL) \ No newline at end of file diff --git a/code/damage/CMakeLists.txt b/code/damage/CMakeLists.txt deleted file mode 100644 index 25d3e7e37..000000000 --- a/code/damage/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# group sources -set (DAMAGE "damage_none" - "damage_local" - "damage_nonlocal" - ) - -# compile damage module -foreach (p ${DAMAGE}) - add_library (${p} "${p}.f90") -endforeach (p) - -# set libraries for linking -foreach (p ${DAMAGE}) - set (DAMASK_LIB ${DAMASK_LIB} ${P}) -endforeach (p) \ No newline at end of file diff --git a/code/damage/damage_local.f90 b/code/damage_local.f90 similarity index 100% rename from code/damage/damage_local.f90 rename to code/damage_local.f90 diff --git a/code/damage/damage_none.f90 b/code/damage_none.f90 similarity index 100% rename from code/damage/damage_none.f90 rename to code/damage_none.f90 diff --git a/code/damage/damage_nonlocal.f90 b/code/damage_nonlocal.f90 similarity index 100% rename from code/damage/damage_nonlocal.f90 rename to code/damage_nonlocal.f90 diff --git a/code/homogenization/homogenization.f90 b/code/homogenization.f90 similarity index 100% rename from code/homogenization/homogenization.f90 rename to code/homogenization.f90 diff --git a/code/homogenization/CMakeLists.txt b/code/homogenization/CMakeLists.txt deleted file mode 100644 index a10de9aaa..000000000 --- a/code/homogenization/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# group sources -set (HOMOGENIZATION "homogenization" - "homogenization_RGC" - "homogenization_isostrain" - "homogenization_none" - ) - -# compile modules -foreach (p ${HOMOGENIZATION}) - add_library (${p} "${p}.f90") -endforeach (p) - -# set libraries/modules for linking -foreach (p ${HOMOGENIZATION}) - set (DAMASK_LIB ${DAMASK_LIB} ${p}) -endforeach (p) \ No newline at end of file diff --git a/code/homogenization/homogenization_RGC.f90 b/code/homogenization_RGC.f90 similarity index 100% rename from code/homogenization/homogenization_RGC.f90 rename to code/homogenization_RGC.f90 diff --git a/code/homogenization/homogenization_isostrain.f90 b/code/homogenization_isostrain.f90 similarity index 100% rename from code/homogenization/homogenization_isostrain.f90 rename to code/homogenization_isostrain.f90 diff --git a/code/homogenization/homogenization_none.f90 b/code/homogenization_none.f90 similarity index 100% rename from code/homogenization/homogenization_none.f90 rename to code/homogenization_none.f90 diff --git a/code/hydrogenflux/CMakeLists.txt b/code/hydrogenflux/CMakeLists.txt deleted file mode 100644 index 33fa04574..000000000 --- a/code/hydrogenflux/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# group sources -set (HYDROGENFLUX "hydrogenflux_isoconc" - "hydrogenflux_cahnhilliard" - ) - -# compile hydrogenflux modules -foreach (p ${HYDROGENFLUX}) - add_library (${p} "${p}.f90") -endforeach (p) - -# set libraries/modules for linking -foreach (p ${HYDROGENFLUX}) - set (DAMASK_LIB ${DAMASK_LIB} ${p}) -endforeach (p) \ No newline at end of file diff --git a/code/hydrogenflux/hydrogenflux_cahnhilliard.f90 b/code/hydrogenflux_cahnhilliard.f90 similarity index 100% rename from code/hydrogenflux/hydrogenflux_cahnhilliard.f90 rename to code/hydrogenflux_cahnhilliard.f90 diff --git a/code/hydrogenflux/hydrogenflux_isoconc.f90 b/code/hydrogenflux_isoconc.f90 similarity index 100% rename from code/hydrogenflux/hydrogenflux_isoconc.f90 rename to code/hydrogenflux_isoconc.f90 diff --git a/code/porosity/CMakeLists.txt b/code/porosity/CMakeLists.txt deleted file mode 100644 index 0e30067e8..000000000 --- a/code/porosity/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# group sources -set (POROSITY "porosity_none" - "porosity_phasefield" - ) - -# compile porosity modules -foreach (p ${POROSITY}) - add_library (${p} "${p}.f90") -endforeach (p) - -# set libraries/modules for linking -foreach (p ${POROSITY}) - set (DAMASK_LIB ${DAMASK_LIB} ${p}) -endforeach (p) \ No newline at end of file diff --git a/code/porosity/porosity_none.f90 b/code/porosity_none.f90 similarity index 100% rename from code/porosity/porosity_none.f90 rename to code/porosity_none.f90 diff --git a/code/porosity/porosity_phasefield.f90 b/code/porosity_phasefield.f90 similarity index 100% rename from code/porosity/porosity_phasefield.f90 rename to code/porosity_phasefield.f90 diff --git a/code/spectral/CMakeLists.txt b/code/spectral/CMakeLists.txt deleted file mode 100644 index 136d1ad88..000000000 --- a/code/spectral/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# group source for sepctral solver driver -set (SPECTRAL "spectral_damage" - "spectral_mech_AL" - "spectral_mech_Basic" - "spectral_mech_Polarisation" - "spectral_thermal" - "spectral_utilities" - ) - -# compile spectral solver driver module -foreach (p ${SPECTRAL}) - add_library (${p} "${p}.f90") -endforeach (p) - -# set libraries/modules for linking -foreach (p ${SPECTRAL}) - set (DAMASK_LIB ${DAMASK_LIB} ${p}) -endforeach (p) \ No newline at end of file diff --git a/code/spectral/spectral_damage.f90 b/code/spectral_damage.f90 similarity index 100% rename from code/spectral/spectral_damage.f90 rename to code/spectral_damage.f90 diff --git a/code/spectral/spectral_mech_AL.f90 b/code/spectral_mech_AL.f90 similarity index 100% rename from code/spectral/spectral_mech_AL.f90 rename to code/spectral_mech_AL.f90 diff --git a/code/spectral/spectral_mech_Basic.f90 b/code/spectral_mech_Basic.f90 similarity index 100% rename from code/spectral/spectral_mech_Basic.f90 rename to code/spectral_mech_Basic.f90 diff --git a/code/spectral/spectral_mech_Polarisation.f90 b/code/spectral_mech_Polarisation.f90 similarity index 100% rename from code/spectral/spectral_mech_Polarisation.f90 rename to code/spectral_mech_Polarisation.f90 diff --git a/code/spectral/spectral_thermal.f90 b/code/spectral_thermal.f90 similarity index 100% rename from code/spectral/spectral_thermal.f90 rename to code/spectral_thermal.f90 diff --git a/code/spectral/spectral_utilities.f90 b/code/spectral_utilities.f90 similarity index 100% rename from code/spectral/spectral_utilities.f90 rename to code/spectral_utilities.f90 diff --git a/code/thermal/CMakeLists.txt b/code/thermal/CMakeLists.txt deleted file mode 100644 index 8f34d0815..000000000 --- a/code/thermal/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# group source related themal module -set (THERMAL "thermal_isothermal" - "thermal_adiabatic" - "thermal_conduction" - ) - -# compiler theraml module -foreach (p ${THERMAL}) - add_library (${p} "${p}.f90") -endforeach (p) - -# set libraries/modules for linking -foreach (p ${THERMAL}) - set (DAMASK_LIB ${DAMASK_LIB} ${p}) -endforeach (p) \ No newline at end of file diff --git a/code/thermal/thermal_adiabatic.f90 b/code/thermal_adiabatic.f90 similarity index 100% rename from code/thermal/thermal_adiabatic.f90 rename to code/thermal_adiabatic.f90 diff --git a/code/thermal/thermal_conduction.f90 b/code/thermal_conduction.f90 similarity index 100% rename from code/thermal/thermal_conduction.f90 rename to code/thermal_conduction.f90 diff --git a/code/thermal/thermal_isothermal.f90 b/code/thermal_isothermal.f90 similarity index 100% rename from code/thermal/thermal_isothermal.f90 rename to code/thermal_isothermal.f90 diff --git a/code/vacancyflux/CMakeLists.txt b/code/vacancyflux/CMakeLists.txt deleted file mode 100644 index 7163f38d7..000000000 --- a/code/vacancyflux/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# group source file -set (VACANCYFLUX "vacancyflux_isoconc" - "vacancyflux_isochempot" - "vacancyflux_cahnhilliard" - ) - -# compiler as module -foreach (p ${VACANCYFLUX}) - add_library (${p} "${p}.f90") -endforeach (p) - -# set libraries/modules for linking -foreach (p ${VACANCYFLUX}) - set (DAMASK_LIB ${DAMASK_LIB} ${p}) -endforeach (p) \ No newline at end of file diff --git a/code/vacancyflux/vacancyflux_cahnhilliard.f90 b/code/vacancyflux_cahnhilliard.f90 similarity index 100% rename from code/vacancyflux/vacancyflux_cahnhilliard.f90 rename to code/vacancyflux_cahnhilliard.f90 diff --git a/code/vacancyflux/vacancyflux_isochempot.f90 b/code/vacancyflux_isochempot.f90 similarity index 100% rename from code/vacancyflux/vacancyflux_isochempot.f90 rename to code/vacancyflux_isochempot.f90 diff --git a/code/vacancyflux/vacancyflux_isoconc.f90 b/code/vacancyflux_isoconc.f90 similarity index 100% rename from code/vacancyflux/vacancyflux_isoconc.f90 rename to code/vacancyflux_isoconc.f90 From 93d8c0045e2d1de68b9674a062ceeadb4644f070 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 29 Feb 2016 15:22:17 -0500 Subject: [PATCH 021/183] test using cmake building spectral solver --- CMakeLists.txt | 32 -------------------------------- code/CMakeLists.txt | 25 +++++++++++++++++-------- 2 files changed, 17 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3f167362..0cdc5db56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,38 +28,6 @@ if (NOT DEFINED HDF5_DIR) message (FATAL_ERROR "HDF5_DIR is not found!" ) endif (NOT DEFINED HDF5_DIR) -# Work around to probe PETSc configuration -# set (petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules") -# set (petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") - -# set (petsc_config_makefile "${DAMASK_SOURCE_DIR}/Makefile.petsc") -# file (WRITE "${petsc_config_makefile}" -# "## This file was autogenerated by FindPETSc.cmake -# # PETSC_DIR = ${PETSC_DIR} -# # PETSC_ARCH = ${PETSC_ARCH} -# include ${petsc_conf_rules} -# include ${petsc_conf_variables} -# show : -# \t-@echo -n \${\${VARIABLE}} -# " ) - -# macro (PETSC_GET_VARIABLE name var) -# set (${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) -# execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} show VARIABLE=${name} -# OUTPUT_VARIABLE ${var} -# RESULT_VARIABLE petsc_return) -# endmacro (PETSC_GET_VARIABLE) - -# petsc_get_variable (PETSC_LIB_DIR petsc_lib_dir) -# petsc_get_variable (PETSC_EXTERNAL_LIB_BASIC petsc_libs_external) -# petsc_get_variable (PETSC_CCPPFLAGS petsc_cpp_line) -# petsc_get_variable (PETSC_INCLUDE petsc_include) -# petsc_get_variable (PCC petsc_cc) -# petsc_get_variable (PCC_FLAGS petsc_cc_flags) -# petsc_get_variable (MPIEXEC petsc_mpiexec) -# # We are done with the temporary Makefile, calling PETSC_GET_VARIABLE after this point is invalid! -# file (REMOVE ${petsc_config_makefile}) - # OUTPUT TYPE set (SPECTRAL OFF) set (FEM OFF) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index e4ea0b01c..7978ae527 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -76,7 +76,9 @@ add_library (DAMASK_SOURCE "source_thermal_dissipation.f90" target_link_libraries(DAMASK_SOURCE DAMASK_DRIVERS) add_library(DAMASK_CONSTITUTIVE "constitutive.f90") -target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_PLASTIC DAMASK_KINEMATICS DAMASK_SOURCE) +target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_PLASTIC ) +target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_KINEMATICS) +target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_SOURCE ) add_library(DAMASK_CRYSTALLITE "crystallite.f90") target_link_libraries(DAMASK_CRYSTALLITE DAMASK_CONSTITUTIVE) @@ -111,12 +113,18 @@ add_library(DAMASK_THERMAL "thermal_isothermal.f90" target_link_libraries(DAMASK_THERMAL DAMASK_CRYSTALLITE) add_library(DAMASK_ENGINE "homogenization.f90") -target_link_libraries(DAMASK_ENGINE DAMASK_THERMAL - DAMASK_DAMAGE - DAMASK_VACANCYFLUX - DAMASK_POROSITY - DAMASK_HYDROGENFLUX - DAMASK_HOMOGENIZATION) +add_dependencies(DAMASK_ENGINE DAMASK_THERMAL + DAMASK_DAMAGE + DAMASK_VACANCYFLUX + DAMASK_POROSITY + DAMASK_HYDROGENFLUX + DAMASK_HOMOGENIZATION) +target_link_libraries(DAMASK_ENGINE DAMASK_THERMAL ) +target_link_libraries(DAMASK_ENGINE DAMASK_DAMAGE ) +target_link_libraries(DAMASK_ENGINE DAMASK_VACANCYFLUX ) +target_link_libraries(DAMASK_ENGINE DAMASK_POROSITY ) +target_link_libraries(DAMASK_ENGINE DAMASK_HYDROGENFLUX ) +target_link_libraries(DAMASK_ENGINE DAMASK_HOMOGENIZATION) add_library(DAMASK_CPFE "CPFEM.f90" "CPFEM2.f90") @@ -140,6 +148,7 @@ if (SPECTRAL) target_link_libraries(DAMASK_SPECTRAL_MECH DAMASK_SPECTRAL_UTILITY) add_executable(DAMASKSpectral.exe DAMASK_spectral.f90) - target_link_libraries(DAMASKSpectral.exe DAMASK_SPECTRAL_BASE + target_link_libraries(DAMASKSpectral.exe DAMASK_CPFE + DAMASK_SPECTRAL_BASE DAMASK_SPECTRAL_MECH) endif(SPECTRAL) \ No newline at end of file From fee445e1bde0c46a4daa81d6482943e679e11910 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 1 Mar 2016 10:36:48 -0500 Subject: [PATCH 022/183] still cannot link to petsc, but the rest is functioning properly --- CMakeLists.txt | 78 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cdc5db56..5ac9771b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,44 @@ if (NOT DEFINED HDF5_DIR) message (FATAL_ERROR "HDF5_DIR is not found!" ) endif (NOT DEFINED HDF5_DIR) +# brutal force to find the variables defined in PETSC +# ref: +# https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake +set(petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") +set(petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) +# A temporary makefile to probe the PETSc configuration +set (petsc_config_makefile "${PROJECT_BINARY_DIR}/Makefile.petsc") +file (WRITE "${petsc_config_makefile}" +"## This file was autogenerated by FindPETSc.cmake +# PETSC_DIR = ${PETSC_DIR} +# PETSC_ARCH = ${PETSC_ARCH} +include ${petsc_conf_rules} +include ${petsc_conf_variables} +show: +\t-@echo -n \${\${VARIABLE}} +") + +macro (PETSC_GET_VARIABLE name var) + set (${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) + execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} + show VARIABLE=${name} + OUTPUT_VARIABLE ${var} + RESULT_VARIABLE petsc_return) +endmacro (PETSC_GET_VARIABLE) +petsc_get_variable (PETSC_LIB_DIR "PETSC_LIB_DIR" ) +petsc_get_variable (PETSC_EXTERNAL_LIB_BASIC "PETSC_LIBS_EXTERNAL") +petsc_get_variable (PETSC_CCPPFLAGS "PETSC_CPP_LINE" ) +petsc_get_variable (PETSC_INCLUDE "PETSC_INCLUDE" ) +petsc_get_variable (PCC "PETSC_CC" ) +petsc_get_variable (PCC_FLAGS "PETSC_CC_FLAGS" ) +petsc_get_variable (MPIEXEC "PETSC_MPIEXEC" ) +# We are done with the temporary Makefile, calling PETSC_GET_VARIABLE after this point is invalid! +# file (REMOVE ${petsc_config_makefile}) + +message("${PETSC_DIR}") +message("${PETSC_LIB_DIR}") +message("${PETSC_INCLUDE}") + # OUTPUT TYPE set (SPECTRAL OFF) set (FEM OFF) @@ -52,7 +90,9 @@ include_directories(${CMAKE_SOURCE_DIR}/code lib ${HDF5_DIR}/include ) -link_directories(${HDF5_DIR}/lib) +link_directories(${HDF5_DIR}/lib + ${PETSC_DIR}/lib + ${PETSC_EXTERNAL_LIB_BASIC}) ## # set compile and debug flags @@ -254,24 +294,24 @@ set (LINK_OPTIONS_ifort "-shared-intel") #-fno-fast-math: # --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) ################################################################################################### -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -DDAMASKVERSION=${DAMASKVERSION}") -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -xf95-cpp-input" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -ffree-line-length-240" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fimplicit-none" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fmodule-private" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wall" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wextra" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wcharacter-truncation" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wunderflow" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wsuggest-attribute=pure" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wsuggest-attribute=noreturn" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wconversion-extra" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wimplicit-procedure" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wno-unused-parameter" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fno-range-check" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fall-intrinsics" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fno-fast-math" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fall-intrinsics" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -DDAMASKVERSION=\\\"${DAMASKVERSION}\\\"") +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -xf95-cpp-input" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -ffree-line-length-240" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fimplicit-none" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fmodule-private" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wall" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wextra" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wcharacter-truncation" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wunderflow" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wsuggest-attribute=pure" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wsuggest-attribute=noreturn" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wconversion-extra" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wimplicit-procedure" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wno-unused-parameter" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fno-range-check" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fall-intrinsics" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fno-fast-math" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fall-intrinsics" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING # -ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) From 22689c105303b97fa9a79fea21143c8c00505647 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 1 Mar 2016 10:37:07 -0500 Subject: [PATCH 023/183] still cannot link to petsc, but the rest is functioning properly --- code/CMakeLists.txt | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 7978ae527..6c1b63dfa 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -83,8 +83,7 @@ target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_SOURCE ) add_library(DAMASK_CRYSTALLITE "crystallite.f90") target_link_libraries(DAMASK_CRYSTALLITE DAMASK_CONSTITUTIVE) -add_library(DAMASK_HOMOGENIZATION "homogenization.f90" - "homogenization_RGC.f90" +add_library(DAMASK_HOMOGENIZATION "homogenization_RGC.f90" "homogenization_isostrain.f90" "homogenization_none.f90") target_link_libraries(DAMASK_HOMOGENIZATION DAMASK_CRYSTALLITE) @@ -113,12 +112,6 @@ add_library(DAMASK_THERMAL "thermal_isothermal.f90" target_link_libraries(DAMASK_THERMAL DAMASK_CRYSTALLITE) add_library(DAMASK_ENGINE "homogenization.f90") -add_dependencies(DAMASK_ENGINE DAMASK_THERMAL - DAMASK_DAMAGE - DAMASK_VACANCYFLUX - DAMASK_POROSITY - DAMASK_HYDROGENFLUX - DAMASK_HOMOGENIZATION) target_link_libraries(DAMASK_ENGINE DAMASK_THERMAL ) target_link_libraries(DAMASK_ENGINE DAMASK_DAMAGE ) target_link_libraries(DAMASK_ENGINE DAMASK_VACANCYFLUX ) @@ -126,17 +119,21 @@ target_link_libraries(DAMASK_ENGINE DAMASK_POROSITY ) target_link_libraries(DAMASK_ENGINE DAMASK_HYDROGENFLUX ) target_link_libraries(DAMASK_ENGINE DAMASK_HOMOGENIZATION) -add_library(DAMASK_CPFE "CPFEM.f90" - "CPFEM2.f90") -target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) + + if (FEM) + add_library(DAMASK_CPFE "CPFEM.f90") + target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) message("special treatment for FEM code") endif(FEM) if (SPECTRAL) + add_library(DAMASK_CPFE "CPFEM2.f90") + target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) + add_library(DAMASK_SPECTRAL_UTILITY spectral_utilities.f90) - target_link_libraries(DAMASK_SPECTRAL_UTILITY DAMASK_CPFE2) + target_link_libraries(DAMASK_SPECTRAL_UTILITY DAMASK_CPFE) add_library(DAMASK_SPECTRAL_BASE "spectral_thermal.f90" "spectral_damage.f90") From 48da078bfe347073b1f202162123af67f3ae028b Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 1 Mar 2016 13:23:47 -0500 Subject: [PATCH 024/183] got petsc related flags for CMake --- CMakeLists.txt | 79 +++++++++++++++++++++++++------------------------- Makefile_bk | 42 --------------------------- 2 files changed, 40 insertions(+), 81 deletions(-) delete mode 100755 Makefile_bk diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ac9771b6..41d895c0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,60 +39,67 @@ file (WRITE "${petsc_config_makefile}" "## This file was autogenerated by FindPETSc.cmake # PETSC_DIR = ${PETSC_DIR} # PETSC_ARCH = ${PETSC_ARCH} +SHELL = /bin/sh include ${petsc_conf_rules} include ${petsc_conf_variables} -show: -\t-@echo -n \${\${VARIABLE}} +INCLUDE_DIRS := \${PETSC_FC_INCLUDES} -DPETSc +LIBRARIES := \${PETSC_WITH_EXTERNAL_LIB} +COMPILERNAME ?= \${FC} +LINKERNAME ?= \${FLINKER} + +includes: +\t@echo \${INCLUDE_DIRS} +extlibs: +\t@echo \${LIBRARIES} +compiler: +\t@echo \${COMPILERNAME} + +linker: +\t@echo \${LINKERNAME} ") -macro (PETSC_GET_VARIABLE name var) - set (${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) - execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} - show VARIABLE=${name} - OUTPUT_VARIABLE ${var} - RESULT_VARIABLE petsc_return) -endmacro (PETSC_GET_VARIABLE) -petsc_get_variable (PETSC_LIB_DIR "PETSC_LIB_DIR" ) -petsc_get_variable (PETSC_EXTERNAL_LIB_BASIC "PETSC_LIBS_EXTERNAL") -petsc_get_variable (PETSC_CCPPFLAGS "PETSC_CPP_LINE" ) -petsc_get_variable (PETSC_INCLUDE "PETSC_INCLUDE" ) -petsc_get_variable (PCC "PETSC_CC" ) -petsc_get_variable (PCC_FLAGS "PETSC_CC_FLAGS" ) -petsc_get_variable (MPIEXEC "PETSC_MPIEXEC" ) -# We are done with the temporary Makefile, calling PETSC_GET_VARIABLE after this point is invalid! -# file (REMOVE ${petsc_config_makefile}) +find_program (MAKE_EXECUTABLE NAMES make gmake) +execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "includes" + RESULT_VARIABLE PETSC_INCLUDES_RETURN + OUTPUT_VARIABLE PETSC_INCLUDES) +execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "extlibs" + RESULT_VARIABLE PETSC_EXTERNAL_LIB_RETURN + OUTPUT_VARIABLE PETSC_EXTERNAL_LIB) +execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "linker" + RESULT_VARIABLE PETSC_LINK_LIB_RETURN + OUTPUT_VARIABLE PETSC_LINK_LIB) +execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compiler" + RESULT_VARIABLE MPIEXEC_RETURN + OUTPUT_VARIABLE MPIEXEC) +file (REMOVE ${petsc_config_makefile}) -message("${PETSC_DIR}") -message("${PETSC_LIB_DIR}") -message("${PETSC_INCLUDE}") +message("\nFound PETSC_DIR:\n${PETSC_DIR}") +message("Set PETSC_INCLUDES to:\n${PETSC_INCLUDES}") +message("Set PETSC_EXTERNAL_LIB to:\n${PETSC_EXTERNAL_LIB}") +message("Set PETSC_LINK_LIB to:\n${PETSC_LINK_LIB}") +message("Use PETSC wrapped compiler @: ${MPIEXEC}") # OUTPUT TYPE set (SPECTRAL OFF) set (FEM OFF) -set (MARC OFF) -set (ABAQUS OFF) if (DAMASK_DRIVER STREQUAL "SPECTRAL") set (SPECTRAL ON ) elseif (DAMASK_DRIVER STREQUAL "FEM") set (FEM ON ) -elseif (DAMASK_DRIVER STREQUAL "MARC") - set (MARC ON ) -elseif (DAMASK_DRIVER STREQUAL "ABAQUS") - set (ABAQUS ON ) else (DAMASK_DRIVER STREQUAL "SPECTRAL") message (FATAL_ERROR "Unknown output, check build script!") endif (DAMASK_DRIVER STREQUAL "SPECTRAL") # set system include directories -include_directories(${CMAKE_SOURCE_DIR}/code - ${PETSC_DIR}/include +include_directories(${PETSC_INCLUDES} lib ${HDF5_DIR}/include ) link_directories(${HDF5_DIR}/lib - ${PETSC_DIR}/lib - ${PETSC_EXTERNAL_LIB_BASIC}) + ${PETSC_LINK_LIB} + ${PETSC_EXTERNAL_LIB} + ) ## # set compile and debug flags @@ -356,7 +363,7 @@ get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) if (Fortran_COMPILER_NAME MATCHES "ifort.*") # need the PETSC wrapped version of ifort - set (CMAKE_Fortran_COMPILER "${PETSC_DIR}/bin/mpif90") + set (CMAKE_Fortran_COMPILER "${MPIEXEC}") # for RELEASE set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}" ) @@ -375,7 +382,7 @@ if (Fortran_COMPILER_NAME MATCHES "ifort.*") set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}") # elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") - set (CMAKE_Fortran_COMPILER "${PETSC_DIR}/bin/mpif90") + set (CMAKE_Fortran_COMPILER "${MPIEXEC}") # for RELEASE set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_gfortran}" ) set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_gfortran}" ) @@ -414,12 +421,6 @@ if (FEM) set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DFEM") endif (FEM) -# set PETSC flags -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DPETSc") -set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -DPETSc") -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DPETSc") -set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DPETSc") - # set default project compiler flags # NOTE: some file might need different flags for compiling, DAMASK_$FLAGS # are essentially the swap for this purpose diff --git a/Makefile_bk b/Makefile_bk deleted file mode 100755 index 8be738090..000000000 --- a/Makefile_bk +++ /dev/null @@ -1,42 +0,0 @@ -SHELL = /bin/sh -######################################################################################## -# Makefile for the installation of DAMASK -######################################################################################## -.PHONY: all -all: spectral marc processing - -.PHONY: spectral -spectral: - $(MAKE) DAMASK_spectral.exe -C code - -.PHONY: FEM -FEM: - $(MAKE) DAMASK_FEM.exe -C code - -.PHONY: marc -marc: - @./installation/mods_MarcMentat/apply_DAMASK_modifications.sh ${MAKEFLAGS} - -.PHONY: processing -processing: - @if hash cython 2>/dev/null; then \ - cd ./lib/damask; \ - CC=gcc python setup_corientation.py build_ext --inplace; \ - rm -rv build; \ - rm *.c; \ - fi - @./installation/compile_CoreModule.py ${MAKEFLAGS} - -.PHONY: tidy -tidy: - @$(MAKE) tidy -C code >/dev/null - -.PHONY: clean -clean: - @$(MAKE) cleanDAMASK -C code >/dev/null - -.PHONY: install -install: - @./installation/symlink_Code.py ${MAKEFLAGS} - @./installation/symlink_Processing.py ${MAKEFLAGS} - From 48dfcd65f223124e04ac528f7ffc0cc38e0007b5 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 2 Mar 2016 09:37:12 -0500 Subject: [PATCH 025/183] clean up syntax --- CMakeLists.txt | 122 +++++++++++++++++++++++++--------------------- build_spectral.sh | 2 +- 2 files changed, 67 insertions(+), 57 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 41d895c0d..30a57f650 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,29 @@ if (NOT DEFINED HDF5_DIR) message (FATAL_ERROR "HDF5_DIR is not found!" ) endif (NOT DEFINED HDF5_DIR) +# OUTPUT TYPE +set (SPECTRAL OFF) +set (FEM OFF) +if (DAMASK_DRIVER STREQUAL "SPECTRAL") + set (SPECTRAL ON ) +elseif (DAMASK_DRIVER STREQUAL "FEM") + set (FEM ON ) +else (DAMASK_DRIVER STREQUAL "SPECTRAL") + message (FATAL_ERROR "Unknown output, check build script!") +endif (DAMASK_DRIVER STREQUAL "SPECTRAL") + +# COMPILE VARIABLES +add_definitions(-DDAMASKVERSION="${DAMASK_V}") +add_definitions(-DPETSc) +add_definitions(-DFLOAT=8) +add_definitions(-DINT=4) +if (SPECTRAL) + add_definitions(-DSpectral) +endif(SPECTRAL) +if (FEM) + add_definitions(-DFEM) +endif(FEM) + # brutal force to find the variables defined in PETSC # ref: # https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake @@ -42,15 +65,17 @@ file (WRITE "${petsc_config_makefile}" SHELL = /bin/sh include ${petsc_conf_rules} include ${petsc_conf_variables} -INCLUDE_DIRS := \${PETSC_FC_INCLUDES} -DPETSc +INCLUDE_DIRS := \${PETSC_FC_INCLUDES} LIBRARIES := \${PETSC_WITH_EXTERNAL_LIB} COMPILERNAME ?= \${FC} LINKERNAME ?= \${FLINKER} includes: \t@echo \${INCLUDE_DIRS} + extlibs: \t@echo \${LIBRARIES} + compiler: \t@echo \${COMPILERNAME} @@ -61,45 +86,31 @@ linker: find_program (MAKE_EXECUTABLE NAMES make gmake) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "includes" RESULT_VARIABLE PETSC_INCLUDES_RETURN - OUTPUT_VARIABLE PETSC_INCLUDES) + OUTPUT_VARIABLE PETSC_INCLUDES + OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "extlibs" RESULT_VARIABLE PETSC_EXTERNAL_LIB_RETURN - OUTPUT_VARIABLE PETSC_EXTERNAL_LIB) + OUTPUT_VARIABLE PETSC_EXTERNAL_LIB + OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "linker" RESULT_VARIABLE PETSC_LINK_LIB_RETURN - OUTPUT_VARIABLE PETSC_LINK_LIB) + OUTPUT_VARIABLE PETSC_LINK_LIB + OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compiler" RESULT_VARIABLE MPIEXEC_RETURN - OUTPUT_VARIABLE MPIEXEC) + OUTPUT_VARIABLE MPIEXEC + OUTPUT_STRIP_TRAILING_WHITESPACE) file (REMOVE ${petsc_config_makefile}) -message("\nFound PETSC_DIR:\n${PETSC_DIR}") -message("Set PETSC_INCLUDES to:\n${PETSC_INCLUDES}") -message("Set PETSC_EXTERNAL_LIB to:\n${PETSC_EXTERNAL_LIB}") -message("Set PETSC_LINK_LIB to:\n${PETSC_LINK_LIB}") -message("Use PETSC wrapped compiler @: ${MPIEXEC}") - -# OUTPUT TYPE -set (SPECTRAL OFF) -set (FEM OFF) -if (DAMASK_DRIVER STREQUAL "SPECTRAL") - set (SPECTRAL ON ) -elseif (DAMASK_DRIVER STREQUAL "FEM") - set (FEM ON ) -else (DAMASK_DRIVER STREQUAL "SPECTRAL") - message (FATAL_ERROR "Unknown output, check build script!") -endif (DAMASK_DRIVER STREQUAL "SPECTRAL") - +message("***Found PETSC_DIR:\n${PETSC_DIR}\n") +message("***Set PETSC_INCLUDES to:\n${PETSC_INCLUDES}\n") +message("***Set PETSC_EXTERNAL_LIB to:\n${PETSC_EXTERNAL_LIB}\n") +message("***Set PETSC_LINK_LIB to:\n${PETSC_LINK_LIB}\n") +message("***Use PETSC wrapped compiler @: ${MPIEXEC}\n") # set system include directories -include_directories(${PETSC_INCLUDES} - lib - ${HDF5_DIR}/include - ) -link_directories(${HDF5_DIR}/lib - ${PETSC_LINK_LIB} - ${PETSC_EXTERNAL_LIB} - ) +set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES} -I${PROJECT_SOURCE_DIR}/lib -I${HDF5_DIR}/include") +set (DAMASK_LINK_FLAGS "${PETSC_LINK_LIB} ${PETSC_EXTERNAL_LIB} -L${HDF5_DIR}/lib") ## # set compile and debug flags @@ -129,7 +140,7 @@ else (OPTIMIZATION STREQUAL "OFF") set (OPTIMIZATION_gfortran "-O2") endif (OPTIMIZATION STREQUAL "OFF") -set (STANDARD_CHECK_ifort "-stand none -standard-semantics") +set (STANDARD_CHECK_ifort "-stand f08 -standard-semantics") set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) ################################################################################################### @@ -163,7 +174,6 @@ set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) # -diag-disable 7410 should disable warning about directory statement in inquire function, # but does not work. hence the other 2 statements ################################################################################################### -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -DDAMASKVERSION=\\\"${DAMASK_V}\\\"" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -fpp" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -ftz" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -assume byterecl,fpe_summary") @@ -301,7 +311,6 @@ set (LINK_OPTIONS_ifort "-shared-intel") #-fno-fast-math: # --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) ################################################################################################### -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -DDAMASKVERSION=\\\"${DAMASKVERSION}\\\"") set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -xf95-cpp-input" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -ffree-line-length-240" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fimplicit-none" ) @@ -349,14 +358,14 @@ set (LINK_OPTIONS_gfortran "-Wl,-undefined,dynamic_lookup") #-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) #-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) ################################################################################################### -set (PRECISION_ifort "-real-size 64 -integer-size 32 -DFLOAT=8 -DINT=4") +set (PRECISION_ifort "-real-size 64 -integer-size 32") ################################################################################################### #-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set #-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used #-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) ################################################################################################### -set (PRECISION_gfortran "-fdefault-real-8 -fdefault-double-8 -DFLOAT=8 -DINT=4") +set (PRECISION_gfortran "-fdefault-real-8 -fdefault-double-8") # set FLAGS get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) @@ -406,28 +415,29 @@ else (Fortran_COMPILER_NAME MATCHES "ifort.*") message (FATAL_ERROR "Require Fortran90 from GNU or Intel.") endif (Fortran_COMPILER_NAME MATCHES "ifort.*") -# additional flag for SPECTRAL solver -if (SPECTRAL) - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DSpectral") - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -DSpectral") - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DSpectral") - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DSpectral") -endif (SPECTRAL) -# additional flags for FEM solver -if (FEM) - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DFEM") - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -DFEM") - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DFEM") - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DFEM") -endif (FEM) +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") +set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DAMASK_LINK_FLAGS}" ) +set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DAMASK_LINK_FLAGS}" ) -# set default project compiler flags -# NOTE: some file might need different flags for compiling, DAMASK_$FLAGS -# are essentially the swap for this purpose -set (DAMASK_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}" ) -set (DAMASK_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}" ) -set (DAMASK_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set (DAMASK_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" ) +# if (SPECTRAL) +# # add_definitions(-DSpectral) +# set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DSpectral") +# set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -DSpectral") +# set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DSpectral") +# set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DSpectral") +# endif (SPECTRAL) +# # additional flags for FEM solver +# if (FEM) +# # add_definitions(-DFEM) +# set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DFEM") +# set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -DFEM") +# set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DFEM") +# set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DFEM") +# endif (FEM) + +message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") +message("***LINK FLAGS:\n${CMAKE_EXE_LINKER_FLAGS_RELEASE}\n") ## # ADD CODE DIRECTORY diff --git a/build_spectral.sh b/build_spectral.sh index 36b60a771..72a778cc7 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -29,7 +29,7 @@ cd build_spectral # CMAKE_BUILD_TYPE | Default set to release (no debugging output) # OPENMP | [ON/OFF] # OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] -# DAMASK_DRIVER | [SPECTRAL, FEM, MARC] +# DAMASK_DRIVER | [SPECTRAL, FEM] cmake -D PETSC_DIR=${PETSC_DIR} \ -D HDF5_DIR=${HDF5_DIR} \ -D DAMASK_V=${DAMASKVERSION} \ From 7335c27b3a548a79376f5e1be06421028b5456d5 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 2 Mar 2016 09:47:18 -0500 Subject: [PATCH 026/183] remove outdated flags --- CMakeLists.txt | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 30a57f650..7f68c7632 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -420,22 +420,6 @@ set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DAMASK_LINK_FLAGS}" ) set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DAMASK_LINK_FLAGS}" ) -# if (SPECTRAL) -# # add_definitions(-DSpectral) -# set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DSpectral") -# set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -DSpectral") -# set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DSpectral") -# set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DSpectral") -# endif (SPECTRAL) -# # additional flags for FEM solver -# if (FEM) -# # add_definitions(-DFEM) -# set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -DFEM") -# set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -DFEM") -# set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -DFEM") -# set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -DFEM") -# endif (FEM) - message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") message("***LINK FLAGS:\n${CMAKE_EXE_LINKER_FLAGS_RELEASE}\n") From aa2a738cccd1a0d09be26f054666ee95f51b799e Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 2 Mar 2016 15:39:31 -0500 Subject: [PATCH 027/183] remove duplicated flags --- CMakeLists.txt | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f68c7632..f20ab4dbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,6 @@ ######################################################################################## # CMAKE for build the Material subroutine for BVP solution ######################################################################################## -# OPTIONS = standard (alternative): meaning -#------------------------------------------------------------- -# F90 = ifort (gfortran): compiler type, choose Intel or GNU -# COMPILERNAME = name of the compiler executable (if not the same as the ype), e.g. using mpich-g90 instead of ifort -# PORTABLE = TRUE (FALSE): decision, if executable is optimized for the machine on which it was built. -# OPTIMIZATION = DEFENSIVE (OFF,AGGRESSIVE,ULTRA): Optimization mode: O2, O0, O3 + further options for most files, O3 + further options for all files -# OPENMP = TRUE (FALSE): OpenMP multiprocessor support -# PREFIX = arbitrary prefix (before compilername) -# OPTION = arbitrary option (just before file to compile) -# SUFFIX = arbitrary suffix (after file to compile) -# STANDARD_CHECK = checking for Fortran 2008, compiler dependend -######################################################################################## cmake_minimum_required (VERSION 3.1.0 FATAL_ERROR) project (DAMASK Fortran) @@ -28,7 +16,7 @@ if (NOT DEFINED HDF5_DIR) message (FATAL_ERROR "HDF5_DIR is not found!" ) endif (NOT DEFINED HDF5_DIR) -# OUTPUT TYPE +# DAMASK DRIVER SELECTION set (SPECTRAL OFF) set (FEM OFF) if (DAMASK_DRIVER STREQUAL "SPECTRAL") @@ -36,7 +24,7 @@ if (DAMASK_DRIVER STREQUAL "SPECTRAL") elseif (DAMASK_DRIVER STREQUAL "FEM") set (FEM ON ) else (DAMASK_DRIVER STREQUAL "SPECTRAL") - message (FATAL_ERROR "Unknown output, check build script!") + message (FATAL_ERROR "Unknown driver detected, check build script!") endif (DAMASK_DRIVER STREQUAL "SPECTRAL") # COMPILE VARIABLES @@ -51,7 +39,7 @@ if (FEM) add_definitions(-DFEM) endif(FEM) -# brutal force to find the variables defined in PETSC +# BRUTAL FORCE TO FIND THE VARIABLES DEFINED IN PETSC # ref: # https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake set(petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") @@ -59,7 +47,7 @@ set(petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) # A temporary makefile to probe the PETSc configuration set (petsc_config_makefile "${PROJECT_BINARY_DIR}/Makefile.petsc") file (WRITE "${petsc_config_makefile}" -"## This file was autogenerated by FindPETSc.cmake +"## This file was auto generated by CMake # PETSC_DIR = ${PETSC_DIR} # PETSC_ARCH = ${PETSC_ARCH} SHELL = /bin/sh @@ -86,11 +74,11 @@ linker: find_program (MAKE_EXECUTABLE NAMES make gmake) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "includes" RESULT_VARIABLE PETSC_INCLUDES_RETURN - OUTPUT_VARIABLE PETSC_INCLUDES + OUTPUT_VARIABLE petsc_includes OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "extlibs" RESULT_VARIABLE PETSC_EXTERNAL_LIB_RETURN - OUTPUT_VARIABLE PETSC_EXTERNAL_LIB + OUTPUT_VARIABLE petsc_external_lib OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "linker" RESULT_VARIABLE PETSC_LINK_LIB_RETURN @@ -102,14 +90,27 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compiler OUTPUT_STRIP_TRAILING_WHITESPACE) file (REMOVE ${petsc_config_makefile}) +# remove duplicate flags for compiler and linking +string( REGEX MATCHALL "-I([^\" ]+)" TMP_LIST "${petsc_includes}") +list(REMOVE_DUPLICATES TMP_LIST) +foreach (dir ${TMP_LIST}) + set(PETSC_INCLUDES "${PETSC_INCLUDES} ${dir}") +endforeach(dir) +string( REGEX MATCHALL "-[lLW]([^\" ]+)" TMP_LIST "${petsc_external_lib}") +list(REMOVE_DUPLICATES TMP_LIST) +foreach (exlib ${TMP_LIST}) + set(PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} ${exlib}") +endforeach(exlib) + + message("***Found PETSC_DIR:\n${PETSC_DIR}\n") message("***Set PETSC_INCLUDES to:\n${PETSC_INCLUDES}\n") message("***Set PETSC_EXTERNAL_LIB to:\n${PETSC_EXTERNAL_LIB}\n") message("***Set PETSC_LINK_LIB to:\n${PETSC_LINK_LIB}\n") -message("***Use PETSC wrapped compiler @: ${MPIEXEC}\n") +message("***Use PETSC wrapped compiler:\n${MPIEXEC}\n") # set system include directories -set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES} -I${PROJECT_SOURCE_DIR}/lib -I${HDF5_DIR}/include") +set (DAMASK_INCLUDE_FLAGS "${PETSC_INCLUDES} -I${PROJECT_SOURCE_DIR}/lib -I${HDF5_DIR}/include -lm") set (DAMASK_LINK_FLAGS "${PETSC_LINK_LIB} ${PETSC_EXTERNAL_LIB} -L${HDF5_DIR}/lib") ## @@ -186,7 +187,6 @@ set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn ignore_loc" set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn alignments" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn unused" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -diag-remark 7410" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -stand none" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn nostderrors" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING From 6397ea561f28c4030fb1657edf2fff7481f5ed32 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Thu, 3 Mar 2016 10:52:09 -0500 Subject: [PATCH 028/183] fix version error in Makefile --- code/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/Makefile b/code/Makefile index 66c70e646..a18cbebac 100644 --- a/code/Makefile +++ b/code/Makefile @@ -98,7 +98,7 @@ OPTIMIZATION_AGGRESSIVE_gfortran :=-O3 -ffast-math -funroll-loops -ftree-vectori LINK_OPTIONS_ifort :=-shared-intel -COMPILE_OPTIONS_ifort :=-DDAMASKVERSION='${DAMASKVERSION}'\ +COMPILE_OPTIONS_ifort :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ -fpp\ -ftz\ -assume byterecl,fpe_summary\ From d768884aa9e617f626af64d50b3a96cd3035e85f Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Thu, 3 Mar 2016 12:45:09 -0500 Subject: [PATCH 029/183] build object first, then exe --- code/CMakeLists.txt | 11 ++++++----- code/Makefile | 12 +++++++----- code/quit__genmod.f90 | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 6c1b63dfa..d2d88a596 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -120,8 +120,6 @@ target_link_libraries(DAMASK_ENGINE DAMASK_HYDROGENFLUX ) target_link_libraries(DAMASK_ENGINE DAMASK_HOMOGENIZATION) - - if (FEM) add_library(DAMASK_CPFE "CPFEM.f90") target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) @@ -144,8 +142,11 @@ if (SPECTRAL) "spectral_mech_Basic.f90") target_link_libraries(DAMASK_SPECTRAL_MECH DAMASK_SPECTRAL_UTILITY) + add_library(DAMASK_SPECTRAL_SOLVER "DAMASK_spectral.f90") + target_link_libraries(DAMASK_SPECTRAL_SOLVER DAMASK_CPFE ) + target_link_libraries(DAMASK_SPECTRAL_SOLVER DAMASK_SPECTRAL_BASE) + target_link_libraries(DAMASK_SPECTRAL_SOLVER DAMASK_SPECTRAL_MECH) + add_executable(DAMASKSpectral.exe DAMASK_spectral.f90) - target_link_libraries(DAMASKSpectral.exe DAMASK_CPFE - DAMASK_SPECTRAL_BASE - DAMASK_SPECTRAL_MECH) + target_link_libraries(DAMASKSpectral.exe DAMASK_SPECTRAL_SOLVER) endif(SPECTRAL) \ No newline at end of file diff --git a/code/Makefile b/code/Makefile index a18cbebac..2a9a3deae 100644 --- a/code/Makefile +++ b/code/Makefile @@ -33,7 +33,7 @@ LINKERNAME ?= $(FLINKER) HDF5 = /mnt/research/CMM/opt/hdf5 # 2. Location of External Libraries (missing in the 1.8.12 version) LIBZ = /mnt/research/CMM/opt/hdf5/lib/libz.a -LIBSZ = /mnt/research/CMM/opt/hdf5/lib/libsz.a +LIBSZ = /mnt/research/CMM/opt/hdf5/lib/libszip.a # 3. Set libraries for HDF5 (LIBS: shared lib, LIBZ: external lib) HDFLIBS = -I$(HDF5)/include -L$(HDF5)/lib HDFLIBZ = -L$(LIBZ) -L$(LIBSZ) @@ -631,6 +631,12 @@ numerics.o: numerics.f90 \ libs.o: libs.f90 \ IO.o +damask_hdf5.o: damask_hdf5.f90 \ + prec.o \ + IO.o + + $(PREFIX) $(COMPILERNAME) $(HDFLIBS) $(HDFLIBZ) -c damask_hdf5.f90 $(SUFFIX) -lm + IO.o: IO.f90 \ DAMASK_interface.o @@ -660,10 +666,6 @@ DAMASK_interface.o: spectral_interface.f90 \ prec.o: prec.f90 $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 $(SUFFIX) -damask_hdf5.o: damask_hdf5.f90 \ - prec.o \ - IO.o - $(PREFIX) $(COMPILERNAME) $(HDFLIBS) $(HDFLIBZ) -c damask_hdf5.f90 $(SUFFIX) -lm endif %.o : %.f90 diff --git a/code/quit__genmod.f90 b/code/quit__genmod.f90 index c6b282470..ef0a49bc0 100644 --- a/code/quit__genmod.f90 +++ b/code/quit__genmod.f90 @@ -1,4 +1,4 @@ - !COMPILER-GENERATED INTERFACE MODULE: Tue Feb 23 16:12:31 2016 + !COMPILER-GENERATED INTERFACE MODULE: Thu Mar 3 12:28:23 2016 MODULE QUIT__genmod INTERFACE SUBROUTINE QUIT(STOP_ID) From ee148fe19c28182de99b40151d40e55926f0f97a Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Thu, 3 Mar 2016 13:11:03 -0500 Subject: [PATCH 030/183] polish syntax --- CMakeLists.txt | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f20ab4dbc..34b4d3765 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,9 +109,14 @@ message("***Set PETSC_EXTERNAL_LIB to:\n${PETSC_EXTERNAL_LIB}\n") message("***Set PETSC_LINK_LIB to:\n${PETSC_LINK_LIB}\n") message("***Use PETSC wrapped compiler:\n${MPIEXEC}\n") -# set system include directories -set (DAMASK_INCLUDE_FLAGS "${PETSC_INCLUDES} -I${PROJECT_SOURCE_DIR}/lib -I${HDF5_DIR}/include -lm") -set (DAMASK_LINK_FLAGS "${PETSC_LINK_LIB} ${PETSC_EXTERNAL_LIB} -L${HDF5_DIR}/lib") +# set include directories +set (DAAMSK_INCLDUE_FLAGS "${DAAMSK_INCLDUE_FLAGS} ${PETSC_INCLUDES}" ) +set (DAAMSK_INCLDUE_FLAGS "${DAAMSK_INCLDUE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") +#set (DAAMSK_INCLDUE_FLAGS "${DAAMSK_INCLDUE_FLAGS} -I${HDF5_DIR}/include -lm" ) +# set link libraries from PETSc +set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} ${PETSC_LINK_LIB}" ) +set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} ${PETSC_EXTERNAL_LIB}") +#set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} -L${HDF5_DIR}/lib" ) ## # set compile and debug flags @@ -226,7 +231,7 @@ set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -warn stderrors" set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -debug-parameters all" ) set (LINK_OPTIONS_ifort "-shared-intel") - +# set (LINK_OPTIONS_ifort "-static-intel") ################################################################################################### # COMPILE SWITCHES # -shared @@ -370,6 +375,10 @@ set (PRECISION_gfortran "-fdefault-real-8 -fdefault-double-8") # set FLAGS get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) +# linker from PETSc goes first +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DAMASK_LINK_FLAGS}" ) +set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DAMASK_LINK_FLAGS}" ) + if (Fortran_COMPILER_NAME MATCHES "ifort.*") # need the PETSC wrapped version of ifort set (CMAKE_Fortran_COMPILER "${MPIEXEC}") @@ -380,15 +389,20 @@ if (Fortran_COMPILER_NAME MATCHES "ifort.*") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_OPTIONS_ifort}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_ifort}") - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}" ) # for DEBUG set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${COMPILE_OPTIONS_ifort}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${PRECISION_ifort}" ) set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINK_OPTIONS_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${OPENMP_FLAG_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINK_OPTIONS_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${STANDARD_CHECK_ifort}") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${OPTIMIZATION_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}" ) # elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") set (CMAKE_Fortran_COMPILER "${MPIEXEC}") @@ -399,15 +413,20 @@ elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_OPTIONS_gfortran}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAG_gfortran}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_gfortran}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_gfortran}") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_gfortran}" ) # for DEBUG set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${COMPILE_OPTIONS_gfortran}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${PRECISION_gfortran}" ) set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINK_OPTIONS_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_gfortran}") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${OPENMP_FLAG_gfortran}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINK_OPTIONS_gfortran}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${STANDARD_CHECK_gfortran}") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${OPTIMIZATION_gfortran}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_gfortran}" ) # elseif (Fortran_COMPILER_NAME MATCHES "g77") message (FATAL_ERROR "Fortran 77 is not supported.") @@ -415,10 +434,9 @@ else (Fortran_COMPILER_NAME MATCHES "ifort.*") message (FATAL_ERROR "Require Fortran90 from GNU or Intel.") endif (Fortran_COMPILER_NAME MATCHES "ifort.*") +# append includes from PETSC at the end set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DAMASK_LINK_FLAGS}" ) -set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DAMASK_LINK_FLAGS}" ) message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") message("***LINK FLAGS:\n${CMAKE_EXE_LINKER_FLAGS_RELEASE}\n") From 2cf5225875fb0669b4f80d0af3e928a31437bdd2 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Thu, 3 Mar 2016 14:12:10 -0500 Subject: [PATCH 031/183] focusing on tweaking ifort branch first --- CMakeLists.txt | 29 +++++++++++++++++------------ build_spectral.sh | 5 +---- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34b4d3765..c385d5323 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ if (DAMASK_DRIVER STREQUAL "SPECTRAL") elseif (DAMASK_DRIVER STREQUAL "FEM") set (FEM ON ) else (DAMASK_DRIVER STREQUAL "SPECTRAL") - message (FATAL_ERROR "Unknown driver detected, check build script!") + message (FATAL_ERROR "!?driver?!, check build script!") endif (DAMASK_DRIVER STREQUAL "SPECTRAL") # COMPILE VARIABLES @@ -110,9 +110,9 @@ message("***Set PETSC_LINK_LIB to:\n${PETSC_LINK_LIB}\n") message("***Use PETSC wrapped compiler:\n${MPIEXEC}\n") # set include directories -set (DAAMSK_INCLDUE_FLAGS "${DAAMSK_INCLDUE_FLAGS} ${PETSC_INCLUDES}" ) -set (DAAMSK_INCLDUE_FLAGS "${DAAMSK_INCLDUE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") -#set (DAAMSK_INCLDUE_FLAGS "${DAAMSK_INCLDUE_FLAGS} -I${HDF5_DIR}/include -lm" ) +set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) +set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") +#set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${HDF5_DIR}/include -lm" ) # set link libraries from PETSc set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} ${PETSC_LINK_LIB}" ) set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} ${PETSC_EXTERNAL_LIB}") @@ -376,8 +376,8 @@ set (PRECISION_gfortran "-fdefault-real-8 -fdefault-double-8") get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) # linker from PETSc goes first -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DAMASK_LINK_FLAGS}" ) -set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DAMASK_LINK_FLAGS}" ) +#set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DAMASK_LINK_FLAGS}" ) +#set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DAMASK_LINK_FLAGS}" ) if (Fortran_COMPILER_NAME MATCHES "ifort.*") # need the PETSC wrapped version of ifort @@ -389,19 +389,24 @@ if (Fortran_COMPILER_NAME MATCHES "ifort.*") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_OPTIONS_ifort}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${PETSC_LINK_LIB}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}" ) - # for DEBUG - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${COMPILE_OPTIONS_ifort}") - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${PRECISION_ifort}" ) - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${PETSC_EXTERNAL_LIB}" ) + + # for DEBUG + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}" ) + + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PETSC_LINK_LIB}" ) set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${OPENMP_FLAG_ifort}" ) set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINK_OPTIONS_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${STANDARD_CHECK_ifort}") set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${OPTIMIZATION_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${STANDARD_CHECK_ifort}") + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PETSC_EXTERNAL_LIB}" ) set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}" ) # elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") diff --git a/build_spectral.sh b/build_spectral.sh index 72a778cc7..e009e174c 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -37,7 +37,4 @@ cmake -D PETSC_DIR=${PETSC_DIR} \ -D OPENMP=ON \ -D OPTIMIZATION=DEFENSIVE \ -D DAMASK_DRIVER=SPECTRAL \ - ../.. - -# instruction for compiling -echo "Please go into the directory above and use make to build DAMASK_spectal.exe" \ No newline at end of file + ../.. \ No newline at end of file From 57c8213d9b0d1610b23aca400bcaa3774129c309 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Thu, 3 Mar 2016 16:09:02 -0500 Subject: [PATCH 032/183] force linker settings in cmake --- CMakeLists.txt | 58 +++++++++++++++++++-------------------------- code/CMakeLists.txt | 14 +++++------ 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c385d5323..398e0d61f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,8 +81,8 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "extlibs" OUTPUT_VARIABLE petsc_external_lib OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "linker" - RESULT_VARIABLE PETSC_LINK_LIB_RETURN - OUTPUT_VARIABLE PETSC_LINK_LIB + RESULT_VARIABLE PETSC_LINKER_RETURN + OUTPUT_VARIABLE PETSC_LINKER OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compiler" RESULT_VARIABLE MPIEXEC_RETURN @@ -104,17 +104,17 @@ endforeach(exlib) message("***Found PETSC_DIR:\n${PETSC_DIR}\n") -message("***Set PETSC_INCLUDES to:\n${PETSC_INCLUDES}\n") -message("***Set PETSC_EXTERNAL_LIB to:\n${PETSC_EXTERNAL_LIB}\n") -message("***Set PETSC_LINK_LIB to:\n${PETSC_LINK_LIB}\n") -message("***Use PETSC wrapped compiler:\n${MPIEXEC}\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 PETSC_MPIEXEC:\n${MPIEXEC}\n") # set include directories set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") #set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${HDF5_DIR}/include -lm" ) # set link libraries from PETSc -set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} ${PETSC_LINK_LIB}" ) +set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} ${PETSC_LINKER}" ) set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} ${PETSC_EXTERNAL_LIB}") #set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} -L${HDF5_DIR}/lib" ) @@ -375,13 +375,7 @@ set (PRECISION_gfortran "-fdefault-real-8 -fdefault-double-8") # set FLAGS get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) -# linker from PETSc goes first -#set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DAMASK_LINK_FLAGS}" ) -#set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DAMASK_LINK_FLAGS}" ) - if (Fortran_COMPILER_NAME MATCHES "ifort.*") - # need the PETSC wrapped version of ifort - set (CMAKE_Fortran_COMPILER "${MPIEXEC}") # for RELEASE set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}" ) @@ -389,25 +383,17 @@ if (Fortran_COMPILER_NAME MATCHES "ifort.*") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_OPTIONS_ifort}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${PETSC_LINK_LIB}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_ifort}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}") - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${PETSC_EXTERNAL_LIB}" ) - + #set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${PETSC_EXTERNAL_LIB}" ) # for DEBUG set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PETSC_LINK_LIB}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${OPENMP_FLAG_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINK_OPTIONS_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${OPTIMIZATION_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${STANDARD_CHECK_ifort}") - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PETSC_EXTERNAL_LIB}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DEBUG_OPTIONS_ifort}" ) # elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") set (CMAKE_Fortran_COMPILER "${MPIEXEC}") @@ -423,15 +409,10 @@ elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_gfortran}") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_gfortran}" ) # for DEBUG - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${COMPILE_OPTIONS_gfortran}") - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${PRECISION_gfortran}" ) - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_gfortran}" ) + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${OPENMP_FLAG_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LINK_OPTIONS_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${STANDARD_CHECK_gfortran}") - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${OPTIMIZATION_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${DEBUG_OPTIONS_gfortran}" ) + set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DEBUG_OPTIONS_gfortran}") # elseif (Fortran_COMPILER_NAME MATCHES "g77") message (FATAL_ERROR "Fortran 77 is not supported.") @@ -439,9 +420,18 @@ else (Fortran_COMPILER_NAME MATCHES "ifort.*") message (FATAL_ERROR "Require Fortran90 from GNU or Intel.") endif (Fortran_COMPILER_NAME MATCHES "ifort.*") -# append includes from PETSC at the end -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") -set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") +# Finalizing +set (CMAKE_Fortran_COMPILER "${MPIEXEC}") +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") +set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") +set (CMAKE_LINKER "${PETSC_LINKER}") +if (CMAKE_BUILD_TYPE STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${DAMASK_EXE} ${PETSC_EXTERNAL_LIB}") +else(CMAKE_BUILD_TYPE STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") +endif(CMAKE_BUILD_TYPE STREQUAL "RELEASE") message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") message("***LINK FLAGS:\n${CMAKE_EXE_LINKER_FLAGS_RELEASE}\n") diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index d2d88a596..481b64fe1 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -142,11 +142,11 @@ if (SPECTRAL) "spectral_mech_Basic.f90") target_link_libraries(DAMASK_SPECTRAL_MECH DAMASK_SPECTRAL_UTILITY) - add_library(DAMASK_SPECTRAL_SOLVER "DAMASK_spectral.f90") - target_link_libraries(DAMASK_SPECTRAL_SOLVER DAMASK_CPFE ) - target_link_libraries(DAMASK_SPECTRAL_SOLVER DAMASK_SPECTRAL_BASE) - target_link_libraries(DAMASK_SPECTRAL_SOLVER DAMASK_SPECTRAL_MECH) - - add_executable(DAMASKSpectral.exe DAMASK_spectral.f90) - target_link_libraries(DAMASKSpectral.exe DAMASK_SPECTRAL_SOLVER) + add_library(DAMASK_EXE "DAMASK_spectral.f90") + target_link_libraries(DAMASK_EXE DAMASK_CPFE ) + target_link_libraries(DAMASK_EXE DAMASK_SPECTRAL_BASE) + target_link_libraries(DAMASK_EXE DAMASK_SPECTRAL_MECH) + + add_executable(DAMASKSpectral.exe "DAMASK_spectral.f90") + target_link_libraries(DAMASKSpectral.exe DAMASK_EXE) endif(SPECTRAL) \ No newline at end of file From 9cb9de9c8a738ce1493ddfeca74aa8e502203965 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Thu, 3 Mar 2016 16:45:15 -0500 Subject: [PATCH 033/183] CMake build system functions properly for spectral solver --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 398e0d61f..cbd8eecd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -387,7 +387,7 @@ if (Fortran_COMPILER_NAME MATCHES "ifort.*") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_ifort}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}") - #set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${PETSC_EXTERNAL_LIB}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${PETSC_EXTERNAL_LIB}" ) # for DEBUG set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") @@ -427,15 +427,16 @@ set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_I set (CMAKE_LINKER "${PETSC_LINKER}") if (CMAKE_BUILD_TYPE STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE - "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${DAMASK_EXE} ${PETSC_EXTERNAL_LIB}") + "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB}") else(CMAKE_BUILD_TYPE STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE - "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") + "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") endif(CMAKE_BUILD_TYPE STREQUAL "RELEASE") message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") message("***LINK FLAGS:\n${CMAKE_EXE_LINKER_FLAGS_RELEASE}\n") + ## # ADD CODE DIRECTORY add_subdirectory(code) From 0e34d0468c7090a7697b72945acae9089887fc5d Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Fri, 4 Mar 2016 11:18:38 -0500 Subject: [PATCH 034/183] adding install target in CMake --- CMakeLists.txt | 35 ++++++++++++++++++++++++----------- build_spectral.sh | 37 ++++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbd8eecd2..97def9456 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,17 +4,28 @@ cmake_minimum_required (VERSION 3.1.0 FATAL_ERROR) project (DAMASK Fortran) -# The version number. +# THE VERSION NUMBER. set (DAMASK_VERSION_MAJOR 1) set (DAMASK_VERSION_MINOR ${DAMASK_V}) -# PETSC and HDF5 is required +# PETSC IS REQUIRED if (NOT DEFINED PETSC_DIR) message (FATAL_ERROR "PETSC_DIR is not found!") endif (NOT DEFINED PETSC_DIR) -if (NOT DEFINED HDF5_DIR) - message (FATAL_ERROR "HDF5_DIR is not found!" ) -endif (NOT DEFINED HDF5_DIR) +# RECOMMEND USING HDF5 FROM PETSC +if (DEFINED HDF5_DIR) + message ("\n***Using HDF5 library found at ${HDF5_DIR}\n") +else(DEFINED HDF5_DIR) + message ("\n***Using HDF5 library from PETSc\n" ) +endif (DEFINED HDF5_DIR) + +# Setting installation prefix +if (NOT DEFINED DAMASK_INSTALL) + set (CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/bin") +elseif(DEFINED DAMASK_INSTALL) + set (CMAKE_INSTALL_PREFIX "${DAMASK_INSTALL}") +endif(NOT DEFINED DAMASK_INSTALL) +message("\n***The binary will be installed at\n${CMAKE_INSTALL_PREFIX}\n") # DAMASK DRIVER SELECTION set (SPECTRAL OFF) @@ -109,14 +120,14 @@ message("***Found PETSC_EXTERNAL_LIB:\n${PETSC_EXTERNAL_LIB}\n") message("***Found PETSC_LINKER:\n${PETSC_LINKER}\n") message("***Found PETSC_MPIEXEC:\n${MPIEXEC}\n") -# set include directories +# SET INCLUDE DIRECTORIES (SNEAK IT IN WITH PETSC) +if (DEFINED HDF5_DIR) + set (DAMASK_INCLUDE_FLAGS "${PETSC_INCLUDES} -I${HDF5_DIR}/include" ) + set (PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} -L${HDF5_DIR}/lib") +endif (DEFINED HDF5_DIR) + set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") -#set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${HDF5_DIR}/include -lm" ) -# set link libraries from PETSc -set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} ${PETSC_LINKER}" ) -set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} ${PETSC_EXTERNAL_LIB}") -#set (DAMASK_LINK_FLAGS "${DAMASK_LINK_FLAGS} -L${HDF5_DIR}/lib" ) ## # set compile and debug flags @@ -440,6 +451,8 @@ message("***LINK FLAGS:\n${CMAKE_EXE_LINKER_FLAGS_RELEASE}\n") ## # ADD CODE DIRECTORY add_subdirectory(code) +INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/code/DAMASKSpectral.exe + DESTINATION ${CMAKE_INSTALL_PREFIX}) ## # ADD TESTING CASES diff --git a/build_spectral.sh b/build_spectral.sh index e009e174c..7c0ff015e 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -23,18 +23,25 @@ cd build_spectral ## # CMake call -# PETSC_DIR | PETSC directory -# HDF5_DIR | HDF5 library (same compiler for DAMASK) -# DAMASK_V | DAMASK current revision -# CMAKE_BUILD_TYPE | Default set to release (no debugging output) -# OPENMP | [ON/OFF] -# OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] -# DAMASK_DRIVER | [SPECTRAL, FEM] -cmake -D PETSC_DIR=${PETSC_DIR} \ - -D HDF5_DIR=${HDF5_DIR} \ - -D DAMASK_V=${DAMASKVERSION} \ - -D CMAKE_BUILD_TYPE=RELEASE \ - -D OPENMP=ON \ - -D OPTIMIZATION=DEFENSIVE \ - -D DAMASK_DRIVER=SPECTRAL \ - ../.. \ No newline at end of file +# PETSC_DIR | PETSC directory +# HDF5_DIR | HDF5 library (same compiler for DAMASK) +# DAMASK_V | DAMASK current revision +# CMAKE_BUILD_TYPE | Default set to release (no debugging output) +# OPENMP | [ON/OFF] +# OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] +# DAMASK_DRIVER | [SPECTRAL, FEM] +# DAMASK_INSTALL | Directory to install binary output +cmake -D PETSC_DIR=${PETSC_DIR} \ + -D DAMASK_V=${DAMASKVERSION} \ + -D CMAKE_BUILD_TYPE=RELEASE \ + -D OPENMP=ON \ + -D OPTIMIZATION=DEFENSIVE \ + -D DAMASK_DRIVER=SPECTRAL \ + -D DAMASK_INSTALL=${HOME}/bin \ + ../.. + +echo +echo "Please move to the build directory using" +echo " cd build/build_spectral" +echo "Using the following command to build DAMASK spectral solver" +echo " make clean all install" \ No newline at end of file From 2a15ff166cd61210878a5abd986485f0f6f294db Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Fri, 4 Mar 2016 11:39:52 -0500 Subject: [PATCH 035/183] adding support for FEM sovler (not tested) --- build_FEM.sh | 48 +++++++++++++++++++++++++++++++++++++++++++++ code/CMakeLists.txt | 32 ++++++++++++++++++++++++------ 2 files changed, 74 insertions(+), 6 deletions(-) mode change 100644 => 100755 build_FEM.sh diff --git a/build_FEM.sh b/build_FEM.sh old mode 100644 new mode 100755 index e69de29bb..4d33ef8ed --- a/build_FEM.sh +++ b/build_FEM.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +cat README +echo +echo "Building FEM solver with ${FC}" +DAMASKVERSION=$(cat VERSION) + +# prepare building directory +# structure: +# BUILD_DIR +# |-BUILD_SPECTRAL +# |-BUILD_FEM +# |-BUILD_MARC +if [ ! -d build ]; then + mkdir build +fi +cd build +if [ -d build_FEM ] ; then + rm -rf build_FEM +fi +mkdir build_FEM +cd build_FEM + +## +# CMake call +# PETSC_DIR | PETSC directory +# HDF5_DIR | HDF5 library (same compiler for DAMASK) +# DAMASK_V | DAMASK current revision +# CMAKE_BUILD_TYPE | Default set to release (no debugging output) +# OPENMP | [ON/OFF] +# OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] +# DAMASK_DRIVER | [SPECTRAL, FEM] +# DAMASK_INSTALL | Directory to install binary output +cmake -D PETSC_DIR=${PETSC_DIR} \ + -D DAMASK_V=${DAMASKVERSION} \ + -D CMAKE_BUILD_TYPE=RELEASE \ + -D OPENMP=ON \ + -D OPTIMIZATION=DEFENSIVE \ + -D DAMASK_DRIVER=FEM \ + -D DAMASK_FEM_DIR=PRIVATE/FEM/code \ + -D DAMASK_INSTALL=${HOME}/bin \ + ../.. + +echo +echo "Please move to the build directory using" +echo " cd build/build_spectral" +echo "Using the following command to build DAMASK spectral solver" +echo " make clean all install" \ No newline at end of file diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 481b64fe1..c1abf4d4e 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -5,10 +5,10 @@ add_library(DAMASK_PREC "prec.f90") if (SPECTRAL) add_library(DAMASK_INTERFACE "spectral_interface.f90") - target_link_libraries(DAMASK_INTERFACE DAMASK_PREC) -elseif(SPECTRAL) - message(FATAL_ERROR "NOT IMPLEMENTED YET") +elseif(FEM) + add_library(DAMASK_INTERFACE "DAMASK_FEM_interface.f90") endif(SPECTRAL) +target_link_libraries(DAMASK_INTERFACE DAMASK_PREC) add_library(DAMASK_IO "IO.f90") target_link_libraries(DAMASK_IO DAMASK_INTERFACE) @@ -32,11 +32,15 @@ target_link_libraries(DAMASK_MATH DAMASK_FEsolving) # source files if (SPECTRAL) add_library(DAMASK_MESH "mesh.f90") + target_link_libraries(DAMASK_MESH DAMASK_MATH) endif(SPECTRAL) if (FEM) - add_library(DAMASK_MESH "${FEM_DIR}/meshFEM.f90") + add_library(DAMASK_FEZoo "FEZoo.f90") + target_link_libraries(DAMASK_FEZoo DAMASK_MATH) + add_library(DAMASK_MESH "meshFEM.f90") + target_link_libraries(DAMASK_MESH DAMASK_FEZoo) endif(FEM) -target_link_libraries(DAMASK_MESH DAMASK_MATH) + add_library(DAMASK_MATERIAL "material.f90") target_link_libraries(DAMASK_MATERIAL DAMASK_MESH) @@ -123,7 +127,23 @@ target_link_libraries(DAMASK_ENGINE DAMASK_HOMOGENIZATION) if (FEM) add_library(DAMASK_CPFE "CPFEM.f90") target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) - message("special treatment for FEM code") + + add_library(DAMASK_FEM_UTILITY "FEM_utilities.f90") + target_link_libraries(DAMASK_FEM_UTILITY DAMASK_CPFE) + + add_library(DAMASK_FEM_BASE "FEM_hydrogenflux.f90" + "FEM_porosity.f90" + "FEM_vacancyflux.f90" + "FEM_damage.f90" + "FEM_thermal.f90" + "FEM_mech.f90") + target_link_libraries(DAMASK_FEM_BASE DAMASK_FEM_UTILITY) + + add_library(DAMASK_FEM_DRIVER "DAMASK_FEM_driver.f90") + target_link_libraries(DAMASK_FEM_DRIVER DAMASK_FEM_BASE) + + add_executable(DAMASK_FEM.exe "DAMASK_FEM_driver.f90") + target_link_libraries(DAMASK_FEM.exe DAMASK_FEM_DRIVER) endif(FEM) if (SPECTRAL) From 005e4df0ddba9e47fe6fa22c8a0eaa70612c2e4b Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Fri, 4 Mar 2016 14:42:55 -0500 Subject: [PATCH 036/183] force using HDF5 from PETSc --- CMakeLists.txt | 34 +- build_FEM.sh | 2 - build_spectral.sh | 1 - code/CMakeLists.txt | 172 - code/CPFEM.f90 | 705 ---- code/CPFEM2.f90 | 367 -- code/DAMASK_abaqus_exp.f | 299 -- code/DAMASK_abaqus_std.f | 342 -- code/DAMASK_marc.f90 | 426 -- code/DAMASK_marc2011.f90 | 1 - code/DAMASK_marc2012.f90 | 1 - code/DAMASK_marc2013.1.f90 | 1 - code/DAMASK_marc2013.f90 | 1 - code/DAMASK_marc2014.2.f90 | 1 - code/DAMASK_marc2014.f90 | 1 - code/DAMASK_marc2015.f90 | 1 - code/DAMASK_spectral.f90 | 751 ---- code/FEsolving.f90 | 171 - code/IO.f90 | 2470 ------------ code/Makefile | 701 ---- code/commercialFEM_fileList.f90 | 59 - code/compilation_info.f90 | 13 - code/constitutive.f90 | 1226 ------ code/core_quit.f90 | 15 - code/crystallite.f90 | 4228 -------------------- code/damage_local.f90 | 327 -- code/damage_none.f90 | 60 - code/damage_nonlocal.f90 | 380 -- code/damask.core.pyf | 126 - code/damask_hdf5.f90 | 16 - code/debug.f90 | 476 --- code/homogenization.f90 | 1396 ------- code/homogenization_RGC.f90 | 1558 -------- code/homogenization_isostrain.f90 | 317 -- code/homogenization_none.f90 | 60 - code/hydrogenflux_cahnhilliard.f90 | 513 --- code/hydrogenflux_isoconc.f90 | 63 - code/kinematics_cleavage_opening.f90 | 303 -- code/kinematics_hydrogen_strain.f90 | 264 -- code/kinematics_slipplane_opening.f90 | 323 -- code/kinematics_thermal_expansion.f90 | 228 -- code/kinematics_vacancy_strain.f90 | 265 -- code/lattice.f90 | 2239 ----------- code/libs.f90 | 14 - code/material.f90 | 1615 -------- code/math.f90 | 2678 ------------- code/mesh.f90 | 4784 ----------------------- code/numerics.f90 | 726 ---- code/plastic_disloUCLA.f90 | 2116 ---------- code/plastic_dislotwin.f90 | 2542 ------------ code/plastic_isotropic.f90 | 678 ---- code/plastic_j2.f90 | 579 --- code/plastic_none.f90 | 109 - code/plastic_nonlocal.f90 | 4031 ------------------- code/plastic_phenoplus.f90 | 1419 ------- code/plastic_phenopowerlaw.f90 | 1226 ------ code/plastic_titanmod.f90 | 1913 --------- code/porosity_none.f90 | 61 - code/porosity_phasefield.f90 | 450 --- code/prec.f90 | 192 - code/quit__genmod.f90 | 8 - code/source_damage_anisoBrittle.f90 | 425 -- code/source_damage_anisoDuctile.f90 | 415 -- code/source_damage_isoBrittle.f90 | 383 -- code/source_damage_isoDuctile.f90 | 350 -- code/source_thermal_dissipation.f90 | 220 -- code/source_thermal_externalheat.f90 | 277 -- code/source_vacancy_irradiation.f90 | 253 -- code/source_vacancy_phenoplasticity.f90 | 215 - code/source_vacancy_thermalfluc.f90 | 255 -- code/spectral_damage.f90 | 414 -- code/spectral_interface.f90 | 568 --- code/spectral_mech_AL.f90 | 715 ---- code/spectral_mech_Basic.f90 | 569 --- code/spectral_mech_Polarisation.f90 | 712 ---- code/spectral_thermal.f90 | 419 -- code/spectral_utilities.f90 | 1262 ------ code/thermal_adiabatic.f90 | 422 -- code/thermal_conduction.f90 | 444 --- code/thermal_isothermal.f90 | 65 - code/vacancyflux_cahnhilliard.f90 | 606 --- code/vacancyflux_isochempot.f90 | 329 -- code/vacancyflux_isoconc.f90 | 63 - 83 files changed, 14 insertions(+), 55411 deletions(-) delete mode 100644 code/CMakeLists.txt delete mode 100644 code/CPFEM.f90 delete mode 100644 code/CPFEM2.f90 delete mode 100644 code/DAMASK_abaqus_exp.f delete mode 100644 code/DAMASK_abaqus_std.f delete mode 100644 code/DAMASK_marc.f90 delete mode 120000 code/DAMASK_marc2011.f90 delete mode 120000 code/DAMASK_marc2012.f90 delete mode 120000 code/DAMASK_marc2013.1.f90 delete mode 120000 code/DAMASK_marc2013.f90 delete mode 120000 code/DAMASK_marc2014.2.f90 delete mode 120000 code/DAMASK_marc2014.f90 delete mode 120000 code/DAMASK_marc2015.f90 delete mode 100644 code/DAMASK_spectral.f90 delete mode 100644 code/FEsolving.f90 delete mode 100644 code/IO.f90 delete mode 100644 code/Makefile delete mode 100644 code/commercialFEM_fileList.f90 delete mode 100644 code/compilation_info.f90 delete mode 100644 code/constitutive.f90 delete mode 100644 code/core_quit.f90 delete mode 100644 code/crystallite.f90 delete mode 100644 code/damage_local.f90 delete mode 100644 code/damage_none.f90 delete mode 100644 code/damage_nonlocal.f90 delete mode 100644 code/damask.core.pyf delete mode 100644 code/damask_hdf5.f90 delete mode 100644 code/debug.f90 delete mode 100644 code/homogenization.f90 delete mode 100644 code/homogenization_RGC.f90 delete mode 100644 code/homogenization_isostrain.f90 delete mode 100644 code/homogenization_none.f90 delete mode 100644 code/hydrogenflux_cahnhilliard.f90 delete mode 100644 code/hydrogenflux_isoconc.f90 delete mode 100644 code/kinematics_cleavage_opening.f90 delete mode 100644 code/kinematics_hydrogen_strain.f90 delete mode 100644 code/kinematics_slipplane_opening.f90 delete mode 100644 code/kinematics_thermal_expansion.f90 delete mode 100644 code/kinematics_vacancy_strain.f90 delete mode 100644 code/lattice.f90 delete mode 100644 code/libs.f90 delete mode 100644 code/material.f90 delete mode 100644 code/math.f90 delete mode 100644 code/mesh.f90 delete mode 100644 code/numerics.f90 delete mode 100644 code/plastic_disloUCLA.f90 delete mode 100644 code/plastic_dislotwin.f90 delete mode 100644 code/plastic_isotropic.f90 delete mode 100644 code/plastic_j2.f90 delete mode 100644 code/plastic_none.f90 delete mode 100644 code/plastic_nonlocal.f90 delete mode 100644 code/plastic_phenoplus.f90 delete mode 100644 code/plastic_phenopowerlaw.f90 delete mode 100644 code/plastic_titanmod.f90 delete mode 100644 code/porosity_none.f90 delete mode 100644 code/porosity_phasefield.f90 delete mode 100644 code/prec.f90 delete mode 100644 code/quit__genmod.f90 delete mode 100644 code/source_damage_anisoBrittle.f90 delete mode 100644 code/source_damage_anisoDuctile.f90 delete mode 100644 code/source_damage_isoBrittle.f90 delete mode 100644 code/source_damage_isoDuctile.f90 delete mode 100644 code/source_thermal_dissipation.f90 delete mode 100644 code/source_thermal_externalheat.f90 delete mode 100644 code/source_vacancy_irradiation.f90 delete mode 100644 code/source_vacancy_phenoplasticity.f90 delete mode 100644 code/source_vacancy_thermalfluc.f90 delete mode 100644 code/spectral_damage.f90 delete mode 100644 code/spectral_interface.f90 delete mode 100644 code/spectral_mech_AL.f90 delete mode 100644 code/spectral_mech_Basic.f90 delete mode 100644 code/spectral_mech_Polarisation.f90 delete mode 100644 code/spectral_thermal.f90 delete mode 100644 code/spectral_utilities.f90 delete mode 100644 code/thermal_adiabatic.f90 delete mode 100644 code/thermal_conduction.f90 delete mode 100644 code/thermal_isothermal.f90 delete mode 100644 code/vacancyflux_cahnhilliard.f90 delete mode 100644 code/vacancyflux_isochempot.f90 delete mode 100644 code/vacancyflux_isoconc.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 97def9456..27dc46e0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,12 +12,6 @@ set (DAMASK_VERSION_MINOR ${DAMASK_V}) if (NOT DEFINED PETSC_DIR) message (FATAL_ERROR "PETSC_DIR is not found!") endif (NOT DEFINED PETSC_DIR) -# RECOMMEND USING HDF5 FROM PETSC -if (DEFINED HDF5_DIR) - message ("\n***Using HDF5 library found at ${HDF5_DIR}\n") -else(DEFINED HDF5_DIR) - message ("\n***Using HDF5 library from PETSc\n" ) -endif (DEFINED HDF5_DIR) # Setting installation prefix if (NOT DEFINED DAMASK_INSTALL) @@ -101,7 +95,7 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compiler OUTPUT_STRIP_TRAILING_WHITESPACE) file (REMOVE ${petsc_config_makefile}) -# remove duplicate flags for compiler and linking +# REMOVE DUPLICATE FLAGS FOR COMPILER AND LINKING string( REGEX MATCHALL "-I([^\" ]+)" TMP_LIST "${petsc_includes}") list(REMOVE_DUPLICATES TMP_LIST) foreach (dir ${TMP_LIST}) @@ -120,11 +114,6 @@ message("***Found PETSC_EXTERNAL_LIB:\n${PETSC_EXTERNAL_LIB}\n") message("***Found PETSC_LINKER:\n${PETSC_LINKER}\n") message("***Found PETSC_MPIEXEC:\n${MPIEXEC}\n") -# SET INCLUDE DIRECTORIES (SNEAK IT IN WITH PETSC) -if (DEFINED HDF5_DIR) - set (DAMASK_INCLUDE_FLAGS "${PETSC_INCLUDES} -I${HDF5_DIR}/include" ) - set (PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} -L${HDF5_DIR}/lib") -endif (DEFINED HDF5_DIR) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") @@ -387,6 +376,7 @@ set (PRECISION_gfortran "-fdefault-real-8 -fdefault-double-8") get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) if (Fortran_COMPILER_NAME MATCHES "ifort.*") + set (INTEL_FORTRAN ON) # for RELEASE set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}" ) @@ -398,7 +388,6 @@ if (Fortran_COMPILER_NAME MATCHES "ifort.*") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_ifort}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}") - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${PETSC_EXTERNAL_LIB}" ) # for DEBUG set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") @@ -407,7 +396,7 @@ if (Fortran_COMPILER_NAME MATCHES "ifort.*") set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DEBUG_OPTIONS_ifort}" ) # elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") - set (CMAKE_Fortran_COMPILER "${MPIEXEC}") + set (GNU_FORTRAN ON) # for RELEASE set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_gfortran}" ) set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_gfortran}" ) @@ -417,8 +406,8 @@ elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAG_gfortran}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_gfortran}") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_gfortran}" ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_gfortran}") # for DEBUG set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_gfortran}" ) @@ -447,12 +436,17 @@ endif(CMAKE_BUILD_TYPE STREQUAL "RELEASE") message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") message("***LINK FLAGS:\n${CMAKE_EXE_LINKER_FLAGS_RELEASE}\n") +# MOVE to SOURCE DIRECTORY for BUILDING +add_subdirectory(src) -## -# ADD CODE DIRECTORY -add_subdirectory(code) -INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/code/DAMASKSpectral.exe - DESTINATION ${CMAKE_INSTALL_PREFIX}) +# INSTALL BUILT BINARIES +if (SPECTRAL) + INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASKSpectral.exe + DESTINATION ${CMAKE_INSTALL_PREFIX}) +elseif (FEM) + INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM.exe + DESTINATION ${CMAKE_INSTALL_PREFIX}) +endif(SPECTRAL) ## # ADD TESTING CASES diff --git a/build_FEM.sh b/build_FEM.sh index 4d33ef8ed..0def3760a 100755 --- a/build_FEM.sh +++ b/build_FEM.sh @@ -24,7 +24,6 @@ cd build_FEM ## # CMake call # PETSC_DIR | PETSC directory -# HDF5_DIR | HDF5 library (same compiler for DAMASK) # DAMASK_V | DAMASK current revision # CMAKE_BUILD_TYPE | Default set to release (no debugging output) # OPENMP | [ON/OFF] @@ -37,7 +36,6 @@ cmake -D PETSC_DIR=${PETSC_DIR} \ -D OPENMP=ON \ -D OPTIMIZATION=DEFENSIVE \ -D DAMASK_DRIVER=FEM \ - -D DAMASK_FEM_DIR=PRIVATE/FEM/code \ -D DAMASK_INSTALL=${HOME}/bin \ ../.. diff --git a/build_spectral.sh b/build_spectral.sh index 7c0ff015e..a48d8d360 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -24,7 +24,6 @@ cd build_spectral ## # CMake call # PETSC_DIR | PETSC directory -# HDF5_DIR | HDF5 library (same compiler for DAMASK) # DAMASK_V | DAMASK current revision # CMAKE_BUILD_TYPE | Default set to release (no debugging output) # OPENMP | [ON/OFF] diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt deleted file mode 100644 index c1abf4d4e..000000000 --- a/code/CMakeLists.txt +++ /dev/null @@ -1,172 +0,0 @@ -# The dependency detection in CMake is not functioning for Fortran -# !!! EXPLICIT DEPENDENCY DECLARATION !!! - -add_library(DAMASK_PREC "prec.f90") - -if (SPECTRAL) - add_library(DAMASK_INTERFACE "spectral_interface.f90") -elseif(FEM) - add_library(DAMASK_INTERFACE "DAMASK_FEM_interface.f90") -endif(SPECTRAL) -target_link_libraries(DAMASK_INTERFACE DAMASK_PREC) - -add_library(DAMASK_IO "IO.f90") -target_link_libraries(DAMASK_IO DAMASK_INTERFACE) - -add_library(DAMASK_LIBS "libs.f90") -target_link_libraries(DAMASK_LIBS DAMASK_IO) - -add_library(DAMASK_NUMERICS "numerics.f90") -target_link_libraries(DAMASK_NUMERICS DAMASK_LIBS) - -add_library(DAMASK_DEBUG "debug.f90") -target_link_libraries(DAMASK_DEBUG DAMASK_NUMERICS) - -add_library(DAMASK_FEsolving "FEsolving.f90") -target_link_libraries(DAMASK_FEsolving DAMASK_DEBUG) - -add_library(DAMASK_MATH "math.f90") -target_link_libraries(DAMASK_MATH DAMASK_FEsolving) - -# SPECTRAL solver and FEM solver use different mesh -# source files -if (SPECTRAL) - add_library(DAMASK_MESH "mesh.f90") - target_link_libraries(DAMASK_MESH DAMASK_MATH) -endif(SPECTRAL) -if (FEM) - add_library(DAMASK_FEZoo "FEZoo.f90") - target_link_libraries(DAMASK_FEZoo DAMASK_MATH) - add_library(DAMASK_MESH "meshFEM.f90") - target_link_libraries(DAMASK_MESH DAMASK_FEZoo) -endif(FEM) - - -add_library(DAMASK_MATERIAL "material.f90") -target_link_libraries(DAMASK_MATERIAL DAMASK_MESH) - -add_library(DAMASK_LATTICE "lattice.f90") -target_link_libraries(DAMASK_LATTICE DAMASK_MATERIAL) -add_library(DAMASK_DRIVERS ALIAS DAMASK_LATTICE) - -# For each modular section -add_library (DAMASK_PLASTIC "plastic_dislotwin.f90" - "plastic_disloUCLA.f90" - "plastic_isotropic.f90" - "plastic_j2.f90" - "plastic_phenopowerlaw.f90" - "plastic_titanmod.f90" - "plastic_nonlocal.f90" - "plastic_none.f90" - "plastic_phenoplus.f90") -target_link_libraries(DAMASK_PLASTIC DAMASK_DRIVERS) - -add_library (DAMASK_KINEMATICS "kinematics_cleavage_opening.f90" - "kinematics_slipplane_opening.f90" - "kinematics_thermal_expansion.f90" - "kinematics_vacancy_strain.f90" - "kinematics_hydrogen_strain.f90") -target_link_libraries(DAMASK_KINEMATICS DAMASK_DRIVERS) - -add_library (DAMASK_SOURCE "source_thermal_dissipation.f90" - "source_thermal_externalheat.f90" - "source_damage_isoBrittle.f90" - "source_damage_isoDuctile.f90" - "source_damage_anisoBrittle.f90" - "source_damage_anisoDuctile.f90" - "source_vacancy_phenoplasticity.f90" - "source_vacancy_irradiation.f90" - "source_vacancy_thermalfluc.f90") -target_link_libraries(DAMASK_SOURCE DAMASK_DRIVERS) - -add_library(DAMASK_CONSTITUTIVE "constitutive.f90") -target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_PLASTIC ) -target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_KINEMATICS) -target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_SOURCE ) - -add_library(DAMASK_CRYSTALLITE "crystallite.f90") -target_link_libraries(DAMASK_CRYSTALLITE DAMASK_CONSTITUTIVE) - -add_library(DAMASK_HOMOGENIZATION "homogenization_RGC.f90" - "homogenization_isostrain.f90" - "homogenization_none.f90") -target_link_libraries(DAMASK_HOMOGENIZATION DAMASK_CRYSTALLITE) - -add_library(DAMASK_HYDROGENFLUX "hydrogenflux_isoconc.f90" - "hydrogenflux_cahnhilliard.f90") -target_link_libraries(DAMASK_HYDROGENFLUX DAMASK_CRYSTALLITE) - -add_library(DAMASK_POROSITY "porosity_none.f90" - "porosity_phasefield.f90") -target_link_libraries(DAMASK_POROSITY DAMASK_CRYSTALLITE) - -add_library(DAMASK_VACANCYFLUX "vacancyflux_isoconc.f90" - "vacancyflux_isochempot.f90" - "vacancyflux_cahnhilliard.f90") -target_link_libraries(DAMASK_VACANCYFLUX DAMASK_CRYSTALLITE) - -add_library(DAMASK_DAMAGE "damage_none.f90" - "damage_local.f90" - "damage_nonlocal.f90") -target_link_libraries(DAMASK_DAMAGE DAMASK_CRYSTALLITE) - -add_library(DAMASK_THERMAL "thermal_isothermal.f90" - "thermal_adiabatic.f90" - "thermal_conduction.f90") -target_link_libraries(DAMASK_THERMAL DAMASK_CRYSTALLITE) - -add_library(DAMASK_ENGINE "homogenization.f90") -target_link_libraries(DAMASK_ENGINE DAMASK_THERMAL ) -target_link_libraries(DAMASK_ENGINE DAMASK_DAMAGE ) -target_link_libraries(DAMASK_ENGINE DAMASK_VACANCYFLUX ) -target_link_libraries(DAMASK_ENGINE DAMASK_POROSITY ) -target_link_libraries(DAMASK_ENGINE DAMASK_HYDROGENFLUX ) -target_link_libraries(DAMASK_ENGINE DAMASK_HOMOGENIZATION) - - -if (FEM) - add_library(DAMASK_CPFE "CPFEM.f90") - target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) - - add_library(DAMASK_FEM_UTILITY "FEM_utilities.f90") - target_link_libraries(DAMASK_FEM_UTILITY DAMASK_CPFE) - - add_library(DAMASK_FEM_BASE "FEM_hydrogenflux.f90" - "FEM_porosity.f90" - "FEM_vacancyflux.f90" - "FEM_damage.f90" - "FEM_thermal.f90" - "FEM_mech.f90") - target_link_libraries(DAMASK_FEM_BASE DAMASK_FEM_UTILITY) - - add_library(DAMASK_FEM_DRIVER "DAMASK_FEM_driver.f90") - target_link_libraries(DAMASK_FEM_DRIVER DAMASK_FEM_BASE) - - add_executable(DAMASK_FEM.exe "DAMASK_FEM_driver.f90") - target_link_libraries(DAMASK_FEM.exe DAMASK_FEM_DRIVER) -endif(FEM) - -if (SPECTRAL) - add_library(DAMASK_CPFE "CPFEM2.f90") - target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) - - add_library(DAMASK_SPECTRAL_UTILITY spectral_utilities.f90) - target_link_libraries(DAMASK_SPECTRAL_UTILITY DAMASK_CPFE) - - add_library(DAMASK_SPECTRAL_BASE "spectral_thermal.f90" - "spectral_damage.f90") - target_link_libraries(DAMASK_SPECTRAL_BASE DAMASK_SPECTRAL_UTILITY) - - add_library(DAMASK_SPECTRAL_MECH "spectral_mech_AL.f90" - "spectral_mech_Polarisation.f90" - "spectral_mech_Basic.f90") - target_link_libraries(DAMASK_SPECTRAL_MECH DAMASK_SPECTRAL_UTILITY) - - add_library(DAMASK_EXE "DAMASK_spectral.f90") - target_link_libraries(DAMASK_EXE DAMASK_CPFE ) - target_link_libraries(DAMASK_EXE DAMASK_SPECTRAL_BASE) - target_link_libraries(DAMASK_EXE DAMASK_SPECTRAL_MECH) - - add_executable(DAMASKSpectral.exe "DAMASK_spectral.f90") - target_link_libraries(DAMASKSpectral.exe DAMASK_EXE) -endif(SPECTRAL) \ No newline at end of file diff --git a/code/CPFEM.f90 b/code/CPFEM.f90 deleted file mode 100644 index 91c3eaa6f..000000000 --- a/code/CPFEM.f90 +++ /dev/null @@ -1,705 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief CPFEM engine -!-------------------------------------------------------------------------------------------------- -module CPFEM - use prec, only: & - pReal, & - pInt - - implicit none - private -#if defined(Marc4DAMASK) || defined(Abaqus) - real(pReal), parameter, private :: & - CPFEM_odd_stress = 1e15_pReal, & !< return value for stress in case of ping pong dummy cycle - CPFEM_odd_jacobian = 1e50_pReal !< return value for jacobian in case of ping pong dummy cycle - real(pReal), dimension (:,:,:), allocatable, private :: & - CPFEM_cs !< Cauchy stress - real(pReal), dimension (:,:,:,:), allocatable, private :: & - CPFEM_dcsdE !< Cauchy stress tangent - real(pReal), dimension (:,:,:,:), allocatable, private :: & - CPFEM_dcsdE_knownGood !< known good tangent -#endif - integer(pInt), public :: & - cycleCounter = 0_pInt, & !< needs description - theInc = -1_pInt, & !< needs description - lastLovl = 0_pInt, & !< lovl in previous call to marc hypela2 - lastStep = 0_pInt !< kstep in previous call to abaqus umat - real(pReal), public :: & - theTime = 0.0_pReal, & !< needs description - theDelta = 0.0_pReal - logical, public :: & - outdatedFFN1 = .false., & !< needs description - lastIncConverged = .false., & !< needs description - outdatedByNewInc = .false. !< needs description - - logical, public, protected :: & - CPFEM_init_done = .false. !< remember whether init has been done already - logical, private :: & - CPFEM_calc_done = .false. !< remember whether first ip has already calced the results - - integer(pInt), parameter, public :: & - CPFEM_COLLECT = 2_pInt**0_pInt, & - CPFEM_CALCRESULTS = 2_pInt**1_pInt, & - CPFEM_AGERESULTS = 2_pInt**2_pInt, & - CPFEM_BACKUPJACOBIAN = 2_pInt**3_pInt, & - CPFEM_RESTOREJACOBIAN = 2_pInt**4_pInt - - - public :: & - CPFEM_general, & - CPFEM_initAll - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief call (thread safe) all module initializations -!-------------------------------------------------------------------------------------------------- -subroutine CPFEM_initAll(el,ip) - use prec, only: & - prec_init - use numerics, only: & - numerics_init - use debug, only: & - debug_init - use FEsolving, only: & - FE_init - use math, only: & - math_init - use mesh, only: & - mesh_init - use lattice, only: & - lattice_init - use material, only: & - material_init - use constitutive, only: & - constitutive_init - use crystallite, only: & - crystallite_init - use homogenization, only: & - homogenization_init - use IO, only: & - IO_init - use DAMASK_interface -#ifdef FEM - use FEZoo, only: & - FEZoo_init -#endif - - implicit none - integer(pInt), intent(in) :: el, & !< FE el number - ip !< FE integration point number - - !$OMP CRITICAL (init) - if (.not. CPFEM_init_done) then - call DAMASK_interface_init ! Spectral and FEM interface to commandline - call prec_init - call IO_init -#ifdef FEM - call FEZoo_init -#endif - call numerics_init - call debug_init - call math_init - call FE_init - call mesh_init(ip, el) ! pass on coordinates to alter calcMode of first ip - call lattice_init - call material_init - call constitutive_init - call crystallite_init - call homogenization_init - call CPFEM_init - CPFEM_init_done = .true. - endif - !$OMP END CRITICAL (init) - -end subroutine CPFEM_initAll - - -!-------------------------------------------------------------------------------------------------- -!> @brief allocate the arrays defined in module CPFEM and initialize them -!-------------------------------------------------------------------------------------------------- -subroutine CPFEM_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pInt - use IO, only: & - IO_read_realFile,& - IO_read_intFile, & - IO_timeStamp, & - IO_error - use numerics, only: & - worldrank - use debug, only: & - debug_level, & - debug_CPFEM, & - debug_levelBasic, & - debug_levelExtensive - use FEsolving, only: & -#if defined(Marc4DAMASK) || defined(Abaqus) - symmetricSolver, & -#endif - restartRead, & - modelName -#if defined(Marc4DAMASK) || defined(Abaqus) - use mesh, only: & - mesh_NcpElems, & - mesh_maxNips -#endif - use material, only: & - material_phase, & - homogState, & - phase_plasticity, & - plasticState, & - material_Nhomogenization - use crystallite, only: & - crystallite_F0, & - crystallite_Fp0, & - crystallite_Lp0, & - crystallite_Fi0, & - crystallite_Li0, & - crystallite_dPdF0, & - crystallite_Tstar0_v - - implicit none - integer(pInt) :: k,l,m,ph,homog - character(len=1024) :: rankStr - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- CPFEM init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -#if defined(Marc4DAMASK) || defined(Abaqus) - ! initialize stress and jacobian to zero - allocate(CPFEM_cs(6,mesh_maxNips,mesh_NcpElems)) ; CPFEM_cs = 0.0_pReal - allocate(CPFEM_dcsdE(6,6,mesh_maxNips,mesh_NcpElems)) ; CPFEM_dcsdE = 0.0_pReal - allocate(CPFEM_dcsdE_knownGood(6,6,mesh_maxNips,mesh_NcpElems)) ; CPFEM_dcsdE_knownGood = 0.0_pReal -#endif - - ! *** restore the last converged values of each essential variable from the binary file - if (restartRead) then - if (iand(debug_level(debug_CPFEM), debug_levelExtensive) /= 0_pInt) then - write(6,'(a)') '<< CPFEM >> restored state variables of last converged step from binary files' - flush(6) - endif - - write(rankStr,'(a1,i0)')'_',worldrank - - call IO_read_intFile(777,'recordedPhase'//trim(rankStr),modelName,size(material_phase)) - read (777,rec=1) material_phase - close (777) - - call IO_read_realFile(777,'convergedF'//trim(rankStr),modelName,size(crystallite_F0)) - read (777,rec=1) crystallite_F0 - close (777) - - call IO_read_realFile(777,'convergedFp'//trim(rankStr),modelName,size(crystallite_Fp0)) - read (777,rec=1) crystallite_Fp0 - close (777) - - call IO_read_realFile(777,'convergedFi'//trim(rankStr),modelName,size(crystallite_Fi0)) - read (777,rec=1) crystallite_Fi0 - close (777) - - call IO_read_realFile(777,'convergedLp'//trim(rankStr),modelName,size(crystallite_Lp0)) - read (777,rec=1) crystallite_Lp0 - close (777) - - call IO_read_realFile(777,'convergedLi'//trim(rankStr),modelName,size(crystallite_Li0)) - read (777,rec=1) crystallite_Li0 - close (777) - - call IO_read_realFile(777,'convergeddPdF'//trim(rankStr),modelName,size(crystallite_dPdF0)) - read (777,rec=1) crystallite_dPdF0 - close (777) - - call IO_read_realFile(777,'convergedTstar'//trim(rankStr),modelName,size(crystallite_Tstar0_v)) - read (777,rec=1) crystallite_Tstar0_v - close (777) - - call IO_read_realFile(777,'convergedStateConst'//trim(rankStr),modelName) - m = 0_pInt - readPlasticityInstances: do ph = 1_pInt, size(phase_plasticity) - do k = 1_pInt, plasticState(ph)%sizeState - do l = 1, size(plasticState(ph)%state0(1,:)) - m = m+1_pInt - read(777,rec=m) plasticState(ph)%state0(k,l) - enddo; enddo - enddo readPlasticityInstances - close (777) - - call IO_read_realFile(777,'convergedStateHomog'//trim(rankStr),modelName) - m = 0_pInt - readHomogInstances: do homog = 1_pInt, material_Nhomogenization - do k = 1_pInt, homogState(homog)%sizeState - do l = 1, size(homogState(homog)%state0(1,:)) - m = m+1_pInt - read(777,rec=m) homogState(homog)%state0(k,l) - enddo; enddo - enddo readHomogInstances - close (777) - -#if defined(Marc4DAMASK) || defined(Abaqus) - call IO_read_realFile(777,'convergeddcsdE',modelName,size(CPFEM_dcsdE)) - read (777,rec=1) CPFEM_dcsdE - close (777) -#endif - restartRead = .false. - endif -#if defined(Marc4DAMASK) || defined(Abaqus) - if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0) then - write(6,'(a32,1x,6(i8,1x))') 'CPFEM_cs: ', shape(CPFEM_cs) - write(6,'(a32,1x,6(i8,1x))') 'CPFEM_dcsdE: ', shape(CPFEM_dcsdE) - write(6,'(a32,1x,6(i8,1x),/)') 'CPFEM_dcsdE_knownGood: ', shape(CPFEM_dcsdE_knownGood) - write(6,'(a32,l1)') 'symmetricSolver: ', symmetricSolver - endif -#endif - flush(6) - -end subroutine CPFEM_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief perform initialization at first call, update variables and call the actual material model -!-------------------------------------------------------------------------------------------------- -#if defined(Marc4DAMASK) || defined(Abaqus) -subroutine CPFEM_general(mode, parallelExecution, ffn, ffn1, temperature_inp, dt, elFE, ip, cauchyStress, jacobian) -#else -subroutine CPFEM_general(mode, ffn, ffn1, dt, elFE, ip) -#endif - use numerics, only: & - defgradTolerance, & - iJacoStiffness, & - worldrank - use debug, only: & - debug_level, & - debug_CPFEM, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & -#if defined(Marc4DAMASK) || defined(Abaqus) - debug_stressMaxLocation, & - debug_stressMinLocation, & - debug_jacobianMaxLocation, & - debug_jacobianMinLocation, & - debug_stressMax, & - debug_stressMin, & - debug_jacobianMax, & - debug_jacobianMin, & -#endif - debug_e, & - debug_i - use FEsolving, only: & - terminallyIll, & - FEsolving_execElem, & - FEsolving_execIP, & - restartWrite - use math, only: & - math_identity2nd, & - math_mul33x33, & - math_det33, & - math_transpose33, & - math_I3, & - math_Mandel3333to66, & - math_Mandel66to3333, & - math_Mandel33to6, & - math_Mandel6to33 - use mesh, only: & - mesh_FEasCP, & - mesh_NcpElems, & - mesh_maxNips, & - mesh_element - use material, only: & - microstructure_elemhomo, & - plasticState, & - sourceState, & - homogState, & - thermalState, & - damageState, & - vacancyfluxState, & - hydrogenfluxState, & - phaseAt, phasememberAt, & - material_phase, & - phase_plasticity, & - temperature, & - thermalMapping, & - phase_Nsources, & - material_homog, & - material_Nhomogenization - use crystallite, only: & - crystallite_partionedF,& - crystallite_F0, & - crystallite_Fp0, & - crystallite_Fp, & - crystallite_Fi0, & - crystallite_Fi, & - crystallite_Lp0, & - crystallite_Lp, & - crystallite_Li0, & - crystallite_Li, & - crystallite_dPdF0, & - crystallite_dPdF, & - crystallite_Tstar0_v, & - crystallite_Tstar_v - use homogenization, only: & - materialpoint_F, & - materialpoint_F0, & -#if defined(Marc4DAMASK) || defined(Abaqus) - materialpoint_P, & - materialpoint_dPdF, & - materialpoint_results, & - materialpoint_sizeResults, & -#endif - materialpoint_stressAndItsTangent, & - materialpoint_postResults - use IO, only: & - IO_write_jobRealFile, & - IO_warning - use DAMASK_interface - - implicit none - integer(pInt), intent(in) :: elFE, & !< FE element number - ip !< integration point number - real(pReal), intent(in) :: dt !< time increment - real(pReal), dimension (3,3), intent(in) :: ffn, & !< deformation gradient for t=t0 - ffn1 !< deformation gradient for t=t1 - integer(pInt), intent(in) :: mode !< computation mode 1: regular computation plus aging of results -#if defined(Marc4DAMASK) || defined(Abaqus) - real(pReal), intent(in) :: temperature_inp !< temperature - logical, intent(in) :: parallelExecution !< flag indicating parallel computation of requested IPs - real(pReal), dimension(6), intent(out) :: cauchyStress !< stress vector in Mandel notation - real(pReal), dimension(6,6), intent(out) :: jacobian !< jacobian in Mandel notation (Consistent tangent dcs/dE) - - real(pReal) J_inverse, & ! inverse of Jacobian - rnd - real(pReal), dimension (3,3) :: Kirchhoff, & ! Piola-Kirchhoff stress in Matrix notation - cauchyStress33 ! stress vector in Matrix notation - real(pReal), dimension (3,3,3,3) :: H_sym, & - H, & - jacobian3333 ! jacobian in Matrix notation -#else - logical, parameter :: parallelExecution = .true. -#endif - - integer(pInt) elCP, & ! crystal plasticity element number - i, j, k, l, m, n, ph, homog, mySource - logical updateJaco ! flag indicating if JAcobian has to be updated - character(len=1024) :: rankStr - -#if defined(Marc4DAMASK) || defined(Abaqus) - elCP = mesh_FEasCP('elem',elFE) -#else - elCP = elFE -#endif - - if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt & - .and. elCP == debug_e .and. ip == debug_i) then - write(6,'(/,a)') '#############################################' - write(6,'(a1,a22,1x,i8,a13)') '#','element', elCP, '#' - write(6,'(a1,a22,1x,i8,a13)') '#','ip', ip, '#' - write(6,'(a1,a22,1x,f15.7,a6)') '#','theTime', theTime, '#' - write(6,'(a1,a22,1x,f15.7,a6)') '#','theDelta', theDelta, '#' - write(6,'(a1,a22,1x,i8,a13)') '#','theInc', theInc, '#' - write(6,'(a1,a22,1x,i8,a13)') '#','cycleCounter', cycleCounter, '#' - write(6,'(a1,a22,1x,i8,a13)') '#','computationMode',mode, '#' - if (terminallyIll) & - write(6,'(a,/)') '# --- terminallyIll --- #' - write(6,'(a,/)') '#############################################'; flush (6) - endif - - -#if defined(Marc4DAMASK) || defined(Abaqus) - if (iand(mode, CPFEM_BACKUPJACOBIAN) /= 0_pInt) & - CPFEM_dcsde_knownGood = CPFEM_dcsde - if (iand(mode, CPFEM_RESTOREJACOBIAN) /= 0_pInt) & - CPFEM_dcsde = CPFEM_dcsde_knownGood -#endif - - !*** age results and write restart data if requested - if (iand(mode, CPFEM_AGERESULTS) /= 0_pInt) then - crystallite_F0 = crystallite_partionedF ! crystallite deformation (_subF is perturbed...) - crystallite_Fp0 = crystallite_Fp ! crystallite plastic deformation - crystallite_Lp0 = crystallite_Lp ! crystallite plastic velocity - crystallite_Fi0 = crystallite_Fi ! crystallite intermediate deformation - crystallite_Li0 = crystallite_Li ! crystallite intermediate velocity - crystallite_dPdF0 = crystallite_dPdF ! crystallite stiffness - crystallite_Tstar0_v = crystallite_Tstar_v ! crystallite 2nd Piola Kirchhoff stress - - forall ( i = 1:size(plasticState )) plasticState(i)%state0 = plasticState(i)%state ! copy state in this lenghty way because: A component cannot be an array if the encompassing structure is an array - do i = 1, size(sourceState) - do mySource = 1,phase_Nsources(i) - sourceState(i)%p(mySource)%state0 = sourceState(i)%p(mySource)%state ! copy state in this lenghty way because: A component cannot be an array if the encompassing structure is an array - enddo; enddo - if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt) then - write(6,'(a)') '<< CPFEM >> aging states' - if (debug_e <= mesh_NcpElems .and. debug_i <= mesh_maxNips) then - write(6,'(a,1x,i8,1x,i2,1x,i4,/,(12x,6(e20.8,1x)),/)') & - '<< CPFEM >> aged state of elFE ip grain',debug_e, debug_i, 1, & - plasticState(phaseAt(1,debug_i,debug_e))%state(:,phasememberAt(1,debug_i,debug_e)) - endif - endif - - do homog = 1_pInt, material_Nhomogenization - homogState (homog)%state0 = homogState (homog)%state - thermalState (homog)%state0 = thermalState (homog)%state - damageState (homog)%state0 = damageState (homog)%state - vacancyfluxState (homog)%state0 = vacancyfluxState (homog)%state - hydrogenfluxState(homog)%state0 = hydrogenfluxState(homog)%state - enddo - - - ! * dump the last converged values of each essential variable to a binary file - - if (restartWrite) then - if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt) & - write(6,'(a)') '<< CPFEM >> writing state variables of last converged step to binary files' - - write(rankStr,'(a1,i0)')'_',worldrank - - call IO_write_jobRealFile(777,'recordedPhase'//trim(rankStr),size(material_phase)) - write (777,rec=1) material_phase - close (777) - - call IO_write_jobRealFile(777,'convergedF'//trim(rankStr),size(crystallite_F0)) - write (777,rec=1) crystallite_F0 - close (777) - - call IO_write_jobRealFile(777,'convergedFp'//trim(rankStr),size(crystallite_Fp0)) - write (777,rec=1) crystallite_Fp0 - close (777) - - call IO_write_jobRealFile(777,'convergedFi'//trim(rankStr),size(crystallite_Fi0)) - write (777,rec=1) crystallite_Fi0 - close (777) - - call IO_write_jobRealFile(777,'convergedLp'//trim(rankStr),size(crystallite_Lp0)) - write (777,rec=1) crystallite_Lp0 - close (777) - - call IO_write_jobRealFile(777,'convergedLi'//trim(rankStr),size(crystallite_Li0)) - write (777,rec=1) crystallite_Li0 - close (777) - - call IO_write_jobRealFile(777,'convergeddPdF'//trim(rankStr),size(crystallite_dPdF0)) - write (777,rec=1) crystallite_dPdF0 - close (777) - - call IO_write_jobRealFile(777,'convergedTstar'//trim(rankStr),size(crystallite_Tstar0_v)) - write (777,rec=1) crystallite_Tstar0_v - close (777) - - call IO_write_jobRealFile(777,'convergedStateConst'//trim(rankStr)) - m = 0_pInt - writePlasticityInstances: do ph = 1_pInt, size(phase_plasticity) - do k = 1_pInt, plasticState(ph)%sizeState - do l = 1, size(plasticState(ph)%state0(1,:)) - m = m+1_pInt - write(777,rec=m) plasticState(ph)%state0(k,l) - enddo; enddo - enddo writePlasticityInstances - close (777) - - call IO_write_jobRealFile(777,'convergedStateHomog'//trim(rankStr)) - m = 0_pInt - writeHomogInstances: do homog = 1_pInt, material_Nhomogenization - do k = 1_pInt, homogState(homog)%sizeState - do l = 1, size(homogState(homog)%state0(1,:)) - m = m+1_pInt - write(777,rec=m) homogState(homog)%state0(k,l) - enddo; enddo - enddo writeHomogInstances - close (777) - -#if defined(Marc4DAMASK) || defined(Abaqus) - call IO_write_jobRealFile(777,'convergeddcsdE',size(CPFEM_dcsdE)) - write (777,rec=1) CPFEM_dcsdE - close (777) -#endif - - endif - endif ! results aging - - - - !*** collection of FEM input with returning of randomize odd stress and jacobian - !* If no parallel execution is required, there is no need to collect FEM input - - if (.not. parallelExecution) then -#if defined(Marc4DAMASK) || defined(Abaqus) - temperature(material_homog(ip,elCP))%p(thermalMapping(material_homog(ip,elCP))%p(ip,elCP)) = & - temperature_inp -#endif - materialpoint_F0(1:3,1:3,ip,elCP) = ffn - materialpoint_F(1:3,1:3,ip,elCP) = ffn1 - - elseif (iand(mode, CPFEM_COLLECT) /= 0_pInt) then -#if defined(Marc4DAMASK) || defined(Abaqus) - call random_number(rnd) - if (rnd < 0.5_pReal) rnd = rnd - 1.0_pReal - CPFEM_cs(1:6,ip,elCP) = rnd * CPFEM_odd_stress - CPFEM_dcsde(1:6,1:6,ip,elCP) = CPFEM_odd_jacobian * math_identity2nd(6) - temperature(material_homog(ip,elCP))%p(thermalMapping(material_homog(ip,elCP))%p(ip,elCP)) = & - temperature_inp -#endif - materialpoint_F0(1:3,1:3,ip,elCP) = ffn - materialpoint_F(1:3,1:3,ip,elCP) = ffn1 - CPFEM_calc_done = .false. - endif ! collection - - - - !*** calculation of stress and jacobian - - if (iand(mode, CPFEM_CALCRESULTS) /= 0_pInt) then - - !*** deformation gradient outdated or any actual deformation gradient differs more than relevantStrain from the stored one - validCalculation: if (terminallyIll & - .or. outdatedFFN1 & - .or. any(abs(ffn1 - materialpoint_F(1:3,1:3,ip,elCP)) > defgradTolerance)) then - if (any(abs(ffn1 - materialpoint_F(1:3,1:3,ip,elCP)) > defgradTolerance)) then - if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt) then - write(6,'(a,1x,i8,1x,i2)') '<< CPFEM >> OUTDATED at elFE ip',elFE,ip - write(6,'(a,/,3(12x,3(f10.6,1x),/))') '<< CPFEM >> FFN1 old:',& - math_transpose33(materialpoint_F(1:3,1:3,ip,elCP)) - write(6,'(a,/,3(12x,3(f10.6,1x),/))') '<< CPFEM >> FFN1 now:',math_transpose33(ffn1) - endif - outdatedFFN1 = .true. - endif -#if defined(Marc4DAMASK) || defined(Abaqus) - call random_number(rnd) - if (rnd < 0.5_pReal) rnd = rnd - 1.0_pReal - CPFEM_cs(1:6,ip,elCP) = rnd*CPFEM_odd_stress - CPFEM_dcsde(1:6,1:6,ip,elCP) = CPFEM_odd_jacobian*math_identity2nd(6) -#endif - - !*** deformation gradient is not outdated - - else validCalculation - updateJaco = mod(cycleCounter,iJacoStiffness) == 0 - !* no parallel computation, so we use just one single elFE and ip for computation - - if (.not. parallelExecution) then - FEsolving_execElem(1) = elCP - FEsolving_execElem(2) = elCP - if (.not. microstructure_elemhomo(mesh_element(4,elCP)) .or. & ! calculate unless homogeneous - (microstructure_elemhomo(mesh_element(4,elCP)) .and. ip == 1_pInt)) then ! and then only first ip - FEsolving_execIP(1,elCP) = ip - FEsolving_execIP(2,elCP) = ip - if (iand(debug_level(debug_CPFEM), debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i8,1x,i2)') '<< CPFEM >> calculation for elFE ip ',elFE,ip - call materialpoint_stressAndItsTangent(updateJaco, dt) ! calculate stress and its tangent - call materialpoint_postResults() - endif - - !* parallel computation and calulation not yet done - - elseif (.not. CPFEM_calc_done) then - if (iand(debug_level(debug_CPFEM), debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i8,a,i8)') '<< CPFEM >> calculation for elements ',FEsolving_execElem(1),& - ' to ',FEsolving_execElem(2) - call materialpoint_stressAndItsTangent(updateJaco, dt) ! calculate stress and its tangent (parallel execution inside) - call materialpoint_postResults() - CPFEM_calc_done = .true. - endif - - !* map stress and stiffness (or return odd values if terminally ill) -#if defined(Marc4DAMASK) || defined(Abaqus) - terminalIllness: if ( terminallyIll ) then - - call random_number(rnd) - if (rnd < 0.5_pReal) rnd = rnd - 1.0_pReal - CPFEM_cs(1:6,ip,elCP) = rnd * CPFEM_odd_stress - CPFEM_dcsde(1:6,1:6,ip,elCP) = CPFEM_odd_jacobian * math_identity2nd(6) - - else terminalIllness - - if (microstructure_elemhomo(mesh_element(4,elCP)) .and. ip > 1_pInt) then ! me homogenous? --> copy from first ip - materialpoint_P(1:3,1:3,ip,elCP) = materialpoint_P(1:3,1:3,1,elCP) - materialpoint_F(1:3,1:3,ip,elCP) = materialpoint_F(1:3,1:3,1,elCP) - materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,elCP) = materialpoint_dPdF(1:3,1:3,1:3,1:3,1,elCP) - materialpoint_results(1:materialpoint_sizeResults,ip,elCP) = & - materialpoint_results(1:materialpoint_sizeResults,1,elCP) - endif - - ! translate from P to CS - Kirchhoff = math_mul33x33(materialpoint_P(1:3,1:3,ip,elCP), math_transpose33(materialpoint_F(1:3,1:3,ip,elCP))) - J_inverse = 1.0_pReal / math_det33(materialpoint_F(1:3,1:3,ip,elCP)) - CPFEM_cs(1:6,ip,elCP) = math_Mandel33to6(J_inverse * Kirchhoff) - - ! 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) + & - materialpoint_F(j,m,ip,elCP) * & - materialpoint_F(l,n,ip,elCP) * & - materialpoint_dPdF(i,m,k,n,ip,elCP) - & - math_I3(j,l) * materialpoint_F(i,m,ip,elCP) * materialpoint_P(k,m,ip,elCP) + & - 0.5_pReal * (math_I3(i,k) * Kirchhoff(j,l) + math_I3(j,l) * Kirchhoff(i,k) + & - math_I3(i,l) * Kirchhoff(j,k) + math_I3(j,k) * Kirchhoff(i,l)) - enddo; enddo; enddo; enddo; enddo; enddo - - forall(i=1:3, j=1:3,k=1:3,l=1:3) & - H_sym(i,j,k,l) = 0.25_pReal * (H(i,j,k,l) + H(j,i,k,l) + H(i,j,l,k) + H(j,i,l,k)) - - CPFEM_dcsde(1:6,1:6,ip,elCP) = math_Mandel3333to66(J_inverse * H_sym) - - endif terminalIllness -#endif - - endif validCalculation - -#if defined(Marc4DAMASK) || defined(Abaqus) - !* report stress and stiffness - if ((iand(debug_level(debug_CPFEM), debug_levelExtensive) /= 0_pInt) & - .and. ((debug_e == elCP .and. debug_i == ip) & - .or. .not. iand(debug_level(debug_CPFEM), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i8,1x,i2,/,12x,6(f10.3,1x)/)') & - '<< CPFEM >> stress/MPa at elFE ip ', elFE, ip, CPFEM_cs(1:6,ip,elCP)*1.0e-6_pReal - write(6,'(a,i8,1x,i2,/,6(12x,6(f10.3,1x)/))') & - '<< CPFEM >> Jacobian/GPa at elFE ip ', elFE, ip, transpose(CPFEM_dcsdE(1:6,1:6,ip,elCP))*1.0e-9_pReal - flush(6) - endif -#endif - - endif - -#if defined(Marc4DAMASK) || defined(Abaqus) - !*** warn if stiffness close to zero - if (all(abs(CPFEM_dcsdE(1:6,1:6,ip,elCP)) < 1e-10_pReal)) call IO_warning(601,elCP,ip) - - !*** copy to output if using commercial FEM solver - cauchyStress = CPFEM_cs (1:6, ip,elCP) - jacobian = CPFEM_dcsdE(1:6,1:6,ip,elCP) - - - !*** remember extreme values of stress ... - cauchyStress33 = math_Mandel6to33(CPFEM_cs(1:6,ip,elCP)) - if (maxval(cauchyStress33) > debug_stressMax) then - debug_stressMaxLocation = [elCP, ip] - debug_stressMax = maxval(cauchyStress33) - endif - if (minval(cauchyStress33) < debug_stressMin) then - debug_stressMinLocation = [elCP, ip] - debug_stressMin = minval(cauchyStress33) - endif - !*** ... and Jacobian - jacobian3333 = math_Mandel66to3333(CPFEM_dcsdE(1:6,1:6,ip,elCP)) - if (maxval(jacobian3333) > debug_jacobianMax) then - debug_jacobianMaxLocation = [elCP, ip] - debug_jacobianMax = maxval(jacobian3333) - endif - if (minval(jacobian3333) < debug_jacobianMin) then - debug_jacobianMinLocation = [elCP, ip] - debug_jacobianMin = minval(jacobian3333) - endif -#endif - -end subroutine CPFEM_general - -end module CPFEM diff --git a/code/CPFEM2.f90 b/code/CPFEM2.f90 deleted file mode 100644 index ea5691495..000000000 --- a/code/CPFEM2.f90 +++ /dev/null @@ -1,367 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id: CPFEM.f90 4761 2016-01-17 13:29:42Z MPIE\m.diehl $ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief needs a good name and description -!-------------------------------------------------------------------------------------------------- -module CPFEM2 - - implicit none - private - - public :: & - CPFEM_general, & - CPFEM_initAll - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief call (thread safe) all module initializations -!-------------------------------------------------------------------------------------------------- -subroutine CPFEM_initAll(el,ip) - use prec, only: & - pInt - use prec, only: & - prec_init - use numerics, only: & - numerics_init - use debug, only: & - debug_init - use FEsolving, only: & - FE_init - use math, only: & - math_init - use mesh, only: & - mesh_init - use lattice, only: & - lattice_init - use material, only: & - material_init - use constitutive, only: & - constitutive_init - use crystallite, only: & - crystallite_init - use homogenization, only: & - homogenization_init, & -materialpoint_postResults - use IO, only: & - IO_init - use DAMASK_interface -#ifdef FEM - use FEZoo, only: & - FEZoo_init -#endif - - implicit none - integer(pInt), intent(in) :: el, & !< FE el number - ip !< FE integration point number - - call DAMASK_interface_init ! Spectral and FEM interface to commandline - call prec_init - call IO_init -#ifdef FEM - call FEZoo_init -#endif - call numerics_init - call debug_init - call math_init - call FE_init - call mesh_init(ip, el) ! pass on coordinates to alter calcMode of first ip - call lattice_init - call material_init - call constitutive_init - call crystallite_init - call homogenization_init - call materialpoint_postResults - call CPFEM_init - -end subroutine CPFEM_initAll - - -!-------------------------------------------------------------------------------------------------- -!> @brief allocate the arrays defined in module CPFEM and initialize them -!-------------------------------------------------------------------------------------------------- -subroutine CPFEM_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pInt - use IO, only: & - IO_read_realFile,& - IO_read_intFile, & - IO_timeStamp, & - IO_error - use numerics, only: & - worldrank - use debug, only: & - debug_level, & - debug_CPFEM, & - debug_levelBasic, & - debug_levelExtensive - use FEsolving, only: & - restartRead, & - modelName - use material, only: & - material_phase, & - homogState, & - phase_plasticity, & - plasticState, & - material_Nhomogenization - use crystallite, only: & - crystallite_F0, & - crystallite_Fp0, & - crystallite_Lp0, & - crystallite_Fi0, & - crystallite_Li0, & - crystallite_dPdF0, & - crystallite_Tstar0_v - - implicit none - integer(pInt) :: k,l,m,ph,homog - character(len=1024) :: rankStr - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- CPFEM init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - ! *** restore the last converged values of each essential variable from the binary file - if (restartRead) then - if (iand(debug_level(debug_CPFEM), debug_levelExtensive) /= 0_pInt) then - write(6,'(a)') '<< CPFEM >> restored state variables of last converged step from binary files' - flush(6) - endif - - write(rankStr,'(a1,i0)')'_',worldrank - - call IO_read_intFile(777,'recordedPhase'//trim(rankStr),modelName,size(material_phase)) - read (777,rec=1) material_phase - close (777) - - call IO_read_realFile(777,'convergedF'//trim(rankStr),modelName,size(crystallite_F0)) - read (777,rec=1) crystallite_F0 - close (777) - - call IO_read_realFile(777,'convergedFp'//trim(rankStr),modelName,size(crystallite_Fp0)) - read (777,rec=1) crystallite_Fp0 - close (777) - - call IO_read_realFile(777,'convergedFi'//trim(rankStr),modelName,size(crystallite_Fi0)) - read (777,rec=1) crystallite_Fi0 - close (777) - - call IO_read_realFile(777,'convergedLp'//trim(rankStr),modelName,size(crystallite_Lp0)) - read (777,rec=1) crystallite_Lp0 - close (777) - - call IO_read_realFile(777,'convergedLi'//trim(rankStr),modelName,size(crystallite_Li0)) - read (777,rec=1) crystallite_Li0 - close (777) - - call IO_read_realFile(777,'convergeddPdF'//trim(rankStr),modelName,size(crystallite_dPdF0)) - read (777,rec=1) crystallite_dPdF0 - close (777) - - call IO_read_realFile(777,'convergedTstar'//trim(rankStr),modelName,size(crystallite_Tstar0_v)) - read (777,rec=1) crystallite_Tstar0_v - close (777) - - call IO_read_realFile(777,'convergedStateConst'//trim(rankStr),modelName) - m = 0_pInt - readPlasticityInstances: do ph = 1_pInt, size(phase_plasticity) - do k = 1_pInt, plasticState(ph)%sizeState - do l = 1, size(plasticState(ph)%state0(1,:)) - m = m+1_pInt - read(777,rec=m) plasticState(ph)%state0(k,l) - enddo; enddo - enddo readPlasticityInstances - close (777) - - call IO_read_realFile(777,'convergedStateHomog'//trim(rankStr),modelName) - m = 0_pInt - readHomogInstances: do homog = 1_pInt, material_Nhomogenization - do k = 1_pInt, homogState(homog)%sizeState - do l = 1, size(homogState(homog)%state0(1,:)) - m = m+1_pInt - read(777,rec=m) homogState(homog)%state0(k,l) - enddo; enddo - enddo readHomogInstances - close (777) - - restartRead = .false. - endif - flush(6) - -end subroutine CPFEM_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief perform initialization at first call, update variables and call the actual material model -!-------------------------------------------------------------------------------------------------- -subroutine CPFEM_general(age, dt) - use prec, only: & - pReal, & - pInt - use numerics, only: & - worldrank - use debug, only: & - debug_level, & - debug_CPFEM, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective - use FEsolving, only: & - terminallyIll, & - restartWrite - use math, only: & - math_identity2nd, & - math_mul33x33, & - math_det33, & - math_transpose33, & - math_I3, & - math_Mandel3333to66, & - math_Mandel66to3333, & - math_Mandel33to6, & - math_Mandel6to33 - use material, only: & - plasticState, & - sourceState, & - homogState, & - thermalState, & - damageState, & - vacancyfluxState, & - hydrogenfluxState, & - material_phase, & - phase_plasticity, & - phase_Nsources, & - material_Nhomogenization - use crystallite, only: & - crystallite_partionedF,& - crystallite_F0, & - crystallite_Fp0, & - crystallite_Fp, & - crystallite_Fi0, & - crystallite_Fi, & - crystallite_Lp0, & - crystallite_Lp, & - crystallite_Li0, & - crystallite_Li, & - crystallite_dPdF0, & - crystallite_dPdF, & - crystallite_Tstar0_v, & - crystallite_Tstar_v - use homogenization, only: & - materialpoint_F, & - materialpoint_F0, & - materialpoint_stressAndItsTangent, & - materialpoint_postResults - use IO, only: & - IO_write_jobRealFile, & - IO_warning - use DAMASK_interface - - implicit none - real(pReal), intent(in) :: dt !< time increment - logical, intent(in) :: age !< age results - - integer(pInt) :: i, k, l, m, ph, homog, mySource - character(len=1024) :: rankStr - - !*** age results and write restart data if requested - if (age) then - crystallite_F0 = crystallite_partionedF ! crystallite deformation (_subF is perturbed...) - crystallite_Fp0 = crystallite_Fp ! crystallite plastic deformation - crystallite_Lp0 = crystallite_Lp ! crystallite plastic velocity - crystallite_Fi0 = crystallite_Fi ! crystallite intermediate deformation - crystallite_Li0 = crystallite_Li ! crystallite intermediate velocity - crystallite_dPdF0 = crystallite_dPdF ! crystallite stiffness - crystallite_Tstar0_v = crystallite_Tstar_v ! crystallite 2nd Piola Kirchhoff stress - - forall ( i = 1:size(plasticState )) plasticState(i)%state0 = plasticState(i)%state ! copy state in this lenghty way because: A component cannot be an array if the encompassing structure is an array - do i = 1, size(sourceState) - do mySource = 1,phase_Nsources(i) - sourceState(i)%p(mySource)%state0 = sourceState(i)%p(mySource)%state ! copy state in this lenghty way because: A component cannot be an array if the encompassing structure is an array - enddo; enddo - if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt) & - write(6,'(a)') '<< CPFEM >> aging states' - - do homog = 1_pInt, material_Nhomogenization - homogState (homog)%state0 = homogState (homog)%state - thermalState (homog)%state0 = thermalState (homog)%state - damageState (homog)%state0 = damageState (homog)%state - vacancyfluxState (homog)%state0 = vacancyfluxState (homog)%state - hydrogenfluxState(homog)%state0 = hydrogenfluxState(homog)%state - enddo - - - if (restartWrite) then - if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt) & - write(6,'(a)') '<< CPFEM >> writing state variables of last converged step to binary files' - - write(rankStr,'(a1,i0)')'_',worldrank - - call IO_write_jobRealFile(777,'recordedPhase'//trim(rankStr),size(material_phase)) - write (777,rec=1) material_phase - close (777) - - call IO_write_jobRealFile(777,'convergedF'//trim(rankStr),size(crystallite_F0)) - write (777,rec=1) crystallite_F0 - close (777) - - call IO_write_jobRealFile(777,'convergedFp'//trim(rankStr),size(crystallite_Fp0)) - write (777,rec=1) crystallite_Fp0 - close (777) - - call IO_write_jobRealFile(777,'convergedFi'//trim(rankStr),size(crystallite_Fi0)) - write (777,rec=1) crystallite_Fi0 - close (777) - - call IO_write_jobRealFile(777,'convergedLp'//trim(rankStr),size(crystallite_Lp0)) - write (777,rec=1) crystallite_Lp0 - close (777) - - call IO_write_jobRealFile(777,'convergedLi'//trim(rankStr),size(crystallite_Li0)) - write (777,rec=1) crystallite_Li0 - close (777) - - call IO_write_jobRealFile(777,'convergeddPdF'//trim(rankStr),size(crystallite_dPdF0)) - write (777,rec=1) crystallite_dPdF0 - close (777) - - call IO_write_jobRealFile(777,'convergedTstar'//trim(rankStr),size(crystallite_Tstar0_v)) - write (777,rec=1) crystallite_Tstar0_v - close (777) - - call IO_write_jobRealFile(777,'convergedStateConst'//trim(rankStr)) - m = 0_pInt - writePlasticityInstances: do ph = 1_pInt, size(phase_plasticity) - do k = 1_pInt, plasticState(ph)%sizeState - do l = 1, size(plasticState(ph)%state0(1,:)) - m = m+1_pInt - write(777,rec=m) plasticState(ph)%state0(k,l) - enddo; enddo - enddo writePlasticityInstances - close (777) - - call IO_write_jobRealFile(777,'convergedStateHomog'//trim(rankStr)) - m = 0_pInt - writeHomogInstances: do homog = 1_pInt, material_Nhomogenization - do k = 1_pInt, homogState(homog)%sizeState - do l = 1, size(homogState(homog)%state0(1,:)) - m = m+1_pInt - write(777,rec=m) homogState(homog)%state0(k,l) - enddo; enddo - enddo writeHomogInstances - close (777) - - endif - endif - - if (.not. terminallyIll) & - call materialpoint_stressAndItsTangent(.True., dt) - -end subroutine CPFEM_general - -end module CPFEM2 diff --git a/code/DAMASK_abaqus_exp.f b/code/DAMASK_abaqus_exp.f deleted file mode 100644 index eff898e3e..000000000 --- a/code/DAMASK_abaqus_exp.f +++ /dev/null @@ -1,299 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Koen Janssens, Paul Scherrer Institut -!> @author Arun Prakash, Fraunhofer IWM -!> @brief interfaces DAMASK with Abaqus/Explicit -!> @details put the included file abaqus_v6.env in either your home or model directory, -!> it is a minimum Abaqus environment file containing all changes necessary to use the -!> DAMASK subroutine (see Abaqus documentation for more information on the use of abaqus_v6.env) -!-------------------------------------------------------------------------------------------------- - -#ifndef INT -#define INT 4 -#endif - -#ifndef FLOAT -#define FLOAT 8 -#endif - -#define Abaqus - -#include "prec.f90" - -module DAMASK_interface - -implicit none -character(len=4), dimension(2), parameter :: INPUTFILEEXTENSION = ['.pes','.inp'] -character(len=4), parameter :: LOGFILEEXTENSION = '.log' - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief just reporting -!-------------------------------------------------------------------------------------------------- -subroutine DAMASK_interface_init - integer, dimension(8) :: & - dateAndTime ! type default integer - call date_and_time(values = dateAndTime) - write(6,'(/,a)') ' <<<+- DAMASK_abaqus_exp -+>>>' - write(6,'(/,a)') ' Version: '//DAMASKVERSION - write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& - dateAndTime(2),'/',& - dateAndTime(1) - write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& - dateAndTime(6),':',& - dateAndTime(7) - write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' -#include "compilation_info.f90" - -end subroutine DAMASK_interface_init - - - -!-------------------------------------------------------------------------------------------------- -!> @brief using Abaqus/Explicit function to get working directory name -!-------------------------------------------------------------------------------------------------- -character(1024) function getSolverWorkingDirectoryName() - - implicit none - integer :: lenOutDir - - getSolverWorkingDirectoryName='' - call vgetOutDir(getSolverWorkingDirectoryName, lenOutDir) - getSolverWorkingDirectoryName=trim(getSolverWorkingDirectoryName)//'/' - -end function getSolverWorkingDirectoryName - - -!-------------------------------------------------------------------------------------------------- -!> @brief using Abaqus/Explicit function to get solver job name -!-------------------------------------------------------------------------------------------------- -character(1024) function getSolverJobName() - - implicit none - integer :: lenJobName - - getSolverJobName='' - call vGetJobName(getSolverJobName, lenJobName) - -end function getSolverJobName - -end module DAMASK_interface - -#include "commercialFEM_fileList.f90" - -subroutine vumat(nBlock, nDir, nshr, nStateV, nFieldV, nProps, lAnneal, & - stepTime, totalTime, dt, cmName, coordMp, charLength, & - props, density, strainInc, relSpinInc, & - tempOld, stretchOld, defgradOld, fieldOld, & - stressOld, stateOld, enerInternOld, enerInelasOld, & - tempNew, stretchNew, defgradNew, fieldNew, & - stressNew, stateNew, enerInternNew, enerInelasNew) - use prec, only: & - pReal, & - pInt -!$ use numerics, only: & -!$ DAMASK_NumThreadsInt - use FEsolving, only: & - symmetricSolver, & - terminallyIll - use math, only: & - invnrmMandel - use debug, only: & - debug_info, & - debug_reset, & - debug_levelBasic, & - debug_level, & - debug_abaqus - use mesh, only: & - mesh_unitlength, & - mesh_FEasCP, & - mesh_ipCoordinates - use CPFEM, only: & - CPFEM_general, & - CPFEM_init_done, & - CPFEM_initAll, & - CPFEM_CALCRESULTS, & - CPFEM_AGERESULTS, & - cycleCounter, & - theTime, & - outdatedByNewInc, & - outdatedFFN1 - use homogenization, only: & - materialpoint_sizeResults, & - materialpoint_results - - implicit none - integer(pInt), intent(in) :: & - nDir, & !< number of direct components in a symmetric tensor - nshr, & !< number of indirect components in a symmetric tensor - nStateV, & !< number of user-defined state variables that are associated with this material type - nFieldV, & !< number of user-defined external field variables - nprops, & !< user-specified number of user-defined material properties - lAnneal !< indicating whether the routine is being called during an annealing process - integer(pInt), dimension(*), intent(in) :: & - nBlock !< 1: No of Materialpoints in this call, 2: No of Materialpoint (IP) - !< 3: No of layer, 4: No of secPoint, 5+: element numbers - character(len=80), intent(in) :: & - cmname !< uses-specified material name, left justified - real(pReal), dimension(nprops), intent(in) :: & - props !< user-supplied material properties - real(pReal), intent(in) :: & - stepTime, & !< value of time since the step began - totalTime, & !< value of total time - dt !< time increment size - real(pReal), dimension(nblock(1)), intent(in) :: & - density, & !< current density at material points in the midstep configuration - charLength, & !< characteristic element length - enerInternOld, & !< internal energy per unit mass at each material point at the beginning of the increment - enerInelasOld, & !< dissipated inelastic energy per unit mass at each material point at the beginning of the increment - tempOld, & !< temperature at each material point at the beginning of the increment - tempNew !< temperature at each material point at the end of the increment (Temperature calculated in ABAQUS boundary conditions) - real(pReal), dimension(nblock(1),*), intent(in) :: & - coordMp !< material point coordinates - real(pReal), dimension(nblock(1),ndir+nshr), intent(in) :: & - strainInc, & !< strain increment tensor at each material point - stretchOld, & !< stretch tensor U at each material point - stretchNew, & !< stretch tensor U at each material point - stressOld !< stress tensor at each material point - real(pReal), dimension(nblock(1),nshr), intent(in) :: & - relSpinInc !< incremental relative rotation vector - real(pReal), dimension(nblock(1),nstatev), intent(in) :: & - stateOld !< state variables at each material point at the beginning of the increment - real(pReal), dimension(nblock(1),nfieldv), intent(in) :: & - fieldOld, & !< user-defined field variables - fieldNew !< user-defined field variables - real(pReal), dimension(nblock(1),ndir+2*nshr), intent(in) :: & - defgradOld, & - defgradNew - real(pReal), dimension(nblock(1)), intent(out) :: & - enerInternNew, & !< internal energy per unit mass at each material point at the end of the increment - enerInelasNew !< dissipated inelastic energy per unit mass at each material point at the end of the increment - real(pReal), dimension(nblock(1),ndir+nshr), intent(out) :: & - stressNew !< stress tensor at each material point at the end of the increment - real(pReal), dimension(nblock(1),nstatev), intent(out) :: & - stateNew !< state variables at each material point at the end of the increment - - real(pReal), dimension(3) :: coordinates - real(pReal), dimension(3,3) :: defgrd0,defgrd1 - real(pReal), dimension(6) :: stress - real(pReal), dimension(6,6) :: ddsdde - real(pReal) :: temp, timeInc, stresspower - integer(pInt) :: computationMode, n, i, cp_en - -#ifdef _OPENMP - integer :: defaultNumThreadsInt !< default value set by Abaqus - include "omp_lib.h" - - defaultNumThreadsInt = omp_get_num_threads() ! remember number of threads set by Marc - call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution set by DAMASK_NUM_THREADS -#endif - - computationMode = CPFEM_CALCRESULTS ! always calculate - do n = 1,nblock(1) ! loop over vector of IPs - temp = tempOld(n) ! temp is intent(in) - if ( .not. CPFEM_init_done ) then - call CPFEM_initAll(nBlock(4_pInt+n),nBlock(2)) - outdatedByNewInc = .false. - - if (iand(debug_level(debug_abaqus),debug_levelBasic) /= 0) then - write(6,'(i8,1x,i2,1x,a)') nBlock(4_pInt+n),nBlock(2),'first call special case..!'; flush(6) - endif - else if (theTime < totalTime) then ! reached convergence - outdatedByNewInc = .true. - - if (iand(debug_level(debug_abaqus),debug_levelBasic) /= 0) then - write (6,'(i8,1x,i2,1x,a)') nBlock(4_pInt+n),nBlock(2),'lastIncConverged + outdated'; flush(6) - endif - - endif - outdatedFFN1 = .false. - terminallyIll = .false. - cycleCounter = 1_pInt - if ( outdatedByNewInc ) then - outdatedByNewInc = .false. - call debug_info() ! first after new inc reports debugging - call debug_reset() ! resets debugging - computationMode = ior(computationMode, CPFEM_AGERESULTS) ! age results - endif - - theTime = totalTime ! record current starting time - if (iand(debug_level(debug_abaqus),debug_levelBasic) /= 0) then - write(6,'(a,i8,i2,a)') '(',nBlock(4_pInt+n),nBlock(2),')'; flush(6) - write(6,'(a,l1)') 'Aging Results: ', iand(computationMode, CPFEM_AGERESULTS) /= 0_pInt - endif - defgrd0 = 0.0_pReal - defgrd1 = 0.0_pReal - timeInc = dt - - ! ABAQUS explicit: deformation gradient as vector 11, 22, 33, 12, 23, 31, 21, 32, 13 - ! ABAQUS explicit: deformation gradient as vector 11, 22, 33, 12, 21 - - forall (i=1:ndir) - defgrd0(i,i) = defgradOld(n,i) - defgrd1(i,i) = defgradNew(n,i) - end forall - if (nshr == 1) then - defgrd0(1,2) = defgradOld(n,4) - defgrd1(1,2) = defgradNew(n,4) - defgrd0(2,1) = defgradOld(n,5) - defgrd1(2,1) = defgradNew(n,5) - else - defgrd0(1,2) = defgradOld(n,4) - defgrd1(1,2) = defgradNew(n,4) - defgrd0(1,3) = defgradOld(n,9) - defgrd1(1,3) = defgradNew(n,9) - defgrd0(2,1) = defgradOld(n,7) - defgrd1(2,1) = defgradNew(n,7) - defgrd0(2,3) = defgradOld(n,5) - defgrd1(2,3) = defgradNew(n,5) - defgrd0(3,1) = defgradOld(n,6) - defgrd1(3,1) = defgradNew(n,6) - defgrd0(3,2) = defgradOld(n,8) - defgrd1(3,2) = defgradNew(n,8) - - endif - cp_en = mesh_FEasCP('elem',nBlock(4_pInt+n)) - mesh_ipCoordinates(1:3,n,cp_en) = mesh_unitlength * coordMp(n,1:3) - - call CPFEM_general(computationMode,.false.,defgrd0,defgrd1,temp,timeInc,cp_en,nBlock(2),stress,ddsdde) - - ! Mandel: 11, 22, 33, SQRT(2)*12, SQRT(2)*23, SQRT(2)*13 - ! straight: 11, 22, 33, 12, 23, 13 - ! ABAQUS implicit: 11, 22, 33, 12, 13, 23 - ! ABAQUS explicit: 11, 22, 33, 12, 23, 13 - ! ABAQUS explicit: 11, 22, 33, 12 - - stressNew(n,1:ndir+nshr) = stress(1:ndir+nshr)*invnrmMandel(1:ndir+nshr) - stateNew(n,1:min(nstatev,materialpoint_sizeResults)) = & - materialpoint_results(1:min(nstatev,materialpoint_sizeResults),& - nBlock(2),mesh_FEasCP('elem', nBlock(4_pInt+n))) - - stresspower = 0.5_pReal*sum((stressOld(n,1:ndir)+stressNew(n,1:ndir))*straininc(n,1:ndir))+& - sum((stressOld(n,ndir+1:ndir+nshr)+stressNew(n,ndir+1:ndir+nshr))*straininc(n,ndir+1:ndir+nshr)) - enerInternNew(n) = enerInternOld(n) + stresspower / density(n) ! Internal energy per unit mass - enerInelasNew(n) = enerInternNew(n) ! Dissipated inelastic energy per unit mass(Temporary output) - - enddo -!$ call omp_set_num_threads(defaultNumThreadsInt) ! reset number of threads to stored default value - -end subroutine vumat - - -!-------------------------------------------------------------------------------------------------- -!> @brief calls the exit function of Abaqus/Explicit -!-------------------------------------------------------------------------------------------------- -subroutine quit(mpie_error) - use prec, only: & - pInt - - implicit none - integer(pInt) :: mpie_error - - flush(6) - call xplb_exit - -end subroutine quit diff --git a/code/DAMASK_abaqus_std.f b/code/DAMASK_abaqus_std.f deleted file mode 100644 index faec60650..000000000 --- a/code/DAMASK_abaqus_std.f +++ /dev/null @@ -1,342 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Koen Janssens, Paul Scherrer Institut -!> @author Arun Prakash, Fraunhofer IWM -!> @brief interfaces DAMASK with Abaqus/Standard -!> @details put the included file abaqus_v6.env in either your home or model directory, -!> it is a minimum Abaqus environment file containing all changes necessary to use the -!> DAMASK subroutine (see Abaqus documentation for more information on the use of abaqus_v6.env) -!-------------------------------------------------------------------------------------------------- - -#ifndef INT -#define INT 4 -#endif - -#ifndef FLOAT -#define FLOAT 8 -#endif - -#define Abaqus - -#include "prec.f90" - -module DAMASK_interface - -implicit none -character(len=4), dimension(2), parameter :: INPUTFILEEXTENSION = ['.pes','.inp'] -character(len=4), parameter :: LOGFILEEXTENSION = '.log' - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief just reporting -!-------------------------------------------------------------------------------------------------- -subroutine DAMASK_interface_init - integer, dimension(8) :: & - dateAndTime ! type default integer - call date_and_time(values = dateAndTime) - write(6,'(/,a)') ' <<<+- DAMASK_abaqus_std -+>>>' - write(6,'(/,a)') ' Version: '//DAMASKVERSION - write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& - dateAndTime(2),'/',& - dateAndTime(1) - write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& - dateAndTime(6),':',& - dateAndTime(7) - write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' -#include "compilation_info.f90" - -end subroutine DAMASK_interface_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief using Abaqus/Standard function to get working directory name -!-------------------------------------------------------------------------------------------------- -character(1024) function getSolverWorkingDirectoryName() - - implicit none - integer :: lenOutDir - - getSolverWorkingDirectoryName='' - call getoutdir(getSolverWorkingDirectoryName, lenOutDir) - getSolverWorkingDirectoryName=trim(getSolverWorkingDirectoryName)//'/' - -end function getSolverWorkingDirectoryName - - -!-------------------------------------------------------------------------------------------------- -!> @brief using Abaqus/Standard function to get solver job name -!-------------------------------------------------------------------------------------------------- -character(1024) function getSolverJobName() - - implicit none - integer :: lenJobName - - getSolverJobName='' - call getJobName(getSolverJobName, lenJobName) - -end function getSolverJobName - -end module DAMASK_interface - -#include "commercialFEM_fileList.f90" - -subroutine UMAT(STRESS,STATEV,DDSDDE,SSE,SPD,SCD,& - RPL,DDSDDT,DRPLDE,DRPLDT,STRAN,DSTRAN,& - TIME,DTIME,TEMP,DTEMP,PREDEF,DPRED,CMNAME,NDI,NSHR,NTENS,& - NSTATV,PROPS,NPROPS,COORDS,DROT,PNEWDT,CELENT,& - DFGRD0,DFGRD1,NOEL,NPT,KSLAY,KSPT,KSTEP,KINC) - use prec, only: & - pReal, & - pInt - use numerics, only: & -!$ DAMASK_NumThreadsInt, & - usePingPong - use FEsolving, only: & - calcMode, & - terminallyIll, & - symmetricSolver - use math, only: & - invnrmMandel - use debug, only: & - debug_info, & - debug_reset, & - debug_levelBasic, & - debug_level, & - debug_abaqus - use mesh, only: & - mesh_unitlength, & - mesh_FEasCP, & - mesh_ipCoordinates - use CPFEM, only: & - CPFEM_general, & - CPFEM_init_done, & - CPFEM_initAll, & - CPFEM_CALCRESULTS, & - CPFEM_AGERESULTS, & - CPFEM_COLLECT, & - CPFEM_RESTOREJACOBIAN, & - CPFEM_BACKUPJACOBIAN, & - cycleCounter, & - theInc, & - theTime, & - theDelta, & - lastIncConverged, & - outdatedByNewInc, & - outdatedFFN1, & - lastStep - use homogenization, only: & - materialpoint_sizeResults, & - materialpoint_results - - implicit none - integer(pInt), intent(in) :: & - nDi, & !< Number of direct stress components at this point - nShr, & !< Number of engineering shear stress components at this point - nTens, & !< Size of the stress or strain component array (NDI + NSHR) - nStatV, & !< Number of solution-dependent state variables - nProps, & !< User-defined number of material constants - noEl, & !< element number - nPt,& !< integration point number - kSlay, & !< layer number (shell elements etc.) - kSpt, & !< section point within the current layer - kStep, & !< step number - kInc !< increment number - character(len=80), intent(in) :: & - cmname !< uses-specified material name, left justified - real(pReal), intent(in) :: & - DTIME, & - TEMP, & - DTEMP, & - CELENT - real(pReal), dimension(1), intent(in) :: & - PREDEF, & - DPRED - real(pReal), dimension(2), intent(in) :: & - TIME !< step time/total time at beginning of the current increment - real(pReal), dimension(3), intent(in) :: & - COORDS - real(pReal), dimension(nTens), intent(in) :: & - STRAN, & !< total strains at beginning of the increment - DSTRAN !< strain increments - real(pReal), dimension(nProps), intent(in) :: & - PROPS - real(pReal), dimension(3,3), intent(in) :: & - DROT, & !< rotation increment matrix - DFGRD0, & !< F at beginning of increment - DFGRD1 !< F at end of increment - real(pReal), intent(inout) :: & - PNEWDT, & !< ratio of suggested new time increment - SSE, & !< specific elastic strain engergy - SPD, & !< specific plastic dissipation - SCD, & !< specific creep dissipation - RPL, & !< volumetric heat generation per unit time at the end of the increment - DRPLDT !< varation of RPL with respect to the temperature - real(pReal), dimension(nTens), intent(inout) :: & - STRESS !< stress tensor at the beginning of the increment, needs to be updated - real(pReal), dimension(nStatV), intent(inout) :: & - STATEV !< solution-dependent state variables - real(pReal), dimension(nTens), intent(out) :: & - DDSDDT, & - DRPLDE - real(pReal), dimension(nTens,nTens), intent(out) :: & - DDSDDE !< Jacobian matrix of the constitutive model - - real(pReal) :: temperature ! temp by Abaqus is intent(in) - real(pReal), dimension(6) :: stress_h - real(pReal), dimension(6,6) :: ddsdde_h - integer(pInt) :: computationMode, i, cp_en - logical :: cutBack - -#ifdef _OPENMP - integer :: defaultNumThreadsInt !< default value set by Abaqus - include "omp_lib.h" - defaultNumThreadsInt = omp_get_num_threads() ! remember number of threads set by Marc - call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution set by DAMASK_NUM_THREADS -#endif - - temperature = temp ! temp is intent(in) - DDSDDT = 0.0_pReal - DRPLDE = 0.0_pReal - - if (iand(debug_level(debug_abaqus),debug_levelBasic) /= 0 .and. noel == 1 .and. npt == 1) then - write(6,*) 'el',noel,'ip',npt - write(6,*) 'got kInc as',kInc - write(6,*) 'got dStran',dStran - flush(6) - endif - - if (.not. CPFEM_init_done) call CPFEM_initAll(noel,npt) - - computationMode = 0 - cp_en = mesh_FEasCP('elem',noel) - if (time(2) > theTime .or. kInc /= theInc) then ! reached convergence - terminallyIll = .false. - cycleCounter = -1 ! first calc step increments this to cycle = 0 - if (kInc == 1) then ! >> start of analysis << - lastIncConverged = .false. ! no Jacobian backup - outdatedByNewInc = .false. ! no aging of state - calcMode = .false. ! pretend last step was collection - write (6,'(i8,1x,i2,1x,a)') noel,npt,'<< UMAT >> start of analysis..!';flush(6) - else if (kInc - theInc > 1) then ! >> restart of broken analysis << - lastIncConverged = .false. ! no Jacobian backup - outdatedByNewInc = .false. ! no aging of state - calcMode = .true. ! pretend last step was calculation - write (6,'(i8,1x,i2,1x,a)') noel,npt,'<< UMAT >> restart of analysis..!';flush(6) - else ! >> just the next inc << - lastIncConverged = .true. ! request Jacobian backup - outdatedByNewInc = .true. ! request aging of state - calcMode = .true. ! assure last step was calculation - write (6,'(i8,1x,i2,1x,a)') noel,npt,'<< UMAT >> new increment..!';flush(6) - endif - else if ( dtime < theDelta ) then ! >> cutBack << - lastIncConverged = .false. ! no Jacobian backup - outdatedByNewInc = .false. ! no aging of state - terminallyIll = .false. - cycleCounter = -1 ! first calc step increments this to cycle = 0 - calcMode = .true. ! pretend last step was calculation - write(6,'(i8,1x,i2,1x,a)') noel,npt,'<< UMAT >> cutback detected..!';flush(6) - endif ! convergence treatment end - - - if (usePingPong) then - calcMode(npt,cp_en) = .not. calcMode(npt,cp_en) ! ping pong (calc <--> collect) - if (calcMode(npt,cp_en)) then ! now --- CALC --- - computationMode = CPFEM_CALCRESULTS - if ( lastStep /= kStep ) then ! first after ping pong - call debug_reset() ! resets debugging - outdatedFFN1 = .false. - cycleCounter = cycleCounter + 1_pInt - endif - if(outdatedByNewInc) then - computationMode = ior(computationMode,CPFEM_AGERESULTS) ! calc and age results - outdatedByNewInc = .false. ! reset flag - endif - else ! now --- COLLECT --- - computationMode = CPFEM_COLLECT ! plain collect - if(lastStep /= kStep .and. .not. terminallyIll) & - call debug_info() ! first after ping pong reports (meaningful) debugging - if (lastIncConverged) then - computationMode = ior(computationMode,CPFEM_BACKUPJACOBIAN) ! collect and backup Jacobian after convergence - lastIncConverged = .false. ! reset flag - endif - mesh_ipCoordinates(1:3,npt,cp_en) = mesh_unitlength * COORDS - endif - else ! --- PLAIN MODE --- - computationMode = CPFEM_CALCRESULTS ! always calc - if (lastStep /= kStep) then - if (.not. terminallyIll) & - call debug_info() ! first reports (meaningful) debugging - call debug_reset() ! and resets debugging - outdatedFFN1 = .false. - cycleCounter = cycleCounter + 1_pInt - endif - if (outdatedByNewInc) then - computationMode = ior(computationMode,CPFEM_AGERESULTS) - outdatedByNewInc = .false. ! reset flag - endif - if (lastIncConverged) then - computationMode = ior(computationMode,CPFEM_BACKUPJACOBIAN) ! backup Jacobian after convergence - lastIncConverged = .false. ! reset flag - endif - endif - - - theTime = time(2) ! record current starting time - theDelta = dtime ! record current time increment - theInc = kInc ! record current increment number - lastStep = kStep ! record step number - - if (iand(debug_level(debug_abaqus),debug_levelBasic) /= 0) then - write(6,'(a16,1x,i2,1x,a,i8,a,i8,1x,i5,a)') 'computationMode',computationMode,'(',cp_en,':',noel,npt,')' - flush(6) - endif - - call CPFEM_general(computationMode,usePingPong,dfgrd0,dfgrd1,temperature,dtime,noel,npt,stress_h,ddsdde_h) - -! Mandel: 11, 22, 33, SQRT(2)*12, SQRT(2)*23, SQRT(2)*13 -! straight: 11, 22, 33, 12, 23, 13 -! ABAQUS explicit: 11, 22, 33, 12, 23, 13 -! ABAQUS implicit: 11, 22, 33, 12, 13, 23 -! ABAQUS implicit: 11, 22, 33, 12 - - forall(i=1:ntens) ddsdde(1:ntens,i) = invnrmMandel(i)*ddsdde_h(1:ntens,i)*invnrmMandel(1:ntens) - stress(1:ntens) = stress_h(1:ntens)*invnrmMandel(1:ntens) - if(symmetricSolver) ddsdde(1:ntens,1:ntens) = 0.5_pReal*(ddsdde(1:ntens,1:ntens) + transpose(ddsdde(1:ntens,1:ntens))) - if(ntens == 6) then - stress_h = stress - stress(5) = stress_h(6) - stress(6) = stress_h(5) - ddsdde_h = ddsdde - ddsdde(:,5) = ddsdde_h(:,6) - ddsdde(:,6) = ddsdde_h(:,5) - ddsdde_h = ddsdde - ddsdde(5,:) = ddsdde_h(6,:) - ddsdde(6,:) = ddsdde_h(5,:) - end if - - statev = materialpoint_results(1:min(nstatv,materialpoint_sizeResults),npt,mesh_FEasCP('elem', noel)) - - if ( terminallyIll ) pnewdt = 0.5_pReal ! force cutback directly ? -!$ call omp_set_num_threads(defaultNumThreadsInt) ! reset number of threads to stored default value - -end subroutine UMAT - - -!-------------------------------------------------------------------------------------------------- -!> @brief calls the exit function of Abaqus/Standard -!-------------------------------------------------------------------------------------------------- -subroutine quit(mpie_error) - use prec, only: & - pInt - - implicit none - integer(pInt) :: mpie_error - - flush(6) - call xit - -end subroutine quit diff --git a/code/DAMASK_marc.f90 b/code/DAMASK_marc.f90 deleted file mode 100644 index 14dcc5c06..000000000 --- a/code/DAMASK_marc.f90 +++ /dev/null @@ -1,426 +0,0 @@ -#define QUOTE(x) #x -#define PASTE(x,y) x ## y - -#ifndef INT -#define INT 4 -#endif - -#ifndef FLOAT -#define FLOAT 8 -#endif - -#include "prec.f90" -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Luc Hantcherli, Max-Planck-Institut für Eisenforschung GmbH -!> @author W.A. Counts -!> @author Denny Tjahjanto, Max-Planck-Institut für Eisenforschung GmbH -!> @author Christoph Kords, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Material subroutine for MSC.Marc -!> @details Usage: -!> @details - choose material as hypela2 -!> @details - set statevariable 2 to index of homogenization -!> @details - set statevariable 3 to index of microstructure -!> @details - make sure the file "material.config" exists in the working directory -!> @details - make sure the file "numerics.config" exists in the working directory -!> @details - use nonsymmetric option for solver (e.g. direct profile or multifrontal sparse, the latter seems to be faster!) -!> @details - in case of ddm (domain decomposition) a SYMMETRIC solver has to be used, i.e uncheck "non-symmetric" -!> @details Marc subroutines used: -!> @details - hypela2 -!> @details - plotv -!> @details - quit -!> @details Marc common blocks included: -!> @details - concom: lovl, inc -!> @details - creeps: timinc -!-------------------------------------------------------------------------------------------------- -module DAMASK_interface - - implicit none - character(len=4), parameter :: InputFileExtension = '.dat' - character(len=4), parameter :: LogFileExtension = '.log' - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief only output of current version -!-------------------------------------------------------------------------------------------------- -subroutine DAMASK_interface_init - - implicit none - integer, dimension(8) :: & - dateAndTime ! type default integer - - call date_and_time(values = dateAndTime) - write(6,'(/,a)') ' <<<+- DAMASK_Marc -+>>>' - write(6,'(/,a)') ' Version: '//DAMASKVERSION - write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& - dateAndTime(2),'/',& - dateAndTime(1) - write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& - dateAndTime(6),':',& - dateAndTime(7) - write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' -#include "compilation_info.f90" - -end subroutine DAMASK_interface_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the current workingDir -!-------------------------------------------------------------------------------------------------- -function getSolverWorkingDirectoryName() - - implicit none - character(1024) getSolverWorkingDirectoryName, inputName - character(len=*), parameter :: pathSep = achar(47)//achar(92) ! forward and backward slash - - getSolverWorkingDirectoryName='' - inputName='' - inquire(5, name=inputName) ! determine inputputfile - getSolverWorkingDirectoryName=inputName(1:scan(inputName,pathSep,back=.true.)) - -end function getSolverWorkingDirectoryName - - -!-------------------------------------------------------------------------------------------------- -!> @brief solver job name (no extension) as combination of geometry and load case name -!-------------------------------------------------------------------------------------------------- -function getSolverJobName() - use prec, only: & - pReal, & - pInt - - implicit none - character(1024) :: getSolverJobName, inputName - character(len=*), parameter :: pathSep = achar(47)//achar(92) ! forward and backward slash - integer(pInt) :: extPos - - getSolverJobName='' - inputName='' - inquire(5, name=inputName) ! determine inputfile - extPos = len_trim(inputName)-4 - getSolverJobName=inputName(scan(inputName,pathSep,back=.true.)+1:extPos) - -end function getSolverJobName - - -end module DAMASK_interface - -#include "commercialFEM_fileList.f90" - -!-------------------------------------------------------------------------------------------------- -!> @brief This is the MSC.Marc user subroutine for defining material behavior -!> @details (1) F,R,U are only available for continuum and membrane elements (not for -!> @details shells and beams). -!> @details -!> @details (2) Use the -> 'Plasticity,3' card(=update+finite+large disp+constant d) -!> @details in the parameter section of input deck (updated Lagrangian formulation). -!> @details -!> @details The following operation obtains U (stretch tensor) at t=n+1 : -!> @details -!> @details call scla(un1,0.d0,itel,itel,1) -!> @details do k=1,3 -!> @details do i=1,3 -!> @details do j=1,3 -!> @details un1(i,j)=un1(i,j)+dsqrt(strechn1(k))*eigvn1(i,k)*eigvn1(j,k) -!> @details enddo -!> @details enddo -!> @details enddo -!-------------------------------------------------------------------------------------------------- -subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, & - dispt,coord,ffn,frotn,strechn,eigvn,ffn1,frotn1, & - strechn1,eigvn1,ncrd,itel,ndeg,ndm,nnode, & - jtype,lclass,ifr,ifu) - use prec, only: & - pReal, & - pInt - use numerics, only: & -!$ DAMASK_NumThreadsInt, & - numerics_unitlength, & - usePingPong - use FEsolving, only: & - calcMode, & - terminallyIll, & - symmetricSolver - use math, only: & - math_transpose33,& - invnrmMandel - use debug, only: & - debug_level, & - debug_LEVELBASIC, & - debug_MARC, & - debug_info, & - debug_reset - use mesh, only: & - mesh_FEasCP, & - mesh_element, & - mesh_node0, & - mesh_node, & - mesh_Ncellnodes, & - mesh_cellnode, & - mesh_build_cellnodes, & - mesh_build_ipCoordinates, & - FE_Nnodes - use CPFEM, only: & - CPFEM_general, & - CPFEM_init_done, & - CPFEM_initAll, & - CPFEM_CALCRESULTS, & - CPFEM_AGERESULTS, & - CPFEM_COLLECT, & - CPFEM_RESTOREJACOBIAN, & - CPFEM_BACKUPJACOBIAN, & - cycleCounter, & - theInc, & - theTime, & - theDelta, & - lastIncConverged, & - outdatedByNewInc, & - outdatedFFN1, & - lastLovl - - implicit none -!$ include "omp_lib.h" ! the openMP function library - integer(pInt), intent(in) :: & ! according to MSC.Marc 2012 Manual D - ngens, & !< size of stress-strain law - nn, & !< integration point number - ndi, & !< number of direct components - nshear, & !< number of shear components - ncrd, & !< number of coordinates - itel, & !< dimension of F and R, either 2 or 3 - ndeg, & !< number of degrees of freedom - ndm, & !< not specified in MSC.Marc 2012 Manual D - nnode, & !< number of nodes per element - jtype, & !< element type - ifr, & !< set to 1 if R has been calculated - ifu !< set to 1 if stretch has been calculated - integer(pInt), dimension(2), intent(in) :: & ! according to MSC.Marc 2012 Manual D - m, & !< (1) user element number, (2) internal element number - matus, & !< (1) user material identification number, (2) internal material identification number - kcus, & !< (1) layer number, (2) internal layer number - lclass !< (1) element class, (2) 0: displacement, 1: low order Herrmann, 2: high order Herrmann - real(pReal), dimension(*), intent(in) :: & ! has dimension(1) according to MSC.Marc 2012 Manual D, but according to example hypela2.f dimension(*) - e, & !< total elastic strain - de, & !< increment of strain - dt !< increment of state variables - real(pReal), dimension(itel), intent(in) :: & ! according to MSC.Marc 2012 Manual D - strechn, & !< square of principal stretch ratios, lambda(i) at t=n - strechn1 !< square of principal stretch ratios, lambda(i) at t=n+1 - real(pReal), dimension(3,3), intent(in) :: & ! has dimension(itel,*) according to MSC.Marc 2012 Manual D, but we alway assume dimension(3,3) - ffn, & !< deformation gradient at t=n - ffn1 !< deformation gradient at t=n+1 - real(pReal), dimension(itel,*), intent(in) :: & ! according to MSC.Marc 2012 Manual D - frotn, & !< rotation tensor at t=n - eigvn, & !< i principal direction components for j eigenvalues at t=n - frotn1, & !< rotation tensor at t=n+1 - eigvn1 !< i principal direction components for j eigenvalues at t=n+1 - real(pReal), dimension(ndeg,*), intent(in) :: & ! according to MSC.Marc 2012 Manual D - disp, & !< incremental displacements - dispt !< displacements at t=n (at assembly, lovl=4) and displacements at t=n+1 (at stress recovery, lovl=6) - real(pReal), dimension(ncrd,*), intent(in) :: & ! according to MSC.Marc 2012 Manual D - coord !< coordinates - real(pReal), dimension(*), intent(inout) :: & ! according to MSC.Marc 2012 Manual D - t !< state variables (comes in at t=n, must be updated to have state variables at t=n+1) - real(pReal), dimension(ndi+nshear), intent(out) :: & ! has dimension(*) according to MSC.Marc 2012 Manual D, but we need to loop over it - s, & !< stress - should be updated by user - g !< change in stress due to temperature effects - real(pReal), dimension(ngens,ngens), intent(out) :: & ! according to MSC.Marc 2012 Manual D, but according to example hypela2.f dimension(ngens,*) - d !< stress-strain law to be formed - -!-------------------------------------------------------------------------------------------------- -! Marc common blocks are in fixed format so they have to be reformated to free format (f90) -! Beware of changes in newer Marc versions - -#include QUOTE(PASTE(../lib/MarcInclude/concom,Marc4DAMASK)) ! concom is needed for inc, lovl -#include QUOTE(PASTE(../lib/MarcInclude/creeps,Marc4DAMASK)) ! creeps is needed for timinc (time increment) - - logical :: cutBack - real(pReal), dimension(6) :: stress - real(pReal), dimension(6,6) :: ddsdde - integer(pInt) :: computationMode, i, cp_en, node, CPnodeID - !$ integer :: defaultNumThreadsInt !< default value set by Marc - - if (iand(debug_level(debug_MARC),debug_LEVELBASIC) /= 0_pInt) then - write(6,'(a,/,i8,i8,i2)') ' MSC.MARC information on shape of element(2), IP:', m, nn - write(6,'(a,2(1i))'), ' Jacobian: ', ngens,ngens - write(6,'(a,1i)'), ' Direct stress: ', ndi - write(6,'(a,1i)'), ' Shear stress: ', nshear - write(6,'(a,1i)'), ' DoF: ', ndeg - write(6,'(a,1i)'), ' Coordinates: ', ncrd - write(6,'(a,1i)'), ' Nodes: ', nnode - write(6,'(a,1i)'), ' Deformation gradient: ', itel - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' Deformation gradient at t=n:', & - math_transpose33(ffn) - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' Deformation gradient at t=n+1:', & - math_transpose33(ffn1) - endif - - !$ defaultNumThreadsInt = omp_get_num_threads() ! remember number of threads set by Marc - - if (.not. CPFEM_init_done) call CPFEM_initAll(m(1),nn) - - !$ call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution set by DAMASK_NUM_THREADS - - computationMode = 0_pInt ! save initialization value, since it does not result in any calculation - if (lovl == 4 ) then ! jacobian requested by marc - if (timinc < theDelta .and. theInc == inc .and. lastLovl /= lovl) & ! first after cutback - computationMode = CPFEM_RESTOREJACOBIAN - elseif (lovl == 6) then ! stress requested by marc - cp_en = mesh_FEasCP('elem',m(1)) - if (cptim > theTime .or. inc /= theInc) then ! reached "convergence" - terminallyIll = .false. - cycleCounter = -1 ! first calc step increments this to cycle = 0 - if (inc == 0) then ! >> start of analysis << - lastIncConverged = .false. ! no Jacobian backup - outdatedByNewInc = .false. ! no aging of state - calcMode = .false. ! pretend last step was collection - lastLovl = lovl ! pretend that this is NOT the first after a lovl change - !$OMP CRITICAL (write2out) - write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> start of analysis..! ',m(1),nn - flush(6) - !$OMP END CRITICAL (write2out) - else if (inc - theInc > 1) then ! >> restart of broken analysis << - lastIncConverged = .false. ! no Jacobian backup - outdatedByNewInc = .false. ! no aging of state - calcMode = .true. ! pretend last step was calculation - !$OMP CRITICAL (write2out) - write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> restart of analysis..! ',m(1),nn - flush(6) - !$OMP END CRITICAL (write2out) - else ! >> just the next inc << - lastIncConverged = .true. ! request Jacobian backup - outdatedByNewInc = .true. ! request aging of state - calcMode = .true. ! assure last step was calculation - !$OMP CRITICAL (write2out) - write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> new increment..! ',m(1),nn - flush(6) - !$OMP END CRITICAL (write2out) - endif - else if ( timinc < theDelta ) then ! >> cutBack << - lastIncConverged = .false. ! no Jacobian backup - outdatedByNewInc = .false. ! no aging of state - terminallyIll = .false. - cycleCounter = -1 ! first calc step increments this to cycle = 0 - calcMode = .true. ! pretend last step was calculation - !$OMP CRITICAL (write2out) - write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> cutback detected..! ',m(1),nn - flush(6) - !$OMP END CRITICAL (write2out) - endif ! convergence treatment end - - - if (usePingPong) then - calcMode(nn,cp_en) = .not. calcMode(nn,cp_en) ! ping pong (calc <--> collect) - if (calcMode(nn,cp_en)) then ! now --- CALC --- - computationMode = CPFEM_CALCRESULTS - if (lastLovl /= lovl) then ! first after ping pong - call debug_reset() ! resets debugging - outdatedFFN1 = .false. - cycleCounter = cycleCounter + 1_pInt - mesh_cellnode = mesh_build_cellnodes(mesh_node,mesh_Ncellnodes) ! update cell node coordinates - call mesh_build_ipCoordinates() ! update ip coordinates - endif - if (outdatedByNewInc) then - computationMode = ior(computationMode,CPFEM_AGERESULTS) ! calc and age results - outdatedByNewInc = .false. ! reset flag - endif - else ! now --- COLLECT --- - computationMode = CPFEM_COLLECT ! plain collect - if (lastLovl /= lovl .and. & .not. terminallyIll) & - call debug_info() ! first after ping pong reports (meaningful) debugging - if (lastIncConverged) then - computationMode = ior(computationMode,CPFEM_BACKUPJACOBIAN) ! collect and backup Jacobian after convergence - lastIncConverged = .false. ! reset flag - endif - do node = 1,FE_Nnodes(mesh_element(2,cp_en)) - CPnodeID = mesh_element(4_pInt+node,cp_en) - mesh_node(1:ndeg,CPnodeID) = mesh_node0(1:ndeg,CPnodeID) + numerics_unitlength * dispt(1:ndeg,node) - enddo - endif - - else ! --- PLAIN MODE --- - computationMode = CPFEM_CALCRESULTS ! always calc - if (lastLovl /= lovl) then - if (.not. terminallyIll) & - call debug_info() ! first reports (meaningful) debugging - call debug_reset() ! and resets debugging - outdatedFFN1 = .false. - cycleCounter = cycleCounter + 1_pInt - mesh_cellnode = mesh_build_cellnodes(mesh_node,mesh_Ncellnodes) ! update cell node coordinates - call mesh_build_ipCoordinates() ! update ip coordinates - endif - if (outdatedByNewInc) then - computationMode = ior(computationMode,CPFEM_AGERESULTS) - outdatedByNewInc = .false. ! reset flag - endif - if (lastIncConverged) then - computationMode = ior(computationMode,CPFEM_BACKUPJACOBIAN) ! backup Jacobian after convergence - lastIncConverged = .false. ! reset flag - endif - endif - - theTime = cptim ! record current starting time - theDelta = timinc ! record current time increment - theInc = inc ! record current increment number - - endif - lastLovl = lovl ! record lovl - - call CPFEM_general(computationMode,usePingPong,ffn,ffn1,t(1),timinc,m(1),nn,stress,ddsdde) - -! Mandel: 11, 22, 33, SQRT(2)*12, SQRT(2)*23, SQRT(2)*13 -! Marc: 11, 22, 33, 12, 23, 13 -! Marc: 11, 22, 33, 12 - - forall(i=1:ngens) d(1:ngens,i) = invnrmMandel(i)*ddsdde(1:ngens,i)*invnrmMandel(1:ngens) - s(1:ndi+nshear) = stress(1:ndi+nshear)*invnrmMandel(1:ndi+nshear) - g = 0.0_pReal - if(symmetricSolver) d = 0.5_pReal*(d+transpose(d)) - - !$ call omp_set_num_threads(defaultNumThreadsInt) ! reset number of threads to stored default value - -end subroutine hypela2 - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets user defined output variables for Marc -!> @details select a variable contour plotting (user subroutine). -!-------------------------------------------------------------------------------------------------- -subroutine plotv(v,s,sp,etot,eplas,ecreep,t,m,nn,layer,ndi,nshear,jpltcd) - use prec, only: & - pReal, & - pInt - use mesh, only: & - mesh_FEasCP - use IO, only: & - IO_error - use homogenization, only: & - materialpoint_results,& - materialpoint_sizeResults - - implicit none - integer(pInt), intent(in) :: & - m, & !< element number - nn, & !< integration point number - layer, & !< layer number - ndi, & !< number of direct stress components - nshear, & !< number of shear stress components - jpltcd !< user variable index - real(pReal), dimension(*), intent(in) :: & - s, & !< stress array - sp, & !< stresses in preferred direction - etot, & !< total strain (generalized) - eplas, & !< total plastic strain - ecreep, & !< total creep strain - t !< current temperature - real(pReal), intent(out) :: & - v !< variable - - if (jpltcd > materialpoint_sizeResults) call IO_error(700_pInt,jpltcd) ! complain about out of bounds error - v = materialpoint_results(jpltcd,nn,mesh_FEasCP('elem', m)) - -end subroutine plotv diff --git a/code/DAMASK_marc2011.f90 b/code/DAMASK_marc2011.f90 deleted file mode 120000 index 2c5bec706..000000000 --- a/code/DAMASK_marc2011.f90 +++ /dev/null @@ -1 +0,0 @@ -DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2012.f90 b/code/DAMASK_marc2012.f90 deleted file mode 120000 index 2c5bec706..000000000 --- a/code/DAMASK_marc2012.f90 +++ /dev/null @@ -1 +0,0 @@ -DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2013.1.f90 b/code/DAMASK_marc2013.1.f90 deleted file mode 120000 index 2c5bec706..000000000 --- a/code/DAMASK_marc2013.1.f90 +++ /dev/null @@ -1 +0,0 @@ -DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2013.f90 b/code/DAMASK_marc2013.f90 deleted file mode 120000 index 2c5bec706..000000000 --- a/code/DAMASK_marc2013.f90 +++ /dev/null @@ -1 +0,0 @@ -DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2014.2.f90 b/code/DAMASK_marc2014.2.f90 deleted file mode 120000 index 2c5bec706..000000000 --- a/code/DAMASK_marc2014.2.f90 +++ /dev/null @@ -1 +0,0 @@ -DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2014.f90 b/code/DAMASK_marc2014.f90 deleted file mode 120000 index 2c5bec706..000000000 --- a/code/DAMASK_marc2014.f90 +++ /dev/null @@ -1 +0,0 @@ -DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_marc2015.f90 b/code/DAMASK_marc2015.f90 deleted file mode 120000 index 2c5bec706..000000000 --- a/code/DAMASK_marc2015.f90 +++ /dev/null @@ -1 +0,0 @@ -DAMASK_marc.f90 \ No newline at end of file diff --git a/code/DAMASK_spectral.f90 b/code/DAMASK_spectral.f90 deleted file mode 100644 index 0d83d1279..000000000 --- a/code/DAMASK_spectral.f90 +++ /dev/null @@ -1,751 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Driver controlling inner and outer load case looping of the various spectral solvers -!> @details doing cutbacking, forwarding in case of restart, reporting statistics, writing -!> results -!-------------------------------------------------------------------------------------------------- -program DAMASK_spectral - use, intrinsic :: & - iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use prec, only: & - pInt, & - pLongInt, & - pReal, & - tol_math_check - use DAMASK_interface, only: & - DAMASK_interface_init, & - loadCaseFile, & - geometryFile, & - getSolverWorkingDirectoryName, & - getSolverJobName, & - appendToOutFile - use IO, only: & - IO_read, & - IO_isBlank, & - IO_open_file, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_error, & - IO_lc, & - IO_intOut, & - IO_warning, & - IO_timeStamp, & - IO_EOF - use debug, only: & - debug_level, & - debug_spectral, & - debug_levelBasic - use math ! need to include the whole module for FFTW - use mesh, only: & - grid, & - geomSize - use CPFEM2, only: & - CPFEM_initAll - use FEsolving, only: & - restartWrite, & - restartInc - use numerics, only: & - worldrank, & - worldsize, & - stagItMax, & - maxCutBack, & - spectral_solver, & - continueCalculation - use homogenization, only: & - materialpoint_sizeResults, & - materialpoint_results, & - materialpoint_postResults - - - use material, only: & - thermal_type, & - damage_type, & - THERMAL_conduction_ID, & - DAMAGE_nonlocal_ID - use spectral_utilities, only: & - utilities_init, & - utilities_destroy, & - tSolutionState, & - tLoadCase, & - cutBack, & - nActiveFields, & - FIELD_UNDEFINED_ID, & - FIELD_MECH_ID, & - FIELD_THERMAL_ID, & - FIELD_DAMAGE_ID - use spectral_mech_Basic - use spectral_mech_AL - use spectral_mech_Polarisation - use spectral_damage - use spectral_thermal - - - implicit none - -#include - -!-------------------------------------------------------------------------------------------------- -! 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 - integer(pInt), parameter :: FILEUNIT = 234_pInt !< file unit, DAMASK IO does not support newunit feature - integer(pInt), allocatable, dimension(:) :: chunkPos - - integer(pInt) :: & - N_t = 0_pInt, & !< # of time indicators found in load case file - N_n = 0_pInt, & !< # of increment specifiers found in load case file - N_def = 0_pInt !< # of rate of deformation specifiers found in load case file - character(len=65536) :: & - line - -!-------------------------------------------------------------------------------------------------- -! loop variables, convergence etc. - real(pReal), dimension(3,3), parameter :: & - ones = 1.0_pReal, & - zeros = 0.0_pReal - integer(pInt), parameter :: & - subStepFactor = 2_pInt !< for each substep, divide the last time increment by 2.0 - real(pReal) :: & - time = 0.0_pReal, & !< elapsed time - time0 = 0.0_pReal, & !< begin of interval - timeinc = 1.0_pReal, & !< current time interval - timeIncOld = 0.0_pReal, & !< previous time interval - remainingLoadCaseTime = 0.0_pReal !< remaining time of current load case - logical :: & - guess, & !< guess along former trajectory - stagIterate - integer(pInt) :: & - i, j, k, l, field, & - errorID, & - cutBackLevel = 0_pInt, & !< cut back level \f$ t = \frac{t_{inc}}{2^l} \f$ - stepFraction = 0_pInt !< fraction of current time interval - integer(pInt) :: & - currentLoadcase = 0_pInt, & !< current load case - inc, & !< current increment in current load case - totalIncsCounter = 0_pInt, & !< total # of increments - convergedCounter = 0_pInt, & !< # of converged increments - notConvergedCounter = 0_pInt, & !< # of non-converged increments - resUnit = 0_pInt, & !< file unit for results writing - statUnit = 0_pInt, & !< file unit for statistics output - lastRestartWritten = 0_pInt, & !< total increment # at which last restart information was written - stagIter - character(len=6) :: loadcase_string - character(len=1024) :: incInfo !< string parsed to solution with information about current load case - type(tLoadCase), allocatable, dimension(:) :: loadCases !< array of all load cases - type(tSolutionState), allocatable, dimension(:) :: solres - integer(MPI_OFFSET_KIND) :: fileOffset - integer(MPI_OFFSET_KIND), dimension(:), allocatable :: outputSize - integer(pInt), parameter :: maxByteOut = 2147483647-4096 !< limit of one file output write https://trac.mpich.org/projects/mpich/ticket/1742 - integer(pLongInt), dimension(2) :: outputIndex - PetscErrorCode :: ierr - external :: & - quit, & - MPI_file_open, & - MPI_file_close, & - MPI_file_seek, & - MPI_file_get_position, & - MPI_file_write, & - MPI_allreduce - -!-------------------------------------------------------------------------------------------------- -! init DAMASK (all modules) - call CPFEM_initAll(el = 1_pInt, ip = 1_pInt) - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- DAMASK_spectral init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!-------------------------------------------------------------------------------------------------- -! initialize field solver information - nActiveFields = 1 - if (any(thermal_type == THERMAL_conduction_ID )) nActiveFields = nActiveFields + 1 - if (any(damage_type == DAMAGE_nonlocal_ID )) nActiveFields = nActiveFields + 1 - allocate(solres(nActiveFields)) - -!-------------------------------------------------------------------------------------------------- -! reading basic information from load case file and allocate data structure containing load cases - call IO_open_file(FILEUNIT,trim(loadCaseFile)) - rewind(FILEUNIT) - do - line = IO_read(FILEUNIT) - if (trim(line) == IO_EOF) exit - if (IO_isBlank(line)) cycle ! skip empty lines - chunkPos = IO_stringPos(line) - do i = 1_pInt, chunkPos(1) ! reading compulsory parameters for loadcase - select case (IO_lc(IO_stringValue(line,chunkPos,i))) - case('l','velocitygrad','velgrad','velocitygradient','fdot','dotf','f') - N_def = N_def + 1_pInt - case('t','time','delta') - N_t = N_t + 1_pInt - case('n','incs','increments','steps','logincs','logincrements','logsteps') - N_n = N_n + 1_pInt - end select - enddo ! count all identifiers to allocate memory and do sanity check - enddo - - if ((N_def /= N_n) .or. (N_n /= N_t) .or. N_n < 1_pInt) & ! sanity check - call IO_error(error_ID=837_pInt,ext_msg = trim(loadCaseFile)) ! error message for incomplete loadcase - allocate (loadCases(N_n)) ! array of load cases - loadCases%P%myType='p' - - do i = 1, size(loadCases) - allocate(loadCases(i)%ID(nActiveFields)) - field = 1 - loadCases(i)%ID(field) = FIELD_MECH_ID ! mechanical active by default - if (any(thermal_type == THERMAL_conduction_ID)) then ! thermal field active - field = field + 1 - loadCases(i)%ID(field) = FIELD_THERMAL_ID - endif - if (any(damage_type == DAMAGE_nonlocal_ID)) then ! damage field active - field = field + 1 - loadCases(i)%ID(field) = FIELD_DAMAGE_ID - endif - enddo - -!-------------------------------------------------------------------------------------------------- -! reading the load case and assign values to the allocated data structure - rewind(FILEUNIT) - do - line = IO_read(FILEUNIT) - if (trim(line) == IO_EOF) exit - if (IO_isBlank(line)) cycle ! skip empty lines - currentLoadCase = currentLoadCase + 1_pInt - chunkPos = IO_stringPos(line) - do i = 1_pInt, chunkPos(1) - select case (IO_lc(IO_stringValue(line,chunkPos,i))) - case('fdot','dotf','l','velocitygrad','velgrad','velocitygradient','f') ! assign values for the deformation BC matrix - temp_valueVector = 0.0_pReal - if (IO_lc(IO_stringValue(line,chunkPos,i)) == 'fdot'.or. & ! in case of Fdot, set type to fdot - IO_lc(IO_stringValue(line,chunkPos,i)) == 'dotf') then - loadCases(currentLoadCase)%deformation%myType = 'fdot' - else if (IO_lc(IO_stringValue(line,chunkPos,i)) == 'f') then - loadCases(currentLoadCase)%deformation%myType = 'f' - else - loadCases(currentLoadCase)%deformation%myType = 'l' - endif - do j = 1_pInt, 9_pInt - temp_maskVector(j) = IO_stringValue(line,chunkPos,i+j) /= '*' ! true if not a * - enddo - do j = 1_pInt,9_pInt - if (temp_maskVector(j)) temp_valueVector(j) = IO_floatValue(line,chunkPos,i+j) ! read value where applicable - enddo - loadCases(currentLoadCase)%deformation%maskLogical = & ! logical mask in 3x3 notation - transpose(reshape(temp_maskVector,[ 3,3])) - loadCases(currentLoadCase)%deformation%maskFloat = & ! float (1.0/0.0) mask in 3x3 notation - merge(ones,zeros,loadCases(currentLoadCase)%deformation%maskLogical) - loadCases(currentLoadCase)%deformation%values = math_plain9to33(temp_valueVector) ! values in 3x3 notation - case('p','pk1','piolakirchhoff','stress', 's') - temp_valueVector = 0.0_pReal - do j = 1_pInt, 9_pInt - temp_maskVector(j) = IO_stringValue(line,chunkPos,i+j) /= '*' ! true if not an asterisk - enddo - do j = 1_pInt,9_pInt - if (temp_maskVector(j)) temp_valueVector(j) = IO_floatValue(line,chunkPos,i+j) ! read value where applicable - enddo - loadCases(currentLoadCase)%P%maskLogical = transpose(reshape(temp_maskVector,[ 3,3])) - loadCases(currentLoadCase)%P%maskFloat = merge(ones,zeros,& - loadCases(currentLoadCase)%P%maskLogical) - loadCases(currentLoadCase)%P%values = math_plain9to33(temp_valueVector) - case('t','time','delta') ! increment time - loadCases(currentLoadCase)%time = IO_floatValue(line,chunkPos,i+1_pInt) - case('n','incs','increments','steps') ! number of increments - loadCases(currentLoadCase)%incs = IO_intValue(line,chunkPos,i+1_pInt) - case('logincs','logincrements','logsteps') ! number of increments (switch to log time scaling) - loadCases(currentLoadCase)%incs = IO_intValue(line,chunkPos,i+1_pInt) - loadCases(currentLoadCase)%logscale = 1_pInt - case('freq','frequency','outputfreq') ! frequency of result writings - loadCases(currentLoadCase)%outputfrequency = IO_intValue(line,chunkPos,i+1_pInt) - case('r','restart','restartwrite') ! frequency of writing restart information - loadCases(currentLoadCase)%restartfrequency = & - max(0_pInt,IO_intValue(line,chunkPos,i+1_pInt)) - case('guessreset','dropguessing') - loadCases(currentLoadCase)%followFormerTrajectory = .false. ! do not continue to predict deformation along former trajectory - case('euler') ! rotation of currentLoadCase given in euler angles - temp_valueVector = 0.0_pReal - l = 1_pInt ! assuming values given in degrees - k = 1_pInt ! assuming keyword indicating degree/radians present - select case (IO_lc(IO_stringValue(line,chunkPos,i+1_pInt))) - case('deg','degree') - case('rad','radian') ! don't convert from degree to radian - l = 0_pInt - case default - k = 0_pInt - end select - do j = 1_pInt, 3_pInt - temp_valueVector(j) = IO_floatValue(line,chunkPos,i+k+j) - enddo - if (l == 1_pInt) temp_valueVector(1:3) = temp_valueVector(1:3) * inRad ! convert to rad - loadCases(currentLoadCase)%rotation = math_EulerToR(temp_valueVector(1:3)) ! convert rad Eulers to rotation matrix - case('rotation','rot') ! assign values for the rotation of currentLoadCase matrix - temp_valueVector = 0.0_pReal - do j = 1_pInt, 9_pInt - temp_valueVector(j) = IO_floatValue(line,chunkPos,i+j) - enddo - loadCases(currentLoadCase)%rotation = math_plain9to33(temp_valueVector) - end select - enddo; enddo - close(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! consistency checks and output of load case - loadCases(1)%followFormerTrajectory = .false. ! cannot guess along trajectory for first inc of first currentLoadCase - errorID = 0_pInt - if (worldrank == 0) then - checkLoadcases: do currentLoadCase = 1_pInt, size(loadCases) - write (loadcase_string, '(i6)' ) currentLoadCase - write(6,'(1x,a,i6)') 'load case: ', currentLoadCase - if (.not. loadCases(currentLoadCase)%followFormerTrajectory) & - write(6,'(2x,a)') 'drop guessing along trajectory' - if (loadCases(currentLoadCase)%deformation%myType=='l') then - do j = 1_pInt, 3_pInt - if (any(loadCases(currentLoadCase)%deformation%maskLogical(j,1:3) .eqv. .true.) .and. & - any(loadCases(currentLoadCase)%deformation%maskLogical(j,1:3) .eqv. .false.)) & - errorID = 832_pInt ! each row should be either fully or not at all defined - enddo - write(6,'(2x,a)') 'velocity gradient:' - else if (loadCases(currentLoadCase)%deformation%myType=='f') then - write(6,'(2x,a)') 'deformation gradient at end of load case:' - else - write(6,'(2x,a)') 'deformation gradient rate:' - endif - do i = 1_pInt, 3_pInt; do j = 1_pInt, 3_pInt - if(loadCases(currentLoadCase)%deformation%maskLogical(i,j)) then - write(6,'(2x,f12.7)',advance='no') loadCases(currentLoadCase)%deformation%values(i,j) - else - write(6,'(2x,12a)',advance='no') ' * ' - endif - enddo; write(6,'(/)',advance='no') - enddo - if (any(loadCases(currentLoadCase)%P%maskLogical .eqv. & - loadCases(currentLoadCase)%deformation%maskLogical)) errorID = 831_pInt ! exclusive or masking only - if (any(loadCases(currentLoadCase)%P%maskLogical .and. & - transpose(loadCases(currentLoadCase)%P%maskLogical) .and. & - reshape([ .false.,.true.,.true.,.true.,.false.,.true.,.true.,.true.,.false.],[ 3,3]))) & - errorID = 838_pInt ! no rotation is allowed by stress BC - write(6,'(2x,a)') 'stress / GPa:' - do i = 1_pInt, 3_pInt; do j = 1_pInt, 3_pInt - if(loadCases(currentLoadCase)%deformation%maskLogical(i,j)) then - write(6,'(2x,f12.7)',advance='no') loadCases(currentLoadCase)%P%values(i,j)*1e-9_pReal - else - write(6,'(2x,12a)',advance='no') ' * ' - endif - enddo; write(6,'(/)',advance='no') - enddo - if (any(abs(math_mul33x33(loadCases(currentLoadCase)%rotation, & - math_transpose33(loadCases(currentLoadCase)%rotation))-math_I3) >& - reshape(spread(tol_math_check,1,9),[ 3,3]))& - .or. abs(math_det33(loadCases(currentLoadCase)%rotation)) > & - 1.0_pReal + tol_math_check) errorID = 846_pInt ! given rotation matrix contains strain - if (any(loadCases(currentLoadCase)%rotation /= math_I3)) & - write(6,'(2x,a,/,3(3(3x,f12.7,1x)/))',advance='no') 'rotation of loadframe:',& - math_transpose33(loadCases(currentLoadCase)%rotation) - if (loadCases(currentLoadCase)%time < 0.0_pReal) errorID = 834_pInt ! negative time increment - write(6,'(2x,a,f12.6)') 'time: ', loadCases(currentLoadCase)%time - if (loadCases(currentLoadCase)%incs < 1_pInt) errorID = 835_pInt ! non-positive incs count - write(6,'(2x,a,i5)') 'increments: ', loadCases(currentLoadCase)%incs - if (loadCases(currentLoadCase)%outputfrequency < 1_pInt) errorID = 836_pInt ! non-positive result frequency - write(6,'(2x,a,i5)') 'output frequency: ', & - loadCases(currentLoadCase)%outputfrequency - write(6,'(2x,a,i5,/)') 'restart frequency: ', & - loadCases(currentLoadCase)%restartfrequency - if (errorID > 0_pInt) call IO_error(error_ID = errorID, ext_msg = loadcase_string) ! exit with error message - enddo checkLoadcases - endif - -!-------------------------------------------------------------------------------------------------- -! doing initialization depending on selected solver - call Utilities_init() - do field = 1, nActiveFields - select case (loadCases(1)%ID(field)) - case(FIELD_MECH_ID) - select case (spectral_solver) - case (DAMASK_spectral_SolverBasicPETSc_label) - call basicPETSc_init - case (DAMASK_spectral_SolverAL_label) - if(iand(debug_level(debug_spectral),debug_levelBasic)/= 0 .and. worldrank == 0_pInt) & - call IO_warning(42_pInt, ext_msg='debug Divergence') - call AL_init - - case (DAMASK_spectral_SolverPolarisation_label) - if(iand(debug_level(debug_spectral),debug_levelBasic)/= 0 .and. worldrank == 0_pInt) & - call IO_warning(42_pInt, ext_msg='debug Divergence') - call Polarisation_init - - case default - call IO_error(error_ID = 891, ext_msg = trim(spectral_solver)) - - end select - - case(FIELD_THERMAL_ID) - call spectral_thermal_init - - case(FIELD_DAMAGE_ID) - call spectral_damage_init() - - end select - enddo - -!-------------------------------------------------------------------------------------------------- -! write header of output file - if (worldrank == 0) then - if (.not. appendToOutFile) then ! after restart, append to existing results file - open(newunit=resUnit,file=trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//& - '.spectralOut',form='UNFORMATTED',status='REPLACE') - write(resUnit) 'load:', trim(loadCaseFile) ! ... and write header - write(resUnit) 'workingdir:', trim(getSolverWorkingDirectoryName()) - write(resUnit) 'geometry:', trim(geometryFile) - write(resUnit) 'grid:', grid - write(resUnit) 'size:', geomSize - write(resUnit) 'materialpoint_sizeResults:', materialpoint_sizeResults - write(resUnit) 'loadcases:', size(loadCases) - write(resUnit) 'frequencies:', loadCases%outputfrequency ! one entry per LoadCase - write(resUnit) 'times:', loadCases%time ! one entry per LoadCase - write(resUnit) 'logscales:', loadCases%logscale - write(resUnit) 'increments:', loadCases%incs ! one entry per LoadCase - write(resUnit) 'startingIncrement:', restartInc - 1_pInt ! start with writing out the previous inc - write(resUnit) 'eoh' - close(resUnit) ! end of header - open(newunit=statUnit,file=trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//& - '.sta',form='FORMATTED',status='REPLACE') - write(statUnit,'(a)') 'Increment Time CutbackLevel Converged IterationsNeeded' ! statistics file - if (iand(debug_level(debug_spectral),debug_levelBasic) /= 0) & - write(6,'(/,a)') ' header of result and statistics file written out' - flush(6) - else ! open new files ... - open(newunit=statUnit,file=trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//& - '.sta',form='FORMATTED', position='APPEND', status='OLD') - endif - endif - -!-------------------------------------------------------------------------------------------------- -! prepare MPI parallel out (including opening of file) - allocate(outputSize(worldsize), source = 0_MPI_OFFSET_KIND) - outputSize(worldrank+1) = int(size(materialpoint_results)*pReal,MPI_OFFSET_KIND) - call MPI_allreduce(MPI_IN_PLACE,outputSize,worldsize,MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get total output size over each process - call MPI_file_open(PETSC_COMM_WORLD, & - trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.spectralOut', & - MPI_MODE_WRONLY + MPI_MODE_APPEND, & - MPI_INFO_NULL, & - resUnit, & - ierr) - call MPI_file_get_position(resUnit,fileOffset,ierr) ! get offset from header - fileOffset = fileOffset + sum(outputSize(1:worldrank)) ! offset of my process in file (header + processes before me) - call MPI_file_seek (resUnit,fileOffset,MPI_SEEK_SET,ierr) - - if (.not. appendToOutFile) then ! if not restarting, write 0th increment - do i=1, size(materialpoint_results,3)/(maxByteOut/(materialpoint_sizeResults*pReal))+1 ! slice the output of my process in chunks not exceeding the limit for one output - outputIndex=[(i-1)*((maxByteOut/pReal)/materialpoint_sizeResults)+1, & - min(i*((maxByteOut/pReal)/materialpoint_sizeResults),size(materialpoint_results,3))] - call MPI_file_write(resUnit,reshape(materialpoint_results(:,:,outputIndex(1):outputIndex(2)),& - [(outputIndex(2)-outputIndex(1)+1)*materialpoint_sizeResults]), & - (outputIndex(2)-outputIndex(1)+1)*materialpoint_sizeResults,& - MPI_DOUBLE, MPI_STATUS_IGNORE, ierr) - fileOffset = fileOffset + sum(outputSize) ! forward to current file position - enddo - if (worldrank == 0) & - write(6,'(1/,a)') ' ... writing initial configuration to file ........................' - endif -!-------------------------------------------------------------------------------------------------- -! loopping over loadcases - loadCaseLooping: do currentLoadCase = 1_pInt, size(loadCases) - time0 = time ! currentLoadCase start time - guess = loadCases(currentLoadCase)%followFormerTrajectory ! change of load case? homogeneous guess for the first inc - -!-------------------------------------------------------------------------------------------------- -! loop oper incs defined in input file for current currentLoadCase - incLooping: do inc = 1_pInt, loadCases(currentLoadCase)%incs - totalIncsCounter = totalIncsCounter + 1_pInt - -!-------------------------------------------------------------------------------------------------- -! forwarding time - timeIncOld = timeinc - if (loadCases(currentLoadCase)%logscale == 0_pInt) then ! linear scale - timeinc = loadCases(currentLoadCase)%time/loadCases(currentLoadCase)%incs ! only valid for given linear time scale. will be overwritten later in case loglinear scale is used - else - if (currentLoadCase == 1_pInt) then ! 1st currentLoadCase of logarithmic scale - if (inc == 1_pInt) then ! 1st inc of 1st currentLoadCase of logarithmic scale - timeinc = loadCases(1)%time*(2.0_pReal**real( 1_pInt-loadCases(1)%incs ,pReal)) ! assume 1st inc is equal to 2nd - else ! not-1st inc of 1st currentLoadCase of logarithmic scale - timeinc = loadCases(1)%time*(2.0_pReal**real(inc-1_pInt-loadCases(1)%incs ,pReal)) - endif - else ! not-1st currentLoadCase of logarithmic scale - timeinc = time0 * & - ( (1.0_pReal + loadCases(currentLoadCase)%time/time0 )**(real( inc,pReal)/& - real(loadCases(currentLoadCase)%incs ,pReal))& - -(1.0_pReal + loadCases(currentLoadCase)%time/time0 )**(real( (inc-1_pInt),pReal)/& - real(loadCases(currentLoadCase)%incs ,pReal))) - endif - endif - timeinc = timeinc / 2.0_pReal**real(cutBackLevel,pReal) ! depending on cut back level, decrease time step - - forwarding: if(totalIncsCounter >= restartInc) then - stepFraction = 0_pInt - -!-------------------------------------------------------------------------------------------------- -! loop over sub incs - subIncLooping: do while (stepFraction/subStepFactor**cutBackLevel <1_pInt) - time = time + timeinc ! forward time - stepFraction = stepFraction + 1_pInt - remainingLoadCaseTime = time0 - time + loadCases(currentLoadCase)%time + timeInc - -!-------------------------------------------------------------------------------------------------- -! report begin of new increment - if (worldrank == 0) then - write(6,'(/,a)') ' ###########################################################################' - write(6,'(1x,a,es12.5'//& - ',a,'//IO_intOut(inc)//',a,'//IO_intOut(loadCases(currentLoadCase)%incs)//& - ',a,'//IO_intOut(stepFraction)//',a,'//IO_intOut(subStepFactor**cutBackLevel)//& - ',a,'//IO_intOut(currentLoadCase)//',a,'//IO_intOut(size(loadCases))//')') & - 'Time', time, & - 's: Increment ', inc, '/', loadCases(currentLoadCase)%incs,& - '-', stepFraction, '/', subStepFactor**cutBackLevel,& - ' of load case ', currentLoadCase,'/',size(loadCases) - flush(6) - write(incInfo,'(a,'//IO_intOut(totalIncsCounter)//',a,'//IO_intOut(sum(loadCases%incs))//& - ',a,'//IO_intOut(stepFraction)//',a,'//IO_intOut(subStepFactor**cutBackLevel)//')') & - 'Increment ',totalIncsCounter,'/',sum(loadCases%incs),& - '-',stepFraction, '/', subStepFactor**cutBackLevel - endif - -!-------------------------------------------------------------------------------------------------- -! forward fields - do field = 1, nActiveFields - select case(loadCases(currentLoadCase)%ID(field)) - case(FIELD_MECH_ID) - select case (spectral_solver) - case (DAMASK_spectral_SolverBasicPETSc_label) - call BasicPETSc_forward (& - guess,timeinc,timeIncOld,remainingLoadCaseTime, & - F_BC = loadCases(currentLoadCase)%deformation, & - P_BC = loadCases(currentLoadCase)%P, & - rotation_BC = loadCases(currentLoadCase)%rotation) - case (DAMASK_spectral_SolverAL_label) - call AL_forward (& - guess,timeinc,timeIncOld,remainingLoadCaseTime, & - F_BC = loadCases(currentLoadCase)%deformation, & - P_BC = loadCases(currentLoadCase)%P, & - rotation_BC = loadCases(currentLoadCase)%rotation) - case (DAMASK_spectral_SolverPolarisation_label) - call Polarisation_forward (& - guess,timeinc,timeIncOld,remainingLoadCaseTime, & - F_BC = loadCases(currentLoadCase)%deformation, & - P_BC = loadCases(currentLoadCase)%P, & - rotation_BC = loadCases(currentLoadCase)%rotation) - end select - - case(FIELD_THERMAL_ID) - call spectral_thermal_forward (& - guess,timeinc,timeIncOld,remainingLoadCaseTime) - - case(FIELD_DAMAGE_ID) - call spectral_damage_forward (& - guess,timeinc,timeIncOld,remainingLoadCaseTime) - end select - enddo - -!-------------------------------------------------------------------------------------------------- -! solve fields - stagIter = 0_pInt - stagIterate = .true. - do while (stagIterate) - do field = 1, nActiveFields - select case(loadCases(currentLoadCase)%ID(field)) - case(FIELD_MECH_ID) - select case (spectral_solver) - case (DAMASK_spectral_SolverBasicPETSc_label) - solres(field) = BasicPETSC_solution (& - incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & - P_BC = loadCases(currentLoadCase)%P, & - F_BC = loadCases(currentLoadCase)%deformation, & - rotation_BC = loadCases(currentLoadCase)%rotation) - - case (DAMASK_spectral_SolverAL_label) - solres(field) = AL_solution (& - incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & - P_BC = loadCases(currentLoadCase)%P, & - F_BC = loadCases(currentLoadCase)%deformation, & - rotation_BC = loadCases(currentLoadCase)%rotation) - - case (DAMASK_spectral_SolverPolarisation_label) - solres(field) = Polarisation_solution (& - incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & - P_BC = loadCases(currentLoadCase)%P, & - F_BC = loadCases(currentLoadCase)%deformation, & - rotation_BC = loadCases(currentLoadCase)%rotation) - - end select - - case(FIELD_THERMAL_ID) - solres(field) = spectral_thermal_solution (& - guess,timeinc,timeIncOld,remainingLoadCaseTime) - - case(FIELD_DAMAGE_ID) - solres(field) = spectral_damage_solution (& - guess,timeinc,timeIncOld,remainingLoadCaseTime) - - end select - if(.not. solres(field)%converged) exit ! no solution found - enddo - stagIter = stagIter + 1_pInt - stagIterate = stagIter < stagItMax .and. & - all(solres(:)%converged) .and. & - .not. all(solres(:)%stagConverged) - enddo - -!-------------------------------------------------------------------------------------------------- -! check solution - cutBack = .False. - if(solres(1)%termIll .or. .not. all(solres(:)%converged .and. solres(:)%stagConverged)) then ! no solution found - if (cutBackLevel < maxCutBack) then ! do cut back - if (worldrank == 0) write(6,'(/,a)') ' cut back detected' - cutBack = .True. - stepFraction = (stepFraction - 1_pInt) * subStepFactor ! adjust to new denominator - cutBackLevel = cutBackLevel + 1_pInt - time = time - timeinc ! rewind time - timeinc = timeinc/2.0_pReal - elseif (solres(1)%termIll) then ! material point model cannot find a solution, exit in any casy - call IO_warning(850_pInt) - call quit(-1_pInt*(lastRestartWritten+1_pInt)) ! quit and provide information about last restart inc written (e.g. for regridding) - elseif (continueCalculation == 1_pInt) then - guess = .true. ! accept non converged BVP solution - else ! default behavior, exit if spectral solver does not converge - call IO_warning(850_pInt) - call quit(-1_pInt*(lastRestartWritten+1_pInt)) ! quit and provide information about last restart inc written (e.g. for regridding) - endif - else - guess = .true. ! start guessing after first converged (sub)inc - endif - if (.not. cutBack) then - if (worldrank == 0) then - write(statUnit,*) totalIncsCounter, time, cutBackLevel, & - solres%converged, solres%iterationsNeeded ! write statistics about accepted solution - flush(statUnit) - endif - endif - enddo subIncLooping - cutBackLevel = max(0_pInt, cutBackLevel - 1_pInt) ! try half number of subincs next inc - if(all(solres(:)%converged)) then ! report converged inc - convergedCounter = convergedCounter + 1_pInt - if (worldrank == 0) & - write(6,'(/,a,'//IO_intOut(totalIncsCounter)//',a)') & - ' increment ', totalIncsCounter, ' converged' - else - if (worldrank == 0) & - write(6,'(/,a,'//IO_intOut(totalIncsCounter)//',a)') & ! report non-converged inc - ' increment ', totalIncsCounter, ' NOT converged' - notConvergedCounter = notConvergedCounter + 1_pInt - endif; flush(6) - if (mod(inc,loadCases(currentLoadCase)%outputFrequency) == 0_pInt) then ! at output frequency - if (worldrank == 0) & - write(6,'(1/,a)') ' ... writing results to file ......................................' - call materialpoint_postResults() - call MPI_file_seek (resUnit,fileOffset,MPI_SEEK_SET,ierr) - do i=1, size(materialpoint_results,3)/(maxByteOut/(materialpoint_sizeResults*pReal))+1 ! slice the output of my process in chunks not exceeding the limit for one output - outputIndex=[(i-1)*maxByteOut/pReal/materialpoint_sizeResults+1, & - min(i*maxByteOut/pReal/materialpoint_sizeResults,size(materialpoint_results,3))] - call MPI_file_write(resUnit,reshape(materialpoint_results(:,:,outputIndex(1):outputIndex(2)),& - [(outputIndex(2)-outputIndex(1)+1)*materialpoint_sizeResults]), & - (outputIndex(2)-outputIndex(1)+1)*materialpoint_sizeResults,& - MPI_DOUBLE, MPI_STATUS_IGNORE, ierr) - fileOffset = fileOffset + sum(outputSize) ! forward to current file position - enddo - endif - if( loadCases(currentLoadCase)%restartFrequency > 0_pInt .and. & ! at frequency of writing restart information set restart parameter for FEsolving - mod(inc,loadCases(currentLoadCase)%restartFrequency) == 0_pInt) then ! first call to CPFEM_general will write? - restartWrite = .true. - lastRestartWritten = inc - endif - else forwarding - time = time + timeinc - guess = .true. - endif forwarding - - enddo incLooping - enddo loadCaseLooping - -!-------------------------------------------------------------------------------------------------- -! report summary of whole calculation - if (worldrank == 0) then - write(6,'(/,a)') ' ###########################################################################' - write(6,'(1x,i6.6,a,i6.6,a,f5.1,a)') convergedCounter, ' out of ', & - notConvergedCounter + convergedCounter, ' (', & - real(convergedCounter, pReal)/& - real(notConvergedCounter + convergedCounter,pReal)*100.0_pReal, & - ' %) increments converged!' - endif - call MPI_file_close(resUnit,ierr) - close(statUnit) - - do field = 1, nActiveFields - select case(loadCases(1)%ID(field)) - case(FIELD_MECH_ID) - select case (spectral_solver) - case (DAMASK_spectral_SolverBasicPETSc_label) - call BasicPETSC_destroy() - case (DAMASK_spectral_SolverAL_label) - call AL_destroy() - case (DAMASK_spectral_SolverPolarisation_label) - call Polarisation_destroy() - end select - case(FIELD_THERMAL_ID) - call spectral_thermal_destroy() - case(FIELD_DAMAGE_ID) - call spectral_damage_destroy() - end select - enddo - call utilities_destroy() - - call PetscFinalize(ierr); CHKERRQ(ierr) - - if (notConvergedCounter > 0_pInt) call quit(3_pInt) ! error if some are not converged - call quit(0_pInt) ! no complains ;) - -end program DAMASK_spectral - - -!-------------------------------------------------------------------------------------------------- -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief quit subroutine to mimic behavior of FEM solvers -!> @details exits the Spectral solver and reports time and duration. Exit code 0 signals -!> everything went fine. Exit code 1 signals an error, message according to IO_error. Exit code -!> 2 signals request for regridding, increment of last saved restart information is written to -!> stderr. Exit code 3 signals no severe problems, but some increments did not converge -!-------------------------------------------------------------------------------------------------- -subroutine quit(stop_id) - use prec, only: & - pInt - use numerics, only: & - worldrank - - implicit none - integer(pInt), intent(in) :: stop_id - integer, dimension(8) :: dateAndTime ! type default integer - - if (worldrank == 0_pInt) then - call date_and_time(values = dateAndTime) - write(6,'(/,a)') 'DAMASK terminated on:' - write(6,'(a,2(i2.2,a),i4.4)') 'Date: ',dateAndTime(3),'/',& - dateAndTime(2),'/',& - dateAndTime(1) - write(6,'(a,2(i2.2,a),i2.2)') 'Time: ',dateAndTime(5),':',& - dateAndTime(6),':',& - dateAndTime(7) - endif - - if (stop_id == 0_pInt) stop 0 ! normal termination - if (stop_id < 0_pInt) then ! trigger regridding - if (worldrank == 0_pInt) & - write(0,'(a,i6)') 'restart information available at ', stop_id*(-1_pInt) - stop 2 - endif - if (stop_id == 3_pInt) stop 3 ! not all incs converged - stop 1 ! error (message from IO_error) - -end subroutine quit diff --git a/code/FEsolving.f90 b/code/FEsolving.f90 deleted file mode 100644 index ed11448d7..000000000 --- a/code/FEsolving.f90 +++ /dev/null @@ -1,171 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief triggering reading in of restart information when doing a restart -!> @todo Descriptions for public variables needed -!-------------------------------------------------------------------------------------------------- -module FEsolving - use prec, only: & - pInt, & - pReal - - implicit none - private - integer(pInt), public :: & - restartInc = 1_pInt !< needs description - - logical, public :: & - symmetricSolver = .false., & !< use a symmetric FEM solver - restartWrite = .false., & !< write current state to enable restart - restartRead = .false., & !< restart information to continue calculation from saved state - terminallyIll = .false. !< at least one material point is terminally ill - - integer(pInt), dimension(:,:), allocatable, public :: & - FEsolving_execIP !< for ping-pong scheme always range to max IP, otherwise one specific IP - - integer(pInt), dimension(2), public :: & - FEsolving_execElem !< for ping-pong scheme always whole range, otherwise one specific element - - character(len=1024), public :: & - modelName !< needs description - - logical, dimension(:,:), allocatable, public :: & - calcMode !< do calculation or simply collect when using ping pong scheme - - public :: FE_init - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief determine whether a symmetric solver is used and whether restart is requested -!> @details restart information is found in input file in case of FEM solvers, in case of spectal -!> solver the information is provided by the interface module -!-------------------------------------------------------------------------------------------------- -subroutine FE_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_FEsolving, & - debug_levelBasic - use IO, only: & - IO_stringPos, & - IO_stringValue, & - IO_intValue, & - IO_lc, & -#if defined(Marc4DAMASK) || defined(Abaqus) - IO_open_inputFile, & - IO_open_logFile, & -#endif - IO_warning, & - IO_timeStamp - use DAMASK_interface - use numerics, only: & - worldrank - - implicit none -#if defined(Marc4DAMASK) || defined(Abaqus) - integer(pInt), parameter :: & - FILEUNIT = 222_pInt - integer(pInt) :: j - character(len=65536) :: tag, line - integer(pInt), allocatable, dimension(:) :: chunkPos -#endif - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- FEsolving init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - modelName = getSolverJobName() -#ifdef Spectral - restartInc = spectralRestartInc - if(restartInc <= 0_pInt) then - call IO_warning(warning_ID=34_pInt) - restartInc = 1_pInt - endif - restartRead = restartInc > 1_pInt ! only read in if "true" restart requested -#elif defined FEM - restartInc = FEMRestartInc - if(restartInc <= 0_pInt) then - call IO_warning(warning_ID=34_pInt) - restartInc = 1_pInt - endif - restartRead = restartInc > 1_pInt -#else - call IO_open_inputFile(FILEUNIT,modelName) - rewind(FILEUNIT) - do - read (FILEUNIT,'(a1024)',END=100) line - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('solver') - read (FILEUNIT,'(a1024)',END=100) line ! next line - chunkPos = IO_stringPos(line) - symmetricSolver = (IO_intValue(line,chunkPos,2_pInt) /= 1_pInt) - case ('restart') - read (FILEUNIT,'(a1024)',END=100) line ! next line - chunkPos = IO_stringPos(line) - restartWrite = iand(IO_intValue(line,chunkPos,1_pInt),1_pInt) > 0_pInt - restartRead = iand(IO_intValue(line,chunkPos,1_pInt),2_pInt) > 0_pInt - case ('*restart') - do j=2_pInt,chunkPos(1) - restartWrite = (IO_lc(IO_StringValue(line,chunkPos,j)) == 'write') .or. restartWrite - restartRead = (IO_lc(IO_StringValue(line,chunkPos,j)) == 'read') .or. restartRead - enddo - if(restartWrite) then - do j=2_pInt,chunkPos(1) - restartWrite = (IO_lc(IO_StringValue(line,chunkPos,j)) /= 'frequency=0') .and. restartWrite - enddo - endif - end select - enddo - 100 close(FILEUNIT) - - if (restartRead) then -#ifdef Marc4DAMASK - call IO_open_logFile(FILEUNIT) - rewind(FILEUNIT) - do - read (FILEUNIT,'(a1024)',END=200) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'restart' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'file' .and. & - IO_lc(IO_stringValue(line,chunkPos,3_pInt)) == 'job' .and. & - IO_lc(IO_stringValue(line,chunkPos,4_pInt)) == 'id' ) & - modelName = IO_StringValue(line,chunkPos,6_pInt) - enddo -#else - call IO_open_inputFile(FILEUNIT,modelName) - rewind(FILEUNIT) - do - read (FILEUNIT,'(a1024)',END=200) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt))=='*heading') then - read (FILEUNIT,'(a1024)',END=200) line - chunkPos = IO_stringPos(line) - modelName = IO_StringValue(line,chunkPos,1_pInt) - endif - enddo -#endif - 200 close(FILEUNIT) - endif - -!-------------------------------------------------------------------------------------------------- -! the following array are allocated by mesh.f90 and need to be deallocated in case of regridding - if (allocated(calcMode)) deallocate(calcMode) - if (allocated(FEsolving_execIP)) deallocate(FEsolving_execIP) -#endif - if (iand(debug_level(debug_FEsolving),debug_levelBasic) /= 0_pInt) then - write(6,'(a21,l1)') ' restart writing: ', restartWrite - write(6,'(a21,l1)') ' restart reading: ', restartRead - if (restartRead) write(6,'(a,/)') ' restart Job: '//trim(modelName) - endif - -end subroutine FE_init - -end module FEsolving diff --git a/code/IO.f90 b/code/IO.f90 deleted file mode 100644 index 95ac6fffd..000000000 --- a/code/IO.f90 +++ /dev/null @@ -1,2470 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @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 Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief input/output functions, partly depending on chosen solver -!-------------------------------------------------------------------------------------------------- -module IO -#ifdef HDF - use hdf5, only: & - HID_T -#endif - use prec, only: & - pInt, & - pReal - - implicit none - private - character(len=5), parameter, public :: & - IO_EOF = '#EOF#' !< end of file string -#ifdef HDF - integer(HID_T), public, protected :: tempCoordinates, tempResults - integer(HID_T), private :: resultsFile, tempFile - integer(pInt), private :: currentInc -#endif - - public :: & -#ifdef HDF - HDF5_mappingConstitutive, & - HDF5_mappingHomogenization, & - HDF5_mappingCells, & - HDF5_addGroup ,& - HDF5_forwardResults, & - HDF5_addScalarDataset, & - IO_formatIntToString ,& -#endif - IO_init, & - IO_read, & - IO_checkAndRewind, & - IO_open_file_stat, & - IO_open_jobFile_stat, & - IO_open_file, & - IO_open_jobFile, & - IO_write_jobFile, & - IO_write_jobRealFile, & - IO_write_jobIntFile, & - IO_read_realFile, & - IO_read_intFile, & - IO_hybridIA, & - IO_isBlank, & - IO_getTag, & - IO_countSections, & - IO_countTagInPart, & - IO_spotTagInPart, & - IO_globalTagInPart, & - IO_stringPos, & - IO_stringValue, & - IO_fixedStringValue ,& - IO_floatValue, & - IO_fixedNoEFloatValue, & - IO_intValue, & - IO_fixedIntValue, & - IO_lc, & - IO_skipChunks, & - IO_extractValue, & - IO_countDataLines, & - IO_countContinuousIntValues, & - IO_continuousIntValues, & - IO_error, & - IO_warning, & - IO_intOut, & - IO_timeStamp -#if defined(Marc4DAMASK) || defined(Abaqus) - public :: & - IO_open_inputFile, & - IO_open_logFile -#endif -#ifdef Abaqus - public :: & - IO_abaqus_hasNoPart -#endif - private :: & - IO_fixedFloatValue, & - IO_verifyFloatValue, & - IO_verifyIntValue -#ifdef Abaqus - private :: & - abaqus_assembleInputFile -#endif - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief only outputs revision number -!-------------------------------------------------------------------------------------------------- -subroutine IO_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - - implicit none - integer(pInt) :: worldrank = 0_pInt -#ifdef PETSc -#include - PetscErrorCode :: ierr -#endif - external :: & - MPI_Comm_rank, & - MPI_Abort - -#ifdef PETSc - call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) -#endif - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- IO init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -#ifdef HDF - call HDF5_createJobFile -#endif - -end subroutine IO_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief recursively reads a line from a text file. -!! Recursion is triggered by "{path/to/inputfile}" in a line -!-------------------------------------------------------------------------------------------------- -recursive function IO_read(fileUnit,reset) result(line) - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - logical, intent(in), optional :: reset - - integer(pInt), dimension(10) :: unitOn = 0_pInt ! save the stack of recursive file units - integer(pInt) :: stack = 1_pInt ! current stack position - character(len=8192), dimension(10) :: pathOn = '' - character(len=512) :: path,input - integer(pInt) :: myStat - character(len=65536) :: line - - character(len=*), parameter :: SEP = achar(47)//achar(92) ! forward and backward slash ("/", "\") - -!-------------------------------------------------------------------------------------------------- -! reset case - if(present(reset)) then; if (reset) then ! do not short circuit here - do while (stack > 1_pInt) ! can go back to former file - close(unitOn(stack)) - stack = stack-1_pInt - enddo - return - endif; endif - - -!-------------------------------------------------------------------------------------------------- -! read from file - unitOn(1) = fileUnit - - read(unitOn(stack),'(a65536)',END=100) line - - input = IO_getTag(line,'{','}') - -!-------------------------------------------------------------------------------------------------- -! normal case - if (input == '') return ! regular line -!-------------------------------------------------------------------------------------------------- -! recursion case - if (stack >= 10_pInt) call IO_error(104_pInt,ext_msg=input) ! recursion limit reached - - inquire(UNIT=unitOn(stack),NAME=path) ! path of current file - stack = stack+1_pInt - if(scan(input,SEP) == 1) then ! absolut path given (UNIX only) - pathOn(stack) = input - else - pathOn(stack) = path(1:scan(path,SEP,.true.))//input ! glue include to current file's dir - endif - - open(newunit=unitOn(stack),iostat=myStat,file=pathOn(stack)) ! open included file - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=pathOn(stack)) - - line = IO_read(fileUnit) - - return - -!-------------------------------------------------------------------------------------------------- -! end of file case -100 if (stack > 1_pInt) then ! can go back to former file - close(unitOn(stack)) - stack = stack-1_pInt - line = IO_read(fileUnit) - else ! top-most file reached - line = IO_EOF - endif - -end function IO_read - - -!-------------------------------------------------------------------------------------------------- -!> @brief checks if unit is opened for reading, if true rewinds. Otherwise stops with -!! error message -!-------------------------------------------------------------------------------------------------- -subroutine IO_checkAndRewind(fileUnit) - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - logical :: fileOpened - character(len=15) :: fileRead - - inquire(unit=fileUnit, opened=fileOpened, read=fileRead) - if (.not. fileOpened .or. trim(fileRead)/='YES') call IO_error(102_pInt) - rewind(fileUnit) - -end subroutine IO_checkAndRewind - - -!-------------------------------------------------------------------------------------------------- -!> @brief opens existing file for reading to given unit. Path to file is relative to working -!! directory -!> @details like IO_open_file_stat, but error is handled via call to IO_error and not via return -!! value -!-------------------------------------------------------------------------------------------------- -subroutine IO_open_file(fileUnit,relPath) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: relPath !< relative path from working directory - - integer(pInt) :: myStat - character(len=1024) :: path - - path = trim(getSolverWorkingDirectoryName())//relPath - open(fileUnit,status='old',iostat=myStat,file=path) - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) - -end subroutine IO_open_file - - -!-------------------------------------------------------------------------------------------------- -!> @brief opens existing file for reading to given unit. Path to file is relative to working -!! directory -!> @details Like IO_open_file, but error is handled via return value and not via call to IO_error -!-------------------------------------------------------------------------------------------------- -logical function IO_open_file_stat(fileUnit,relPath) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: relPath !< relative path from working directory - - integer(pInt) :: myStat - character(len=1024) :: path - - path = trim(getSolverWorkingDirectoryName())//relPath - open(fileUnit,status='old',iostat=myStat,file=path) - IO_open_file_stat = (myStat == 0_pInt) - -end function IO_open_file_stat - - -!-------------------------------------------------------------------------------------------------- -!> @brief opens existing file for reading to given unit. File is named after solver job name -!! plus given extension and located in current working directory -!> @details like IO_open_jobFile_stat, but error is handled via call to IO_error and not via return -!! value -!-------------------------------------------------------------------------------------------------- -subroutine IO_open_jobFile(fileUnit,ext) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & - getSolverJobName - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: ext !< extension of file - - integer(pInt) :: myStat - character(len=1024) :: path - - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext - open(fileUnit,status='old',iostat=myStat,file=path) - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) - -end subroutine IO_open_jobFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief opens existing file for reading to given unit. File is named after solver job name -!! plus given extension and located in current working directory -!> @details Like IO_open_jobFile, but error is handled via return value and not via call to -!! IO_error -!-------------------------------------------------------------------------------------------------- -logical function IO_open_jobFile_stat(fileUnit,ext) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & - getSolverJobName - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: ext !< extension of file - - integer(pInt) :: myStat - character(len=1024) :: path - - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext - open(fileUnit,status='old',iostat=myStat,file=path) - IO_open_jobFile_stat = (myStat == 0_pInt) - -end function IO_open_JobFile_stat - - -#if defined(Marc4DAMASK) || defined(Abaqus) -!-------------------------------------------------------------------------------------------------- -!> @brief opens FEM input file for reading located in current working directory to given unit -!-------------------------------------------------------------------------------------------------- -subroutine IO_open_inputFile(fileUnit,modelName) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName,& - getSolverJobName, & - inputFileExtension - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: modelName !< model name, in case of restart not solver job name - - integer(pInt) :: myStat - character(len=1024) :: path -#ifdef Abaqus - integer(pInt) :: fileType - - fileType = 1_pInt ! assume .pes - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension(fileType) ! attempt .pes, if it exists: it should be used - open(fileUnit+1,status='old',iostat=myStat,file=path) - if(myStat /= 0_pInt) then ! if .pes does not work / exist; use conventional extension, i.e.".inp" - fileType = 2_pInt - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension(fileType) - open(fileUnit+1,status='old',iostat=myStat,file=path) - endif - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) - - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension(fileType)//'_assembly' - open(fileUnit,iostat=myStat,file=path) - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) - if (.not.abaqus_assembleInputFile(fileUnit,fileUnit+1_pInt)) call IO_error(103_pInt) ! strip comments and concatenate any "include"s - close(fileUnit+1_pInt) -#endif -#ifdef Marc4DAMASK - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension - open(fileUnit,status='old',iostat=myStat,file=path) - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) -#endif - -end subroutine IO_open_inputFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief opens existing FEM log file for reading to given unit. File is named after solver job -!! name and located in current working directory -!-------------------------------------------------------------------------------------------------- -subroutine IO_open_logFile(fileUnit) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & - getSolverJobName, & - LogFileExtension - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - - integer(pInt) :: myStat - character(len=1024) :: path - - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//LogFileExtension - open(fileUnit,status='old',iostat=myStat,file=path) - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) - -end subroutine IO_open_logFile -#endif - - -!-------------------------------------------------------------------------------------------------- -!> @brief opens ASCII file to given unit for writing. File is named after solver job name plus -!! given extension and located in current working directory -!-------------------------------------------------------------------------------------------------- -subroutine IO_write_jobFile(fileUnit,ext) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & - getSolverJobName - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: ext !< extension of file - - integer(pInt) :: myStat - character(len=1024) :: path - - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext - open(fileUnit,status='replace',iostat=myStat,file=path) - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) - -end subroutine IO_write_jobFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief opens binary file containing array of pReal numbers to given unit for writing. File is -!! named after solver job name plus given extension and located in current working directory -!-------------------------------------------------------------------------------------------------- -subroutine IO_write_jobRealFile(fileUnit,ext,recMultiplier) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & - getSolverJobName - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: ext !< extension of file - integer(pInt), intent(in), optional :: recMultiplier !< record length (multiple of pReal Numbers, if not given set to one) - - integer(pInt) :: myStat - character(len=1024) :: path - - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext - if (present(recMultiplier)) then - open(fileUnit,status='replace',form='unformatted',access='direct', & - recl=pReal*recMultiplier,iostat=myStat,file=path) - else - open(fileUnit,status='replace',form='unformatted',access='direct', & - recl=pReal,iostat=myStat,file=path) - endif - - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) - -end subroutine IO_write_jobRealFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief opens binary file containing array of pInt numbers to given unit for writing. File is -!! named after solver job name plus given extension and located in current working directory -!-------------------------------------------------------------------------------------------------- -subroutine IO_write_jobIntFile(fileUnit,ext,recMultiplier) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & - getSolverJobName - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: ext !< extension of file - integer(pInt), intent(in), optional :: recMultiplier !< record length (multiple of pReal Numbers, if not given set to one) - - integer(pInt) :: myStat - character(len=1024) :: path - - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext - if (present(recMultiplier)) then - open(fileUnit,status='replace',form='unformatted',access='direct', & - recl=pInt*recMultiplier,iostat=myStat,file=path) - else - open(fileUnit,status='replace',form='unformatted',access='direct', & - recl=pInt,iostat=myStat,file=path) - endif - - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) - -end subroutine IO_write_jobIntFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief opens binary file containing array of pReal numbers to given unit for reading. File is -!! located in current working directory -!-------------------------------------------------------------------------------------------------- -subroutine IO_read_realFile(fileUnit,ext,modelName,recMultiplier) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: ext, & !< extension of file - modelName !< model name, in case of restart not solver job name - integer(pInt), intent(in), optional :: recMultiplier !< record length (multiple of pReal Numbers, if not given set to one) - - integer(pInt) :: myStat - character(len=1024) :: path - - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//'.'//ext - if (present(recMultiplier)) then - open(fileUnit,status='old',form='unformatted',access='direct', & - recl=pReal*recMultiplier,iostat=myStat,file=path) - else - open(fileUnit,status='old',form='unformatted',access='direct', & - recl=pReal,iostat=myStat,file=path) - endif - if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) - -end subroutine IO_read_realFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief opens binary file containing array of pInt numbers to given unit for reading. File is -!! located in current working directory -!-------------------------------------------------------------------------------------------------- -subroutine IO_read_intFile(fileUnit,ext,modelName,recMultiplier) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName - - implicit none - integer(pInt), intent(in) :: fileUnit !< file unit - character(len=*), intent(in) :: ext, & !< extension of file - modelName !< model name, in case of restart not solver job name - integer(pInt), intent(in), optional :: recMultiplier !< record length (multiple of pReal Numbers, if not given set to one) - - integer(pInt) :: myStat - character(len=1024) :: path - - path = trim(getSolverWorkingDirectoryName())//trim(modelName)//'.'//ext - if (present(recMultiplier)) then - open(fileUnit,status='old',form='unformatted',access='direct', & - recl=pInt*recMultiplier,iostat=myStat,file=path) - else - open(fileUnit,status='old',form='unformatted',access='direct', & - recl=pInt,iostat=myStat,file=path) - endif - if (myStat /= 0) call IO_error(100_pInt,ext_msg=path) - -end subroutine IO_read_intFile - - -#ifdef Abaqus -!-------------------------------------------------------------------------------------------------- -!> @brief check if the input file for Abaqus contains part info -!-------------------------------------------------------------------------------------------------- -logical function IO_abaqus_hasNoPart(fileUnit) - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=65536) :: line - - IO_abaqus_hasNoPart = .true. - -610 FORMAT(A65536) - rewind(fileUnit) - do - read(fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - if (IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) then - IO_abaqus_hasNoPart = .false. - exit - endif - enddo - -620 end function IO_abaqus_hasNoPart -#endif - -!-------------------------------------------------------------------------------------------------- -!> @brief hybrid IA sampling of ODFfile -!-------------------------------------------------------------------------------------------------- -function IO_hybridIA(Nast,ODFfileName) - use prec, only: & - tol_math_check - - implicit none - integer(pInt), intent(in) :: Nast !< number of samples? - real(pReal), dimension(3,Nast) :: IO_hybridIA - character(len=*), intent(in) :: ODFfileName !< name of ODF file including total path - -!-------------------------------------------------------------------------------------------------- -! math module is not available - real(pReal), parameter :: PI = 3.14159265358979323846264338327950288419716939937510_pReal - real(pReal), parameter :: INRAD = PI/180.0_pReal - - integer(pInt) :: i,j,bin,NnonZero,Nset,Nreps,reps,phi1,Phi,phi2 - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt), dimension(3) :: steps !< number of steps in phi1, Phi, and phi2 direction - integer(pInt), dimension(4) :: columns !< columns in linearODF file where eulerangles and density are located - integer(pInt), dimension(:), allocatable :: binSet - real(pReal) :: center,sum_dV_V,prob,dg_0,C,lowerC,upperC,rnd - real(pReal), dimension(2,3) :: limits !< starting and end values for eulerangles - real(pReal), dimension(3) :: deltas, & !< angular step size in phi1, Phi, and phi2 direction - eulers !< euler angles when reading from file - real(pReal), dimension(:,:,:), allocatable :: dV_V - character(len=65536) :: line, keyword - integer(pInt) :: headerLength - integer(pInt), parameter :: FILEUNIT = 999_pInt - - IO_hybridIA = 0.0_pReal ! initialize return value for case of error - write(6,'(/,a,/)',advance='no') ' Using linear ODF file: '//trim(ODFfileName) - -!-------------------------------------------------------------------------------------------------- -! parse header of ODF file - call IO_open_file(FILEUNIT,ODFfileName) - headerLength = 0_pInt - line=IO_read(FILEUNIT) - chunkPos = IO_stringPos(line) - keyword = IO_lc(IO_StringValue(line,chunkPos,2_pInt,.true.)) - if (keyword(1:4) == 'head') then - headerLength = IO_intValue(line,chunkPos,1_pInt) + 1_pInt - else - call IO_error(error_ID=156_pInt, ext_msg='no header found') - endif - -!-------------------------------------------------------------------------------------------------- -! figure out columns containing data - do i = 1_pInt, headerLength-1_pInt - line=IO_read(FILEUNIT) - enddo - columns = 0_pInt - chunkPos = IO_stringPos(line) - do i = 1_pInt, chunkPos(1) - select case ( IO_lc(IO_StringValue(line,chunkPos,i,.true.)) ) - case ('phi1') - columns(1) = i - case ('phi') - columns(2) = i - case ('phi2') - columns(3) = i - case ('intensity') - columns(4) = i - end select - enddo - - if (any(columns<1)) call IO_error(error_ID = 156_pInt, ext_msg='could not find expected header') - -!-------------------------------------------------------------------------------------------------- -! determine limits, number of steps and step size - limits(1,1:3) = 721.0_pReal - limits(2,1:3) = -1.0_pReal - steps = 0_pInt - - line=IO_read(FILEUNIT) - do while (trim(line) /= IO_EOF) - chunkPos = IO_stringPos(line) - eulers=[IO_floatValue(line,chunkPos,columns(1)),& - IO_floatValue(line,chunkPos,columns(2)),& - IO_floatValue(line,chunkPos,columns(3))] - steps = steps + merge(1,0,eulers>limits(2,1:3)) - limits(1,1:3) = min(limits(1,1:3),eulers) - limits(2,1:3) = max(limits(2,1:3),eulers) - line=IO_read(FILEUNIT) - enddo - - deltas = (limits(2,1:3)-limits(1,1:3))/real(steps-1_pInt,pReal) - - write(6,'(/,a,/,3(2x,f12.4,1x))',advance='no') ' Starting angles / ° = ',limits(1,1:3) - write(6,'(/,a,/,3(2x,f12.4,1x))',advance='no') ' Ending angles / ° = ',limits(2,1:3) - write(6,'(/,a,/,3(2x,f12.4,1x))',advance='no') ' Angular steps / ° = ',deltas - - if (all(abs(limits(1,1:3)) < tol_math_check)) then - write(6,'(/,a,/)',advance='no') ' assuming vertex centered data' - center = 0.0_pReal ! no need to shift - if (any(mod(int(limits(2,1:3),pInt),90)==0)) & - call IO_error(error_ID = 156_pInt, ext_msg='linear ODF data repeated at right boundary') - else - write(6,'(/,a,/)',advance='no') ' assuming cell centered data' - center = 0.5_pReal ! shift data by half of a bin - endif - - limits = limits*INRAD - deltas = deltas*INRAD - -!-------------------------------------------------------------------------------------------------- -! read in data - allocate(dV_V(steps(3),steps(2),steps(1)),source=0.0_pReal) - sum_dV_V = 0.0_pReal - dg_0 = deltas(1)*deltas(3)*2.0_pReal*sin(deltas(2)/2.0_pReal) - NnonZero = 0_pInt - - call IO_checkAndRewind(FILEUNIT) ! forward - do i = 1_pInt, headerLength - line=IO_read(FILEUNIT) - enddo - - do phi1=1_pInt,steps(1); do Phi=1_pInt,steps(2); do phi2=1_pInt,steps(3) - line=IO_read(FILEUNIT) - chunkPos = IO_stringPos(line) - eulers=[IO_floatValue(line,chunkPos,columns(1)),& ! read in again for consistency check only - IO_floatValue(line,chunkPos,columns(2)),& - IO_floatValue(line,chunkPos,columns(3))]*INRAD - if (any(abs((real([phi1,phi,phi2],pReal) -1.0_pReal + center)*deltas-eulers)>tol_math_check)) & ! check if data is in expected order (phi2 fast) and correct for Fortran starting at 1 - call IO_error(error_ID = 156_pInt, ext_msg='linear ODF data not in expected order') - - prob = IO_floatValue(line,chunkPos,columns(4)) - if (prob > 0.0_pReal) then - NnonZero = NnonZero+1_pInt - sum_dV_V = sum_dV_V+prob - else - prob = 0.0_pReal - endif - dV_V(phi2,Phi,phi1) = prob*dg_0*sin((Phi-1.0_pReal+center)*deltas(2)) - enddo; enddo; enddo - close(FILEUNIT) - dV_V = dV_V/sum_dV_V ! normalize to 1 - -!-------------------------------------------------------------------------------------------------- -! now fix bounds - Nset = max(Nast,NnonZero) ! if less than non-zero voxel count requested, sample at least that much - lowerC = 0.0_pReal - upperC = real(Nset, pReal) - - do while (hybridIA_reps(dV_V,steps,upperC) < Nset) - lowerC = upperC - upperC = upperC*2.0_pReal - enddo - -!-------------------------------------------------------------------------------------------------- -! binary search for best C - do - C = (upperC+lowerC)/2.0_pReal - Nreps = hybridIA_reps(dV_V,steps,C) - if (abs(upperC-lowerC) < upperC*1.0e-14_pReal) then - C = upperC - Nreps = hybridIA_reps(dV_V,steps,C) - exit - elseif (Nreps < Nset) then - lowerC = C - elseif (Nreps > Nset) then - upperC = C - else - exit - endif - enddo - - allocate(binSet(Nreps)) - bin = 0_pInt ! bin counter - i = 1_pInt ! set counter - do phi1=1_pInt,steps(1); do Phi=1_pInt,steps(2) ;do phi2=1_pInt,steps(3) - reps = nint(C*dV_V(phi2,Phi,phi1), pInt) - binSet(i:i+reps-1) = bin - bin = bin+1_pInt ! advance bin - i = i+reps ! advance set - enddo; enddo; enddo - - do i=1_pInt,Nast - if (i < Nast) then - call random_number(rnd) - j = nint(rnd*(Nreps-i)+i+0.5_pReal,pInt) - else - j = i - endif - bin = binSet(j) - IO_hybridIA(1,i) = deltas(1)*(real(mod(bin/(steps(3)*steps(2)),steps(1)),pReal)+center) ! phi1 - IO_hybridIA(2,i) = deltas(2)*(real(mod(bin/ steps(3) ,steps(2)),pReal)+center) ! Phi - IO_hybridIA(3,i) = deltas(3)*(real(mod(bin ,steps(3)),pReal)+center) ! phi2 - binSet(j) = binSet(i) - enddo - - contains - !-------------------------------------------------------------------------------------------------- - !> @brief counts hybrid IA repetitions - !-------------------------------------------------------------------------------------------------- - integer(pInt) pure function hybridIA_reps(dV_V,steps,C) - - implicit none - integer(pInt), intent(in), dimension(3) :: steps !< number of bins in Euler space - real(pReal), intent(in), dimension(steps(3),steps(2),steps(1)) :: dV_V !< needs description - real(pReal), intent(in) :: C !< needs description - - integer(pInt) :: phi1,Phi,phi2 - - hybridIA_reps = 0_pInt - do phi1=1_pInt,steps(1); do Phi =1_pInt,steps(2); do phi2=1_pInt,steps(3) - hybridIA_reps = hybridIA_reps+nint(C*dV_V(phi2,Phi,phi1), pInt) - enddo; enddo; enddo - - end function hybridIA_reps - -end function IO_hybridIA - - -!-------------------------------------------------------------------------------------------------- -!> @brief identifies strings without content -!-------------------------------------------------------------------------------------------------- -logical pure function IO_isBlank(string) - - implicit none - character(len=*), intent(in) :: string !< string to check for content - - character(len=*), parameter :: blankChar = achar(32)//achar(9)//achar(10)//achar(13) ! whitespaces - character(len=*), parameter :: comment = achar(35) ! comment id '#' - - integer :: posNonBlank, posComment ! no pInt - - posNonBlank = verify(string,blankChar) - posComment = scan(string,comment) - IO_isBlank = posNonBlank == 0 .or. posNonBlank == posComment - -end function IO_isBlank - - -!-------------------------------------------------------------------------------------------------- -!> @brief get tagged content of string -!-------------------------------------------------------------------------------------------------- -pure function IO_getTag(string,openChar,closeChar) - - implicit none - character(len=*), intent(in) :: string !< string to check for tag - character(len=len_trim(string)) :: IO_getTag - - character(len=*), intent(in) :: openChar, & !< indicates beginning of tag - closeChar !< indicates end of tag - - character(len=*), parameter :: SEP=achar(32)//achar(9)//achar(10)//achar(13) ! whitespaces - - integer :: left,right ! no pInt - - IO_getTag = '' - left = scan(string,openChar) - right = scan(string,closeChar) - - if (left == verify(string,SEP) .and. right > left) & ! openChar is first and closeChar occurs - IO_getTag = string(left+1:right-1) - -end function IO_getTag - - -!-------------------------------------------------------------------------------------------------- -!> @brief count number of [sections] in for given file handle -!-------------------------------------------------------------------------------------------------- -integer(pInt) function IO_countSections(fileUnit,part) - - implicit none - integer(pInt), intent(in) :: fileUnit !< file handle - character(len=*), intent(in) :: part !< part name in which sections are counted - - character(len=65536) :: line - - line = '' - IO_countSections = 0_pInt - rewind(fileUnit) - - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= part) ! search for part - line = IO_read(fileUnit) - enddo - - do while (trim(line) /= IO_EOF) - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') & ! found [section] identifier - IO_countSections = IO_countSections + 1_pInt - enddo - -end function IO_countSections - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns array of tag counts within for at most N [sections] -!-------------------------------------------------------------------------------------------------- -function IO_countTagInPart(fileUnit,part,tag,Nsections) - - implicit none - integer(pInt), intent(in) :: Nsections !< maximum number of sections in which tag is searched for - integer(pInt), dimension(Nsections) :: IO_countTagInPart - integer(pInt), intent(in) :: fileUnit !< file handle - character(len=*),intent(in) :: part, & !< part in which tag is searched for - tag !< tag to search for - - - integer(pInt), dimension(Nsections) :: counter - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: section - character(len=65536) :: line - - line = '' - counter = 0_pInt - section = 0_pInt - - rewind(fileUnit) - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= part) ! search for part - line = IO_read(fileUnit) - enddo - - do while (trim(line) /= IO_EOF) - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') section = section + 1_pInt ! found [section] identifier - if (section > 0) then - chunkPos = IO_stringPos(line) - if (tag == trim(IO_lc(IO_stringValue(line,chunkPos,1_pInt)))) & ! match - counter(section) = counter(section) + 1_pInt - endif - enddo - - IO_countTagInPart = counter - -end function IO_countTagInPart - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns array of tag presence within for at most N [sections] -!-------------------------------------------------------------------------------------------------- -function IO_spotTagInPart(fileUnit,part,tag,Nsections) - - implicit none - integer(pInt), intent(in) :: Nsections !< maximum number of sections in which tag is searched for - logical, dimension(Nsections) :: IO_spotTagInPart - integer(pInt), intent(in) :: fileUnit !< file handle - character(len=*),intent(in) :: part, & !< part in which tag is searched for - tag !< tag to search for - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: section - character(len=65536) :: line - - IO_spotTagInPart = .false. ! assume to nowhere spot tag - section = 0_pInt - line ='' - - rewind(fileUnit) - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= part) ! search for part - line = IO_read(fileUnit) - enddo - - do while (trim(line) /= IO_EOF) - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') section = section + 1_pInt ! found [section] identifier - if (section > 0_pInt) then - chunkPos = IO_stringPos(line) - if (tag == trim(IO_lc(IO_stringValue(line,chunkPos,1_pInt)))) & ! match - IO_spotTagInPart(section) = .true. - endif - enddo - - end function IO_spotTagInPart - - -!-------------------------------------------------------------------------------------------------- -!> @brief return logical whether tag is present within before any [sections] -!-------------------------------------------------------------------------------------------------- -logical function IO_globalTagInPart(fileUnit,part,tag) - - implicit none - integer(pInt), intent(in) :: fileUnit !< file handle - character(len=*),intent(in) :: part, & !< part in which tag is searched for - tag !< tag to search for - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: section - character(len=65536) :: line - - IO_globalTagInPart = .false. ! assume to nowhere spot tag - section = 0_pInt - line ='' - - rewind(fileUnit) - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= part) ! search for part - line = IO_read(fileUnit) - enddo - - do while (trim(line) /= IO_EOF) - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') section = section + 1_pInt ! found [section] identifier - if (section == 0_pInt) then - chunkPos = IO_stringPos(line) - if (tag == trim(IO_lc(IO_stringValue(line,chunkPos,1_pInt)))) & ! match - IO_globalTagInPart = .true. - endif - enddo - -end function IO_globalTagInPart - - -!-------------------------------------------------------------------------------------------------- -!> @brief locates all space-separated chunks in given string and returns array containing number -!! them and the left/right position to be used by IO_xxxVal -!! Array size is dynamically adjusted to number of chunks found in string -!! IMPORTANT: first element contains number of chunks! -!-------------------------------------------------------------------------------------------------- -pure function IO_stringPos(string) - - implicit none - integer(pInt), dimension(:), allocatable :: IO_stringPos - character(len=*), intent(in) :: string !< string in which chunk positions are searched for - - character(len=*), parameter :: SEP=achar(44)//achar(32)//achar(9)//achar(10)//achar(13) ! comma and whitespaces - integer :: left, right ! no pInt (verify and scan return default integer) - - allocate(IO_stringPos(1), source=0_pInt) - right = 0 - - do while (verify(string(right+1:),SEP)>0) - left = right + verify(string(right+1:),SEP) - right = left + scan(string(left:),SEP) - 2 - if ( string(left:left) == '#' ) exit - IO_stringPos = [IO_stringPos,int(left, pInt), int(right, pInt)] - IO_stringPos(1) = IO_stringPos(1)+1_pInt - enddo - -end function IO_stringPos - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads string value at myChunk from string -!-------------------------------------------------------------------------------------------------- -function IO_stringValue(string,chunkPos,myChunk,silent) - - implicit none - integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - character(len=:), allocatable :: IO_stringValue - - logical, optional,intent(in) :: silent !< switch to trigger verbosity - character(len=16), parameter :: MYNAME = 'IO_stringValue: ' - - logical :: warn - - if (.not. present(silent)) then - warn = .false. - else - warn = silent - endif - - IO_stringValue = '' - valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then - if (warn) call IO_warning(201,el=myChunk,ext_msg=MYNAME//trim(string)) - else valuePresent - IO_stringValue = string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) - endif valuePresent - -end function IO_stringValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads string value at myChunk from fixed format string -!-------------------------------------------------------------------------------------------------- -pure function IO_fixedStringValue (string,ends,myChunk) - - implicit none - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - integer(pInt), dimension(:), intent(in) :: ends !< positions of end of each tag/chunk in given string - character(len=ends(myChunk+1)-ends(myChunk)) :: IO_fixedStringValue - character(len=*), intent(in) :: string !< raw input with known ends of each chunk - - IO_fixedStringValue = string(ends(myChunk)+1:ends(myChunk+1)) - -end function IO_fixedStringValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads float value at myChunk from string -!-------------------------------------------------------------------------------------------------- -real(pReal) function IO_floatValue (string,chunkPos,myChunk) - - implicit none - integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - character(len=15), parameter :: MYNAME = 'IO_floatValue: ' - character(len=17), parameter :: VALIDCHARACTERS = '0123456789eEdD.+-' - - IO_floatValue = 0.0_pReal - - valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then - call IO_warning(201,el=myChunk,ext_msg=MYNAME//trim(string)) - else valuePresent - IO_floatValue = & - IO_verifyFloatValue(trim(adjustl(string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)))),& - VALIDCHARACTERS,MYNAME) - endif valuePresent - -end function IO_floatValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads float value at myChunk from fixed format string -!-------------------------------------------------------------------------------------------------- -real(pReal) function IO_fixedFloatValue (string,ends,myChunk) - - implicit none - character(len=*), intent(in) :: string !< raw input with known ends of each chunk - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - integer(pInt), dimension(:), intent(in) :: ends !< positions of end of each tag/chunk in given string - character(len=20), parameter :: MYNAME = 'IO_fixedFloatValue: ' - character(len=17), parameter :: VALIDCHARACTERS = '0123456789eEdD.+-' - - IO_fixedFloatValue = & - IO_verifyFloatValue(trim(adjustl(string(ends(myChunk)+1_pInt:ends(myChunk+1_pInt)))),& - VALIDCHARACTERS,MYNAME) - -end function IO_fixedFloatValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads float x.y+z value at myChunk from format string -!-------------------------------------------------------------------------------------------------- -real(pReal) function IO_fixedNoEFloatValue (string,ends,myChunk) - - implicit none - character(len=*), intent(in) :: string !< raw input with known ends of each chunk - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - integer(pInt), dimension(:), intent(in) :: ends !< positions of end of each tag/chunk in given string - character(len=22), parameter :: MYNAME = 'IO_fixedNoEFloatValue ' - character(len=13), parameter :: VALIDBASE = '0123456789.+-' - character(len=12), parameter :: VALIDEXP = '0123456789+-' - - real(pReal) :: base - integer(pInt) :: expon - integer :: pos_exp - - pos_exp = scan(string(ends(myChunk)+1:ends(myChunk+1)),'+-',back=.true.) - hasExponent: if (pos_exp > 1) then - base = IO_verifyFloatValue(trim(adjustl(string(ends(myChunk)+1_pInt:ends(myChunk)+pos_exp-1_pInt))),& - VALIDBASE,MYNAME//'(base): ') - expon = IO_verifyIntValue(trim(adjustl(string(ends(myChunk)+pos_exp:ends(myChunk+1_pInt)))),& - VALIDEXP,MYNAME//'(exp): ') - else hasExponent - base = IO_verifyFloatValue(trim(adjustl(string(ends(myChunk)+1_pInt:ends(myChunk+1_pInt)))),& - VALIDBASE,MYNAME//'(base): ') - expon = 0_pInt - endif hasExponent - IO_fixedNoEFloatValue = base*10.0_pReal**real(expon,pReal) - -end function IO_fixedNoEFloatValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads integer value at myChunk from string -!-------------------------------------------------------------------------------------------------- -integer(pInt) function IO_intValue(string,chunkPos,myChunk) - - implicit none - character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string - character(len=13), parameter :: MYNAME = 'IO_intValue: ' - character(len=12), parameter :: VALIDCHARACTERS = '0123456789+-' - - IO_intValue = 0_pInt - - valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then - call IO_warning(201,el=myChunk,ext_msg=MYNAME//trim(string)) - else valuePresent - IO_intValue = IO_verifyIntValue(trim(adjustl(string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)))),& - VALIDCHARACTERS,MYNAME) - endif valuePresent - -end function IO_intValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads integer value at myChunk from fixed format string -!-------------------------------------------------------------------------------------------------- -integer(pInt) function IO_fixedIntValue(string,ends,myChunk) - - implicit none - character(len=*), intent(in) :: string !< raw input with known ends of each chunk - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - integer(pInt), dimension(:), intent(in) :: ends !< positions of end of each tag/chunk in given string - character(len=20), parameter :: MYNAME = 'IO_fixedIntValue: ' - character(len=12), parameter :: VALIDCHARACTERS = '0123456789+-' - - IO_fixedIntValue = IO_verifyIntValue(trim(adjustl(string(ends(myChunk)+1_pInt:ends(myChunk+1_pInt)))),& - VALIDCHARACTERS,MYNAME) - -end function IO_fixedIntValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief changes characters in string to lower case -!-------------------------------------------------------------------------------------------------- -pure function IO_lc(string) - - implicit none - character(len=*), intent(in) :: string !< string to convert - character(len=len(string)) :: IO_lc - - character(26), parameter :: LOWER = 'abcdefghijklmnopqrstuvwxyz' - character(26), parameter :: UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - - integer :: i,n ! no pInt (len returns default integer) - - IO_lc = string - do i=1,len(string) - n = index(UPPER,IO_lc(i:i)) - if (n/=0) IO_lc(i:i) = LOWER(n:n) - enddo - -end function IO_lc - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads file to skip (at least) N chunks (may be over multiple lines) -!-------------------------------------------------------------------------------------------------- -subroutine IO_skipChunks(fileUnit,N) - - implicit none - integer(pInt), intent(in) :: fileUnit, & !< file handle - N !< minimum number of chunks to skip - - integer(pInt) :: remainingChunks - character(len=65536) :: line - - line = '' - remainingChunks = N - - do while (trim(line) /= IO_EOF .and. remainingChunks > 0) - line = IO_read(fileUnit) - remainingChunks = remainingChunks - (size(IO_stringPos(line))-1_pInt)/2_pInt - enddo -end subroutine IO_skipChunks - - -!-------------------------------------------------------------------------------------------------- -!> @brief extracts string value from key=value pair and check whether key matches -!-------------------------------------------------------------------------------------------------- -character(len=300) pure function IO_extractValue(pair,key) - - implicit none - character(len=*), intent(in) :: pair, & !< key=value pair - key !< key to be expected - - character(len=*), parameter :: SEP = achar(61) ! '=' - - integer :: myChunk !< position number of desired chunk - - IO_extractValue = '' - - myChunk = scan(pair,SEP) - if (myChunk > 0 .and. pair(:myChunk-1) == key(:myChunk-1)) & - IO_extractValue = pair(myChunk+1:) ! extract value if key matches - -end function IO_extractValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief count lines containig data up to next *keyword -!-------------------------------------------------------------------------------------------------- -integer(pInt) function IO_countDataLines(fileUnit) - - implicit none - integer(pInt), intent(in) :: fileUnit !< file handle - - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=65536) :: line, & - tmp - - IO_countDataLines = 0_pInt - line = '' - - do while (trim(line) /= IO_EOF) - line = IO_read(fileUnit) - chunkPos = IO_stringPos(line) - tmp = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) - if (tmp(1:1) == '*' .and. tmp(2:2) /= '*') then ! found keyword - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - else - if (tmp(2:2) /= '*') IO_countDataLines = IO_countDataLines + 1_pInt - endif - enddo - backspace(fileUnit) - -end function IO_countDataLines - - -!-------------------------------------------------------------------------------------------------- -!> @brief count items in consecutive lines depending on lines -!> @details Marc: ints concatenated by "c" as last char or range of values a "to" b -!> Abaqus: triplet of start,stop,inc -!> Spectral: ints concatenated range of a "to" b, multiple entries with a "of" b -!-------------------------------------------------------------------------------------------------- -integer(pInt) function IO_countContinuousIntValues(fileUnit) - - implicit none - integer(pInt), intent(in) :: fileUnit - -#ifdef Abaqus - integer(pInt) :: l,c -#endif - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=65536) :: line - - IO_countContinuousIntValues = 0_pInt - line = '' - -#ifndef Abaqus - do while (trim(line) /= IO_EOF) - line = IO_read(fileUnit) - chunkPos = IO_stringPos(line) - if (chunkPos(1) < 1_pInt) then ! empty line - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - elseif (IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'to' ) then ! found range indicator - IO_countContinuousIntValues = 1_pInt + IO_intValue(line,chunkPos,3_pInt) & - - IO_intValue(line,chunkPos,1_pInt) - line = IO_read(fileUnit, .true.) ! reset IO_read - exit ! only one single range indicator allowed - else if (IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'of' ) then ! found multiple entries indicator - IO_countContinuousIntValues = IO_intValue(line,chunkPos,1_pInt) - line = IO_read(fileUnit, .true.) ! reset IO_read - exit ! only one single multiplier allowed - else - IO_countContinuousIntValues = IO_countContinuousIntValues+chunkPos(1)-1_pInt ! add line's count when assuming 'c' - if ( IO_lc(IO_stringValue(line,chunkPos,chunkPos(1))) /= 'c' ) then ! line finished, read last value - IO_countContinuousIntValues = IO_countContinuousIntValues+1_pInt - line = IO_read(fileUnit, .true.) ! reset IO_read - exit ! data ended - endif - endif - enddo -#else - c = IO_countDataLines(fileUnit) - do l = 1_pInt,c - backspace(fileUnit) ! ToDo: substitute by rewind? - enddo - - l = 1_pInt - do while (trim(line) /= IO_EOF .and. l <= c) ! ToDo: is this correct - l = l + 1_pInt - line = IO_read(fileUnit) - chunkPos = IO_stringPos(line) - IO_countContinuousIntValues = IO_countContinuousIntValues + 1_pInt + & ! assuming range generation - (IO_intValue(line,chunkPos,2_pInt)-IO_intValue(line,chunkPos,1_pInt))/& - max(1_pInt,IO_intValue(line,chunkPos,3_pInt)) - enddo -#endif - -end function IO_countContinuousIntValues - - -!-------------------------------------------------------------------------------------------------- -!> @brief return integer list corrsponding to items in consecutive lines. -!! First integer in array is counter -!> @details Marc: ints concatenated by "c" as last char, range of a "to" b, or named set -!! Abaqus: triplet of start,stop,inc or named set -!! Spectral: ints concatenated range of a "to" b, multiple entries with a "of" b -!-------------------------------------------------------------------------------------------------- -function IO_continuousIntValues(fileUnit,maxN,lookupName,lookupMap,lookupMaxN) - - implicit none - integer(pInt), intent(in) :: maxN - integer(pInt), dimension(1+maxN) :: IO_continuousIntValues - - integer(pInt), intent(in) :: fileUnit, & - lookupMaxN - integer(pInt), dimension(:,:), intent(in) :: lookupMap - character(len=64), dimension(:), intent(in) :: lookupName - integer(pInt) :: i -#ifdef Abaqus - integer(pInt) :: j,l,c,first,last -#endif - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=65536) line - logical rangeGeneration - - IO_continuousIntValues = 0_pInt - rangeGeneration = .false. - -#ifndef Abaqus - do - read(fileUnit,'(A65536)',end=100) line - chunkPos = IO_stringPos(line) - if (chunkPos(1) < 1_pInt) then ! empty line - exit - elseif (verify(IO_stringValue(line,chunkPos,1_pInt),'0123456789') > 0) then ! a non-int, i.e. set name - do i = 1_pInt, lookupMaxN ! loop over known set names - if (IO_stringValue(line,chunkPos,1_pInt) == lookupName(i)) then ! found matching name - IO_continuousIntValues = lookupMap(:,i) ! return resp. entity list - exit - endif - enddo - exit - else if (chunkPos(1) > 2_pInt .and. IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'to' ) then ! found range indicator - do i = IO_intValue(line,chunkPos,1_pInt),IO_intValue(line,chunkPos,3_pInt) - IO_continuousIntValues(1) = IO_continuousIntValues(1) + 1_pInt - IO_continuousIntValues(1+IO_continuousIntValues(1)) = i - enddo - exit - else if (chunkPos(1) > 2_pInt .and. IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'of' ) then ! found multiple entries indicator - IO_continuousIntValues(1) = IO_intValue(line,chunkPos,1_pInt) - IO_continuousIntValues(2:IO_continuousIntValues(1)+1) = IO_intValue(line,chunkPos,3_pInt) - exit - else - do i = 1_pInt,chunkPos(1)-1_pInt ! interpret up to second to last value - IO_continuousIntValues(1) = IO_continuousIntValues(1) + 1_pInt - IO_continuousIntValues(1+IO_continuousIntValues(1)) = IO_intValue(line,chunkPos,i) - enddo - if ( IO_lc(IO_stringValue(line,chunkPos,chunkPos(1))) /= 'c' ) then ! line finished, read last value - IO_continuousIntValues(1) = IO_continuousIntValues(1) + 1_pInt - IO_continuousIntValues(1+IO_continuousIntValues(1)) = IO_intValue(line,chunkPos,chunkPos(1)) - exit - endif - endif - enddo -#else - c = IO_countDataLines(fileUnit) - do l = 1_pInt,c - backspace(fileUnit) - enddo - -!-------------------------------------------------------------------------------------------------- -! check if the element values in the elset are auto generated - backspace(fileUnit) - read(fileUnit,'(A65536)',end=100) line - chunkPos = IO_stringPos(line) - do i = 1_pInt,chunkPos(1) - if (IO_lc(IO_stringValue(line,chunkPos,i)) == 'generate') rangeGeneration = .true. - enddo - - do l = 1_pInt,c - read(fileUnit,'(A65536)',end=100) line - chunkPos = IO_stringPos(line) - if (verify(IO_stringValue(line,chunkPos,1_pInt),'0123456789') > 0) then ! a non-int, i.e. set names follow on this line - do i = 1_pInt,chunkPos(1) ! loop over set names in line - do j = 1_pInt,lookupMaxN ! look through known set names - if (IO_stringValue(line,chunkPos,i) == lookupName(j)) then ! found matching name - first = 2_pInt + IO_continuousIntValues(1) ! where to start appending data - last = first + lookupMap(1,j) - 1_pInt ! up to where to append data - IO_continuousIntValues(first:last) = lookupMap(2:1+lookupMap(1,j),j) ! add resp. entity list - IO_continuousIntValues(1) = IO_continuousIntValues(1) + lookupMap(1,j) ! count them - endif - enddo - enddo - else if (rangeGeneration) then ! range generation - do i = IO_intValue(line,chunkPos,1_pInt),& - IO_intValue(line,chunkPos,2_pInt),& - max(1_pInt,IO_intValue(line,chunkPos,3_pInt)) - IO_continuousIntValues(1) = IO_continuousIntValues(1) + 1_pInt - IO_continuousIntValues(1+IO_continuousIntValues(1)) = i - enddo - else ! read individual elem nums - do i = 1_pInt,chunkPos(1) - IO_continuousIntValues(1) = IO_continuousIntValues(1) + 1_pInt - IO_continuousIntValues(1+IO_continuousIntValues(1)) = IO_intValue(line,chunkPos,i) - enddo - endif - enddo -#endif - -100 end function IO_continuousIntValues - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns format string for integer values without leading zeros -!-------------------------------------------------------------------------------------------------- -pure function IO_intOut(intToPrint) - - implicit none - character(len=19) :: N_Digits ! maximum digits for 64 bit integer - character(len=40) :: IO_intOut - integer(pInt), intent(in) :: intToPrint - - write(N_Digits, '(I19.19)') 1_pInt + int(log10(real(intToPrint)),pInt) - IO_intOut = 'I'//trim(N_Digits)//'.'//trim(N_Digits) - -end function IO_intOut - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns time stamp -!-------------------------------------------------------------------------------------------------- -function IO_timeStamp() - - implicit none - character(len=10) :: IO_timeStamp - integer(pInt), dimension(8) :: values - - call DATE_AND_TIME(VALUES=values) - write(IO_timeStamp,'(i2.2,a1,i2.2,a1,i2.2)') values(5),':',values(6),':',values(7) - -end function IO_timeStamp - - -!-------------------------------------------------------------------------------------------------- -!> @brief write error statements to standard out and terminate the Marc/spectral run with exit #9xxx -!> in ABAQUS either time step is reduced or execution terminated -!-------------------------------------------------------------------------------------------------- -subroutine IO_error(error_ID,el,ip,g,ext_msg) - - implicit none - integer(pInt), intent(in) :: error_ID - integer(pInt), optional, intent(in) :: el,ip,g - character(len=*), optional, intent(in) :: ext_msg - - external :: quit - character(len=1024) :: msg - character(len=1024) :: formatString - - select case (error_ID) - -!-------------------------------------------------------------------------------------------------- -! internal errors - case (0_pInt) - msg = 'internal check failed:' - -!-------------------------------------------------------------------------------------------------- -! file handling errors - case (100_pInt) - msg = 'could not open file:' - case (101_pInt) - msg = 'write error for file:' - case (102_pInt) - msg = 'could not read file:' - case (103_pInt) - msg = 'could not assemble input files' - case (104_pInt) - msg = '{input} recursion limit reached' - case (105_pInt) - msg = 'unknown output:' - -!-------------------------------------------------------------------------------------------------- -! lattice error messages - case (130_pInt) - msg = 'unknown lattice structure encountered' - case (131_pInt) - msg = 'hex lattice structure with invalid c/a ratio' - case (132_pInt) - msg = 'trans_lattice_structure not possible' - case (133_pInt) - msg = 'transformed hex lattice structure with invalid c/a ratio' - case (135_pInt) - msg = 'zero entry on stiffness diagonal' - case (136_pInt) - msg = 'zero entry on stiffness diagonal for transformed phase' - -!-------------------------------------------------------------------------------------------------- -! material error messages and related messages in mesh - case (150_pInt) - msg = 'index out of bounds' - case (151_pInt) - msg = 'microstructure has no constituents' - case (153_pInt) - msg = 'sum of phase fractions differs from 1' - case (154_pInt) - msg = 'homogenization index out of bounds' - case (155_pInt) - msg = 'microstructure index out of bounds' - case (156_pInt) - msg = 'reading from ODF file' - case (157_pInt) - msg = 'illegal texture transformation specified' - case (160_pInt) - msg = 'no entries in config part' - case (165_pInt) - msg = 'homogenization configuration' - case (170_pInt) - msg = 'no homogenization specified via State Variable 2' - case (180_pInt) - msg = 'no microstructure specified via State Variable 3' - case (190_pInt) - msg = 'unknown element type:' - -!-------------------------------------------------------------------------------------------------- -! plasticity error messages - case (200_pInt) - msg = 'unknown elasticity specified:' - case (201_pInt) - msg = 'unknown plasticity specified:' - - case (210_pInt) - msg = 'unknown material parameter:' - case (211_pInt) - msg = 'material parameter out of bounds:' - -!-------------------------------------------------------------------------------------------------- -! numerics error messages - case (300_pInt) - msg = 'unknown numerics parameter:' - case (301_pInt) - msg = 'numerics parameter out of bounds:' - -!-------------------------------------------------------------------------------------------------- -! math errors - case (400_pInt) - msg = 'matrix inversion error' - case (401_pInt) - msg = 'math_check: quat -> axisAngle -> quat failed' - case (402_pInt) - msg = 'math_check: quat -> R -> quat failed' - case (403_pInt) - msg = 'math_check: quat -> euler -> quat failed' - case (404_pInt) - msg = 'math_check: R -> euler -> R failed' - case (405_pInt) - msg = 'I_TO_HALTON-error: an input base BASE is <= 1' - case (406_pInt) - msg = 'Prime-error: N must be between 0 and PRIME_MAX' - case (407_pInt) - msg = 'Polar decomposition error' - case (409_pInt) - msg = 'math_check: R*v == q*v failed' - case (410_pInt) - msg = 'eigenvalues computation error' - case (450_pInt) - msg = 'unknown symmetry type specified' - -!------------------------------------------------------------------------------------------------- -! homogenization errors - case (500_pInt) - msg = 'unknown homogenization specified' - -!-------------------------------------------------------------------------------------------------- -! user errors - case (600_pInt) - msg = 'Ping-Pong not possible when using non-DAMASK elements' - case (601_pInt) - msg = 'Ping-Pong needed when using non-local plasticity' - case (602_pInt) - msg = 'invalid element/IP/component (grain) selected for debug' - -!------------------------------------------------------------------------------------------------- -! DAMASK_marc errors - case (700_pInt) - msg = 'invalid materialpoint result requested' - -!------------------------------------------------------------------------------------------------- -! errors related to spectral solver - case (809_pInt) - msg = 'initializing FFTW' - case (810_pInt) - msg = 'FFTW plan creation' - case (831_pInt) - msg = 'mask consistency violated in spectral loadcase' - case (832_pInt) - msg = 'ill-defined L (line partly defined) in spectral loadcase' - case (834_pInt) - msg = 'negative time increment in spectral loadcase' - case (835_pInt) - msg = 'non-positive increments in spectral loadcase' - case (836_pInt) - msg = 'non-positive result frequency in spectral loadcase' - case (837_pInt) - msg = 'incomplete loadcase' - case (838_pInt) - msg = 'mixed boundary conditions allow rotation' - case (841_pInt) - msg = 'missing header length info in spectral mesh' - case (842_pInt) - msg = 'homogenization in spectral mesh' - case (843_pInt) - msg = 'grid in spectral mesh' - case (844_pInt) - msg = 'size in spectral mesh' - case (845_pInt) - msg = 'incomplete information in spectral mesh header' - case (846_pInt) - msg = 'not a rotation defined for loadcase rotation' - case (847_pInt) - msg = 'update of gamma operator not possible when pre-calculated' - case (880_pInt) - msg = 'mismatch of microstructure count and a*b*c in geom file' - case (890_pInt) - msg = 'invalid input for regridding' - case (891_pInt) - msg = 'unknown solver type selected' - case (892_pInt) - msg = 'unknown filter type selected' - case (893_pInt) - msg = 'PETSc: SNES_DIVERGED_FNORM_NAN' - -!------------------------------------------------------------------------------------------------- -! error messages related to parsing of Abaqus input file - case (900_pInt) - msg = 'improper definition of nodes in input file (Nnodes < 2)' - case (901_pInt) - msg = 'no elements defined in input file (Nelems = 0)' - case (902_pInt) - msg = 'no element sets defined in input file (No *Elset exists)' - case (903_pInt) - msg = 'no materials defined in input file (Look into section assigments)' - case (904_pInt) - msg = 'no elements could be assigned for Elset: ' - case (905_pInt) - msg = 'error in mesh_abaqus_map_materials' - case (906_pInt) - msg = 'error in mesh_abaqus_count_cpElements' - case (907_pInt) - msg = 'size of mesh_mapFEtoCPelem in mesh_abaqus_map_elements' - case (908_pInt) - msg = 'size of mesh_mapFEtoCPnode in mesh_abaqus_map_nodes' - case (909_pInt) - msg = 'size of mesh_node in mesh_abaqus_build_nodes not equal to mesh_Nnodes' - - -!------------------------------------------------------------------------------------------------- -! general error messages - case (666_pInt) - msg = 'memory leak detected' - case default - msg = 'unknown error number...' - - end select - - !$OMP CRITICAL (write2out) - write(6,'(/,a)') ' +--------------------------------------------------------+' - write(6,'(a)') ' + error +' - write(6,'(a,i3,a)') ' + ',error_ID,' +' - write(6,'(a)') ' + +' - write(formatString,'(a,i6.6,a,i6.6,a)') '(1x,a2,a',max(1,len(trim(msg))),',',& - max(1,60-len(trim(msg))-5),'x,a)' - write(6,formatString) '+ ', trim(msg),'+' - if (present(ext_msg)) then - write(formatString,'(a,i6.6,a,i6.6,a)') '(1x,a2,a',max(1,len(trim(ext_msg))),',',& - max(1,60-len(trim(ext_msg))-5),'x,a)' - write(6,formatString) '+ ', trim(ext_msg),'+' - endif - if (present(el)) then - if (present(ip)) then - if (present(g)) then - write(6,'(a13,1x,i9,1x,a2,1x,i2,1x,a5,1x,i4,18x,a1)') ' + at element',el,'IP',ip,'grain',g,'+' - else - write(6,'(a13,1x,i9,1x,a2,1x,i2,29x,a1)') ' + at element',el,'IP',ip,'+' - endif - else - write(6,'(a13,1x,i9,35x,a1)') ' + at element',el,'+' - endif - elseif (present(ip)) then ! now having the meaning of "instance" - write(6,'(a15,1x,i9,33x,a1)') ' + for instance',ip,'+' - endif - write(6,'(a)') ' +--------------------------------------------------------+' - flush(6) - call quit(9000_pInt+error_ID) - !$OMP END CRITICAL (write2out) - -end subroutine IO_error - - -!-------------------------------------------------------------------------------------------------- -!> @brief writes warning statement to standard out -!-------------------------------------------------------------------------------------------------- -subroutine IO_warning(warning_ID,el,ip,g,ext_msg) - - implicit none - integer(pInt), intent(in) :: warning_ID - integer(pInt), optional, intent(in) :: el,ip,g - character(len=*), optional, intent(in) :: ext_msg - - character(len=1024) :: msg - character(len=1024) :: formatString - - select case (warning_ID) - case (1_pInt) - msg = 'unknown key' - case (34_pInt) - msg = 'invalid restart increment given' - case (35_pInt) - msg = 'could not get $DAMASK_NUM_THREADS' - case (40_pInt) - msg = 'found spectral solver parameter' - case (42_pInt) - msg = 'parameter has no effect' - case (43_pInt) - msg = 'main diagonal of C66 close to zero' - case (47_pInt) - msg = 'no valid parameter for FFTW, using FFTW_PATIENT' - case (50_pInt) - msg = 'not all available slip system families are defined' - case (51_pInt) - msg = 'not all available twin system families are defined' - case (52_pInt) - msg = 'not all available parameters are defined' - case (53_pInt) - msg = 'not all available transformation system families are defined' - case (101_pInt) - msg = 'crystallite debugging off' - case (201_pInt) - msg = 'position not found when parsing line' - case (202_pInt) - msg = 'invalid character in string chunk' - case (203_pInt) - msg = 'interpretation of string chunk failed' - case (600_pInt) - msg = 'crystallite responds elastically' - case (601_pInt) - msg = 'stiffness close to zero' - case (650_pInt) - msg = 'polar decomposition failed' - case (700_pInt) - msg = 'unknown crystal symmetry' - case (850_pInt) - msg = 'max number of cut back exceeded, terminating' - case default - msg = 'unknown warning number' - end select - - !$OMP CRITICAL (write2out) - write(6,'(/,a)') ' +--------------------------------------------------------+' - write(6,'(a)') ' + warning +' - write(6,'(a,i3,a)') ' + ',warning_ID,' +' - write(6,'(a)') ' + +' - write(formatString,'(a,i6.6,a,i6.6,a)') '(1x,a2,a',max(1,len(trim(msg))),',',& - max(1,60-len(trim(msg))-5),'x,a)' - write(6,formatString) '+ ', trim(msg),'+' - if (present(ext_msg)) then - write(formatString,'(a,i6.6,a,i6.6,a)') '(1x,a2,a',max(1,len(trim(ext_msg))),',',& - max(1,60-len(trim(ext_msg))-5),'x,a)' - write(6,formatString) '+ ', trim(ext_msg),'+' - endif - if (present(el)) then - if (present(ip)) then - if (present(g)) then - write(6,'(a13,1x,i9,1x,a2,1x,i2,1x,a5,1x,i4,18x,a1)') ' + at element',el,'IP',ip,'grain',g,'+' - else - write(6,'(a13,1x,i9,1x,a2,1x,i2,29x,a1)') ' + at element',el,'IP',ip,'+' - endif - else - write(6,'(a13,1x,i9,35x,a1)') ' + at element',el,'+' - endif - endif - write(6,'(a)') ' +--------------------------------------------------------+' - flush(6) - !$OMP END CRITICAL (write2out) - -end subroutine IO_warning - - -!-------------------------------------------------------------------------------------------------- -! internal helper functions - -!-------------------------------------------------------------------------------------------------- -!> @brief returns verified integer value in given string -!-------------------------------------------------------------------------------------------------- -integer(pInt) function IO_verifyIntValue (string,validChars,myName) - - implicit none - character(len=*), intent(in) :: string, & !< string for conversion to int value. Must not contain spaces! - validChars, & !< valid characters in string - myName !< name of caller function (for debugging) - integer(pInt) :: readStatus, invalidWhere - !character(len=len(trim(string))) :: trimmed does not work with ifort 14.0.1 - - IO_verifyIntValue = 0_pInt - - invalidWhere = verify(string,validChars) - if (invalidWhere == 0_pInt) then - read(UNIT=string,iostat=readStatus,FMT=*) IO_verifyIntValue ! no offending chars found - if (readStatus /= 0_pInt) & ! error during string to float conversion - call IO_warning(203_pInt,ext_msg=myName//'"'//string//'"') - else - call IO_warning(202_pInt,ext_msg=myName//'"'//string//'"') ! complain about offending characters - read(UNIT=string(1_pInt:invalidWhere-1_pInt),iostat=readStatus,FMT=*) IO_verifyIntValue ! interpret remaining string - if (readStatus /= 0_pInt) & ! error during string to float conversion - call IO_warning(203_pInt,ext_msg=myName//'"'//string(1_pInt:invalidWhere-1_pInt)//'"') - endif - -end function IO_verifyIntValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns verified float value in given string -!-------------------------------------------------------------------------------------------------- -real(pReal) function IO_verifyFloatValue (string,validChars,myName) - - implicit none - character(len=*), intent(in) :: string, & !< string for conversion to int value. Must not contain spaces! - validChars, & !< valid characters in string - myName !< name of caller function (for debugging) - - integer(pInt) :: readStatus, invalidWhere - !character(len=len(trim(string))) :: trimmed does not work with ifort 14.0.1 - - IO_verifyFloatValue = 0.0_pReal - - invalidWhere = verify(string,validChars) - if (invalidWhere == 0_pInt) then - read(UNIT=string,iostat=readStatus,FMT=*) IO_verifyFloatValue ! no offending chars found - if (readStatus /= 0_pInt) & ! error during string to float conversion - call IO_warning(203_pInt,ext_msg=myName//'"'//string//'"') - else - call IO_warning(202_pInt,ext_msg=myName//'"'//string//'"') ! complain about offending characters - read(UNIT=string(1_pInt:invalidWhere-1_pInt),iostat=readStatus,FMT=*) IO_verifyFloatValue ! interpret remaining string - if (readStatus /= 0_pInt) & ! error during string to float conversion - call IO_warning(203_pInt,ext_msg=myName//'"'//string(1_pInt:invalidWhere-1_pInt)//'"') - endif - -end function IO_verifyFloatValue - -#ifdef Abaqus -!-------------------------------------------------------------------------------------------------- -!> @brief create a new input file for abaqus simulations by removing all comment lines and -!> including "include"s -!-------------------------------------------------------------------------------------------------- -recursive function abaqus_assembleInputFile(unit1,unit2) result(createSuccess) - use DAMASK_interface, only: & - getSolverWorkingDirectoryName - - implicit none - integer(pInt), intent(in) :: unit1, & - unit2 - - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=65536) :: line,fname - logical :: createSuccess,fexist - - - do - read(unit2,'(A65536)',END=220) line - chunkPos = IO_stringPos(line) - - if (IO_lc(IO_StringValue(line,chunkPos,1_pInt))=='*include') then - fname = trim(getSolverWorkingDirectoryName())//trim(line(9+scan(line(9:),'='):)) - inquire(file=fname, exist=fexist) - if (.not.(fexist)) then - !$OMP CRITICAL (write2out) - write(6,*)'ERROR: file does not exist error in abaqus_assembleInputFile' - write(6,*)'filename: ', trim(fname) - !$OMP END CRITICAL (write2out) - createSuccess = .false. - return - endif - open(unit2+1,err=200,status='old',file=fname) - if (abaqus_assembleInputFile(unit1,unit2+1_pInt)) then - createSuccess=.true. - close(unit2+1) - else - createSuccess=.false. - return - endif - else if (line(1:2) /= '**' .OR. line(1:8)=='**damask') then - write(unit1,'(A)') trim(line) - endif - enddo - -220 createSuccess = .true. - return - -200 createSuccess =.false. - -end function abaqus_assembleInputFile -#endif - - -#ifdef HDF -!-------------------------------------------------------------------------------------------------- -!> @brief creates and initializes HDF5 output files -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_createJobFile - use hdf5 - use DAMASK_interface, only: & - getSolverWorkingDirectoryName, & - getSolverJobName - - implicit none - integer :: hdferr - integer(SIZE_T) :: typeSize - character(len=1024) :: path - integer(HID_T) :: prp_id - integer(SIZE_T), parameter :: increment = 104857600 ! increase temp file in memory in 100MB steps - - -!-------------------------------------------------------------------------------------------------- -! initialize HDF5 library and check if integer and float type size match - call h5open_f(hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_createJobFile: h5open_f') - call h5tget_size_f(H5T_NATIVE_INTEGER,typeSize, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_createJobFile: h5tget_size_f (int)') - if (int(pInt,SIZE_T)/=typeSize) call IO_error(0_pInt,ext_msg='pInt does not match H5T_NATIVE_INTEGER') - call h5tget_size_f(H5T_NATIVE_DOUBLE,typeSize, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_createJobFile: h5tget_size_f (double)') - if (int(pReal,SIZE_T)/=typeSize) call IO_error(0_pInt,ext_msg='pReal does not match H5T_NATIVE_DOUBLE') - -!-------------------------------------------------------------------------------------------------- -! open file - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//'DAMASKout' - call h5fcreate_f(path,H5F_ACC_TRUNC_F,resultsFile,hdferr) - if (hdferr < 0) call IO_error(100_pInt,ext_msg=path) - call HDF5_addStringAttribute(resultsFile,'createdBy','$Id$') - -!-------------------------------------------------------------------------------------------------- -! open temp file - path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//'DAMASKoutTemp' - call h5pcreate_f(H5P_FILE_ACCESS_F, prp_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_createJobFile: h5pcreate_f') - call h5pset_fapl_core_f(prp_id, increment, .false., hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_createJobFile: h5pset_fapl_core_f') - call h5fcreate_f(path,H5F_ACC_TRUNC_F,tempFile,hdferr) - if (hdferr < 0) call IO_error(100_pInt,ext_msg=path) - -!-------------------------------------------------------------------------------------------------- -! create mapping groups in out file - call HDF5_closeGroup(HDF5_addGroup("mapping")) - call HDF5_closeGroup(HDF5_addGroup("results")) - call HDF5_closeGroup(HDF5_addGroup("coordinates")) - -!-------------------------------------------------------------------------------------------------- -! create results group in temp file - tempResults = HDF5_addGroup("results",tempFile) - tempCoordinates = HDF5_addGroup("coordinates",tempFile) - -end subroutine HDF5_createJobFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief creates and initializes HDF5 output file -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_closeJobFile() - use hdf5 - - implicit none - integer :: hdferr - call h5fclose_f(resultsFile,hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_closeJobFile: h5fclose_f') - -end subroutine HDF5_closeJobFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief adds a new group to the results file, or if loc is present at the given location -!-------------------------------------------------------------------------------------------------- -integer(HID_T) function HDF5_addGroup(path,loc) - use hdf5 - - implicit none - character(len=*), intent(in) :: path - integer(HID_T), intent(in),optional :: loc - integer :: hdferr - - if (present(loc)) then - call h5gcreate_f(loc, trim(path), HDF5_addGroup, hdferr) - else - call h5gcreate_f(resultsFile, trim(path), HDF5_addGroup, hdferr) - endif - if (hdferr < 0) call IO_error(1_pInt,ext_msg = 'HDF5_addGroup: h5gcreate_f ('//trim(path)//' )') - -end function HDF5_addGroup - - - -!-------------------------------------------------------------------------------------------------- -!> @brief adds a new group to the results file -!-------------------------------------------------------------------------------------------------- -integer(HID_T) function HDF5_openGroup(path) - use hdf5 - - implicit none - character(len=*), intent(in) :: path - integer :: hdferr - - call h5gopen_f(resultsFile, trim(path), HDF5_openGroup, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg = 'HDF5_openGroup: h5gopen_f ('//trim(path)//' )') - -end function HDF5_openGroup - - -!-------------------------------------------------------------------------------------------------- -!> @brief closes a group -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_closeGroup(ID) - use hdf5 - - implicit none - integer(HID_T), intent(in) :: ID - integer :: hdferr - - call h5gclose_f(ID, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg = 'HDF5_closeGroup: h5gclose_f') - -end subroutine HDF5_closeGroup - - -!-------------------------------------------------------------------------------------------------- -!> @brief adds a new group to the results file -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_addStringAttribute(entity,attrLabel,attrValue) - use hdf5 - - implicit none - integer(HID_T), intent(in) :: entity - character(len=*), intent(in) :: attrLabel, attrValue - integer :: hdferr - integer(HID_T) :: attr_id, space_id, type_id - - call h5screate_f(H5S_SCALAR_F,space_id,hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5screate_f') - call h5tcopy_f(H5T_NATIVE_CHARACTER, type_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5tcopy_f') - call h5tset_size_f(type_id, int(len(trim(attrValue)),HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5tset_size_f') - call h5acreate_f(entity, trim(attrLabel),type_id,space_id,attr_id,hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5acreate_f') - call h5awrite_f(attr_id, type_id, trim(attrValue), int([1],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5awrite_f') - call h5aclose_f(attr_id,hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5aclose_f') - call h5sclose_f(space_id,hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5sclose_f') - -end subroutine HDF5_addStringAttribute - - -!-------------------------------------------------------------------------------------------------- -!> @brief adds the unique mapping from spatial position and constituent ID to results -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_mappingConstitutive(mapping) - use hdf5 - - implicit none - integer(pInt), intent(in), dimension(:,:,:) :: mapping - - integer :: hdferr, NmatPoints,Nconstituents - integer(HID_T) :: mapping_id, dtype_id, dset_id, space_id,instance_id,position_id - - Nconstituents=size(mapping,1) - NmatPoints=size(mapping,2) - mapping_ID = HDF5_openGroup("mapping") - -!-------------------------------------------------------------------------------------------------- -! create dataspace - call h5screate_simple_f(2, int([Nconstituents,NmatPoints],HSIZE_T), space_id, hdferr, & - int([Nconstituents,NmatPoints],HSIZE_T)) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive') - -!-------------------------------------------------------------------------------------------------- -! compound type - call h5tcreate_f(H5T_COMPOUND_F, 6_SIZE_T, dtype_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tcreate_f dtype_id') - - call h5tinsert_f(dtype_id, "Constitutive Instance", 0_SIZE_T, H5T_STD_U16LE, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tinsert_f 0') - call h5tinsert_f(dtype_id, "Position in Instance Results", 2_SIZE_T, H5T_STD_U32LE, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tinsert_f 2') - -!-------------------------------------------------------------------------------------------------- -! create Dataset - call h5dcreate_f(mapping_id, "Constitutive", dtype_id, space_id, dset_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive') - -!-------------------------------------------------------------------------------------------------- -! Create memory types (one compound datatype for each member) - call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), instance_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tcreate_f instance_id') - call h5tinsert_f(instance_id, "Constitutive Instance", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tinsert_f instance_id') - - call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), position_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tcreate_f position_id') - call h5tinsert_f(position_id, "Position in Instance Results", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tinsert_f position_id') - -!-------------------------------------------------------------------------------------------------- -! write data by fields in the datatype. Fields order is not important. - call h5dwrite_f(dset_id, position_id, mapping(1:Nconstituents,1:NmatPoints,1), & - int([Nconstituents, NmatPoints],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5dwrite_f position_id') - - call h5dwrite_f(dset_id, instance_id, mapping(1:Nconstituents,1:NmatPoints,2), & - int([Nconstituents, NmatPoints],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5dwrite_f instance_id') - -!-------------------------------------------------------------------------------------------------- -!close types, dataspaces - call h5tclose_f(dtype_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tclose_f dtype_id') - call h5tclose_f(position_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tclose_f position_id') - call h5tclose_f(instance_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tclose_f instance_id') - call h5dclose_f(dset_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5dclose_f') - call h5sclose_f(space_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5sclose_f') - call HDF5_closeGroup(mapping_ID) - -end subroutine HDF5_mappingConstitutive - - -!-------------------------------------------------------------------------------------------------- -!> @brief adds the unique mapping from spatial position and constituent ID to results -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_mappingCrystallite(mapping) - use hdf5 - - implicit none - integer(pInt), intent(in), dimension(:,:,:) :: mapping - - integer :: hdferr, NmatPoints,Nconstituents - integer(HID_T) :: mapping_id, dtype_id, dset_id, space_id,instance_id,position_id - - Nconstituents=size(mapping,1) - NmatPoints=size(mapping,2) - mapping_ID = HDF5_openGroup("mapping") - -!-------------------------------------------------------------------------------------------------- -! create dataspace - call h5screate_simple_f(2, int([Nconstituents,NmatPoints],HSIZE_T), space_id, hdferr, & - int([Nconstituents,NmatPoints],HSIZE_T)) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite') - -!-------------------------------------------------------------------------------------------------- -! compound type - call h5tcreate_f(H5T_COMPOUND_F, 6_SIZE_T, dtype_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tcreate_f dtype_id') - - call h5tinsert_f(dtype_id, "Crystallite Instance", 0_SIZE_T, H5T_STD_U16LE, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tinsert_f 0') - call h5tinsert_f(dtype_id, "Position in Instance Results", 2_SIZE_T, H5T_STD_U32LE, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tinsert_f 2') - -!-------------------------------------------------------------------------------------------------- -! create Dataset - call h5dcreate_f(mapping_id, "Crystallite", dtype_id, space_id, dset_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite') - -!-------------------------------------------------------------------------------------------------- -! Create memory types (one compound datatype for each member) - call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), instance_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tcreate_f instance_id') - call h5tinsert_f(instance_id, "Crystallite Instance", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tinsert_f instance_id') - - call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), position_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tcreate_f position_id') - call h5tinsert_f(position_id, "Position in Instance Results", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tinsert_f position_id') - -!-------------------------------------------------------------------------------------------------- -! write data by fields in the datatype. Fields order is not important. - call h5dwrite_f(dset_id, position_id, mapping(1:Nconstituents,1:NmatPoints,1), & - int([Nconstituents, NmatPoints],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5dwrite_f position_id') - - call h5dwrite_f(dset_id, instance_id, mapping(1:Nconstituents,1:NmatPoints,2), & - int([Nconstituents, NmatPoints],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5dwrite_f instance_id') - -!-------------------------------------------------------------------------------------------------- -!close types, dataspaces - call h5tclose_f(dtype_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tclose_f dtype_id') - call h5tclose_f(position_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tclose_f position_id') - call h5tclose_f(instance_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tclose_f instance_id') - call h5dclose_f(dset_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5dclose_f') - call h5sclose_f(space_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5sclose_f') - call HDF5_closeGroup(mapping_ID) - -end subroutine HDF5_mappingCrystallite - - -!-------------------------------------------------------------------------------------------------- -!> @brief adds the unique mapping from spatial position to results -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_mappingHomogenization(mapping) - use hdf5 - - implicit none - integer(pInt), intent(in), dimension(:,:) :: mapping - - integer :: hdferr, NmatPoints - integer(HID_T) :: mapping_id, dtype_id, dset_id, space_id,instance_id,position_id,elem_id,ip_id - - NmatPoints=size(mapping,1) - mapping_ID = HDF5_openGroup("mapping") - -!-------------------------------------------------------------------------------------------------- -! create dataspace - call h5screate_simple_f(1, int([NmatPoints],HSIZE_T), space_id, hdferr, & - int([NmatPoints],HSIZE_T)) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization') - -!-------------------------------------------------------------------------------------------------- -! compound type - call h5tcreate_f(H5T_COMPOUND_F, 11_SIZE_T, dtype_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tcreate_f dtype_id') - - call h5tinsert_f(dtype_id, "Homogenization Instance", 0_SIZE_T, H5T_STD_U16LE, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f 0') - call h5tinsert_f(dtype_id, "Position in Instance Results", 2_SIZE_T, H5T_STD_U32LE, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f 2') - call h5tinsert_f(dtype_id, "Element Number", 6_SIZE_T, H5T_STD_U32LE, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f 6') - call h5tinsert_f(dtype_id, "Material Point Number", 10_SIZE_T, H5T_STD_U8LE, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f 10') - -!-------------------------------------------------------------------------------------------------- -! create Dataset - call h5dcreate_f(mapping_id, "Homogenization", dtype_id, space_id, dset_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization') - -!-------------------------------------------------------------------------------------------------- -! Create memory types (one compound datatype for each member) - call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), instance_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tcreate_f instance_id') - call h5tinsert_f(instance_id, "Homogenization Instance", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f instance_id') - - call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), position_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tcreate_f position_id') - call h5tinsert_f(position_id, "Position in Instance Results", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f position_id') - - call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), elem_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tcreate_f elem_id') - call h5tinsert_f(elem_id, "Element Number", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f elem_id') - - call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), ip_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tcreate_f ip_id') - call h5tinsert_f(ip_id, "Material Point Number", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f ip_id') - -!-------------------------------------------------------------------------------------------------- -! write data by fields in the datatype. Fields order is not important. - call h5dwrite_f(dset_id, position_id, mapping(1:NmatPoints,1), & - int([NmatPoints],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5dwrite_f position_id') - - call h5dwrite_f(dset_id, instance_id, mapping(1:NmatPoints,2), & - int([NmatPoints],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5dwrite_f position_id') - - call h5dwrite_f(dset_id, elem_id, mapping(1:NmatPoints,3), & - int([NmatPoints],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5dwrite_f elem_id') - - call h5dwrite_f(dset_id, ip_id, mapping(1:NmatPoints,4), & - int([NmatPoints],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5dwrite_f ip_id') - -!-------------------------------------------------------------------------------------------------- -!close types, dataspaces - call h5tclose_f(dtype_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tclose_f dtype_id') - call h5tclose_f(position_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tclose_f position_id') - call h5tclose_f(instance_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tclose_f instance_id') - call h5tclose_f(ip_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tclose_f ip_id') - call h5tclose_f(elem_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tclose_f elem_id') - call h5dclose_f(dset_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5dclose_f') - call h5sclose_f(space_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5sclose_f') - call HDF5_closeGroup(mapping_ID) - -end subroutine HDF5_mappingHomogenization - - -!-------------------------------------------------------------------------------------------------- -!> @brief adds the unique cell to node mapping -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_mappingCells(mapping) - use hdf5 - - implicit none - integer(pInt), intent(in), dimension(:) :: mapping - - integer :: hdferr, Nnodes - integer(HID_T) :: mapping_id, dset_id, space_id - - Nnodes=size(mapping) - mapping_ID = HDF5_openGroup("mapping") - -!-------------------------------------------------------------------------------------------------- -! create dataspace - call h5screate_simple_f(1, int([Nnodes],HSIZE_T), space_id, hdferr, & - int([Nnodes],HSIZE_T)) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCells: h5screate_simple_f') - -!-------------------------------------------------------------------------------------------------- -! create Dataset - call h5dcreate_f(mapping_id, "Cell",H5T_NATIVE_INTEGER, space_id, dset_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCells') - -!-------------------------------------------------------------------------------------------------- -! write data by fields in the datatype. Fields order is not important. - call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER, mapping, int([Nnodes],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCells: h5dwrite_f instance_id') - -!-------------------------------------------------------------------------------------------------- -!close types, dataspaces - call h5dclose_f(dset_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5dclose_f') - call h5sclose_f(space_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5sclose_f') - call HDF5_closeGroup(mapping_ID) - -end subroutine HDF5_mappingCells - - -!-------------------------------------------------------------------------------------------------- -!> @brief creates a new scalar dataset in the given group location -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_addScalarDataset(group,nnodes,label,SIunit) - use hdf5 - - implicit none - integer(HID_T), intent(in) :: group - integer(pInt), intent(in) :: nnodes - character(len=*), intent(in) :: SIunit,label - - integer :: hdferr - integer(HID_T) :: dset_id, space_id - -!-------------------------------------------------------------------------------------------------- -! create dataspace - call h5screate_simple_f(1, int([Nnodes],HSIZE_T), space_id, hdferr, & - int([Nnodes],HSIZE_T)) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_addScalarDataset: h5screate_simple_f') - -!-------------------------------------------------------------------------------------------------- -! create Dataset - call h5dcreate_f(group, trim(label),H5T_NATIVE_DOUBLE, space_id, dset_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_addScalarDataset: h5dcreate_f') - call HDF5_addStringAttribute(dset_id,'unit',trim(SIunit)) - -!-------------------------------------------------------------------------------------------------- -!close types, dataspaces - call h5dclose_f(dset_id, hdferr) - if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_addScalarDataset: h5dclose_f') - call h5sclose_f(space_id, hdferr) - -end subroutine HDF5_addScalarDataset - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns nicely formatted string of integer value -!-------------------------------------------------------------------------------------------------- -function IO_formatIntToString(myInt) - - implicit none - integer(pInt), intent(in) :: myInt - character(len=1_pInt + int(log10(real(myInt)),pInt)) :: IO_formatIntToString - write(IO_formatIntToString,'('//IO_intOut(myInt)//')') myInt - - end function - - -!-------------------------------------------------------------------------------------------------- -!> @brief copies the current temp results to the actual results file -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_forwardResults - use hdf5 - - implicit none - integer :: hdferr - integer(HID_T) :: new_loc_id - - new_loc_id = HDF5_openGroup("results") - currentInc = currentInc + 1_pInt - call h5ocopy_f(tempFile, 'results', new_loc_id,dst_name=IO_formatIntToString(currentInc), hdferr=hdferr) - if (hdferr < 0_pInt) call IO_error(1_pInt,ext_msg='HDF5_forwardResults: h5ocopy_f') - call HDF5_closeGroup(new_loc_id) - -end subroutine HDF5_forwardResults - - -#endif -end module IO diff --git a/code/Makefile b/code/Makefile deleted file mode 100644 index 2a9a3deae..000000000 --- a/code/Makefile +++ /dev/null @@ -1,701 +0,0 @@ -SHELL = /bin/sh -######################################################################################## -# Makefile to compile the Material subroutine for BVP solution using spectral method -######################################################################################## -# Be sure to remove all files compiled with different options by using "make clean" -######################################################################################## -# OPTIONS = standard (alternative): meaning -#------------------------------------------------------------- -# F90 = ifort (gfortran): compiler type, choose Intel or GNU -# COMPILERNAME = name of the compiler executable (if not the same as the ype), e.g. using mpich-g90 instead of ifort -# PORTABLE = TRUE (FALSE): decision, if executable is optimized for the machine on which it was built. -# OPTIMIZATION = DEFENSIVE (OFF,AGGRESSIVE,ULTRA): Optimization mode: O2, O0, O3 + further options for most files, O3 + further options for all files -# OPENMP = TRUE (FALSE): OpenMP multiprocessor support -# PREFIX = arbitrary prefix (before compilername) -# OPTION = arbitrary option (just before file to compile) -# SUFFIX = arbitrary suffix (after file to compile) -# STANDARD_CHECK = checking for Fortran 2008, compiler dependend -######################################################################################## -# including PETSc files. PETSC_ARCH is loaded from these files. -DAMASKVERSION :=$(shell cat ../VERSION) - -include ${PETSC_DIR}/lib/petsc/conf/variables -include ${PETSC_DIR}/lib/petsc/conf/rules - -INCLUDE_DIRS := $(PETSC_FC_INCLUDES) -DPETSc -I../lib -LIBRARIES := $(PETSC_WITH_EXTERNAL_LIB) -COMPILERNAME ?= $(FC) -LINKERNAME ?= $(FLINKER) - -# -# setting up for HDF5 support (hard link for now) -# 1. Location of HDF5 binaries (with include/ and lib/ underneath) -HDF5 = /mnt/research/CMM/opt/hdf5 -# 2. Location of External Libraries (missing in the 1.8.12 version) -LIBZ = /mnt/research/CMM/opt/hdf5/lib/libz.a -LIBSZ = /mnt/research/CMM/opt/hdf5/lib/libszip.a -# 3. Set libraries for HDF5 (LIBS: shared lib, LIBZ: external lib) -HDFLIBS = -I$(HDF5)/include -L$(HDF5)/lib -HDFLIBZ = -L$(LIBZ) -L$(LIBSZ) - -# MPI compiler wrappers will tell if they are pointing to ifort or gfortran -COMPILEROUT :=$(shell $(FC) -show) -# search in FC or COMPILEROUT for gfortran/ifort if not defined -ifeq ($(strip $(F90)),) - F90 :=$(findstring gfortran,$(FC) $(COMPILEROUT)) -endif -ifeq ($(strip $(F90)),) - F90 :=$(findstring ifort,$(FC) $(COMPILEROUT)) -endif - -OPENMP ?= ON -OPTIMIZATION ?= DEFENSIVE - -ifeq "$(OPTIMIZATION)" "OFF" -OPTI := OFF -MAXOPTI := OFF -endif -ifeq "$(OPTIMIZATION)" "DEFENSIVE" -OPTI := DEFENSIVE -MAXOPTI := DEFENSIVE -endif -ifeq "$(OPTIMIZATION)" "AGGRESSIVE" -OPTI := AGGRESSIVE -MAXOPTI := DEFENSIVE -endif -ifeq "$(OPTIMIZATION)" "ULTRA" -OPTI := AGGRESSIVE -MAXOPTI := AGGRESSIVE -endif - -ifndef OPTI -OPTI := DEFENSIVE -MAXOPTI := DEFENSIVE -endif - -# settings for shared memory multicore support -ifeq "$(OPENMP)" "ON" -OPENMP_FLAG_ifort =-openmp -openmp-report0 -parallel -OPENMP_FLAG_gfortran =-fopenmp -endif - -ifdef STANDARD_CHECK -STANDARD_CHECK_ifort =$(STANDARD_CHECK) -STANDARD_CHECK_gfortran =$(STANDARD_CHECK) -endif - -STANDARD_CHECK_ifort ?=-stand f08 -standard-semantics -STANDARD_CHECK_gfortran ?=-std=f2008ts -pedantic-errors - -#-pedantic: more strict on standard, enables some warnings -# -pedantic-errors: like pedantic, but errors instead of warnings -OPTIMIZATION_OFF_ifort :=-O0 -no-ip -OPTIMIZATION_OFF_gfortran :=-O0 -OPTIMIZATION_DEFENSIVE_ifort :=-O2 -OPTIMIZATION_DEFENSIVE_gfortran :=-O2 -OPTIMIZATION_AGGRESSIVE_ifort :=-ipo -O3 -no-prec-div -fp-model fast=2 -xHost #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost -OPTIMIZATION_AGGRESSIVE_gfortran :=-O3 -ffast-math -funroll-loops -ftree-vectorize - - -LINK_OPTIONS_ifort :=-shared-intel -COMPILE_OPTIONS_ifort :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ - -fpp\ - -ftz\ - -assume byterecl,fpe_summary\ - -diag-disable 5268\ - -warn declarations\ - -warn general\ - -warn usage\ - -warn interfaces\ - -warn ignore_loc\ - -warn alignments\ - -warn unused - -################################################################################################### -#COMPILE SWITCHES -#-shared-intel: Link against shared Intel libraries instead of static ones -#-fpp: preprocessor -#-ftz: flush unterflow to zero, automatically set if O<0,1,2,3> >0 -#-assume byterecl record length is given in bytes (also set by -standard-semantics) -# fpe_summary print list of floating point exceptions occured during execution -#-fimplicit-none: assume "implicit-none" even if not present in source -#-diag-disable: disables warnings, where -# warning ID 5268: the text exceeds right hand column allowed on the line (we have only comments there) -#-warn: enables warnings, where -# declarations: any undeclared names (alternative name: -implicitnone) -# general: warning messages and informational messages are issued by the compiler -# usage: questionable programming practices -# interfaces: checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks -# ignore_loc: %LOC is stripped from an actual argument -# alignments: data that is not naturally aligned -# unused: declared variables that are never used -# stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) -# -################################################################################################### -#MORE OPTIONS FOR DEBUGGING DURING COMPILATION -#-warn: enables warnings, where -# truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) -# uncalled: Determines whether warnings occur when a statement function is never called -# all: -# -name as_is: case sensitive Fortran! - -DEBUG_OPTIONS_ifort :=-g\ - -traceback\ - -gen-interfaces\ - -fp-stack-check\ - -fp-model strict\ - -check bounds,format,output_conversion,pointers,uninit\ - -ftrapuv\ - -fpe-all0\ - -warn errors\ - -warn stderrors\ - -debug-parameters all - -################################################################################################### -#COMPILE SWITCHES FOR RUNTIME DEBUGGING -#-g: Generate symbolic debugging information in the object file -#-traceback: Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. -#-gen-interfaces: Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ -#-fp-stack-check: Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. -#-ftrapuv Trap uninitalized variables -#-check: checks at runtime, where -# bounds: check if an array index is too small (<1) or too large! -# format: Checking for the data type of an item being formatted for output. -# output_conversion: Checking for the fit of data items within a designated format descriptor field. -# pointers: Checking for certain disassociated or uninitialized pointers or unallocated allocatable objects. -# uninit: Checking for uninitialized variables. -#-fpe-all0 capture all floating-point exceptions, sets -ftz automatically -#-warn: enables warnings, where -# errors: warnings are changed to errors -# stderrors: warnings about Fortran standard violations are changed to errors -# information on http://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors/ -################################################################################################### -#MORE OPTIONS FOR RUNTIME DEBUGGING -#-heap-arrays: should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits -#-check: checks at runtime, where -# arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) -# stack: -LINK_OPTIONS_gfortran :=-Wl,-undefined,dynamic_lookup -COMPILE_OPTIONS_gfortran :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ - -xf95-cpp-input\ - -ffree-line-length-132\ - -fimplicit-none\ - -fmodule-private\ - -Wall\ - -Wextra\ - -Wcharacter-truncation\ - -Wunderflow\ - -Wsuggest-attribute=pure\ - -Wsuggest-attribute=noreturn\ - -Wconversion-extra\ - -Wimplicit-procedure\ - -Wno-unused-parameter -#-ffpe-summary=all only for newer gfortran -################################################################################################### -#COMPILE SWITCHES -#-shared -#-Wl,-undefined,dynamic_lookup:ensure to link against dynamic libraries -#-xf95-cpp-input: preprocessor -#-ffree-line-length-132: restrict line length to the standard 132 characters -#-ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) -#-fimplicit-none: assume "implicit-none" even if not present in source -#-fmodule-private: assume "private" even if not present in source -#-Wcharacter-truncation: warn if character expressions (strings) are truncated -#-Wunderflow: produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation -#-Wsuggest-attribute=pure: -#-Wsuggest-attribute=noreturn: -#-Wconversion-extra -#-Wimplicit-procedure -#-Wall: sets the following Fortran options: -# -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. -# -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line -# -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime -# -Wconversion: warn about implicit conversions between different type -# -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. -# -Wc-binding-type: -# -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error -# -Wno-tabs: do not allow tabs in source -# -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic -# -Wline-truncation: -# -Wtarget-lifetime: -# -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter -# -Wunused: a number of unused-xxx warnings -# these are general (non -Fortran options) implied by -Wall -# -Waddress -# -Warray-bounds (only with -O2) -# -Wc++11-compat -# -Wchar-subscripts -# -Wcomment -# -Wformat -# -Wmaybe-uninitialized -# -Wnonnull -# -Wparentheses -# -Wpointer-sign -# -Wreorder -# -Wreturn-type -# -Wsequence-point -# -Wstrict-aliasing -# -Wstrict-overflow=1 -# -Wswitch -# -Wtrigraphs -# -Wuninitialized -# -Wunknown-pragmas -# -Wunused-function -# -Wunused-label -# -Wunused-value -# -Wunused-variable -# -Wvolatile-register-var -#-Wextra: sets the following Fortran options: -# -Wunuses-parameter: -# -Wcompare-reals: -# these are general (non -Fortran options) implied by -Wextra -# -Wclobbered -# -Wempty-body -# -Wignored-qualifiers -# -Wmissing-field-initializers -# -Woverride-init -# -Wsign-compare -# -Wtype-limits -# -Wuninitialized -# -Wunused-but-set-parameter (only with -Wunused or -Wall) -# -Wno-globals - -################################################################################################### -#MORE OPTIONS FOR DEBUGGING DURING COMPILATION -#-Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): -#-Wimplicit-interface: no interfaces for lapack routines -#-Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. -#-Wstrict-overflow: - -DEBUG_OPTIONS_gfortran :=-g\ - -fbacktrace\ - -fdump-core\ - -fcheck=all\ - -ffpe-trap=invalid,zero,overflow - -################################################################################################### -#COMPILE SWITCHES FOR RUNTIME DEBUGGING -#-ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) -# zero,\ -# overflow -#-fcheck=all: sets the following Fortran options: -#array-temps -#bounds -#do -#mem -#pointer -#recursion -################################################################################################### -#MORE OPTIONS FOR RUNTIME DEBUGGING -#-ffpe-trap=precision,\ -# denormal, \ -# underflow - -ifeq "$(DEBUG)" "ON" -COMPILE_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) -LINK_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) -endif -LINK_OPTIONS_$(F90) += $(OPTIMIZATION_$(MAXOPTI)_$(F90)) - -PRECISION_ifort :=-real-size 64 -integer-size 32 -DFLOAT=8 -DINT=4 -#-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) -#-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) -PRECISION_gfortran :=-fdefault-real-8 -fdefault-double-8 -DFLOAT=8 -DINT=4 -#-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set -#-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used -#-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) - -################################################################################################### -COMPILE =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(OPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) -COMPILE_MAXOPTI =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) -################################################################################################### -SOURCE_FILES = \ - source_thermal_dissipation.o source_thermal_externalheat.o \ - source_damage_isoBrittle.o source_damage_isoDuctile.o source_damage_anisoBrittle.o source_damage_anisoDuctile.o \ - source_vacancy_phenoplasticity.o source_vacancy_irradiation.o source_vacancy_thermalfluc.o - -KINEMATICS_FILES = \ - kinematics_cleavage_opening.o kinematics_slipplane_opening.o \ - kinematics_thermal_expansion.o \ - kinematics_vacancy_strain.o kinematics_hydrogen_strain.o - -PLASTIC_FILES = \ - plastic_dislotwin.o plastic_disloUCLA.o plastic_isotropic.o plastic_j2.o \ - plastic_phenopowerlaw.o plastic_titanmod.o plastic_nonlocal.o plastic_none.o \ - plastic_phenoplus.o - -THERMAL_FILES = \ - thermal_isothermal.o thermal_adiabatic.o thermal_conduction.o - -DAMAGE_FILES = \ - damage_none.o damage_local.o damage_nonlocal.o - -VACANCYFLUX_FILES = \ - vacancyflux_isoconc.o vacancyflux_isochempot.o vacancyflux_cahnhilliard.o - -POROSITY_FILES = \ - porosity_none.o porosity_phasefield.o - -HYDROGENFLUX_FILES = \ - hydrogenflux_isoconc.o hydrogenflux_cahnhilliard.o - -HOMOGENIZATION_FILES = \ - homogenization_RGC.o homogenization_isostrain.o homogenization_none.o - -##################### -# Spectral Solver -##################### -DAMASK_spectral.exe: IGNORE := \# -DAMASK_spectral.exe: COMPILE += -DSpectral -DAMASK_spectral.exe: COMPILE_MAXOPTI += -DSpectral -DAMASK_spectral.exe: MESHNAME := mesh.f90 -DAMASK_spectral.exe: INTERFACENAME := spectral_interface.f90 - -DAMASK_spectral.o: IGNORE := \# -DAMASK_spectral.o: COMPILE += -DSpectral -DAMASK_spectral.o: COMPILE_MAXOPTI += -DSpectral -DAMASK_spectral.o: MESHNAME := mesh.f90 -DAMASK_spectral.o: INTERFACENAME := spectral_interface.f90 - - -SPECTRAL_SOLVER_FILES = spectral_mech_AL.o spectral_mech_Basic.o spectral_mech_Polarisation.o \ - spectral_thermal.o spectral_damage.o - -SPECTRAL_FILES = prec.o DAMASK_interface.o IO.o libs.o numerics.o debug.o math.o damask_hdf5.o \ - FEsolving.o mesh.o material.o lattice.o \ - $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ - crystallite.o \ - $(THERMAL_FILES) $(DAMAGE_FILES) $(VACANCYFLUX_FILES) $(HYDROGENFLUX_FILES) $(POROSITY_FILES) \ - $(HOMOGENIZATION_FILES) homogenization.o \ - CPFEM2.o \ - spectral_utilities.o \ - $(SPECTRAL_SOLVER_FILES) - -DAMASK_spectral.exe: DAMASK_spectral.o \ - $(SPECTRAL_FILES) - $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ - -o DAMASK_spectral.exe DAMASK_spectral.o \ - $(SPECTRAL_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) - - -DAMASK_spectral.o: DAMASK_spectral.f90 \ - $(SPECTRAL_SOLVER_FILES) - $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c DAMASK_spectral.f90 $(SUFFIX) - -spectral_mech_AL.o: spectral_mech_AL.f90 \ - spectral_utilities.o - -spectral_mech_Polarisation.o: spectral_mech_Polarisation.f90 \ - spectral_utilities.o - -spectral_mech_Basic.o: spectral_mech_Basic.f90 \ - spectral_utilities.o - -spectral_thermal.o: spectral_thermal.f90 \ - spectral_utilities.o - -spectral_damage.o: spectral_damage.f90 \ - spectral_utilities.o - -spectral_utilities.o: spectral_utilities.f90 \ - CPFEM2.o - -##################### -# FEM Solver -##################### -VPATH := ../private/FEM/code -DAMASK_FEM.exe: COMPILE += -DFEM -DAMASK_FEM.exe: COMPILE_MAXOPTI += -DFEM -DAMASK_FEM.exe: MESHNAME := ../private/FEM/code/meshFEM.f90 -DAMASK_FEM.exe: INTERFACENAME := ../private/FEM/code/DAMASK_FEM_interface.f90 -DAMASK_FEM.exe: INCLUDE_DIRS += -I./ - -FEM_SOLVER_FILES = FEM_mech.o FEM_thermal.o FEM_damage.o FEM_vacancyflux.o FEM_porosity.o FEM_hydrogenflux.o - -FEM_FILES = prec.o DAMASK_interface.o FEZoo.o IO.o libs.o numerics.o debug.o math.o \ - FEsolving.o mesh.o material.o lattice.o \ - $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ - crystallite.o \ - $(THERMAL_FILES) $(DAMAGE_FILES) $(VACANCYFLUX_FILES) $(HYDROGENFLUX_FILES) $(POROSITY_FILES) \ - $(HOMOGENIZATION_FILES) homogenization.o \ - CPFEM.o \ - FEM_utilities.o $(FEM_SOLVER_FILES) - -DAMASK_FEM.exe: DAMASK_FEM_driver.o - $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ - -o DAMASK_FEM.exe DAMASK_FEM_driver.o \ - $(FEM_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) - -DAMASK_FEM_driver.o: DAMASK_FEM_driver.f90 $(FEM_SOLVER_FILES) - $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c ../private/FEM/code/DAMASK_FEM_driver.f90 $(SUFFIX) - -FEM_mech.o: FEM_mech.f90 \ - FEM_utilities.o - -FEM_thermal.o: FEM_thermal.f90 \ - FEM_utilities.o - -FEM_damage.o: FEM_damage.f90 \ - FEM_utilities.o - -FEM_vacancyflux.o: FEM_vacancyflux.f90 \ - FEM_utilities.o - -FEM_porosity.o: FEM_porosity.f90 \ - FEM_utilities.o - -FEM_hydrogenflux.o: FEM_hydrogenflux.f90 \ - FEM_utilities.o - -FEM_utilities.o: FEM_utilities.f90 \ - CPFEM.o - -FEZoo.o: $(wildcard FEZoo.f90) \ - IO.o - $(IGNORE) $(PREFIX) $(COMPILERNAME) $(COMPILE) -c ../private/FEM/code/FEZoo.f90 $(SUFFIX) - touch FEZoo.o - -CPFEM.o: CPFEM.f90 \ - homogenization.o - -CPFEM2.o: CPFEM2.f90 \ - homogenization.o - -homogenization.o: homogenization.f90 \ - $(THERMAL_FILES) \ - $(DAMAGE_FILES) \ - $(VACANCYFLUX_FILES) \ - $(POROSITY_FILES) \ - $(HYDROGENFLUX_FILES) \ - $(HOMOGENIZATION_FILES) - -thermal_isothermal.o: thermal_isothermal.f90 \ - crystallite.o - -thermal_adiabatic.o: thermal_adiabatic.f90 \ - crystallite.o - -thermal_conduction.o: thermal_conduction.f90 \ - crystallite.o - -damage_none.o: damage_none.f90 \ - crystallite.o - -damage_local.o: damage_local.f90 \ - crystallite.o - -damage_nonlocal.o: damage_nonlocal.f90 \ - crystallite.o - -thermal_conduction.o: thermal_conduction.f90 \ - crystallite.o - -vacancyflux_isoconc.o: vacancyflux_isoconc.f90 \ - crystallite.o - -vacancyflux_isochempot.o: vacancyflux_isochempot.f90 \ - crystallite.o - -vacancyflux_cahnhilliard.o: vacancyflux_cahnhilliard.f90 \ - crystallite.o - -porosity_none.o: porosity_none.f90 \ - crystallite.o - -porosity_phasefield.o: porosity_phasefield.f90 \ - crystallite.o - -hydrogenflux_isoconc.o: hydrogenflux_isoconc.f90 \ - crystallite.o - -hydrogenflux_cahnhilliard.o: hydrogenflux_cahnhilliard.f90 \ - crystallite.o - -homogenization_RGC.o: homogenization_RGC.f90 \ - crystallite.o - -homogenization_isostrain.o: homogenization_isostrain.f90 \ - crystallite.o - -homogenization_none.o: homogenization_none.f90 \ - crystallite.o - -crystallite.o: crystallite.f90 \ - constitutive.o - -constitutive.o: constitutive.f90 \ - $(SOURCE_FILES) \ - $(KINEMATICS_FILES) \ - $(PLASTIC_FILES) - -source_thermal_dissipation.o: source_thermal_dissipation.f90 \ - lattice.o - -source_thermal_externalheat.o: source_thermal_externalheat.f90 \ - lattice.o - -source_damage_isoBrittle.o: source_damage_isoBrittle.f90 \ - lattice.o - -source_damage_isoDuctile.o: source_damage_isoDuctile.f90 \ - lattice.o - -source_damage_anisoBrittle.o: source_damage_anisoBrittle.f90 \ - lattice.o - -source_damage_anisoDuctile.o: source_damage_anisoDuctile.f90 \ - lattice.o - -source_vacancy_phenoplasticity.o: source_vacancy_phenoplasticity.f90 \ - lattice.o - -source_vacancy_irradiation.o: source_vacancy_irradiation.f90 \ - lattice.o - -source_vacancy_thermalfluc.o: source_vacancy_thermalfluc.f90 \ - lattice.o - -kinematics_cleavage_opening.o: kinematics_cleavage_opening.f90 \ - lattice.o - -kinematics_slipplane_opening.o: kinematics_slipplane_opening.f90 \ - lattice.o - -kinematics_thermal_expansion.o: kinematics_thermal_expansion.f90 \ - lattice.o - -kinematics_vacancy_strain.o: kinematics_vacancy_strain.f90 \ - lattice.o - -kinematics_hydrogen_strain.o: kinematics_hydrogen_strain.f90 \ - lattice.o - -plastic_nonlocal.o: plastic_nonlocal.f90 \ - lattice.o - -plastic_titanmod.o: plastic_titanmod.f90 \ - lattice.o - -plastic_disloUCLA.o: plastic_disloUCLA.f90 \ - lattice.o - -plastic_dislotwin.o: plastic_dislotwin.f90 \ - lattice.o - -plastic_phenopowerlaw.o: plastic_phenopowerlaw.f90 \ - lattice.o - -plastic_phenoplus.o: plastic_phenoplus.f90 \ - lattice.o - -plastic_isotropic.o: plastic_isotropic.f90 \ - lattice.o - -plastic_j2.o: plastic_j2.f90 \ - lattice.o - -plastic_none.o: plastic_none.f90 \ - lattice.o -ifeq "$(F90)" "gfortran" -lattice.o: lattice.f90 \ - material.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -ffree-line-length-240 -c lattice.f90 $(SUFFIX) -# long lines for interaction matrix -else -lattice.o: lattice.f90 \ - material.o -endif - -material.o: material.f90 \ - mesh.o - -mesh.o: mesh.f90 \ - $(wildcard meshFEM.f90) \ - FEsolving.o \ - math.o \ - FEZoo.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(MESHNAME) -o mesh.o $(SUFFIX) - -FEsolving.o: FEsolving.f90 \ - debug.o - -math.o: math.f90 \ - debug.o - -debug.o: debug.f90 \ - numerics.o - -numerics.o: numerics.f90 \ - libs.o - -libs.o: libs.f90 \ - IO.o - -damask_hdf5.o: damask_hdf5.f90 \ - prec.o \ - IO.o - - $(PREFIX) $(COMPILERNAME) $(HDFLIBS) $(HDFLIBZ) -c damask_hdf5.f90 $(SUFFIX) -lm - -IO.o: IO.f90 \ - DAMASK_interface.o - -ifeq "$(F90)" "gfortran" -DAMASK_interface.o: spectral_interface.f90 \ - $(wildcard DAMASK_FEM_interface.f90) \ - prec.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -fall-intrinsics -o DAMASK_interface.o $(SUFFIX) -#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored -# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external -# --> allows the use of 'getcwd' -prec.o: prec.f90 - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 -fno-range-check -fall-intrinsics -fno-fast-math $(SUFFIX) -# fno-range-check: Disable range checking on results of simplification of constant expressions during compilation -# --> allows the definition of DAMASK_NaN -#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored -# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external -# --> allows the use of 'isnan' -#-fno-fast-math: -# --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) -else -DAMASK_interface.o: spectral_interface.f90 \ - $(wildcard DAMASK_FEM_interface.f90) \ - prec.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -diag-remark 7410 -stand none -warn nostderrors -o DAMASK_interface.o $(SUFFIX) -# -diag-disable 7410 should disable warning about directory statement in inquire function, but does not work. hence the other 2 statements -prec.o: prec.f90 - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 $(SUFFIX) - -endif - -%.o : %.f90 - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $< $(SUFFIX) - -.PHONY: tidy -tidy: - @rm -rf *.o - @rm -rf *.mod - @rm -rf *.inst.f90 # for instrumentation - @rm -rf *.pomp.f90 # for instrumentation - @rm -rf *.pp.f90 # for instrumentation - @rm -rf *.pdb # for instrumnentation - @rm -rf *.opari.inc # for instrumnentation - -.PHONY: cleanDAMASK -cleanDAMASK: - @rm -rf *.exe - @rm -rf *.marc - @rm -rf *.o - @rm -rf *.mod - @rm -rf *.inst.f90 # for instrumentation - @rm -rf *.pomp.f90 # for instrumentation - @rm -rf *.pp.f90 # for instrumentation - @rm -rf *.pdb # for instrumentation - @rm -rf *.opari.inc # for instrumentation - -.PHONY: help -help: - F90="$(F90)" - COMPILERNAME="$(COMPILERNAME)" - COMPILEROUT="$(COMPILEROUT)" - diff --git a/code/commercialFEM_fileList.f90 b/code/commercialFEM_fileList.f90 deleted file mode 100644 index 8567da5b1..000000000 --- a/code/commercialFEM_fileList.f90 +++ /dev/null @@ -1,59 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief all DAMASK files without solver -!> @details List of files needed by MSC.Marc, Abaqus/Explicit, and Abaqus/Standard -!-------------------------------------------------------------------------------------------------- -#include "IO.f90" -#include "libs.f90" -#include "numerics.f90" -#include "debug.f90" -#include "math.f90" -#include "FEsolving.f90" -#include "mesh.f90" -#include "material.f90" -#include "lattice.f90" -#include "source_thermal_dissipation.f90" -#include "source_thermal_externalheat.f90" -#include "source_damage_isoBrittle.f90" -#include "source_damage_isoDuctile.f90" -#include "source_damage_anisoBrittle.f90" -#include "source_damage_anisoDuctile.f90" -#include "source_vacancy_phenoplasticity.f90" -#include "source_vacancy_irradiation.f90" -#include "source_vacancy_thermalfluc.f90" -#include "kinematics_cleavage_opening.f90" -#include "kinematics_slipplane_opening.f90" -#include "kinematics_thermal_expansion.f90" -#include "kinematics_vacancy_strain.f90" -#include "kinematics_hydrogen_strain.f90" -#include "plastic_none.f90" -#include "plastic_isotropic.f90" -#include "plastic_j2.f90" -#include "plastic_phenopowerlaw.f90" -#include "plastic_phenoplus.f90" -#include "plastic_titanmod.f90" -#include "plastic_dislotwin.f90" -#include "plastic_disloUCLA.f90" -#include "plastic_nonlocal.f90" -#include "constitutive.f90" -#include "crystallite.f90" -#include "homogenization_none.f90" -#include "homogenization_isostrain.f90" -#include "homogenization_RGC.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 "vacancyflux_isoconc.f90" -#include "vacancyflux_isochempot.f90" -#include "vacancyflux_cahnhilliard.f90" -#include "porosity_none.f90" -#include "porosity_phasefield.f90" -#include "hydrogenflux_isoconc.f90" -#include "hydrogenflux_cahnhilliard.f90" -#include "homogenization.f90" -#include "CPFEM.f90" diff --git a/code/compilation_info.f90 b/code/compilation_info.f90 deleted file mode 100644 index 64e6b136c..000000000 --- a/code/compilation_info.f90 +++ /dev/null @@ -1,13 +0,0 @@ -!############################################################## -!$Id$ -#ifdef __GFORTRAN__ - write(6,*) 'Compiled with ', compiler_version() !not supported by and ifort <= 15 (and old gfortran) - write(6,*) 'With options ', compiler_options() -#endif -#ifdef __INTEL_COMPILER - write(6,'(a,i4.4,a,i8.8)') ' Compiled with Intel fortran version ', __INTEL_COMPILER,& - ', build date ', __INTEL_COMPILER_BUILD_DATE -#endif -write(6,*) 'Compiled on ', __DATE__,' at ',__TIME__ -write(6,*) -flush(6) diff --git a/code/constitutive.f90 b/code/constitutive.f90 deleted file mode 100644 index 50c77b481..000000000 --- a/code/constitutive.f90 +++ /dev/null @@ -1,1226 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief elasticity, plasticity, internal microstructure state -!-------------------------------------------------------------------------------------------------- -module constitutive - use prec, only: & - pInt - - implicit none - private - integer(pInt), public, protected :: & - constitutive_plasticity_maxSizePostResults, & - constitutive_plasticity_maxSizeDotState, & - constitutive_source_maxSizePostResults, & - constitutive_source_maxSizeDotState - - public :: & - constitutive_init, & - constitutive_homogenizedC, & - constitutive_microstructure, & - constitutive_LpAndItsTangent, & - constitutive_LiAndItsTangent, & - constitutive_initialFi, & - constitutive_TandItsTangent, & - constitutive_collectDotState, & - constitutive_collectDeltaState, & - constitutive_postResults - - private :: & - constitutive_hooke_TandItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates arrays pointing to array of the various constitutive modules -!-------------------------------------------------------------------------------------------------- -subroutine constitutive_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal - use debug, only: & - debug_constitutive, & - debug_levelBasic - use numerics, only: & - worldrank - use IO, only: & - IO_error, & - IO_open_file, & - IO_checkAndRewind, & - IO_open_jobFile_stat, & - IO_write_jobFile, & - IO_write_jobIntFile, & - IO_timeStamp - use mesh, only: & - FE_geomtype - use material, only: & - material_phase, & - material_Nphase, & - material_localFileExt, & - material_configFile, & - phase_name, & - phase_plasticity, & - phase_plasticityInstance, & - phase_Nsources, & - phase_source, & - phase_kinematics, & - ELASTICITY_hooke_ID, & - PLASTICITY_none_ID, & - PLASTICITY_isotropic_ID, & - PLASTICITY_j2_ID, & - PLASTICITY_phenopowerlaw_ID, & - PLASTICITY_phenoplus_ID, & - PLASTICITY_dislotwin_ID, & - PLASTICITY_disloucla_ID, & - PLASTICITY_titanmod_ID, & - PLASTICITY_nonlocal_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, & - SOURCE_vacancy_phenoplasticity_ID, & - SOURCE_vacancy_irradiation_ID, & - SOURCE_vacancy_thermalfluc_ID, & - KINEMATICS_cleavage_opening_ID, & - KINEMATICS_slipplane_opening_ID, & - KINEMATICS_thermal_expansion_ID, & - KINEMATICS_vacancy_strain_ID, & - KINEMATICS_hydrogen_strain_ID, & - ELASTICITY_HOOKE_label, & - PLASTICITY_NONE_label, & - PLASTICITY_ISOTROPIC_label, & - PLASTICITY_J2_label, & - PLASTICITY_PHENOPOWERLAW_label, & - PLASTICITY_PHENOPLUS_label, & - PLASTICITY_DISLOTWIN_label, & - PLASTICITY_DISLOUCLA_label, & - PLASTICITY_TITANMOD_label, & - PLASTICITY_NONLOCAL_label, & - SOURCE_thermal_dissipation_label, & - SOURCE_thermal_externalheat_label, & - SOURCE_damage_isoBrittle_label, & - SOURCE_damage_isoDuctile_label, & - SOURCE_damage_anisoBrittle_label, & - SOURCE_damage_anisoDuctile_label, & - SOURCE_vacancy_phenoplasticity_label, & - SOURCE_vacancy_irradiation_label, & - SOURCE_vacancy_thermalfluc_label, & - plasticState, & - sourceState - - use plastic_none - use plastic_isotropic - use plastic_j2 - use plastic_phenopowerlaw - use plastic_phenoplus - use plastic_dislotwin - use plastic_disloucla - use plastic_titanmod - use plastic_nonlocal - use source_thermal_dissipation - use source_thermal_externalheat - use source_damage_isoBrittle - use source_damage_isoDuctile - use source_damage_anisoBrittle - use source_damage_anisoDuctile - use source_vacancy_phenoplasticity - use source_vacancy_irradiation - use source_vacancy_thermalfluc - use kinematics_cleavage_opening - use kinematics_slipplane_opening - use kinematics_thermal_expansion - use kinematics_vacancy_strain - use kinematics_hydrogen_strain - - implicit none - integer(pInt), parameter :: FILEUNIT = 200_pInt - integer(pInt) :: & - o, & !< counter in output loop - p, & !< counter in phase loop - s, & !< counter in source loop - ins !< instance of plasticity/source - - integer(pInt), dimension(:,:), pointer :: thisSize - integer(pInt), dimension(:) , pointer :: thisNoutput - character(len=64), dimension(:,:), pointer :: thisOutput - character(len=32) :: outputName !< name of output, intermediate fix until HDF5 output is ready - logical :: knownPlasticity, knownSource, nonlocalConstitutionPresent - nonlocalConstitutionPresent = .false. - -!-------------------------------------------------------------------------------------------------- -! open material.config - if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... - call IO_open_file(FILEUNIT,material_configFile) ! ... open material.config file - -!-------------------------------------------------------------------------------------------------- -! parse plasticities from config file - if (any(phase_plasticity == PLASTICITY_NONE_ID)) call plastic_none_init - if (any(phase_plasticity == PLASTICITY_ISOTROPIC_ID)) call plastic_isotropic_init(FILEUNIT) - if (any(phase_plasticity == PLASTICITY_J2_ID)) call plastic_j2_init(FILEUNIT) - if (any(phase_plasticity == PLASTICITY_PHENOPOWERLAW_ID)) call plastic_phenopowerlaw_init(FILEUNIT) - if (any(phase_plasticity == PLASTICITY_PHENOPLUS_ID)) call plastic_phenoplus_init(FILEUNIT) - if (any(phase_plasticity == PLASTICITY_DISLOTWIN_ID)) call plastic_dislotwin_init(FILEUNIT) - if (any(phase_plasticity == PLASTICITY_DISLOUCLA_ID)) call plastic_disloucla_init(FILEUNIT) - if (any(phase_plasticity == PLASTICITY_TITANMOD_ID)) call plastic_titanmod_init(FILEUNIT) - if (any(phase_plasticity == PLASTICITY_NONLOCAL_ID)) then - call plastic_nonlocal_init(FILEUNIT) - call plastic_nonlocal_stateInit() - endif - -!-------------------------------------------------------------------------------------------------- -! parse source mechanisms from config file - call IO_checkAndRewind(FILEUNIT) - if (any(phase_source == SOURCE_thermal_dissipation_ID)) call source_thermal_dissipation_init(FILEUNIT) - if (any(phase_source == SOURCE_thermal_externalheat_ID)) call source_thermal_externalheat_init(FILEUNIT) - if (any(phase_source == SOURCE_damage_isoBrittle_ID)) call source_damage_isoBrittle_init(FILEUNIT) - if (any(phase_source == SOURCE_damage_isoDuctile_ID)) call source_damage_isoDuctile_init(FILEUNIT) - if (any(phase_source == SOURCE_damage_anisoBrittle_ID)) call source_damage_anisoBrittle_init(FILEUNIT) - if (any(phase_source == SOURCE_damage_anisoDuctile_ID)) call source_damage_anisoDuctile_init(FILEUNIT) - if (any(phase_source == SOURCE_vacancy_phenoplasticity_ID)) call source_vacancy_phenoplasticity_init(FILEUNIT) - if (any(phase_source == SOURCE_vacancy_irradiation_ID)) call source_vacancy_irradiation_init(FILEUNIT) - if (any(phase_source == SOURCE_vacancy_thermalfluc_ID)) call source_vacancy_thermalfluc_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse kinematic mechanisms from config file - call IO_checkAndRewind(FILEUNIT) - if (any(phase_kinematics == KINEMATICS_cleavage_opening_ID)) call kinematics_cleavage_opening_init(FILEUNIT) - if (any(phase_kinematics == KINEMATICS_slipplane_opening_ID)) call kinematics_slipplane_opening_init(FILEUNIT) - if (any(phase_kinematics == KINEMATICS_thermal_expansion_ID)) call kinematics_thermal_expansion_init(FILEUNIT) - if (any(phase_kinematics == KINEMATICS_vacancy_strain_ID)) call kinematics_vacancy_strain_init(FILEUNIT) - if (any(phase_kinematics == KINEMATICS_hydrogen_strain_ID)) call kinematics_hydrogen_strain_init(FILEUNIT) - close(FILEUNIT) - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - -!-------------------------------------------------------------------------------------------------- -! write description file for constitutive output - call IO_write_jobFile(FILEUNIT,'outputConstitutive') - PhaseLoop: do p = 1_pInt,material_Nphase - activePhase: if (any(material_phase == p)) then - ins = phase_plasticityInstance(p) - knownPlasticity = .true. ! assume valid - plasticityType: select case(phase_plasticity(p)) - case (PLASTICITY_NONE_ID) plasticityType - outputName = PLASTICITY_NONE_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (PLASTICITY_ISOTROPIC_ID) plasticityType - outputName = PLASTICITY_ISOTROPIC_label - thisNoutput => plastic_isotropic_Noutput - thisOutput => plastic_isotropic_output - thisSize => plastic_isotropic_sizePostResult - case (PLASTICITY_J2_ID) plasticityType - outputName = PLASTICITY_J2_label - thisNoutput => plastic_j2_Noutput - thisOutput => plastic_j2_output - thisSize => plastic_j2_sizePostResult - case (PLASTICITY_PHENOPOWERLAW_ID) plasticityType - outputName = PLASTICITY_PHENOPOWERLAW_label - thisNoutput => plastic_phenopowerlaw_Noutput - thisOutput => plastic_phenopowerlaw_output - thisSize => plastic_phenopowerlaw_sizePostResult - case (PLASTICITY_PHENOPLUS_ID) plasticityType - outputName = PLASTICITY_PHENOPLUS_label - thisNoutput => plastic_phenoplus_Noutput - thisOutput => plastic_phenoplus_output - thisSize => plastic_phenoplus_sizePostResult - case (PLASTICITY_DISLOTWIN_ID) plasticityType - outputName = PLASTICITY_DISLOTWIN_label - thisNoutput => plastic_dislotwin_Noutput - thisOutput => plastic_dislotwin_output - thisSize => plastic_dislotwin_sizePostResult - case (PLASTICITY_DISLOUCLA_ID) plasticityType - outputName = PLASTICITY_DISLOUCLA_label - thisNoutput => plastic_disloucla_Noutput - thisOutput => plastic_disloucla_output - thisSize => plastic_disloucla_sizePostResult - case (PLASTICITY_TITANMOD_ID) plasticityType - outputName = PLASTICITY_TITANMOD_label - thisNoutput => plastic_titanmod_Noutput - thisOutput => plastic_titanmod_output - thisSize => plastic_titanmod_sizePostResult - case (PLASTICITY_NONLOCAL_ID) plasticityType - outputName = PLASTICITY_NONLOCAL_label - thisNoutput => plastic_nonlocal_Noutput - thisOutput => plastic_nonlocal_output - thisSize => plastic_nonlocal_sizePostResult - case default plasticityType - knownPlasticity = .false. - end select plasticityType - write(FILEUNIT,'(/,a,/)') '['//trim(phase_name(p))//']' - if (knownPlasticity) then - - write(FILEUNIT,'(a)') '(plasticity)'//char(9)//trim(outputName) - if (phase_plasticity(p) /= PLASTICITY_NONE_ID) then - OutputPlasticityLoop: do o = 1_pInt,thisNoutput(ins) - write(FILEUNIT,'(a,i4)') trim(thisOutput(o,ins))//char(9),thisSize(o,ins) - enddo OutputPlasticityLoop - endif - endif - SourceLoop: do s = 1_pInt, phase_Nsources(p) - knownSource = .true. ! assume valid - sourceType: select case (phase_source(s,p)) - case (SOURCE_thermal_dissipation_ID) sourceType - ins = source_thermal_dissipation_instance(p) - outputName = SOURCE_thermal_dissipation_label - thisNoutput => source_thermal_dissipation_Noutput - thisOutput => source_thermal_dissipation_output - thisSize => source_thermal_dissipation_sizePostResult - case (SOURCE_thermal_externalheat_ID) sourceType - ins = source_thermal_externalheat_instance(p) - outputName = SOURCE_thermal_externalheat_label - thisNoutput => source_thermal_externalheat_Noutput - thisOutput => source_thermal_externalheat_output - thisSize => source_thermal_externalheat_sizePostResult - case (SOURCE_damage_isoBrittle_ID) sourceType - ins = source_damage_isoBrittle_instance(p) - outputName = SOURCE_damage_isoBrittle_label - thisNoutput => source_damage_isoBrittle_Noutput - thisOutput => source_damage_isoBrittle_output - thisSize => source_damage_isoBrittle_sizePostResult - case (SOURCE_damage_isoDuctile_ID) sourceType - ins = source_damage_isoDuctile_instance(p) - outputName = SOURCE_damage_isoDuctile_label - thisNoutput => source_damage_isoDuctile_Noutput - thisOutput => source_damage_isoDuctile_output - thisSize => source_damage_isoDuctile_sizePostResult - case (SOURCE_damage_anisoBrittle_ID) sourceType - ins = source_damage_anisoBrittle_instance(p) - outputName = SOURCE_damage_anisoBrittle_label - thisNoutput => source_damage_anisoBrittle_Noutput - thisOutput => source_damage_anisoBrittle_output - thisSize => source_damage_anisoBrittle_sizePostResult - case (SOURCE_damage_anisoDuctile_ID) sourceType - ins = source_damage_anisoDuctile_instance(p) - outputName = SOURCE_damage_anisoDuctile_label - thisNoutput => source_damage_anisoDuctile_Noutput - thisOutput => source_damage_anisoDuctile_output - thisSize => source_damage_anisoDuctile_sizePostResult - case (SOURCE_vacancy_phenoplasticity_ID) sourceType - ins = source_vacancy_phenoplasticity_instance(p) - outputName = SOURCE_vacancy_phenoplasticity_label - thisNoutput => source_vacancy_phenoplasticity_Noutput - thisOutput => source_vacancy_phenoplasticity_output - thisSize => source_vacancy_phenoplasticity_sizePostResult - case (SOURCE_vacancy_irradiation_ID) sourceType - ins = source_vacancy_irradiation_instance(p) - outputName = SOURCE_vacancy_irradiation_label - thisNoutput => source_vacancy_irradiation_Noutput - thisOutput => source_vacancy_irradiation_output - thisSize => source_vacancy_irradiation_sizePostResult - case (SOURCE_vacancy_thermalfluc_ID) sourceType - ins = source_vacancy_thermalfluc_instance(p) - outputName = SOURCE_vacancy_thermalfluc_label - thisNoutput => source_vacancy_thermalfluc_Noutput - thisOutput => source_vacancy_thermalfluc_output - thisSize => source_vacancy_thermalfluc_sizePostResult - case default sourceType - knownSource = .false. - end select sourceType - if (knownSource) then - write(FILEUNIT,'(a)') '(source)'//char(9)//trim(outputName) - OutputSourceLoop: do o = 1_pInt,thisNoutput(ins) - write(FILEUNIT,'(a,i4)') trim(thisOutput(o,ins))//char(9),thisSize(o,ins) - enddo OutputSourceLoop - endif - enddo SourceLoop - endif activePhase - enddo PhaseLoop - close(FILEUNIT) - endif mainProcess - - constitutive_plasticity_maxSizeDotState = 0_pInt - constitutive_plasticity_maxSizePostResults = 0_pInt - constitutive_source_maxSizeDotState = 0_pInt - constitutive_source_maxSizePostResults = 0_pInt - - PhaseLoop2:do p = 1_pInt,material_Nphase -!-------------------------------------------------------------------------------------------------- -! partition and inititalize state - plasticState(p)%partionedState0 = plasticState(p)%State0 - plasticState(p)%State = plasticState(p)%State0 - forall(s = 1_pInt:phase_Nsources(p)) - sourceState(p)%p(s)%partionedState0 = sourceState(p)%p(s)%State0 - sourceState(p)%p(s)%State = sourceState(p)%p(s)%State0 - end forall -!-------------------------------------------------------------------------------------------------- -! determine max size of state and output - constitutive_plasticity_maxSizeDotState = max(constitutive_plasticity_maxSizeDotState, & - plasticState(p)%sizeDotState) - constitutive_plasticity_maxSizePostResults = max(constitutive_plasticity_maxSizePostResults, & - plasticState(p)%sizePostResults) - constitutive_source_maxSizeDotState = max(constitutive_source_maxSizeDotState, & - maxval(sourceState(p)%p(:)%sizeDotState)) - constitutive_source_maxSizePostResults = max(constitutive_source_maxSizePostResults, & - maxval(sourceState(p)%p(:)%sizePostResults)) - enddo PhaseLoop2 - - -#ifdef TODO -!-------------------------------------------------------------------------------------------------- -! report - constitutive_maxSizeState = maxval(constitutive_sizeState) - constitutive_plasticity_maxSizeDotState = maxval(constitutive_sizeDotState) - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) then - write(6,'(a32,1x,7(i8,1x))') 'constitutive_state0: ', shape(constitutive_state0) - write(6,'(a32,1x,7(i8,1x))') 'constitutive_partionedState0: ', shape(constitutive_partionedState0) - write(6,'(a32,1x,7(i8,1x))') 'constitutive_subState0: ', shape(constitutive_subState0) - write(6,'(a32,1x,7(i8,1x))') 'constitutive_state: ', shape(constitutive_state) - write(6,'(a32,1x,7(i8,1x))') 'constitutive_aTolState: ', shape(constitutive_aTolState) - write(6,'(a32,1x,7(i8,1x))') 'constitutive_dotState: ', shape(constitutive_dotState) - write(6,'(a32,1x,7(i8,1x))') 'constitutive_deltaState: ', shape(constitutive_deltaState) - write(6,'(a32,1x,7(i8,1x))') 'constitutive_sizeState: ', shape(constitutive_sizeState) - write(6,'(a32,1x,7(i8,1x))') 'constitutive_sizeDotState: ', shape(constitutive_sizeDotState) - write(6,'(a32,1x,7(i8,1x),/)') 'constitutive_sizePostResults: ', shape(constitutive_sizePostResults) - write(6,'(a32,1x,7(i8,1x))') 'maxSizeState: ', constitutive_maxSizeState - write(6,'(a32,1x,7(i8,1x))') 'maxSizeDotState: ', constitutive_plasticity_maxSizeDotState - write(6,'(a32,1x,7(i8,1x))') 'maxSizePostResults: ', constitutive_plasticity_maxSizePostResults - endif - flush(6) -#endif - - -end subroutine constitutive_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenize elasticity matrix -!-------------------------------------------------------------------------------------------------- -function constitutive_homogenizedC(ipc,ip,el) - use prec, only: & - pReal - use material, only: & - phase_plasticity, & - material_phase, & - PLASTICITY_TITANMOD_ID, & - PLASTICITY_DISLOTWIN_ID, & - PLASTICITY_DISLOUCLA_ID - use plastic_titanmod, only: & - plastic_titanmod_homogenizedC - use plastic_dislotwin, only: & - plastic_dislotwin_homogenizedC - use plastic_disloucla, only: & - plastic_disloucla_homogenizedC - use lattice, only: & - lattice_C66 - - implicit none - real(pReal), dimension(6,6) :: constitutive_homogenizedC - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) - case (PLASTICITY_DISLOTWIN_ID) plasticityType - constitutive_homogenizedC = plastic_dislotwin_homogenizedC(ipc,ip,el) - case (PLASTICITY_DISLOUCLA_ID) plasticityType - constitutive_homogenizedC = plastic_disloucla_homogenizedC(ipc,ip,el) - case (PLASTICITY_TITANMOD_ID) plasticityType - constitutive_homogenizedC = plastic_titanmod_homogenizedC (ipc,ip,el) - case default plasticityType - constitutive_homogenizedC = lattice_C66(1:6,1:6,material_phase (ipc,ip,el)) - end select plasticityType - -end function constitutive_homogenizedC - -!-------------------------------------------------------------------------------------------------- -!> @brief calls microstructure function of the different constitutive models -!-------------------------------------------------------------------------------------------------- -subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el) - use prec, only: & - pReal - use material, only: & - phase_plasticity, & - material_phase, & - material_homog, & - temperature, & - thermalMapping, & - PLASTICITY_dislotwin_ID, & - PLASTICITY_disloucla_ID, & - PLASTICITY_titanmod_ID, & - PLASTICITY_nonlocal_ID, & - PLASTICITY_phenoplus_ID - use plastic_titanmod, only: & - plastic_titanmod_microstructure - use plastic_nonlocal, only: & - plastic_nonlocal_microstructure - use plastic_dislotwin, only: & - plastic_dislotwin_microstructure - use plastic_disloucla, only: & - plastic_disloucla_microstructure - use plastic_phenoplus, only: & - plastic_phenoplus_microstructure - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(3,3) :: & - Fe, & !< elastic deformation gradient - Fp !< plastic deformation gradient - integer(pInt) :: & - ho, & !< homogenization - tme !< thermal member position - real(pReal), intent(in), dimension(:,:,:,:) :: & - orientations !< crystal orientations as quaternions - - ho = material_homog(ip,el) - tme = thermalMapping(ho)%p(ip,el) - - plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) - case (PLASTICITY_DISLOTWIN_ID) plasticityType - call plastic_dislotwin_microstructure(temperature(ho)%p(tme),ipc,ip,el) - case (PLASTICITY_DISLOUCLA_ID) plasticityType - call plastic_disloucla_microstructure(temperature(ho)%p(tme),ipc,ip,el) - case (PLASTICITY_TITANMOD_ID) plasticityType - call plastic_titanmod_microstructure (temperature(ho)%p(tme),ipc,ip,el) - case (PLASTICITY_NONLOCAL_ID) plasticityType - call plastic_nonlocal_microstructure (Fe,Fp,ip,el) - case (PLASTICITY_PHENOPLUS_ID) plasticityType - call plastic_phenoplus_microstructure(orientations,ipc,ip,el) - end select plasticityType - -end subroutine constitutive_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine constitutive_LpAndItsTangent(Lp, dLp_dTstar3333, dLp_dFi3333, Tstar_v, Fi, ipc, ip, el) - use prec, only: & - pReal - use math, only: & - math_mul33x33, & - math_Mandel6to33, & - math_Mandel33to6, & - math_Plain99to3333 - use material, only: & - phase_plasticity, & - material_phase, & - material_homog, & - temperature, & - thermalMapping, & - PLASTICITY_NONE_ID, & - PLASTICITY_ISOTROPIC_ID, & - PLASTICITY_J2_ID, & - PLASTICITY_PHENOPOWERLAW_ID, & - PLASTICITY_PHENOPLUS_ID, & - PLASTICITY_DISLOTWIN_ID, & - PLASTICITY_DISLOUCLA_ID, & - PLASTICITY_TITANMOD_ID, & - PLASTICITY_NONLOCAL_ID - use plastic_isotropic, only: & - plastic_isotropic_LpAndItsTangent - use plastic_j2, only: & - plastic_j2_LpAndItsTangent - use plastic_phenopowerlaw, only: & - plastic_phenopowerlaw_LpAndItsTangent - use plastic_phenoplus, only: & - plastic_phenoplus_LpAndItsTangent - use plastic_dislotwin, only: & - plastic_dislotwin_LpAndItsTangent - use plastic_disloucla, only: & - plastic_disloucla_LpAndItsTangent - use plastic_titanmod, only: & - plastic_titanmod_LpAndItsTangent - use plastic_nonlocal, only: & - plastic_nonlocal_LpAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola-Kirchhoff stress - real(pReal), intent(in), dimension(3,3) :: & - Fi !< intermediate deformation gradient - real(pReal), intent(out), dimension(3,3) :: & - Lp !< plastic velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLp_dTstar3333, & !< derivative of Lp with respect to Tstar (4th-order tensor) - dLp_dFi3333 !< derivative of Lp with respect to Fi (4th-order tensor) - real(pReal), dimension(6) :: & - Mstar_v !< Mandel stress work conjugate with Lp - real(pReal), dimension(9,9) :: & - dLp_dMstar !< derivative of Lp with respect to Mstar (4th-order tensor) - real(pReal), dimension(3,3) :: & - temp_33 - integer(pInt) :: & - ho, & !< homogenization - tme !< thermal member position - integer(pInt) :: & - i, j - - ho = material_homog(ip,el) - tme = thermalMapping(ho)%p(ip,el) - - Mstar_v = math_Mandel33to6(math_mul33x33(math_mul33x33(transpose(Fi),Fi),math_Mandel6to33(Tstar_v))) - - plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) - case (PLASTICITY_NONE_ID) plasticityType - Lp = 0.0_pReal - dLp_dMstar = 0.0_pReal - case (PLASTICITY_ISOTROPIC_ID) plasticityType - call plastic_isotropic_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v,ipc,ip,el) - case (PLASTICITY_J2_ID) plasticityType - call plastic_j2_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v,ipc,ip,el) - case (PLASTICITY_PHENOPOWERLAW_ID) plasticityType - call plastic_phenopowerlaw_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v,ipc,ip,el) - case (PLASTICITY_PHENOPLUS_ID) plasticityType - call plastic_phenoplus_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v,ipc,ip,el) - case (PLASTICITY_NONLOCAL_ID) plasticityType - call plastic_nonlocal_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v, & - temperature(ho)%p(tme),ip,el) - case (PLASTICITY_DISLOTWIN_ID) plasticityType - call plastic_dislotwin_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v, & - temperature(ho)%p(tme),ipc,ip,el) - case (PLASTICITY_DISLOUCLA_ID) plasticityType - call plastic_disloucla_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v, & - temperature(ho)%p(tme), ipc,ip,el) - case (PLASTICITY_TITANMOD_ID) plasticityType - call plastic_titanmod_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v, & - temperature(ho)%p(tme), ipc,ip,el) - end select plasticityType - - dLp_dTstar3333 = math_Plain99to3333(dLp_dMstar) - temp_33 = math_mul33x33(Fi,math_Mandel6to33(Tstar_v)) - forall(i = 1_pInt:3_pInt, j = 1_pInt:3_pInt) & - dLp_dFi3333(i,j,1:3,1:3) = math_mul33x33(temp_33,transpose(dLp_dTstar3333(i,j,1:3,1:3))) + & - math_mul33x33(math_mul33x33(Fi,dLp_dTstar3333(i,j,1:3,1:3)),math_Mandel6to33(Tstar_v)) - - temp_33 = math_mul33x33(transpose(Fi),Fi) - - forall(i = 1_pInt:3_pInt, j = 1_pInt:3_pInt) & - dLp_dTstar3333(i,j,1:3,1:3) = math_mul33x33(temp_33,dLp_dTstar3333(i,j,1:3,1:3)) - -end subroutine constitutive_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine constitutive_LiAndItsTangent(Li, dLi_dTstar3333, dLi_dFi3333, Tstar_v, Fi, ipc, ip, el) - use prec, only: & - pReal - use math, only: & - math_I3, & - math_inv33, & - math_det33, & - math_mul33x33 - use material, only: & - phase_plasticity, & - material_phase, & - material_homog, & - phaseAt, phasememberAt, & - phase_kinematics, & - phase_Nkinematics, & - PLASTICITY_isotropic_ID, & - KINEMATICS_cleavage_opening_ID, & - KINEMATICS_slipplane_opening_ID, & - KINEMATICS_thermal_expansion_ID, & - KINEMATICS_vacancy_strain_ID, & - KINEMATICS_hydrogen_strain_ID - use plastic_isotropic, only: & - plastic_isotropic_LiAndItsTangent - use kinematics_cleavage_opening, only: & - kinematics_cleavage_opening_LiAndItsTangent - use kinematics_slipplane_opening, only: & - kinematics_slipplane_opening_LiAndItsTangent - use kinematics_thermal_expansion, only: & - kinematics_thermal_expansion_LiAndItsTangent - use kinematics_vacancy_strain, only: & - kinematics_vacancy_strain_LiAndItsTangent - use kinematics_hydrogen_strain, only: & - kinematics_hydrogen_strain_LiAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola-Kirchhoff stress - real(pReal), intent(in), dimension(3,3) :: & - Fi !< intermediate deformation gradient - real(pReal), intent(out), dimension(3,3) :: & - Li !< intermediate velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLi_dTstar3333, & !< derivative of Li with respect to Tstar (4th-order tensor) - dLi_dFi3333 - real(pReal), dimension(3,3) :: & - my_Li !< intermediate velocity gradient - real(pReal), dimension(3,3,3,3) :: & - my_dLi_dTstar - real(pReal), dimension(3,3) :: & - FiInv, & - temp_33 - real(pReal) :: & - detFi - integer(pInt) :: & - k !< counter in kinematics loop - integer(pInt) :: & - i, j - - Li = 0.0_pReal - dLi_dTstar3333 = 0.0_pReal - dLi_dFi3333 = 0.0_pReal - - plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) - case (PLASTICITY_isotropic_ID) plasticityType - call plastic_isotropic_LiAndItsTangent(my_Li, my_dLi_dTstar, Tstar_v, ipc, ip, el) - case default plasticityType - my_Li = 0.0_pReal - my_dLi_dTstar = 0.0_pReal - end select plasticityType - - Li = Li + my_Li - dLi_dTstar3333 = dLi_dTstar3333 + my_dLi_dTstar - - KinematicsLoop: do k = 1_pInt, phase_Nkinematics(material_phase(ipc,ip,el)) - kinematicsType: select case (phase_kinematics(k,material_phase(ipc,ip,el))) - case (KINEMATICS_cleavage_opening_ID) kinematicsType - call kinematics_cleavage_opening_LiAndItsTangent(my_Li, my_dLi_dTstar, Tstar_v, ipc, ip, el) - case (KINEMATICS_slipplane_opening_ID) kinematicsType - call kinematics_slipplane_opening_LiAndItsTangent(my_Li, my_dLi_dTstar, Tstar_v, ipc, ip, el) - case (KINEMATICS_thermal_expansion_ID) kinematicsType - call kinematics_thermal_expansion_LiAndItsTangent(my_Li, my_dLi_dTstar, ipc, ip, el) - case (KINEMATICS_vacancy_strain_ID) kinematicsType - call kinematics_vacancy_strain_LiAndItsTangent(my_Li, my_dLi_dTstar, ipc, ip, el) - case (KINEMATICS_hydrogen_strain_ID) kinematicsType - call kinematics_hydrogen_strain_LiAndItsTangent(my_Li, my_dLi_dTstar, ipc, ip, el) - case default kinematicsType - my_Li = 0.0_pReal - my_dLi_dTstar = 0.0_pReal - end select kinematicsType - Li = Li + my_Li - dLi_dTstar3333 = dLi_dTstar3333 + my_dLi_dTstar - enddo KinematicsLoop - - FiInv = math_inv33(Fi) - detFi = math_det33(Fi) - Li = math_mul33x33(math_mul33x33(Fi,Li),FiInv)*detFi !< push forward to intermediate configuration - temp_33 = math_mul33x33(FiInv,Li) - forall(i = 1_pInt:3_pInt, j = 1_pInt:3_pInt) - dLi_dTstar3333(1:3,1:3,i,j) = math_mul33x33(math_mul33x33(Fi,dLi_dTstar3333(1:3,1:3,i,j)),FiInv)*detFi - dLi_dFi3333 (1:3,1:3,i,j) = dLi_dFi3333(1:3,1:3,i,j) + Li*FiInv(j,i) - dLi_dFi3333 (1:3,i,1:3,j) = dLi_dFi3333(1:3,i,1:3,j) + math_I3*temp_33(j,i) + Li*FiInv(j,i) - end forall - -end subroutine constitutive_LiAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief collects initial intermediate deformation gradient -!-------------------------------------------------------------------------------------------------- -pure function constitutive_initialFi(ipc, ip, el) - use prec, only: & - pReal - use math, only: & - math_I3, & - math_inv33, & - math_mul33x33 - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - material_phase, & - KINEMATICS_thermal_expansion_ID, & - KINEMATICS_vacancy_strain_ID, & - KINEMATICS_hydrogen_strain_ID - use kinematics_thermal_expansion, only: & - kinematics_thermal_expansion_initialStrain - use kinematics_vacancy_strain, only: & - kinematics_vacancy_strain_initialStrain - use kinematics_hydrogen_strain, only: & - kinematics_hydrogen_strain_initialStrain - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(3,3) :: & - constitutive_initialFi !< composite initial intermediate deformation gradient - integer(pInt) :: & - k !< counter in kinematics loop - - constitutive_initialFi = math_I3 - - KinematicsLoop: do k = 1_pInt, phase_Nkinematics(material_phase(ipc,ip,el)) !< Warning: small initial strain assumption - kinematicsType: select case (phase_kinematics(k,material_phase(ipc,ip,el))) - case (KINEMATICS_thermal_expansion_ID) kinematicsType - constitutive_initialFi = & - constitutive_initialFi + kinematics_thermal_expansion_initialStrain(ipc, ip, el) - case (KINEMATICS_vacancy_strain_ID) kinematicsType - constitutive_initialFi = & - constitutive_initialFi + kinematics_vacancy_strain_initialStrain(ipc, ip, el) - case (KINEMATICS_hydrogen_strain_ID) kinematicsType - constitutive_initialFi = & - constitutive_initialFi + kinematics_hydrogen_strain_initialStrain(ipc, ip, el) - end select kinematicsType - enddo KinematicsLoop - -end function constitutive_initialFi - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the 2nd Piola-Kirchhoff stress tensor and its tangent with respect to -!> the elastic deformation gradient depending on the selected elastic law (so far no case switch -!! because only hooke is implemented -!-------------------------------------------------------------------------------------------------- -subroutine constitutive_TandItsTangent(T, dT_dFe, dT_dFi, Fe, Fi, ipc, ip, el) - use prec, only: & - pReal - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(3,3) :: & - Fe, & !< elastic deformation gradient - Fi !< intermediate deformation gradient - real(pReal), intent(out), dimension(3,3) :: & - T !< 2nd Piola-Kirchhoff stress tensor - real(pReal), intent(out), dimension(3,3,3,3) :: & - dT_dFe, & !< derivative of 2nd P-K stress with respect to elastic deformation gradient - dT_dFi !< derivative of 2nd P-K stress with respect to intermediate deformation gradient - - call constitutive_hooke_TandItsTangent(T, dT_dFe, dT_dFi, Fe, Fi, ipc, ip, el) - - -end subroutine constitutive_TandItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the 2nd Piola-Kirchhoff stress tensor and its tangent with respect to -!> the elastic deformation gradient using hookes law -!-------------------------------------------------------------------------------------------------- -subroutine constitutive_hooke_TandItsTangent(T, dT_dFe, dT_dFi, Fe, Fi, ipc, ip, el) - use prec, only: & - pReal - use math, only : & - math_mul3x3, & - math_mul33x33, & - math_mul3333xx33, & - math_Mandel66to3333, & - math_trace33, & - math_I3 - use material, only: & - material_phase, & - material_homog, & - phase_NstiffnessDegradations, & - phase_stiffnessDegradation, & - damage, & - damageMapping, & - porosity, & - porosityMapping, & - STIFFNESS_DEGRADATION_damage_ID, & - STIFFNESS_DEGRADATION_porosity_ID - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(3,3) :: & - Fe, & !< elastic deformation gradient - Fi !< intermediate deformation gradient - real(pReal), intent(out), dimension(3,3) :: & - T !< 2nd Piola-Kirchhoff stress tensor in lattice configuration - real(pReal), intent(out), dimension(3,3,3,3) :: & - dT_dFe, & !< derivative of 2nd P-K stress with respect to elastic deformation gradient - dT_dFi !< derivative of 2nd P-K stress with respect to intermediate deformation gradient - real(pReal), dimension(3,3) :: E - real(pReal), dimension(3,3,3,3) :: C - integer(pInt) :: & - ho, & !< homogenization - d !< counter in degradation loop - integer(pInt) :: & - i, j - - ho = material_homog(ip,el) - - C = math_Mandel66to3333(constitutive_homogenizedC(ipc,ip,el)) - - DegradationLoop: do d = 1_pInt, phase_NstiffnessDegradations(material_phase(ipc,ip,el)) - degradationType: select case(phase_stiffnessDegradation(d,material_phase(ipc,ip,el))) - case (STIFFNESS_DEGRADATION_damage_ID) degradationType - C = C * damage(ho)%p(damageMapping(ho)%p(ip,el))**2_pInt - case (STIFFNESS_DEGRADATION_porosity_ID) degradationType - C = C * porosity(ho)%p(porosityMapping(ho)%p(ip,el))**2_pInt - end select degradationType - enddo DegradationLoop - - E = 0.5_pReal*(math_mul33x33(transpose(Fe),Fe)-math_I3) !< Green-Lagrange strain in unloaded configuration - T = math_mul3333xx33(C,math_mul33x33(math_mul33x33(transpose(Fi),E),Fi)) !< 2PK stress in lattice configuration in work conjugate with GL strain pulled back to lattice configuration - - dT_dFe = 0.0_pReal - forall (i=1_pInt:3_pInt, j=1_pInt:3_pInt) - dT_dFe(i,j,1:3,1:3) = & - math_mul33x33(Fe,math_mul33x33(math_mul33x33(Fi,C(i,j,1:3,1:3)),transpose(Fi))) !< dT_ij/dFe_kl = C_ijmn * Fi_lm * Fi_on * Fe_ko - dT_dFi(i,j,1:3,1:3) = 2.0_pReal*math_mul33x33(math_mul33x33(E,Fi),C(i,j,1:3,1:3)) !< dT_ij/dFi_kl = C_ijln * E_km * Fe_mn - end forall - -end subroutine constitutive_hooke_TandItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine constitutive_collectDotState(Tstar_v, FeArray, FpArray, subdt, subfracArray,ipc, ip, el) - use prec, only: & - pReal, & - pLongInt - use debug, only: & - debug_cumDotStateCalls, & - debug_cumDotStateTicks, & - debug_level, & - debug_constitutive, & - debug_levelBasic - use mesh, only: & - mesh_NcpElems, & - mesh_maxNips - use material, only: & - phase_plasticity, & - phase_source, & - phase_Nsources, & - material_phase, & - material_homog, & - temperature, & - thermalMapping, & - homogenization_maxNgrains, & - PLASTICITY_none_ID, & - PLASTICITY_isotropic_ID, & - PLASTICITY_j2_ID, & - PLASTICITY_phenopowerlaw_ID, & - PLASTICITY_phenoplus_ID, & - PLASTICITY_dislotwin_ID, & - PLASTICITY_disloucla_ID, & - PLASTICITY_titanmod_ID, & - PLASTICITY_nonlocal_ID, & - SOURCE_damage_isoDuctile_ID, & - SOURCE_damage_anisoBrittle_ID, & - SOURCE_damage_anisoDuctile_ID, & - SOURCE_thermal_externalheat_ID - use plastic_isotropic, only: & - plastic_isotropic_dotState - use plastic_j2, only: & - plastic_j2_dotState - use plastic_phenopowerlaw, only: & - plastic_phenopowerlaw_dotState - use plastic_phenoplus, only: & - plastic_phenoplus_dotState - use plastic_dislotwin, only: & - plastic_dislotwin_dotState - use plastic_disloucla, only: & - plastic_disloucla_dotState - use plastic_titanmod, only: & - plastic_titanmod_dotState - use plastic_nonlocal, only: & - plastic_nonlocal_dotState - use source_damage_isoDuctile, only: & - source_damage_isoDuctile_dotState - use source_damage_anisoBrittle, only: & - source_damage_anisoBrittle_dotState - use source_damage_anisoDuctile, only: & - source_damage_anisoDuctile_dotState - use source_thermal_externalheat, only: & - source_thermal_externalheat_dotState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - subdt !< timestep - real(pReal), intent(in), dimension(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & - subfracArray !< subfraction of timestep - real(pReal), intent(in), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & - FeArray, & !< elastic deformation gradient - FpArray !< plastic deformation gradient - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) - integer(pLongInt) :: & - tick, tock, & - tickrate, & - maxticks - integer(pInt) :: & - ho, & !< homogenization - tme, & !< thermal member position - s !< counter in source loop - - if (iand(debug_level(debug_constitutive), debug_levelBasic) /= 0_pInt) & - call system_clock(count=tick,count_rate=tickrate,count_max=maxticks) - - ho = material_homog( ip,el) - tme = thermalMapping(ho)%p(ip,el) - - plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) - case (PLASTICITY_ISOTROPIC_ID) plasticityType - call plastic_isotropic_dotState (Tstar_v,ipc,ip,el) - case (PLASTICITY_J2_ID) plasticityType - call plastic_j2_dotState (Tstar_v,ipc,ip,el) - case (PLASTICITY_PHENOPOWERLAW_ID) plasticityType - call plastic_phenopowerlaw_dotState(Tstar_v,ipc,ip,el) - case (PLASTICITY_PHENOPLUS_ID) plasticityType - call plastic_phenoplus_dotState (Tstar_v,ipc,ip,el) - case (PLASTICITY_DISLOTWIN_ID) plasticityType - call plastic_dislotwin_dotState (Tstar_v,temperature(ho)%p(tme), & - ipc,ip,el) - case (PLASTICITY_DISLOUCLA_ID) plasticityType - call plastic_disloucla_dotState (Tstar_v,temperature(ho)%p(tme), & - ipc,ip,el) - case (PLASTICITY_TITANMOD_ID) plasticityType - call plastic_titanmod_dotState (Tstar_v,temperature(ho)%p(tme), & - ipc,ip,el) - case (PLASTICITY_NONLOCAL_ID) plasticityType - call plastic_nonlocal_dotState (Tstar_v,FeArray,FpArray,temperature(ho)%p(tme), & - subdt,subfracArray,ip,el) - end select plasticityType - - SourceLoop: do s = 1_pInt, phase_Nsources(material_phase(ipc,ip,el)) - sourceType: select case (phase_source(s,material_phase(ipc,ip,el))) - case (SOURCE_damage_anisoBrittle_ID) sourceType - call source_damage_anisoBrittle_dotState (Tstar_v, ipc, ip, el) - 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( ipc, ip, el) - end select sourceType - enddo SourceLoop - - if (iand(debug_level(debug_constitutive), debug_levelBasic) /= 0_pInt) then - call system_clock(count=tock,count_rate=tickrate,count_max=maxticks) - !$OMP CRITICAL (debugTimingDotState) - debug_cumDotStateCalls = debug_cumDotStateCalls + 1_pInt - debug_cumDotStateTicks = debug_cumDotStateTicks + tock-tick - !$OMP FLUSH (debug_cumDotStateTicks) - if (tock < tick) debug_cumDotStateTicks = debug_cumDotStateTicks + maxticks - !$OMP END CRITICAL (debugTimingDotState) - endif -end subroutine constitutive_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 -!-------------------------------------------------------------------------------------------------- -subroutine constitutive_collectDeltaState(Tstar_v, Fe, ipc, ip, el) - use prec, only: & - pReal, & - pLongInt - use debug, only: & - debug_cumDeltaStateCalls, & - debug_cumDeltaStateTicks, & - debug_level, & - debug_constitutive, & - debug_levelBasic - use material, only: & - phase_plasticity, & - phase_source, & - phase_Nsources, & - material_phase, & - PLASTICITY_NONLOCAL_ID, & - SOURCE_damage_isoBrittle_ID, & - SOURCE_vacancy_irradiation_ID, & - SOURCE_vacancy_thermalfluc_ID - use plastic_nonlocal, only: & - plastic_nonlocal_deltaState - use source_damage_isoBrittle, only: & - source_damage_isoBrittle_deltaState - use source_vacancy_irradiation, only: & - source_vacancy_irradiation_deltaState - use source_vacancy_thermalfluc, only: & - source_vacancy_thermalfluc_deltaState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola-Kirchhoff stress - real(pReal), intent(in), dimension(3,3) :: & - Fe !< elastic deformation gradient - integer(pInt) :: & - s !< counter in source loop - integer(pLongInt) :: & - tick, tock, & - tickrate, & - maxticks - - if (iand(debug_level(debug_constitutive), debug_levelBasic) /= 0_pInt) & - call system_clock(count=tick,count_rate=tickrate,count_max=maxticks) - - if(phase_plasticity(material_phase(ipc,ip,el)) == PLASTICITY_NONLOCAL_ID) & - call plastic_nonlocal_deltaState(Tstar_v,ip,el) - - - SourceLoop: do s = 1_pInt, phase_Nsources(material_phase(ipc,ip,el)) - sourceType: select case (phase_source(s,material_phase(ipc,ip,el))) - case (SOURCE_damage_isoBrittle_ID) sourceType - call source_damage_isoBrittle_deltaState (constitutive_homogenizedC(ipc,ip,el), Fe, & - ipc, ip, el) - case (SOURCE_vacancy_irradiation_ID) sourceType - call source_vacancy_irradiation_deltaState(ipc, ip, el) - case (SOURCE_vacancy_thermalfluc_ID) sourceType - call source_vacancy_thermalfluc_deltaState(ipc, ip, el) - end select sourceType - enddo SourceLoop - - if (iand(debug_level(debug_constitutive), debug_levelBasic) /= 0_pInt) then - call system_clock(count=tock,count_rate=tickrate,count_max=maxticks) - !$OMP CRITICAL (debugTimingDeltaState) - debug_cumDeltaStateCalls = debug_cumDeltaStateCalls + 1_pInt - debug_cumDeltaStateTicks = debug_cumDeltaStateTicks + tock-tick - !$OMP FLUSH (debug_cumDeltaStateTicks) - if (tock < tick) debug_cumDeltaStateTicks = debug_cumDeltaStateTicks + maxticks - !$OMP END CRITICAL (debugTimingDeltaState) - endif - -end subroutine constitutive_collectDeltaState - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns array of constitutive results -!-------------------------------------------------------------------------------------------------- -function constitutive_postResults(Tstar_v, FeArray, ipc, ip, el) - use prec, only: & - pReal - use mesh, only: & - mesh_NcpElems, & - mesh_maxNips - use material, only: & - plasticState, & - sourceState, & - phase_plasticity, & - phase_source, & - phase_Nsources, & - material_phase, & - material_homog, & - temperature, & - thermalMapping, & - homogenization_maxNgrains, & - PLASTICITY_NONE_ID, & - PLASTICITY_ISOTROPIC_ID, & - PLASTICITY_J2_ID, & - PLASTICITY_PHENOPOWERLAW_ID, & - PLASTICITY_PHENOPLUS_ID, & - PLASTICITY_DISLOTWIN_ID, & - PLASTICITY_DISLOUCLA_ID, & - PLASTICITY_TITANMOD_ID, & - PLASTICITY_NONLOCAL_ID, & - SOURCE_damage_isoBrittle_ID, & - SOURCE_damage_isoDuctile_ID, & - SOURCE_damage_anisoBrittle_ID, & - SOURCE_damage_anisoDuctile_ID - use plastic_isotropic, only: & - plastic_isotropic_postResults - use plastic_j2, only: & - plastic_j2_postResults - use plastic_phenopowerlaw, only: & - plastic_phenopowerlaw_postResults - use plastic_phenoplus, only: & - plastic_phenoplus_postResults - use plastic_dislotwin, only: & - plastic_dislotwin_postResults - use plastic_disloucla, only: & - plastic_disloucla_postResults - use plastic_titanmod, only: & - plastic_titanmod_postResults - use plastic_nonlocal, only: & - plastic_nonlocal_postResults - use source_damage_isoBrittle, only: & - source_damage_isoBrittle_postResults - use source_damage_isoDuctile, only: & - source_damage_isoDuctile_postResults - use source_damage_anisoBrittle, only: & - source_damage_anisoBrittle_postResults - use source_damage_anisoDuctile, only: & - source_damage_anisoDuctile_postResults - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(plasticState(material_phase(ipc,ip,el))%sizePostResults + & - sum(sourceState(material_phase(ipc,ip,el))%p(:)%sizePostResults)) :: & - constitutive_postResults - real(pReal), intent(in), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & - FeArray !< elastic deformation gradient - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) - integer(pInt) :: & - startPos, endPos - integer(pInt) :: & - ho, & !< homogenization - tme, & !< thermal member position - s !< counter in source loop - - constitutive_postResults = 0.0_pReal - - ho = material_homog( ip,el) - tme = thermalMapping(ho)%p(ip,el) - - startPos = 1_pInt - endPos = plasticState(material_phase(ipc,ip,el))%sizePostResults - - plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) - case (PLASTICITY_TITANMOD_ID) plasticityType - constitutive_postResults(startPos:endPos) = plastic_titanmod_postResults(ipc,ip,el) - case (PLASTICITY_ISOTROPIC_ID) plasticityType - constitutive_postResults(startPos:endPos) = plastic_isotropic_postResults(Tstar_v,ipc,ip,el) - case (PLASTICITY_J2_ID) plasticityType - constitutive_postResults(startPos:endPos) = plastic_j2_postResults(Tstar_v,ipc,ip,el) - case (PLASTICITY_PHENOPOWERLAW_ID) plasticityType - constitutive_postResults(startPos:endPos) = & - plastic_phenopowerlaw_postResults(Tstar_v,ipc,ip,el) - case (PLASTICITY_PHENOPLUS_ID) plasticityType - constitutive_postResults(startPos:endPos) = & - plastic_phenoplus_postResults(Tstar_v,ipc,ip,el) - case (PLASTICITY_DISLOTWIN_ID) plasticityType - constitutive_postResults(startPos:endPos) = & - plastic_dislotwin_postResults(Tstar_v,temperature(ho)%p(tme),ipc,ip,el) - case (PLASTICITY_DISLOUCLA_ID) plasticityType - constitutive_postResults(startPos:endPos) = & - plastic_disloucla_postResults(Tstar_v,temperature(ho)%p(tme),ipc,ip,el) - case (PLASTICITY_NONLOCAL_ID) plasticityType - constitutive_postResults(startPos:endPos) = & - plastic_nonlocal_postResults (Tstar_v,FeArray,ip,el) - end select plasticityType - - SourceLoop: do s = 1_pInt, phase_Nsources(material_phase(ipc,ip,el)) - startPos = endPos + 1_pInt - endPos = endPos + sourceState(material_phase(ipc,ip,el))%p(s)%sizePostResults - sourceType: select case (phase_source(s,material_phase(ipc,ip,el))) - case (SOURCE_damage_isoBrittle_ID) sourceType - constitutive_postResults(startPos:endPos) = source_damage_isoBrittle_postResults(ipc, ip, el) - case (SOURCE_damage_isoDuctile_ID) sourceType - constitutive_postResults(startPos:endPos) = source_damage_isoDuctile_postResults(ipc, ip, el) - case (SOURCE_damage_anisoBrittle_ID) sourceType - constitutive_postResults(startPos:endPos) = source_damage_anisoBrittle_postResults(ipc, ip, el) - case (SOURCE_damage_anisoDuctile_ID) sourceType - constitutive_postResults(startPos:endPos) = source_damage_anisoDuctile_postResults(ipc, ip, el) - end select sourceType - enddo SourceLoop - -end function constitutive_postResults - -end module constitutive diff --git a/code/core_quit.f90 b/code/core_quit.f90 deleted file mode 100644 index 8446e77c8..000000000 --- a/code/core_quit.f90 +++ /dev/null @@ -1,15 +0,0 @@ -!################################################################################################## -! $Id$ -!################################################################################################## -!******************************************************************** -! quit subroutine to satisfy IO_error for core module -! -!******************************************************************** -subroutine quit(stop_id) - use prec, only: & - pInt - - implicit none - integer(pInt), intent(in) :: stop_id - -end subroutine diff --git a/code/crystallite.f90 b/code/crystallite.f90 deleted file mode 100644 index 6ca40ffef..000000000 --- a/code/crystallite.f90 +++ /dev/null @@ -1,4228 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @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, only: & - pReal, & - pInt - - implicit none - - private - character(len=64), dimension(:,:), allocatable, private :: & - crystallite_output !< name of each post result output - integer(pInt), public, protected :: & - crystallite_maxSizePostResults !< description not available - integer(pInt), dimension(:), allocatable, public, protected :: & - crystallite_sizePostResults !< description not available - integer(pInt), dimension(:,:), allocatable, private :: & - crystallite_sizePostResult !< description not available - - real(pReal), dimension(:,:,:), allocatable, public :: & - crystallite_dt !< requested time increment of each grain - real(pReal), dimension(:,:,:), allocatable, private :: & - crystallite_subdt, & !< substepped time increment of each grain - crystallite_subFrac, & !< already calculated fraction of increment - crystallite_subStep !< size of next integration step - real(pReal), dimension(:,:,:,:), allocatable, public :: & - crystallite_Tstar_v, & !< current 2nd Piola-Kirchhoff stress vector (end of converged time step) - crystallite_Tstar0_v, & !< 2nd Piola-Kirchhoff stress vector at start of FE inc - crystallite_partionedTstar0_v !< 2nd Piola-Kirchhoff stress vector at start of homog inc - real(pReal), dimension(:,:,:,:), allocatable, private :: & - crystallite_subTstar0_v, & !< 2nd Piola-Kirchhoff stress vector at start of crystallite inc - crystallite_orientation, & !< orientation as quaternion - crystallite_orientation0, & !< initial orientation as quaternion - crystallite_rotation !< grain rotation away from initial orientation as axis-angle (in degrees) in crystal reference frame - real(pReal), dimension(:,:,:,:,:), allocatable, public :: & - crystallite_Fp, & !< current plastic def grad (end of converged time step) - crystallite_Fp0, & !< plastic def grad at start of FE inc - crystallite_partionedFp0,& !< plastic def grad at start of homog inc - crystallite_Fi, & !< current intermediate def grad (end of converged time step) - crystallite_Fi0, & !< intermediate def grad at start of FE inc - crystallite_partionedFi0,& !< intermediate def grad at start of homog inc - crystallite_F0, & !< def grad at start of FE inc - crystallite_partionedF, & !< def grad to be reached at end of homog inc - crystallite_partionedF0, & !< def grad at start of homog inc - crystallite_Lp, & !< current plastic velocitiy grad (end of converged time step) - crystallite_Lp0, & !< plastic velocitiy grad at start of FE inc - crystallite_partionedLp0,& !< 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_partionedLi0,& !< intermediate velocity grad at start of homog inc - crystallite_Fe, & !< current "elastic" def grad (end of converged time step) - crystallite_P !< 1st Piola-Kirchhoff stress per grain - real(pReal), dimension(:,:,:,:,:), allocatable, private :: & - crystallite_subFe0,& !< "elastic" def grad at start of crystallite inc - crystallite_invFp, & !< inverse of current plastic def grad (end of converged time step) - crystallite_subFp0,& !< plastic def grad at start of crystallite inc - crystallite_invFi, & !< inverse of current intermediate def grad (end of converged time step) - crystallite_subFi0,& !< intermediate def grad at start of crystallite inc - crystallite_subF, & !< def grad to be reached at end of crystallite inc - crystallite_subF0, & !< def grad at start of crystallite inc - crystallite_subLp0,& !< plastic velocity grad at start of crystallite inc - crystallite_subLi0,& !< intermediate velocity grad at start of crystallite inc - crystallite_disorientation !< disorientation between two neighboring ips (only calculated for single grain IPs) - real(pReal), dimension(:,:,:,:,:,:,:), allocatable, public :: & - crystallite_dPdF, & !< current individual dPdF per grain (end of converged time step) - crystallite_dPdF0, & !< individual dPdF per grain at start of FE inc - crystallite_partioneddPdF0 !< individual dPdF per grain at start of homog inc - real(pReal), dimension(:,:,:,:,:,:,:), allocatable, private :: & - crystallite_fallbackdPdF !< dPdF fallback for non-converged grains (elastic prediction) - logical, dimension(:,:,:), allocatable, public :: & - crystallite_requested !< flag to request crystallite calculation - logical, dimension(:,:,:), allocatable, public, protected :: & - crystallite_converged, & !< convergence flag - crystallite_localPlasticity !< indicates this grain to have purely local constitutive law - logical, dimension(:,:,:), allocatable, private :: & - crystallite_todo !< flag to indicate need for further computation - logical, dimension(:,:), allocatable, private :: & - crystallite_clearToWindForward, & !< description not available - crystallite_clearToCutback, & !< description not available - crystallite_syncSubFrac, & !< description not available - crystallite_syncSubFracCompleted, & !< description not available - crystallite_neighborEnforcedCutback !< description not available - - enum, bind(c) - enumerator :: undefined_ID, & - phase_ID, & - texture_ID, & - volume_ID, & - grainrotationx_ID, & - grainrotationy_ID, & - grainrotationz_ID, & - orientation_ID, & - grainrotation_ID, & - eulerangles_ID, & - defgrad_ID, & - fe_ID, & - fp_ID, & - fi_ID, & - lp_ID, & - li_ID, & - e_ID, & - ee_ID, & - p_ID, & - s_ID, & - elasmatrix_ID, & - neighboringip_ID, & - neighboringelement_ID - end enum - integer(kind(undefined_ID)),dimension(:,:), allocatable, private :: & - crystallite_outputID !< ID of each post result output - - public :: & - crystallite_init, & - crystallite_stressAndItsTangent, & - crystallite_orientations, & - crystallite_push33ToRef, & - crystallite_postResults - private :: & - crystallite_integrateStateFPI, & - crystallite_integrateStateEuler, & - crystallite_integrateStateAdaptiveEuler, & - crystallite_integrateStateRK4, & - crystallite_integrateStateRKCK45, & - crystallite_integrateStress, & - crystallite_stateJump - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates and initialize per grain variables -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_info, & - debug_reset, & - debug_level, & - debug_crystallite, & - debug_levelBasic - use numerics, only: & - worldrank, & - usePingPong - use math, only: & - math_I3, & - math_EulerToR, & - math_inv33, & - math_transpose33, & - math_mul33xx33, & - math_mul33x33 - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP - use mesh, only: & - mesh_element, & - mesh_NcpElems, & - mesh_maxNips, & - mesh_maxNipNeighbors - use IO, only: & - IO_read, & - IO_timeStamp, & - IO_open_jobFile_stat, & - IO_open_file, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_write_jobFile, & - IO_error, & - IO_EOF - use material - use constitutive, only: & - constitutive_initialFi, & - constitutive_microstructure ! derived (shortcut) quantities of given state - - implicit none - integer(pInt), parameter :: & - FILEUNIT = 200_pInt - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - c, & !< counter in integration point component loop - i, & !< counter in integration point loop - e, & !< counter in element loop - o, & !< counter in output loop - r, & !< counter in crystallite loop - cMax, & !< maximum number of integration point components - iMax, & !< maximum number of integration points - eMax, & !< maximum number of elements - nMax, & !< maximum number of ip neighbors - myNcomponents, & !< number of components at current IP - section = 0_pInt, & - j, & - p, & - mySize - - character(len=65536) :: & - tag = '', & - line= '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- crystallite init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - cMax = homogenization_maxNgrains - iMax = mesh_maxNips - eMax = mesh_NcpElems - nMax = mesh_maxNipNeighbors - - - allocate(crystallite_Tstar0_v(6,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_partionedTstar0_v(6,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subTstar0_v(6,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_Tstar_v(6,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_P(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_F0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_partionedF0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_partionedF(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subF0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subF(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_Fp0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_partionedFp0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subFp0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_Fp(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_invFp(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_Fi0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_partionedFi0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subFi0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_Fi(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_invFi(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_Fe(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subFe0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_Lp0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_partionedLp0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subLp0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_Lp(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_Li0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_partionedLi0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subLi0(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_Li(3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_dPdF(3,3,3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_dPdF0(3,3,3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_partioneddPdF0(3,3,3,3,cMax,iMax,eMax),source=0.0_pReal) - allocate(crystallite_fallbackdPdF(3,3,3,3,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_dt(cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subdt(cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subFrac(cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_subStep(cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_orientation(4,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_orientation0(4,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_rotation(4,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_disorientation(4,nMax,cMax,iMax,eMax), source=0.0_pReal) - allocate(crystallite_localPlasticity(cMax,iMax,eMax), source=.true.) - allocate(crystallite_requested(cMax,iMax,eMax), source=.false.) - allocate(crystallite_todo(cMax,iMax,eMax), source=.false.) - allocate(crystallite_converged(cMax,iMax,eMax), source=.true.) - allocate(crystallite_clearToWindForward(iMax,eMax), source=.true.) - allocate(crystallite_syncSubFrac(iMax,eMax), source=.false.) - allocate(crystallite_syncSubFracCompleted(iMax,eMax), source=.false.) - allocate(crystallite_clearToCutback(iMax,eMax), source=.true.) - allocate(crystallite_neighborEnforcedCutback(iMax,eMax), source=.false.) - allocate(crystallite_output(maxval(crystallite_Noutput), & - material_Ncrystallite)) ; crystallite_output = '' - allocate(crystallite_outputID(maxval(crystallite_Noutput), & - material_Ncrystallite), source=undefined_ID) - allocate(crystallite_sizePostResults(material_Ncrystallite),source=0_pInt) - allocate(crystallite_sizePostResult(maxval(crystallite_Noutput), & - material_Ncrystallite), source=0_pInt) - - if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... - call IO_open_file(FILEUNIT,material_configFile) ! ...open material.config file - - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partCrystallite) ! wind forward to - line = IO_read(FILEUNIT) - enddo - - do while (trim(line) /= IO_EOF) ! read through sections of crystallite part - line = IO_read(FILEUNIT) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(FILEUNIT, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - o = 0_pInt ! reset output counter - cycle ! skip to next line - endif - if (section > 0_pInt) then - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - o = o + 1_pInt - crystallite_output(o,section) = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - outputName: select case(crystallite_output(o,section)) - case ('phase') outputName - crystallite_outputID(o,section) = phase_ID - case ('texture') outputName - crystallite_outputID(o,section) = texture_ID - case ('volume') outputName - crystallite_outputID(o,section) = volume_ID - case ('grainrotationx') outputName - crystallite_outputID(o,section) = grainrotationx_ID - case ('grainrotationy') outputName - crystallite_outputID(o,section) = grainrotationy_ID - case ('grainrotationz') outputName - crystallite_outputID(o,section) = grainrotationx_ID - case ('orientation') outputName - crystallite_outputID(o,section) = orientation_ID - case ('grainrotation') outputName - crystallite_outputID(o,section) = grainrotation_ID - case ('eulerangles') outputName - crystallite_outputID(o,section) = eulerangles_ID - case ('defgrad','f') outputName - crystallite_outputID(o,section) = defgrad_ID - case ('fe') outputName - crystallite_outputID(o,section) = fe_ID - case ('fp') outputName - crystallite_outputID(o,section) = fp_ID - case ('fi') outputName - crystallite_outputID(o,section) = fi_ID - case ('lp') outputName - crystallite_outputID(o,section) = lp_ID - case ('li') outputName - crystallite_outputID(o,section) = li_ID - case ('e') outputName - crystallite_outputID(o,section) = e_ID - case ('ee') outputName - crystallite_outputID(o,section) = ee_ID - case ('p','firstpiola','1stpiola') outputName - crystallite_outputID(o,section) = p_ID - case ('s','tstar','secondpiola','2ndpiola') outputName - crystallite_outputID(o,section) = s_ID - case ('elasmatrix') outputName - crystallite_outputID(o,section) = elasmatrix_ID - case ('neighboringip') outputName - crystallite_outputID(o,section) = neighboringip_ID - case ('neighboringelement') outputName - crystallite_outputID(o,section) = neighboringelement_ID - case default outputName - call IO_error(105_pInt,ext_msg=IO_stringValue(line,chunkPos,2_pInt)//' (Crystallite)') - end select outputName - end select - endif - enddo - - close(FILEUNIT) - - do r = 1_pInt,material_Ncrystallite - do o = 1_pInt,crystallite_Noutput(r) - select case(crystallite_outputID(o,r)) - case(phase_ID,texture_ID,volume_ID,grainrotationx_ID,grainrotationy_ID,grainrotationz_ID) - mySize = 1_pInt - case(orientation_ID,grainrotation_ID) - mySize = 4_pInt - case(eulerangles_ID) - mySize = 3_pInt - case(defgrad_ID,fe_ID,fp_ID,fi_ID,lp_ID,li_ID,e_ID,ee_ID,p_ID,s_ID) - mySize = 9_pInt - case(elasmatrix_ID) - mySize = 36_pInt - case(neighboringip_ID,neighboringelement_ID) - mySize = mesh_maxNipNeighbors - case default - mySize = 0_pInt - end select - crystallite_sizePostResult(o,r) = mySize - crystallite_sizePostResults(r) = crystallite_sizePostResults(r) + mySize - enddo - enddo - - crystallite_maxSizePostResults = & - maxval(crystallite_sizePostResults(microstructure_crystallite),microstructure_active) - - -!-------------------------------------------------------------------------------------------------- -! write description file for crystallite output - if (worldrank == 0_pInt) then - call IO_write_jobFile(FILEUNIT,'outputCrystallite') - - do r = 1_pInt,material_Ncrystallite - if (any(microstructure_crystallite(mesh_element(4,:)) == r)) then - write(FILEUNIT,'(/,a,/)') '['//trim(crystallite_name(r))//']' - do o = 1_pInt,crystallite_Noutput(r) - write(FILEUNIT,'(a,i4)') trim(crystallite_output(o,r))//char(9),crystallite_sizePostResult(o,r) - enddo - endif - enddo - - close(FILEUNIT) - endif - -!-------------------------------------------------------------------------------------------------- -! initialize -!$OMP PARALLEL DO PRIVATE(myNcomponents) - do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1_pInt:myNcomponents) - crystallite_Fp0(1:3,1:3,c,i,e) = math_EulerToR(material_EulerAngles(1:3,c,i,e)) ! plastic def gradient reflects init orientation - 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_localPlasticity(c,i,e) = phase_localPlasticity(material_phase(c,i,e)) - crystallite_Fe(1:3,1:3,c,i,e) = math_inv33(math_mul33x33(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. - endforall - enddo - !$OMP END PARALLEL DO - - if(any(.not. crystallite_localPlasticity) .and. .not. usePingPong) call IO_error(601_pInt) ! exit if nonlocal but no ping-pong - - crystallite_partionedFp0 = crystallite_Fp0 - crystallite_partionedFi0 = crystallite_Fi0 - crystallite_partionedF0 = crystallite_F0 - crystallite_partionedF = crystallite_F0 - - call crystallite_orientations() - crystallite_orientation0 = crystallite_orientation ! store initial orientations for calculation of grain rotations - - !$OMP PARALLEL DO PRIVATE(myNcomponents) - do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - do c = 1_pInt,myNcomponents - call constitutive_microstructure(crystallite_orientation, & ! pass orientation to constitutive module - crystallite_Fe(1:3,1:3,c,i,e), & - crystallite_Fp(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 - - call crystallite_stressAndItsTangent(.true.) ! request elastic answers - crystallite_fallbackdPdF = crystallite_dPdF ! use initial elastic stiffness as fallback - -!-------------------------------------------------------------------------------------------------- -! debug output - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Fe: ', shape(crystallite_Fe) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Fp: ', shape(crystallite_Fp) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Fi: ', shape(crystallite_Fi) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Lp: ', shape(crystallite_Lp) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Li: ', shape(crystallite_Li) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_F0: ', shape(crystallite_F0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Fp0: ', shape(crystallite_Fp0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Fi0: ', shape(crystallite_Fi0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Lp0: ', shape(crystallite_Lp0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Li0: ', shape(crystallite_Li0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedF: ', shape(crystallite_partionedF) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedF0: ', shape(crystallite_partionedF0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedFp0: ', shape(crystallite_partionedFp0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedFi0: ', shape(crystallite_partionedFi0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedLp0: ', shape(crystallite_partionedLp0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedLi0: ', shape(crystallite_partionedLi0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subF: ', shape(crystallite_subF) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subF0: ', shape(crystallite_subF0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subFe0: ', shape(crystallite_subFe0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subFp0: ', shape(crystallite_subFp0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subFi0: ', shape(crystallite_subFi0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subLp0: ', shape(crystallite_subLp0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subLi0: ', shape(crystallite_subLi0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_P: ', shape(crystallite_P) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Tstar_v: ', shape(crystallite_Tstar_v) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_Tstar0_v: ', shape(crystallite_Tstar0_v) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedTstar0_v: ', shape(crystallite_partionedTstar0_v) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subTstar0_v: ', shape(crystallite_subTstar0_v) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_dPdF: ', shape(crystallite_dPdF) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_dPdF0: ', shape(crystallite_dPdF0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_partioneddPdF0: ', shape(crystallite_partioneddPdF0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_fallbackdPdF: ', shape(crystallite_fallbackdPdF) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_orientation: ', shape(crystallite_orientation) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_orientation0: ', shape(crystallite_orientation0) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_rotation: ', shape(crystallite_rotation) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_disorientation: ', shape(crystallite_disorientation) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_dt: ', shape(crystallite_dt) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subdt: ', shape(crystallite_subdt) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subFrac: ', shape(crystallite_subFrac) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_subStep: ', shape(crystallite_subStep) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_localPlasticity: ', shape(crystallite_localPlasticity) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_requested: ', shape(crystallite_requested) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_todo: ', shape(crystallite_todo) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_converged: ', shape(crystallite_converged) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_sizePostResults: ', shape(crystallite_sizePostResults) - write(6,'(a35,1x,7(i8,1x))') 'crystallite_sizePostResult: ', shape(crystallite_sizePostResult) - write(6,'(/,a35,1x,i10)') 'Number of nonlocal grains: ',count(.not. crystallite_localPlasticity) - flush(6) - endif - - call debug_info - call debug_reset - -end subroutine crystallite_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate stress (P) and tangent (dPdF) for crystallites -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_stressAndItsTangent(updateJaco) - use prec, only: & - tol_math_check - use numerics, only: & - subStepMinCryst, & - subStepSizeCryst, & - stepIncreaseCryst, & - pert_Fg, & - pert_method, & - nCryst, & - numerics_integrator, & - numerics_integrationMode, & - numerics_timeSyncing, & - analyticJaco - use debug, only: & - debug_level, & - debug_crystallite, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_g, & - debug_CrystalliteLoopDistribution - use IO, only: & - IO_warning, & - IO_error - use math, only: & - math_inv33, & - math_identity2nd, & - math_transpose33, & - math_mul33x33, & - math_mul66x6, & - math_Mandel6to33, & - math_Mandel33to6, & - math_Plain3333to99, & - math_Plain99to3333, & - math_I3, & - math_mul3333xx3333, & - math_mul33xx33, & - math_invert, & - math_det33 - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP - use mesh, only: & - mesh_element, & - mesh_NcpElems, & - mesh_maxNips, & - mesh_ipNeighborhood, & - FE_NipNeighbors, & - FE_geomtype, & - FE_cellType - use material, only: & - homogenization_Ngrains, & - plasticState, & - sourceState, & - phase_Nsources, & - phaseAt, phasememberAt, & - homogenization_maxNgrains - use constitutive, only: & - constitutive_TandItsTangent, & - constitutive_LpAndItsTangent, & - constitutive_LiAndItsTangent - - implicit none - logical, intent(in) :: & - updateJaco !< whether to update the Jacobian (stiffness) or not - real(pReal) :: & - myPert, & ! perturbation with correct sign - formerSubStep, & - subFracIntermediate - real(pReal), dimension(3,3) :: & - invFp, & ! inverse of the plastic deformation gradient - Fe_guess, & ! guess for elastic deformation gradient - Tstar ! 2nd Piola-Kirchhoff stress tensor - real(pReal), allocatable, dimension(:,:,:,:,:,:,:) :: & - dPdF_perturbation1, & - dPdF_perturbation2 - real(pReal), allocatable, dimension(:,:,:,:,:) :: & - F_backup, & - Fp_backup, & - InvFp_backup, & - Fi_backup, & - InvFi_backup, & - Fe_backup, & - Lp_backup, & - Li_backup, & - P_backup - real(pReal), allocatable, dimension(:,:,:,:) :: & - Tstar_v_backup - logical, allocatable, dimension(:,:,:) :: & - convergenceFlag_backup - integer(pInt) :: & - 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 - k, & - l, & - n, startIP, endIP, & - neighboring_e, & - neighboring_i, & - o, & - p, & - perturbation , & ! loop counter for forward,backward perturbation mode - myNcomponents, & - mySource - ! local variables used for calculating analytic Jacobian - real(pReal), dimension(3,3) :: temp_33 - real(pReal), dimension(3,3,3,3) :: dSdFe, & - dSdF, & - dSdFi, & - dLidS, & - dLidFi, & - dLpdS, & - dLpdFi, & - dFidS, & - dFpinvdF, & - rhs_3333, & - lhs_3333, & - temp_3333 - real(pReal), dimension(9,9):: temp_99 - logical :: error - - - if (iand(debug_level(debug_crystallite),debug_levelSelective) /= 0_pInt & - .and. FEsolving_execElem(1) <= debug_e & - .and. debug_e <= FEsolving_execElem(2)) then - write(6,'(/,a,i8,1x,a,i8,a,1x,i2,1x,i3)') '<< CRYST >> boundary values at el ip ipc ', & - debug_e,'(',mesh_element(1,debug_e), ')',debug_i, debug_g - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> F ', & - math_transpose33(crystallite_partionedF(1:3,1:3,debug_g,debug_i,debug_e)) - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> F0 ', & - math_transpose33(crystallite_partionedF0(1:3,1:3,debug_g,debug_i,debug_e)) - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Fp0', & - math_transpose33(crystallite_partionedFp0(1:3,1:3,debug_g,debug_i,debug_e)) - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Fi0', & - math_transpose33(crystallite_partionedFi0(1:3,1:3,debug_g,debug_i,debug_e)) - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Lp0', & - math_transpose33(crystallite_partionedLp0(1:3,1:3,debug_g,debug_i,debug_e)) - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Li0', & - math_transpose33(crystallite_partionedLi0(1:3,1:3,debug_g,debug_i,debug_e)) - endif - -!-------------------------------------------------------------------------------------------------- -! initialize to starting condition - crystallite_subStep = 0.0_pReal - - !$OMP PARALLEL DO PRIVATE(myNcomponents) - elementLooping1: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do c = 1_pInt,myNcomponents - if (crystallite_requested(c,i,e)) then - plasticState (phaseAt(c,i,e))%subState0( :,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%partionedState0(:,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%subState0( :,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%partionedState0(:,phasememberAt(c,i,e)) - enddo - crystallite_subFp0(1:3,1:3,c,i,e) = crystallite_partionedFp0(1:3,1:3,c,i,e) ! ...plastic def grad - crystallite_subLp0(1:3,1:3,c,i,e) = crystallite_partionedLp0(1:3,1:3,c,i,e) ! ...plastic velocity grad - crystallite_subFi0(1:3,1:3,c,i,e) = crystallite_partionedFi0(1:3,1:3,c,i,e) ! ...intermediate def grad - crystallite_subLi0(1:3,1:3,c,i,e) = crystallite_partionedLi0(1:3,1:3,c,i,e) ! ...intermediate velocity grad - crystallite_dPdF0(1:3,1:3,1:3,1:3,c,i,e) = crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,c,i,e) ! ...stiffness - crystallite_subF0(1:3,1:3,c,i,e) = crystallite_partionedF0(1:3,1:3,c,i,e) ! ...def grad - crystallite_subTstar0_v(1:6,c,i,e) = crystallite_partionedTstar0_v(1:6,c,i,e) !...2nd PK stress - crystallite_subFe0(1:3,1:3,c,i,e) = math_mul33x33(math_mul33x33(crystallite_subF0(1:3,1:3,c,i,e), & - math_inv33(crystallite_subFp0(1:3,1:3,c,i,e))), & - math_inv33(crystallite_subFi0(1:3,1:3,c,i,e)))! only needed later on for stiffness calculation - crystallite_subFrac(c,i,e) = 0.0_pReal - crystallite_subStep(c,i,e) = 1.0_pReal/subStepSizeCryst - crystallite_todo(c,i,e) = .true. - crystallite_converged(c,i,e) = .false. ! pretend failed step of twice the required size - endif - enddo; enddo - enddo elementLooping1 - !$OMP END PARALLEL DO - - singleRun: if (FEsolving_execELem(1) == FEsolving_execElem(2) .and. & - FEsolving_execIP(1,FEsolving_execELem(1))==FEsolving_execIP(2,FEsolving_execELem(1))) then - startIP = FEsolving_execIP(1,FEsolving_execELem(1)) - endIP = startIP - else singleRun - startIP = 1_pInt - endIP = mesh_maxNips - endif singleRun - - NiterationCrystallite = 0_pInt - numerics_integrationMode = 1_pInt - cutbackLooping: do while (any(crystallite_todo(:,startIP:endIP,FEsolving_execELem(1):FEsolving_execElem(2)))) - - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i6)') '<< CRYST >> crystallite iteration ',NiterationCrystallite - - timeSyncing1: if (any(.not. crystallite_localPlasticity) .and. numerics_timeSyncing) then - - ! Time synchronization can only be used for nonlocal calculations, and only there it makes sense. - ! The idea is that in nonlocal calculations often the vast majority of the ips - ! converges in one iteration whereas a small fraction of ips has to do a lot of cutbacks. - ! Hence, we try to minimize the computational effort by just doing a lot of cutbacks - ! in the vicinity of the "bad" ips and leave the easily converged volume more or less as it is. - ! However, some synchronization of the time step has to be done at the border between "bad" ips - ! and the ones that immediately converged. - - if (any(crystallite_syncSubFrac)) then - - ! Just did a time synchronization. - ! If all synchronizers converged, then do nothing else than winding them forward. - ! If any of the synchronizers did not converge, something went completely wrong - ! and its not clear how to fix this, so all nonlocals become terminally ill. - - if (any(crystallite_syncSubFrac .and. .not. crystallite_converged(1,:,:))) then - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) then - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if (crystallite_syncSubFrac(i,e) .and. .not. crystallite_converged(1,i,e)) & - write(6,'(a,i8,1x,i2)') '<< CRYST >> time synchronization: failed at el,ip ',e,i - enddo - enddo - endif - crystallite_syncSubFrac = .false. - where(.not. crystallite_localPlasticity) - crystallite_substep = 0.0_pReal - crystallite_todo = .false. - endwhere - else - !$OMP PARALLEL DO - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - crystallite_clearToWindForward(i,e) = crystallite_localPlasticity(1,i,e) .or. crystallite_syncSubFrac(i,e) - crystallite_clearToCutback(i,e) = crystallite_localPlasticity(1,i,e) - enddo - enddo - !$OMP END PARALLEL DO - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i6)') '<< CRYST >> time synchronization: wind forward' - endif - - elseif (any(crystallite_syncSubFracCompleted)) then - - ! Just completed a time synchronization. - ! Make sure that the ips that synchronized their time step start non-converged - - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if (crystallite_syncSubFracCompleted(i,e)) crystallite_converged(1,i,e) = .false. - crystallite_syncSubFracCompleted(i,e) = .false. - crystallite_clearToWindForward(i,e) = crystallite_localPlasticity(1,i,e) - crystallite_clearToCutback(i,e) = crystallite_localPlasticity(1,i,e) .or. .not. crystallite_converged(1,i,e) - enddo - enddo - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i6)') '<< CRYST >> time synchronization: done, proceed with cutback' - else - - ! Normal calculation. - ! If all converged and are at the end of the time increment, then just do a final wind forward. - ! If all converged, but not all reached the end of the time increment, then we only wind - ! those forward that are still on their way, all others have to wait. - ! If some did not converge and all are still at the start of the time increment, - ! then all non-convergers force their converged neighbors to also do a cutback. - ! In case that some ips have already wound forward to an intermediate time (subfrac), - ! then all those ips that converged in the first iteration, but now have a non-converged neighbor - ! have to synchronize their time step to the same intermediate time. If such a synchronization - ! takes place, all other ips have to wait and only the synchronizers do a cutback. In the next - ! iteration those will do a wind forward while all others still wait. - - !$OMP PARALLEL DO - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - crystallite_clearToWindForward(i,e) = crystallite_localPlasticity(1,i,e) - crystallite_clearToCutback(i,e) = crystallite_localPlasticity(1,i,e) - enddo - enddo - !$OMP END PARALLEL DO - if (all(crystallite_localPlasticity .or. crystallite_converged)) then - if (all(crystallite_localPlasticity .or. crystallite_subStep + crystallite_subFrac >= 1.0_pReal)) then - crystallite_clearToWindForward = .true. ! final wind forward - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i6)') '<< CRYST >> final wind forward' - else - !$OMP PARALLEL DO - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - crystallite_clearToWindForward(i,e) = crystallite_localPlasticity(1,i,e) .or. crystallite_subStep(1,i,e) < 1.0_pReal - enddo - enddo - !$OMP END PARALLEL DO - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i6)') '<< CRYST >> wind forward' - endif - else - subFracIntermediate = maxval(crystallite_subFrac, mask=.not.crystallite_localPlasticity) - if (abs(subFracIntermediate) > tiny(0.0_pReal)) then - crystallite_neighborEnforcedCutback = .false. ! look for ips that require a cutback because of a nonconverged neighbor - !$OMP PARALLEL - !$OMP DO PRIVATE(neighboring_e,neighboring_i) - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if (.not. crystallite_localPlasticity(1,i,e) .and. crystallite_converged(1,i,e)) then - do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) - neighboring_e = mesh_ipNeighborhood(1,n,i,e) - neighboring_i = mesh_ipNeighborhood(2,n,i,e) - if (neighboring_e > 0_pInt .and. neighboring_i > 0_pInt) then - if (.not. crystallite_localPlasticity(1,neighboring_i,neighboring_e) & - .and. .not. crystallite_converged(1,neighboring_i,neighboring_e)) then - crystallite_neighborEnforcedCutback(i,e) = .true. -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & - write(6,'(a12,i5,1x,i2,a,i5,1x,i2)') '<< CRYST >> ', neighboring_e,neighboring_i, & - ' enforced cutback at ',e,i -#endif - exit - endif - endif - enddo - endif - enddo - enddo - !$OMP END DO - !$OMP DO - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if(crystallite_neighborEnforcedCutback(i,e)) crystallite_converged(1,i,e) = .false. - enddo - enddo - !$OMP END DO - !$OMP END PARALLEL - else - crystallite_syncSubFrac = .false. ! look for ips that have to do a time synchronization because of a nonconverged neighbor - !$OMP PARALLEL - !$OMP DO PRIVATE(neighboring_e,neighboring_i) - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if (.not. crystallite_localPlasticity(1,i,e) .and. abs(crystallite_subFrac(1,i,e)) > tiny(0.0_pReal)) then - do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) - neighboring_e = mesh_ipNeighborhood(1,n,i,e) - neighboring_i = mesh_ipNeighborhood(2,n,i,e) - if (neighboring_e > 0_pInt .and. neighboring_i > 0_pInt) then - if (.not. crystallite_localPlasticity(1,neighboring_i,neighboring_e) & - .and. .not. crystallite_converged(1,neighboring_i,neighboring_e)) then - crystallite_syncSubFrac(i,e) = .true. -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & - write(6,'(a12,i5,1x,i2,a,i5,1x,i2)') '<< CRYST >> ',neighboring_e,neighboring_i, & - ' enforced time synchronization at ',e,i -#endif - exit - endif - endif - enddo - endif - enddo - enddo - !$OMP END DO - !$OMP DO - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if(crystallite_syncSubFrac(i,e)) crystallite_converged(1,i,e) = .false. - enddo - enddo - !$OMP END DO - !$OMP END PARALLEL - endif - where(.not. crystallite_localPlasticity .and. crystallite_subStep < 1.0_pReal) & - crystallite_converged = .false. - if (any(crystallite_syncSubFrac)) then ! have to do syncing now, so all wait except for the synchronizers which do a cutback - !$OMP PARALLEL DO - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - crystallite_clearToWindForward(i,e) = crystallite_localPlasticity(1,i,e) - crystallite_clearToCutback(i,e) = crystallite_localPlasticity(1,i,e) .or. crystallite_syncSubFrac(i,e) - enddo - enddo - !$OMP END PARALLEL DO - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i6)') '<< CRYST >> time synchronization: cutback' - else - !$OMP PARALLEL DO - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if(.not. crystallite_converged(1,i,e)) crystallite_clearToCutback(i,e) = .true. - enddo - enddo - !$OMP END PARALLEL DO - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i6)') '<< CRYST >> cutback' - endif - endif - endif - - ! Make sure that all cutbackers start with the same substep - - where(.not. crystallite_localPlasticity .and. .not. crystallite_converged) & - crystallite_subStep = minval(crystallite_subStep, mask=.not. crystallite_localPlasticity & - .and. .not. crystallite_converged) - - ! Those that do neither wind forward nor cutback are not to do - - !$OMP PARALLEL DO - elementLooping2: do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if(.not. crystallite_clearToWindForward(i,e) .and. .not. crystallite_clearToCutback(i,e)) & - crystallite_todo(1,i,e) = .false. - enddo - enddo elementLooping2 - !$OMP END PARALLEL DO - - endif timeSyncing1 - - !$OMP PARALLEL DO PRIVATE(myNcomponents,formerSubStep) - elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) ! iterate over IPs of this element to be processed - do c = 1,myNcomponents - ! --- wind forward --- - - if (crystallite_converged(c,i,e) .and. crystallite_clearToWindForward(i,e)) then - formerSubStep = crystallite_subStep(c,i,e) - crystallite_subFrac(c,i,e) = crystallite_subFrac(c,i,e) + crystallite_subStep(c,i,e) - !$OMP FLUSH(crystallite_subFrac) - crystallite_subStep(c,i,e) = min(1.0_pReal - crystallite_subFrac(c,i,e), & - stepIncreaseCryst * crystallite_subStep(c,i,e)) - !$OMP FLUSH(crystallite_subStep) - if (crystallite_subStep(c,i,e) > 0.0_pReal) then - crystallite_subF0(1:3,1:3,c,i,e) = crystallite_subF(1:3,1:3,c,i,e) ! ...def grad - !$OMP FLUSH(crystallite_subF0) - crystallite_subLp0(1:3,1:3,c,i,e) = crystallite_Lp(1:3,1:3,c,i,e) ! ...plastic velocity gradient - crystallite_subLi0(1:3,1:3,c,i,e) = crystallite_Li(1:3,1:3,c,i,e) ! ...intermediate velocity gradient - crystallite_subFp0(1:3,1:3,c,i,e) = crystallite_Fp(1:3,1:3,c,i,e) ! ...plastic def grad - crystallite_subFi0(1:3,1:3,c,i,e) = crystallite_Fi(1:3,1:3,c,i,e) ! ...intermediate def grad - crystallite_subFe0(1:3,1:3,c,i,e) = math_mul33x33(math_mul33x33(crystallite_subF (1:3,1:3,c,i,e), & - crystallite_invFp(1:3,1:3,c,i,e)), & - crystallite_invFi(1:3,1:3,c,i,e)) ! only needed later on for stiffness calculation - !if abbrevation, make c and p private in omp - plasticState (phaseAt(c,i,e))%subState0(:,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%subState0(:,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) - enddo - crystallite_subTstar0_v(1:6,c,i,e) = crystallite_Tstar_v(1:6,c,i,e) ! ...2nd PK stress - if (crystallite_syncSubFrac(i,e)) then ! if we just did a synchronization of states, then we wind forward without any further time integration - crystallite_syncSubFracCompleted(i,e) = .true. - crystallite_syncSubFrac(i,e) = .false. - crystallite_todo(c,i,e) = .false. - else - crystallite_todo(c,i,e) = .true. - endif - !$OMP FLUSH(crystallite_todo) -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite),debug_levelBasic) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i .and. c == debug_g) & - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) & - write(6,'(a,f12.8,a,f12.8,a,i8,1x,i2,1x,i3,/)') '<< CRYST >> winding forward from ', & - crystallite_subFrac(c,i,e)-formerSubStep,' to current crystallite_subfrac ', & - crystallite_subFrac(c,i,e),' in crystallite_stressAndItsTangent at el ip ipc ',e,i,c -#endif - else ! this crystallite just converged for the entire timestep - crystallite_todo(c,i,e) = .false. ! so done here - !$OMP FLUSH(crystallite_todo) - if (iand(debug_level(debug_crystallite),debug_levelBasic) /= 0_pInt & - .and. formerSubStep > 0.0_pReal) then - !$OMP CRITICAL (distributionCrystallite) - debug_CrystalliteLoopDistribution(min(nCryst+1_pInt,NiterationCrystallite)) = & - debug_CrystalliteLoopDistribution(min(nCryst+1_pInt,NiterationCrystallite)) + 1_pInt - !$OMP END CRITICAL (distributionCrystallite) - endif - endif - - ! --- cutback --- - - elseif (.not. crystallite_converged(c,i,e) .and. crystallite_clearToCutback(i,e)) then - if (crystallite_syncSubFrac(i,e)) then ! synchronize time - crystallite_subStep(c,i,e) = subFracIntermediate - else - crystallite_subStep(c,i,e) = subStepSizeCryst * crystallite_subStep(c,i,e) ! cut step in half and restore... - endif - !$OMP FLUSH(crystallite_subStep) - crystallite_Fp(1:3,1:3,c,i,e) = crystallite_subFp0(1:3,1:3,c,i,e) ! ...plastic def grad - !$OMP FLUSH(crystallite_Fp) - crystallite_invFp(1:3,1:3,c,i,e) = math_inv33(crystallite_Fp(1:3,1:3,c,i,e)) - !$OMP FLUSH(crystallite_invFp) - crystallite_Fi(1:3,1:3,c,i,e) = crystallite_subFi0(1:3,1:3,c,i,e) ! ...intermediate def grad - !$OMP FLUSH(crystallite_Fi) - crystallite_invFi(1:3,1:3,c,i,e) = math_inv33(crystallite_Fi(1:3,1:3,c,i,e)) - !$OMP FLUSH(crystallite_invFi) - crystallite_Lp(1:3,1:3,c,i,e) = crystallite_subLp0(1:3,1:3,c,i,e) ! ...plastic velocity grad - crystallite_Li(1:3,1:3,c,i,e) = crystallite_subLi0(1:3,1:3,c,i,e) ! ...intermediate velocity grad - plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%subState0(:,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%subState0(:,phasememberAt(c,i,e)) - enddo - crystallite_Tstar_v(1:6,c,i,e) = crystallite_subTstar0_v(1:6,c,i,e) ! ...2nd PK stress - - ! cant restore dotState here, since not yet calculated in first cutback after initialization - crystallite_todo(c,i,e) = crystallite_subStep(c,i,e) > subStepMinCryst ! still on track or already done (beyond repair) - !$OMP FLUSH(crystallite_todo) -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite),debug_levelBasic) /= 0_pInt) then - if (crystallite_todo(c,i,e)) then - write(6,'(a,f12.8,a,i8,1x,i2,1x,i3,/)') '<< CRYST >> cutback step in crystallite_stressAndItsTangent & - &with new crystallite_subStep: ',& - crystallite_subStep(c,i,e),' at el ip ipc ',e,i,c - else - write(6,'(a,i8,1x,i2,1x,i3,/)') '<< CRYST >> reached minimum step size & - &in crystallite_stressAndItsTangent at el ip ipc ',e,i,c - endif - endif -#endif - endif - - ! --- prepare for integration --- - - if (crystallite_todo(c,i,e) .and. (crystallite_clearToWindForward(i,e) .or. crystallite_clearToCutback(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_partionedF(1:3,1:3,c,i,e) & - - crystallite_partionedF0(1:3,1:3,c,i,e)) - !$OMP FLUSH(crystallite_subF) - crystallite_Fe(1:3,1:3,c,i,e) = math_mul33x33(math_mul33x33(crystallite_subF (1:3,1:3,c,i,e), & - crystallite_invFp(1:3,1:3,c,i,e)), & - crystallite_invFi(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. ! start out non-converged - endif - - enddo ! grains - enddo ! IPs - enddo elementLooping3 - !$OMP END PARALLEL DO - - timeSyncing2: if(numerics_timeSyncing) then - if (any(.not. crystallite_localPlasticity .and. .not. crystallite_todo .and. .not. crystallite_converged & - .and. crystallite_subStep <= subStepMinCryst)) then ! no way of rescuing a nonlocal ip that violated the lower time step limit, ... - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) then - elementLooping4: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - do c = 1,myNcomponents - if (.not. crystallite_localPlasticity(c,i,e) .and. .not. crystallite_todo(c,i,e) & - .and. .not. crystallite_converged(c,i,e) .and. crystallite_subStep(c,i,e) <= subStepMinCryst) & - write(6,'(a,i8,1x,i2,1x,i3)') '<< CRYST >> nonlocal violated minimum subStep at el ip ipc ',e,i,c - enddo - enddo - enddo elementLooping4 - endif - where(.not. crystallite_localPlasticity) - crystallite_todo = .false. ! ... so let all nonlocal ips die peacefully - crystallite_subStep = 0.0_pReal - endwhere - endif - endif timeSyncing2 - - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) then - write(6,'(/,a,e12.5)') '<< CRYST >> min(subStep) ',minval(crystallite_subStep) - write(6,'(a,e12.5)') '<< CRYST >> max(subStep) ',maxval(crystallite_subStep) - write(6,'(a,e12.5)') '<< CRYST >> min(subFrac) ',minval(crystallite_subFrac) - write(6,'(a,e12.5,/)') '<< CRYST >> max(subFrac) ',maxval(crystallite_subFrac) - flush(6) - endif - - ! --- integrate --- requires fully defined state array (basic + dependent state) - - if (any(crystallite_todo)) then - select case(numerics_integrator(numerics_integrationMode)) - case(1_pInt) - call crystallite_integrateStateFPI() - case(2_pInt) - call crystallite_integrateStateEuler() - case(3_pInt) - call crystallite_integrateStateAdaptiveEuler() - case(4_pInt) - call crystallite_integrateStateRK4() - case(5_pInt) - call crystallite_integrateStateRKCK45() - end select - endif - - where(.not. crystallite_converged .and. crystallite_subStep > subStepMinCryst) & ! do not try non-converged & fully cutbacked any further - crystallite_todo = .true. - - NiterationCrystallite = NiterationCrystallite + 1_pInt - - enddo cutbackLooping - - -! --+>> CHECK FOR NON-CONVERGED CRYSTALLITES <<+-- - - elementLooping5: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) ! iterate over IPs of this element to be processed - do c = 1,myNcomponents - if (.not. crystallite_converged(c,i,e)) then ! respond fully elastically (might be not required due to becoming terminally ill anyway) - if(iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) & - write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3,/)') '<< CRYST >> no convergence: respond fully elastic at el (elFE) ip ipc ', & - e,'(',mesh_element(1,e),')',i,c - invFp = math_inv33(crystallite_partionedFp0(1:3,1:3,c,i,e)) - Fe_guess = math_mul33x33(math_mul33x33(crystallite_partionedF(1:3,1:3,c,i,e), invFp), & - math_inv33(crystallite_partionedFi0(1:3,1:3,c,i,e))) - call constitutive_TandItsTangent(Tstar,dSdFe,dSdFi,Fe_guess,crystallite_partionedFi0(1:3,1:3,c,i,e),c,i,e) - crystallite_P(1:3,1:3,c,i,e) = math_mul33x33(math_mul33x33(crystallite_partionedF(1:3,1:3,c,i,e), invFp), & - math_mul33x33(Tstar,transpose(invFp))) - endif - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i .and. c == debug_g) & - .or. .not. iand(debug_level(debug_crystallite),debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i8,1x,i2,1x,i3)') '<< CRYST >> central solution of cryst_StressAndTangent at el ip ipc ',e,i,c - write(6,'(/,a,/,3(12x,3(f12.4,1x)/))') '<< CRYST >> P / MPa', & - math_transpose33(crystallite_P(1:3,1:3,c,i,e))*1.0e-6_pReal - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Fp', & - math_transpose33(crystallite_Fp(1:3,1:3,c,i,e)) - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Fi', & - math_transpose33(crystallite_Fi(1:3,1:3,c,i,e)) - write(6,'(a,/,3(12x,3(f14.9,1x)/),/)') '<< CRYST >> Lp', & - math_transpose33(crystallite_Lp(1:3,1:3,c,i,e)) - write(6,'(a,/,3(12x,3(f14.9,1x)/),/)') '<< CRYST >> Li', & - math_transpose33(crystallite_Li(1:3,1:3,c,i,e)) - flush(6) - endif - enddo - enddo - enddo elementLooping5 - - -! --+>> STIFFNESS CALCULATION <<+-- - - computeJacobian: if(updateJaco) then - jacobianMethod: if (analyticJaco) then - - ! --- ANALYTIC JACOBIAN --- - - !$OMP PARALLEL DO PRIVATE(dSdF,dSdFe,dSdFi,dLpdS,dLpdFi,dFpinvdF,dLidS,dLidFi,dFidS,& - !$OMP rhs_3333,lhs_3333,temp_99,temp_33,temp_3333,myNcomponents,error) - elementLooping6: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) ! iterate over IPs of this element to be processed - do c = 1_pInt,myNcomponents - call constitutive_TandItsTangent(temp_33,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 law to calculate elastic stress tangent - - call constitutive_LiAndItsTangent(temp_33,dLidS,dLidFi,crystallite_Tstar_v(1:6,c,i,e), & - crystallite_Fi(1:3,1:3,c,i,e), & - c,i,e) ! call constitutive law to calculate Li tangent in lattice configuration - if (sum(abs(dLidS)) < tol_math_check) then - dFidS = 0.0_pReal - else - temp_33 = math_inv33(crystallite_subFi0(1:3,1:3,c,i,e)) - lhs_3333 = 0.0_pReal; rhs_3333 = 0.0_pReal - do o=1_pInt,3_pInt; do p=1_pInt,3_pInt - lhs_3333(1:3,1:3,o,p) = lhs_3333(1:3,1:3,o,p) + & - crystallite_subdt(c,i,e)*math_mul33x33(temp_33,dLidFi(1:3,1:3,o,p)) - lhs_3333(1:3,o,1:3,p) = lhs_3333(1:3,o,1:3,p) + & - crystallite_invFi(1:3,1:3,c,i,e)*crystallite_invFi(p,o,c,i,e) - rhs_3333(1:3,1:3,o,p) = rhs_3333(1:3,1:3,o,p) - & - crystallite_subdt(c,i,e)*math_mul33x33(temp_33,dLidS(1:3,1:3,o,p)) - enddo; enddo - call math_invert(9_pInt,math_Plain3333to99(lhs_3333),temp_99,error) - if (error) then - call IO_warning(warning_ID=600_pInt,el=e,ip=i,g=c, & - ext_msg='inversion error in analytic tangent calculation') - dFidS = 0.0_pReal - else - dFidS = math_mul3333xx3333(math_Plain99to3333(temp_99),rhs_3333) - endif - dLidS = math_mul3333xx3333(dLidFi,dFidS) + dLidS - endif - - call constitutive_LpAndItsTangent(temp_33,dLpdS,dLpdFi,crystallite_Tstar_v(1:6,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 - - temp_33 = math_transpose33(math_mul33x33(crystallite_invFp(1:3,1:3,c,i,e), & - crystallite_invFi(1:3,1:3,c,i,e))) - rhs_3333 = 0.0_pReal - forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & - rhs_3333(p,o,1:3,1:3) = math_mul33x33(dSdFe(p,o,1:3,1:3),temp_33) - - temp_3333 = 0.0_pReal - temp_33 = math_mul33x33(crystallite_subF(1:3,1:3,c,i,e), & - math_inv33(crystallite_subFp0(1:3,1:3,c,i,e))) - forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & - temp_3333(1:3,1:3,p,o) = math_mul33x33(math_mul33x33(temp_33,dLpdS(1:3,1:3,p,o)), & - crystallite_invFi(1:3,1:3,c,i,e)) - - temp_33 = math_mul33x33(math_mul33x33(crystallite_subF(1:3,1:3,c,i,e), & - crystallite_invFp(1:3,1:3,c,i,e)), & - math_inv33(crystallite_subFi0(1:3,1:3,c,i,e))) - forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & - temp_3333(1:3,1:3,p,o) = temp_3333(1:3,1:3,p,o) + math_mul33x33(temp_33,dLidS(1:3,1:3,p,o)) - - lhs_3333 = crystallite_subdt(c,i,e)*math_mul3333xx3333(dSdFe,temp_3333) + & - math_mul3333xx3333(dSdFi,dFidS) - - call math_invert(9_pInt,math_identity2nd(9_pInt)+math_Plain3333to99(lhs_3333),temp_99,error) - if (error) then - call IO_warning(warning_ID=600_pInt,el=e,ip=i,g=c, & - ext_msg='inversion error in analytic tangent calculation') - dSdF = rhs_3333 - else - dSdF = math_mul3333xx3333(math_Plain99to3333(temp_99),rhs_3333) - endif - - dFpinvdF = 0.0_pReal - temp_3333 = math_mul3333xx3333(dLpdS,dSdF) - forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & - dFpinvdF(1:3,1:3,p,o) = -crystallite_subdt(c,i,e)* & - math_mul33x33(math_inv33(crystallite_subFp0(1:3,1:3,c,i,e)), & - math_mul33x33(temp_3333(1:3,1:3,p,o), & - crystallite_invFi(1:3,1:3,c,i,e))) - - crystallite_dPdF(1:3,1:3,1:3,1:3,c,i,e) = 0.0_pReal - temp_33 = math_mul33x33(crystallite_invFp(1:3,1:3,c,i,e), & - math_mul33x33(math_Mandel6to33(crystallite_Tstar_v(1:6,c,i,e)), & - math_transpose33(crystallite_invFp(1:3,1:3,c,i,e)))) - forall(p=1_pInt:3_pInt) & - crystallite_dPdF(p,1:3,p,1:3,c,i,e) = math_transpose33(temp_33) - - temp_33 = math_mul33x33(math_Mandel6to33(crystallite_Tstar_v(1:6,c,i,e)), & - math_transpose33(crystallite_invFp(1:3,1:3,c,i,e))) - forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & - crystallite_dPdF(1:3,1:3,p,o,c,i,e) = crystallite_dPdF(1:3,1:3,p,o,c,i,e) + & - math_mul33x33(math_mul33x33(crystallite_subF(1:3,1:3,c,i,e),dFpinvdF(1:3,1:3,p,o)),temp_33) - - temp_33 = math_mul33x33(crystallite_subF(1:3,1:3,c,i,e), & - crystallite_invFp(1:3,1:3,c,i,e)) - forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & - crystallite_dPdF(1:3,1:3,p,o,c,i,e) = crystallite_dPdF(1:3,1:3,p,o,c,i,e) + & - math_mul33x33(math_mul33x33(temp_33,dSdF(1:3,1:3,p,o)), & - math_transpose33(crystallite_invFp(1:3,1:3,c,i,e))) - - temp_33 = math_mul33x33(math_mul33x33(crystallite_subF(1:3,1:3,c,i,e), & - crystallite_invFp(1:3,1:3,c,i,e)), & - math_Mandel6to33(crystallite_Tstar_v(1:6,c,i,e))) - forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & - crystallite_dPdF(1:3,1:3,p,o,c,i,e) = crystallite_dPdF(1:3,1:3,p,o,c,i,e) + & - math_mul33x33(temp_33,math_transpose33(dFpinvdF(1:3,1:3,p,o))) - - enddo; enddo - enddo elementLooping6 - !$OMP END PARALLEL DO - - else jacobianMethod - - ! --- STANDARD (PERTURBATION METHOD) FOR JACOBIAN --- - - numerics_integrationMode = 2_pInt - - ! --- BACKUP --- - allocate(dPdF_perturbation1(3,3,3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(dPdF_perturbation2(3,3,3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(F_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(Fp_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(InvFp_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(Fi_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(InvFi_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(Fe_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(Lp_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(Li_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(P_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(Tstar_v_backup (6, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) - allocate(convergenceFlag_backup (homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = .false.) - - !$OMP PARALLEL DO PRIVATE(myNcomponents) - elementLooping7: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do c = 1,myNcomponents - - plasticState (phaseAt(c,i,e))%state_backup(:,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%state_backup(:,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) - enddo - - plasticState (phaseAt(c,i,e))%dotState_backup(:,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%dotState( :,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%dotState_backup(:,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%dotState( :,phasememberAt(c,i,e)) - enddo - - F_backup(1:3,1:3,c,i,e) = crystallite_subF(1:3,1:3,c,i,e) ! ... and kinematics - Fp_backup(1:3,1:3,c,i,e) = crystallite_Fp(1:3,1:3,c,i,e) - InvFp_backup(1:3,1:3,c,i,e) = crystallite_invFp(1:3,1:3,c,i,e) - Fi_backup(1:3,1:3,c,i,e) = crystallite_Fi(1:3,1:3,c,i,e) - InvFi_backup(1:3,1:3,c,i,e) = crystallite_invFi(1:3,1:3,c,i,e) - Fe_backup(1:3,1:3,c,i,e) = crystallite_Fe(1:3,1:3,c,i,e) - Lp_backup(1:3,1:3,c,i,e) = crystallite_Lp(1:3,1:3,c,i,e) - Li_backup(1:3,1:3,c,i,e) = crystallite_Li(1:3,1:3,c,i,e) - Tstar_v_backup(1:6,c,i,e) = crystallite_Tstar_v(1:6,c,i,e) - P_backup(1:3,1:3,c,i,e) = crystallite_P(1:3,1:3,c,i,e) - convergenceFlag_backup(c,i,e) = crystallite_converged(c,i,e) - enddo; enddo - enddo elementLooping7 - !$END PARALLEL DO - ! --- CALCULATE STATE AND STRESS FOR PERTURBATION --- - - dPdF_perturbation1 = crystallite_dPdF0 ! initialize stiffness with known good values from last increment - dPdF_perturbation2 = crystallite_dPdF0 ! initialize stiffness with known good values from last increment - pertubationLoop: do perturbation = 1,2 ! forward and backward perturbation - if (iand(pert_method,perturbation) > 0_pInt) then ! mask for desired direction - myPert = -pert_Fg * (-1.0_pReal)**perturbation ! set perturbation step - do k = 1,3; do l = 1,3 ! ...alter individual components - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i .and. c == debug_g) & - .or. .not. iand(debug_level(debug_crystallite),debug_levelSelective) /= 0_pInt)) & - write(6,'(a,2(1x,i1),1x,a,/)') '<< CRYST >> [[[[[[ Stiffness perturbation',k,l,']]]]]]' - ! --- INITIALIZE UNPERTURBED STATE --- - - select case(numerics_integrator(numerics_integrationMode)) - case(1_pInt) -!why not OMP? ! Fix-point method: restore to last converged state at end of subinc, since this is probably closest to perturbed state - do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do c = 1,myNcomponents - - plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%state_backup(:,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%state_backup(:,phasememberAt(c,i,e)) - enddo - - plasticState (phaseAt(c,i,e))%dotState( :,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%dotState_backup(:,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%dotState( :,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%dotState_backup(:,phasememberAt(c,i,e)) - enddo - - crystallite_Fp(1:3,1:3,c,i,e) = Fp_backup(1:3,1:3,c,i,e) - crystallite_invFp(1:3,1:3,c,i,e) = InvFp_backup(1:3,1:3,c,i,e) - crystallite_Fi(1:3,1:3,c,i,e) = Fi_backup(1:3,1:3,c,i,e) - crystallite_invFi(1:3,1:3,c,i,e) = InvFi_backup(1:3,1:3,c,i,e) - crystallite_Fe(1:3,1:3,c,i,e) = Fe_backup(1:3,1:3,c,i,e) - crystallite_Lp(1:3,1:3,c,i,e) = Lp_backup(1:3,1:3,c,i,e) - crystallite_Li(1:3,1:3,c,i,e) = Li_backup(1:3,1:3,c,i,e) - crystallite_Tstar_v(1:6,c,i,e) = Tstar_v_backup(1:6,c,i,e) - enddo; enddo - enddo - case(2_pInt,3_pInt) ! explicit Euler methods: nothing to restore (except for F), since we are only doing a stress integration step - case(4_pInt,5_pInt) -!why not OMP? ! explicit Runge-Kutta methods: restore to start of subinc, since we are doing a full integration of state and stress - do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do c = 1,myNcomponents - - plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%subState0(:,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%subState0(:,phasememberAt(c,i,e)) - enddo - - plasticState (phaseAt(c,i,e))%dotState( :,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%dotState_backup(:,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%dotState( :,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%dotState_backup(:,phasememberAt(c,i,e)) - enddo - - 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_Fe(1:3,1:3,c,i,e) = crystallite_subFe0(1:3,1:3,c,i,e) - crystallite_Lp(1:3,1:3,c,i,e) = crystallite_subLp0(1:3,1:3,c,i,e) - crystallite_Li(1:3,1:3,c,i,e) = crystallite_subLi0(1:3,1:3,c,i,e) - crystallite_Tstar_v(1:6,c,i,e) = crystallite_subTstar0_v(1:6,c,i,e) - enddo; enddo - enddo - end select - - ! --- PERTURB EITHER FORWARD OR BACKWARD --- -!why not OMP? - do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - do c = 1,myNcomponents - crystallite_subF(1:3,1:3,c,i,e) = F_backup(1:3,1:3,c,i,e) - crystallite_subF(k,l,c,i,e) = crystallite_subF(k,l,c,i,e) + myPert - crystallite_todo(c,i,e) = crystallite_requested(c,i,e) & - .and. convergenceFlag_backup(c,i,e) - if (crystallite_todo(c,i,e)) crystallite_converged(c,i,e) = .false. ! start out non-converged - enddo; enddo; enddo - - - select case(numerics_integrator(numerics_integrationMode)) - case(1_pInt) - call crystallite_integrateStateFPI() - case(2_pInt) - call crystallite_integrateStateEuler() - case(3_pInt) - call crystallite_integrateStateAdaptiveEuler() - case(4_pInt) - call crystallite_integrateStateRK4() - case(5_pInt) - call crystallite_integrateStateRKCK45() - end select - !why not OMP? - elementLooping8: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - select case(perturbation) - case(1_pInt) - forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & - crystallite_requested(c,i,e) .and. crystallite_converged(c,i,e)) & ! converged state warrants stiffness update - dPdF_perturbation1(1:3,1:3,k,l,c,i,e) = & - (crystallite_P(1:3,1:3,c,i,e) - P_backup(1:3,1:3,c,i,e)) / myPert ! tangent dP_ij/dFg_kl - case(2_pInt) - forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & - crystallite_requested(c,i,e) .and. crystallite_converged(c,i,e)) & ! converged state warrants stiffness update - dPdF_perturbation2(1:3,1:3,k,l,c,i,e) = & - (crystallite_P(1:3,1:3,c,i,e) - P_backup(1:3,1:3,c,i,e)) / myPert ! tangent dP_ij/dFg_kl - end select - enddo elementLooping8 - - enddo; enddo ! k,l component perturbation loop - - endif - enddo pertubationLoop - - ! --- STIFFNESS ACCORDING TO PERTURBATION METHOD AND CONVERGENCE --- - - elementLooping9: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - select case(pert_method) - case(1_pInt) - forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & - crystallite_requested(c,i,e) .and. convergenceFlag_backup(c,i,e)) & ! perturbation mode 1: central solution converged - crystallite_dPdF(1:3,1:3,1:3,1:3,c,i,e) = dPdF_perturbation1(1:3,1:3,1:3,1:3,c,i,e) - case(2_pInt) - forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & - crystallite_requested(c,i,e) .and. convergenceFlag_backup(c,i,e)) & ! perturbation mode 2: central solution converged - crystallite_dPdF(1:3,1:3,1:3,1:3,c,i,e) = dPdF_perturbation2(1:3,1:3,1:3,1:3,c,i,e) - case(3_pInt) - forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & - crystallite_requested(c,i,e) .and. convergenceFlag_backup(c,i,e)) & ! perturbation mode 3: central solution converged - crystallite_dPdF(1:3,1:3,1:3,1:3,c,i,e) = 0.5_pReal* ( dPdF_perturbation1(1:3,1:3,1:3,1:3,c,i,e) & - + dPdF_perturbation2(1:3,1:3,1:3,1:3,c,i,e)) - end select - forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & - crystallite_requested(c,i,e) .and. .not. convergenceFlag_backup(c,i,e)) & ! for any pertubation mode: if central solution did not converge... - crystallite_dPdF(1:3,1:3,1:3,1:3,c,i,e) = crystallite_fallbackdPdF(1:3,1:3,1:3,1:3,c,i,e) ! ...use (elastic) fallback - enddo elementLooping9 - - ! --- RESTORE --- -!why not OMP? - elementLooping10: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNcomponents = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do c = 1,myNcomponents - - plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%state_backup(:,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%state_backup(:,phasememberAt(c,i,e)) - enddo - - plasticState (phaseAt(c,i,e))%dotState( :,phasememberAt(c,i,e)) = & - plasticState (phaseAt(c,i,e))%dotState_backup(:,phasememberAt(c,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) - sourceState(phaseAt(c,i,e))%p(mySource)%dotState( :,phasememberAt(c,i,e)) = & - sourceState(phaseAt(c,i,e))%p(mySource)%dotState_backup(:,phasememberAt(c,i,e)) - enddo - - crystallite_subF(1:3,1:3,c,i,e) = F_backup(1:3,1:3,c,i,e) - crystallite_Fp(1:3,1:3,c,i,e) = Fp_backup(1:3,1:3,c,i,e) - crystallite_invFp(1:3,1:3,c,i,e) = InvFp_backup(1:3,1:3,c,i,e) - crystallite_Fi(1:3,1:3,c,i,e) = Fi_backup(1:3,1:3,c,i,e) - crystallite_invFi(1:3,1:3,c,i,e) = InvFi_backup(1:3,1:3,c,i,e) - crystallite_Fe(1:3,1:3,c,i,e) = Fe_backup(1:3,1:3,c,i,e) - crystallite_Lp(1:3,1:3,c,i,e) = Lp_backup(1:3,1:3,c,i,e) - crystallite_Li(1:3,1:3,c,i,e) = Li_backup(1:3,1:3,c,i,e) - crystallite_Tstar_v(1:6,c,i,e) = Tstar_v_backup(1:6,c,i,e) - crystallite_P(1:3,1:3,c,i,e) = P_backup(1:3,1:3,c,i,e) - crystallite_converged(c,i,e) = convergenceFlag_backup(c,i,e) - enddo; enddo - enddo elementLooping10 - - deallocate(dPdF_perturbation1) - deallocate(dPdF_perturbation2) - deallocate(F_backup ) - deallocate(Fp_backup ) - deallocate(InvFp_backup ) - deallocate(Fi_backup ) - deallocate(InvFi_backup ) - deallocate(Fe_backup ) - deallocate(Lp_backup ) - deallocate(Li_backup ) - deallocate(P_backup ) - deallocate(Tstar_v_backup ) - deallocate(convergenceFlag_backup) - - endif jacobianMethod - endif computeJacobian -!why not OMP? - -end subroutine crystallite_stressAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief integrate stress, state with 4th order explicit Runge Kutta method -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_integrateStateRK4() - use prec, only: & - prec_isNaN - use numerics, only: & - numerics_integrationMode - use debug, only: & - debug_level, & - debug_crystallite, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_g, & - debug_StateLoopDistribution - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP - use mesh, only: & - mesh_element, & - mesh_NcpElems - use material, only: & - homogenization_Ngrains, & - plasticState, & - sourceState, & - phase_Nsources, & - material_Nphase, & - phaseAt, phasememberAt - use constitutive, only: & - constitutive_collectDotState, & - constitutive_microstructure - - implicit none - real(pReal), dimension(4), parameter :: & - TIMESTEPFRACTION = [0.5_pReal, 0.5_pReal, 1.0_pReal, 1.0_pReal] ! factor giving the fraction of the original timestep used for Runge Kutta Integration - real(pReal), dimension(4), parameter :: & - WEIGHT = [1.0_pReal, 2.0_pReal, 2.0_pReal, 1.0_pReal/6.0_pReal] ! weight of slope used for Runge Kutta integration (final weight divided by 6) - - integer(pInt) :: e, & ! element index in element loop - i, & ! integration point index in ip loop - g, & ! grain index in grain loop - p, & ! phase loop - c, & - n, & - mySource, & - mySizePlasticDotState, & - mySizeSourceDotState - integer(pInt), dimension(2) :: eIter ! bounds for element iteration - integer(pInt), dimension(2,mesh_NcpElems) :: iIter, & ! bounds for ip iteration - gIter ! bounds for grain iteration - logical :: NaN, & - singleRun ! flag indicating computation for single (g,i,e) triple - - eIter = FEsolving_execElem(1:2) - do e = eIter(1),eIter(2) - iIter(1:2,e) = FEsolving_execIP(1:2,e) - gIter(1:2,e) = [ 1_pInt,homogenization_Ngrains(mesh_element(3,e))] - enddo - - singleRun = (eIter(1) == eIter(2) .and. iIter(1,eIter(1)) == iIter(2,eIter(2))) - -!-------------------------------------------------------------------------------------------------- -! initialize dotState - if (.not. singleRun) then - do p = 1_pInt, material_Nphase - plasticState(p)%RK4dotState = 0.0_pReal - do mySource = 1_pInt, phase_Nsources(p) - sourceState(p)%p(mySource)%RK4dotState = 0.0_pReal - enddo - enddo - else - e = eIter(1) - i = iIter(1,e) - do g = gIter(1,e), gIter(2,e) - plasticState(phaseAt(g,i,e))%RK4dotState(:,phasememberAt(g,i,e)) = 0.0_pReal - do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) - sourceState(phaseAt(g,i,e))%p(mySource)%RK4dotState(:,phasememberAt(g,i,e)) = 0.0_pReal - enddo - enddo - endif - -!-------------------------------------------------------------------------------------------------- -! first Runge-Kutta step - !$OMP PARALLEL - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & - crystallite_Fe, & - crystallite_Fp, & - crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP DO PRIVATE(p,c,NaN) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - c = phasememberAt(g,i,e) - p = phaseAt(g,i,e) - NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) - do mySource = 1_pInt, phase_Nsources(p) - NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) - enddo - if (NaN) then ! NaN occured in any dotState - if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - else ! if broken local... - crystallite_todo(g,i,e) = .false. ! ... skip this one next time - endif - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - !$OMP END PARALLEL -!-------------------------------------------------------------------------------------------------- -! --- SECOND TO FOURTH RUNGE KUTTA STEP PLUS FINAL INTEGRATION --- - - do n = 1_pInt,4_pInt - ! --- state update --- - - !$OMP PARALLEL - !$OMP DO PRIVATE(p,c) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - plasticState(p)%RK4dotState(:,c) = plasticState(p)%RK4dotState(:,c) & - + weight(n)*plasticState(p)%dotState(:,c) - do mySource = 1_pInt, phase_Nsources(p) - sourceState(p)%p(mySource)%RK4dotState(:,c) = sourceState(p)%p(mySource)%RK4dotState(:,c) & - + weight(n)*sourceState(p)%p(mySource)%dotState(:,c) - enddo - endif - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,c) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - mySizePlasticDotState = plasticState(p)%sizeDotState - plasticState(p)%state (1:mySizePlasticDotState,c) = & - plasticState(p)%subState0(1:mySizePlasticDotState,c) & - + plasticState(p)%dotState (1:mySizePlasticDotState,c) & - * crystallite_subdt(g,i,e) * timeStepFraction(n) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceState(p)%p(mySource)%state (1:mySizeSourceDotState,c) = & - sourceState(p)%p(mySource)%subState0(1:mySizeSourceDotState,c) & - + sourceState(p)%p(mySource)%dotState (1:mySizeSourceDotState,c) & - * crystallite_subdt(g,i,e) * timeStepFraction(n) - enddo - -#ifndef _OPENMP - if (n == 4 & - .and. iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i .and. g == debug_g) & - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then ! final integration step - - write(6,'(a,i8,1x,i2,1x,i3,/)') '<< CRYST >> updateState at el ip g ',e,i,g - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> dotState', plasticState(p)%dotState(1:mySizePlasticDotState,c) - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state', plasticState(p)%state(1:mySizePlasticDotState,c) - endif -#endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- state jump --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- update dependent states --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - !***dirty way to pass orientation information - call constitutive_microstructure(crystallite_orientation, & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- stress integration --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e,timeStepFraction(n)) ! fraction of original times step - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- dot state and RK dot state--- - - first3steps: if (n < 4) then - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & - crystallite_Fe, & - crystallite_Fp, & - timeStepFraction(n)*crystallite_subdt(g,i,e), & ! fraction of original timestep - crystallite_subFrac, g,i,e) - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP DO PRIVATE(p,c,NaN) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) - do mySource = 1_pInt, phase_Nsources(p) - NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) - enddo - if (NaN) then ! NaN occured in any dotState - if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - else ! if broken local... - crystallite_todo(g,i,e) = .false. ! ... skip this one next time - endif - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - endif first3steps - !$OMP END PARALLEL - - enddo - - - ! --- SET CONVERGENCE FLAG --- - - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - crystallite_converged(g,i,e) = .true. ! if still "to do" then converged per definitionem - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionState) - debug_StateLoopDistribution(4,numerics_integrationMode) = & - debug_StateLoopDistribution(4,numerics_integrationMode) + 1_pInt - !$OMP END CRITICAL (distributionState) - endif - endif - enddo; enddo; enddo - - - ! --- CHECK NONLOCAL CONVERGENCE --- - - if (.not. singleRun) then ! if not requesting Integration of just a single IP - if (any(.not. crystallite_converged .and. .not. crystallite_localPlasticity)) then ! any non-local not yet converged (or broken)... - crystallite_converged = crystallite_converged .and. crystallite_localPlasticity ! ...restart all non-local as not converged - endif - endif - -end subroutine crystallite_integrateStateRK4 - - -!-------------------------------------------------------------------------------------------------- -!> @brief integrate stress, state with 5th order Runge-Kutta Cash-Karp method with -!> adaptive step size (use 5th order solution to advance = "local extrapolation") -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_integrateStateRKCK45() - use prec, only: & - prec_isNaN - use debug, only: & - debug_level, & - debug_crystallite, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_g, & - debug_StateLoopDistribution - use numerics, only: & - rTol_crystalliteState, & - numerics_integrationMode - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP - use mesh, only: & - mesh_element, & - mesh_NcpElems, & - mesh_maxNips - use material, only: & - homogenization_Ngrains, & - plasticState, & - sourceState, & - phase_Nsources, & - phaseAt, phasememberAt, & - homogenization_maxNgrains - use constitutive, only: & - constitutive_collectDotState, & - constitutive_plasticity_maxSizeDotState, & - constitutive_source_maxSizeDotState, & - constitutive_microstructure - - implicit none - real(pReal), dimension(5,5), parameter :: & - A = reshape([& - .2_pReal, .075_pReal, .3_pReal, -11.0_pReal/54.0_pReal, 1631.0_pReal/55296.0_pReal, & - .0_pReal, .225_pReal, -.9_pReal, 2.5_pReal, 175.0_pReal/512.0_pReal, & - .0_pReal, .0_pReal, 1.2_pReal, -70.0_pReal/27.0_pReal, 575.0_pReal/13824.0_pReal, & - .0_pReal, .0_pReal, .0_pReal, 35.0_pReal/27.0_pReal, 44275.0_pReal/110592.0_pReal, & - .0_pReal, .0_pReal, .0_pReal, .0_pReal, 253.0_pReal/4096.0_pReal], & - [5,5], order=[2,1]) !< coefficients in Butcher tableau (used for preliminary integration in stages 2 to 6) - - 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], & !< coefficients in Butcher tableau (used for final integration and error estimate) - 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, 0.25_pReal] !< coefficients in Butcher tableau (used for final integration and error estimate) - - real(pReal), dimension(5), parameter :: & - C = [0.2_pReal, 0.3_pReal, 0.6_pReal, 1.0_pReal, 0.875_pReal] !< coefficients in Butcher tableau (fractions of original time step in stages 2 to 6) - - integer(pInt) :: & - e, & ! element index in element loop - i, & ! integration point index in ip loop - g, & ! grain index in grain loop - stage, & ! stage index in integration stage loop - s, & ! state index - n, & - p, & - cc, & - mySource, & - mySizePlasticDotState, & ! size of dot States - mySizeSourceDotState - integer(pInt), dimension(2) :: & - eIter ! bounds for element iteration - integer(pInt), dimension(2,mesh_NcpElems) :: & - iIter, & ! bounds for ip iteration - gIter ! bounds for grain iteration - - real(pReal), dimension(constitutive_plasticity_maxSizeDotState, & - homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & - plasticStateResiduum, & ! residuum from evolution in microstructure - relPlasticStateResiduum ! relative residuum from evolution in microstructure - real(pReal), dimension(constitutive_source_maxSizeDotState, & - maxval(phase_Nsources), & - homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & - sourceStateResiduum, & ! residuum from evolution in microstructure - relSourceStateResiduum ! relative residuum from evolution in microstructure - logical :: & - NaN, & - singleRun ! flag indicating computation for single (g,i,e) triple - - eIter = FEsolving_execElem(1:2) - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & - write(6,'(a,1x,i1)') '<< CRYST >> Runge--Kutta step',1 - - ! --- LOOP ITERATOR FOR ELEMENT, GRAIN, IP --- - do e = eIter(1),eIter(2) - iIter(1:2,e) = FEsolving_execIP(1:2,e) - gIter(1:2,e) = [ 1_pInt,homogenization_Ngrains(mesh_element(3,e))] - enddo - - singleRun = (eIter(1) == eIter(2) .and. iIter(1,eIter(1)) == iIter(2,eIter(2))) - - - - ! --- FIRST RUNGE KUTTA STEP --- - - !$OMP PARALLEL - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & - crystallite_Fe, & - crystallite_Fp, & - crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) - enddo; enddo; enddo - !$OMP ENDDO - !$OMP DO PRIVATE(p,cc,NaN) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - cc = phasememberAt(g,i,e) - p = phaseAt(g,i,e) - NaN = any(prec_isNaN(plasticState(p)%dotState(:,cc))) - do mySource = 1_pInt, phase_Nsources(p) - NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,cc))) - enddo - if (NaN) then ! NaN occured in any dotState - if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - else ! if broken local... - crystallite_todo(g,i,e) = .false. ! ... skip this one next time - endif - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - !$OMP END PARALLEL - - - ! --- SECOND TO SIXTH RUNGE KUTTA STEP --- - - do stage = 1_pInt,5_pInt - - ! --- state update --- - - !$OMP PARALLEL - !$OMP DO PRIVATE(p,cc) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - cc = phasememberAt(g,i,e) - plasticState(p)%RKCK45dotState(stage,:,cc) = plasticState(p)%dotState(:,cc) ! store Runge-Kutta dotState - do mySource = 1_pInt, phase_Nsources(p) - sourceState(p)%p(mySource)%RKCK45dotState(stage,:,cc) = sourceState(p)%p(mySource)%dotState(:,cc) - enddo - endif - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP DO PRIVATE(p,cc,n) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - cc = phasememberAt(g,i,e) - - plasticState(p)%dotState(:,cc) = A(1,stage) * plasticState(p)%RKCK45dotState(1,:,cc) - do mySource = 1_pInt, phase_Nsources(p) - sourceState(p)%p(mySource)%dotState(:,cc) = A(1,stage) * sourceState(p)%p(mySource)%RKCK45dotState(1,:,cc) - enddo - do n = 2_pInt, stage - plasticState(p)%dotState(:,cc) = & - plasticState(p)%dotState(:,cc) + A(n,stage) * plasticState(p)%RKCK45dotState(n,:,cc) - do mySource = 1_pInt, phase_Nsources(p) - sourceState(p)%p(mySource)%dotState(:,cc) = & - sourceState(p)%p(mySource)%dotState(:,cc) + A(n,stage) * sourceState(p)%p(mySource)%RKCK45dotState(n,:,cc) - enddo - enddo - endif - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,cc) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - cc = phasememberAt(g,i,e) - mySizePlasticDotState = plasticState(p)%sizeDotState - plasticState (p)%state (1:mySizePlasticDotState, cc) = & - plasticState (p)%subState0(1:mySizePlasticDotState, cc) & - + plasticState (p)%dotState (1:mySizePlasticDotState, cc) & - * crystallite_subdt(g,i,e) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceState(p)%p(mySource)%state (1:mySizeSourceDotState,cc) = & - sourceState(p)%p(mySource)%subState0(1:mySizeSourceDotState,cc) & - + sourceState(p)%p(mySource)%dotState (1:mySizeSourceDotState,cc) & - * crystallite_subdt(g,i,e) - enddo - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- state jump --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- update dependent states --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - !***dirty way to pass orientations to constitutive_microstructure - call constitutive_microstructure(crystallite_orientation, & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- stress integration --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e,C(stage)) ! fraction of original time step - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- dot state and RK dot state--- -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & - write(6,'(a,1x,i1)') '<< CRYST >> Runge--Kutta step',stage+1_pInt -#endif - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & - crystallite_Fe, & - crystallite_Fp, & - C(stage)*crystallite_subdt(g,i,e), & ! fraction of original timestep - crystallite_subFrac, g,i,e) - enddo; enddo; enddo - !$OMP ENDDO - !$OMP DO PRIVATE(p,cc,NaN) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - - p = phaseAt(g,i,e) - cc = phasememberAt(g,i,e) - NaN = any(prec_isNaN(plasticState(p)%dotState(:,cc))) - do mySource = 1_pInt, phase_Nsources(p) - NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,cc))) - enddo - if (NaN) then ! NaN occured in any dotState - if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - else ! if broken local... - crystallite_todo(g,i,e) = .false. ! ... skip this one next time - endif - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - !$OMP END PARALLEL - - enddo - - -!-------------------------------------------------------------------------------------------------- -! --- STATE UPDATE WITH ERROR ESTIMATE FOR STATE --- - - relPlasticStateResiduum = 0.0_pReal - relSourceStateResiduum = 0.0_pReal - !$OMP PARALLEL - !$OMP DO PRIVATE(p,cc) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - cc = phasememberAt(g,i,e) - plasticState(p)%RKCK45dotState(6,:,cc) = plasticState (p)%dotState(:,cc) ! store Runge-Kutta dotState - do mySource = 1_pInt, phase_Nsources(p) - sourceState(p)%p(mySource)%RKCK45dotState(6,:,cc) = sourceState(p)%p(mySource)%dotState(:,cc) ! store Runge-Kutta dotState - enddo - endif - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,cc) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - cc = phasememberAt(g,i,e) - - ! --- absolute residuum in state --- - mySizePlasticDotState = plasticState(p)%sizeDotState - plasticStateResiduum(1:mySizePlasticDotState,g,i,e) = & - matmul(transpose(plasticState(p)%RKCK45dotState(1:6,1:mySizePlasticDotState,cc)),DB) & - * crystallite_subdt(g,i,e) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e) = & - matmul(transpose(sourceState(p)%p(mySource)%RKCK45dotState(1:6,1:mySizeSourceDotState,cc)),DB) & - * crystallite_subdt(g,i,e) - enddo - - ! --- dot state --- - plasticState(p)%dotState(:,cc) = & - matmul(transpose(plasticState(p)%RKCK45dotState(1:6,1:mySizePlasticDotState,cc)), B) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceState(p)%p(mySource)%dotState(:,cc) = & - matmul(transpose(sourceState(p)%p(mySource)%RKCK45dotState(1:6,1:mySizeSourceDotState,cc)),B) - enddo - endif - enddo; enddo; enddo - !$OMP ENDDO - - ! --- state and update --- - - !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,cc) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - - p = phaseAt(g,i,e) - cc = phasememberAt(g,i,e) - mySizePlasticDotState = plasticState(p)%sizeDotState - plasticState(p)%state (1:mySizePlasticDotState,cc) = & - plasticState(p)%subState0(1:mySizePlasticDotState,cc) & - + plasticState(p)%dotState (1:mySizePlasticDotState,cc) & - * crystallite_subdt(g,i,e) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceState(p)%p(mySource)%state (1:mySizeSourceDotState,cc) = & - sourceState(p)%p(mySource)%subState0(1:mySizeSourceDotState,cc) & - + sourceState(p)%p(mySource)%dotState (1:mySizeSourceDotState,cc)& - * crystallite_subdt(g,i,e) - enddo - endif - enddo; enddo; enddo - !$OMP ENDDO - - ! --- relative residui and state convergence --- - - !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,cc,s) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - cc = phasememberAt(g,i,e) - mySizePlasticDotState = plasticState(p)%sizeDotState - forall (s = 1_pInt:mySizePlasticDotState, abs(plasticState(p)%state(s,cc)) > 0.0_pReal) & - relPlasticStateResiduum(s,g,i,e) = & - plasticStateResiduum(s,g,i,e) / plasticState(p)%state(s,cc) - - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - forall (s = 1_pInt:mySizeSourceDotState,abs(sourceState(p)%p(mySource)%state(s,cc)) > 0.0_pReal) & - relSourceStateResiduum(s,mySource,g,i,e) = & - sourceStateResiduum(s,mySource,g,i,e) / sourceState(p)%p(mySource)%state(s,cc) - enddo - !$OMP FLUSH(relPlasticStateResiduum) - !$OMP FLUSH(relSourceStateResiduum) -! @Martin: do we need flushing? why..? - crystallite_todo(g,i,e) = all(abs(relPlasticStateResiduum(1:mySizePlasticDotState,g,i,e)) < & - rTol_crystalliteState .or. & - abs(plasticStateResiduum(1:mySizePlasticDotState,g,i,e)) < & - plasticState(p)%aTolState(1:mySizePlasticDotState)) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. & - all(abs(relSourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e)) < & - rTol_crystalliteState .or. & - abs(sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e)) < & - sourceState(p)%p(mySource)%aTolState(1:mySizeSourceDotState)) - enddo - -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt& - .and. ((e == debug_e .and. i == debug_i .and. g == debug_g)& - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i8,1x,i3,1x,i3,/)') '<< CRYST >> updateState at el ip ipc ',e,i,g - write(6,'(a,/,(12x,12(f12.1,1x)),/)') '<< CRYST >> absolute residuum tolerance', & - plasticStateResiduum(1:mySizePlasticDotState,g,i,e) / plasticState(p)%aTolState(1:mySizePlasticDotState) - write(6,'(a,/,(12x,12(f12.1,1x)),/)') '<< CRYST >> relative residuum tolerance', & - relPlasticStateResiduum(1:mySizePlasticDotState,g,i,e) / rTol_crystalliteState - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> dotState', & - plasticState(p)%dotState(1:mySizePlasticDotState,cc) - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state', & - plasticState(p)%state(1:mySizePlasticDotState,cc) - endif -#endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- STATE JUMP --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - -!-------------------------------------------------------------------------------------------------- -! --- UPDATE DEPENDENT STATES IF RESIDUUM BELOW TOLERANCE --- - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - !***dirty way to pass orientations to constitutive_microstructure - call constitutive_microstructure(crystallite_orientation, & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states - enddo; enddo; enddo - !$OMP ENDDO - - -!-------------------------------------------------------------------------------------------------- -! --- FINAL STRESS INTEGRATION STEP IF RESIDUUM BELOW TOLERANCE --- - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e) - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - -!-------------------------------------------------------------------------------------------------- -! --- SET CONVERGENCE FLAG --- - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - crystallite_converged(g,i,e) = .true. ! if still "to do" then converged per definition - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionState) - debug_StateLoopDistribution(6,numerics_integrationMode) = & - debug_StateLoopDistribution(6,numerics_integrationMode) + 1_pInt - !$OMP END CRITICAL (distributionState) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP END PARALLEL - - - ! --- nonlocal convergence check --- - - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i8,a,i2,/)') '<< CRYST >> ', count(crystallite_converged(:,:,:)), ' grains converged' ! if not requesting Integration of just a single IP - if ((.not. singleRun) .and. any(.not. crystallite_converged .and. .not. crystallite_localPlasticity)) & ! any non-local not yet converged (or broken)... - crystallite_converged = crystallite_converged .and. crystallite_localPlasticity ! ...restart all non-local as not converged - -end subroutine crystallite_integrateStateRKCK45 - - -!-------------------------------------------------------------------------------------------------- -!> @brief integrate stress, state with 1st order Euler method with adaptive step size -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_integrateStateAdaptiveEuler() - use prec, only: & - prec_isNaN - use debug, only: & - debug_level, & - debug_crystallite, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_g, & - debug_StateLoopDistribution - use numerics, only: & - rTol_crystalliteState, & - numerics_integrationMode - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP - use mesh, only: & - mesh_element, & - mesh_NcpElems, & - mesh_maxNips - use material, only: & - homogenization_Ngrains, & - plasticState, & - sourceState, & - phaseAt, phasememberAt, & - phase_Nsources, & - homogenization_maxNgrains - use constitutive, only: & - constitutive_collectDotState, & - constitutive_microstructure, & - constitutive_plasticity_maxSizeDotState, & - constitutive_source_maxSizeDotState - - implicit none - integer(pInt) :: & - e, & ! element index in element loop - i, & ! integration point index in ip loop - g, & ! grain index in grain loop - s, & ! state index - p, & - c, & - mySource, & - mySizePlasticDotState, & ! size of dot states - mySizeSourceDotState - integer(pInt), dimension(2) :: & - eIter ! bounds for element iteration - integer(pInt), dimension(2,mesh_NcpElems) :: & - iIter, & ! bounds for ip iteration - gIter ! bounds for grain iteration - real(pReal), dimension(constitutive_plasticity_maxSizeDotState, & - homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & - plasticStateResiduum, & ! residuum from evolution in micrstructure - relPlasticStateResiduum ! relative residuum from evolution in microstructure - real(pReal), dimension(constitutive_source_maxSizeDotState,& - maxval(phase_Nsources), & - homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & - sourceStateResiduum, & ! residuum from evolution in micrstructure - relSourceStateResiduum ! relative residuum from evolution in microstructure - - logical :: & - converged, & - NaN, & - singleRun ! flag indicating computation for single (g,i,e) triple - - - ! --- LOOP ITERATOR FOR ELEMENT, GRAIN, IP --- - eIter = FEsolving_execElem(1:2) - do e = eIter(1),eIter(2) - iIter(1:2,e) = FEsolving_execIP(1:2,e) - gIter(1:2,e) = [ 1_pInt,homogenization_Ngrains(mesh_element(3,e))] - enddo - - singleRun = (eIter(1) == eIter(2) .and. iIter(1,eIter(1)) == iIter(2,eIter(2))) - - - plasticStateResiduum = 0.0_pReal - relPlasticStateResiduum = 0.0_pReal - sourceStateResiduum = 0.0_pReal - relSourceStateResiduum = 0.0_pReal - - integrationMode: if (numerics_integrationMode == 1_pInt) then - - !$OMP PARALLEL - ! --- DOT STATE (EULER INTEGRATION) --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & - crystallite_Fe, & - crystallite_Fp, & - crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) - enddo; enddo; enddo - !$OMP ENDDO - !$OMP DO PRIVATE(p,c,NaN) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) - do mySource = 1_pInt, phase_Nsources(p) - NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) - enddo - if (NaN) then ! NaN occured in any dotState - if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - else ! if broken local... - crystallite_todo(g,i,e) = .false. ! ... skip this one next time - endif - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- STATE UPDATE (EULER INTEGRATION) --- - - !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,c) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - mySizePlasticDotState = plasticState(p)%sizeDotState - plasticStateResiduum(1:mySizePlasticDotState,g,i,e) = & - - 0.5_pReal & - * plasticState(p)%dotstate(1:mySizePlasticDotState,c) & - * crystallite_subdt(g,i,e) ! contribution to absolute residuum in state - plasticState(p)%state (1:mySizePlasticDotState,c) = & - plasticState(p)%state (1:mySizePlasticDotState,c) & - + plasticState(p)%dotstate(1:mySizePlasticDotState,c) & - * crystallite_subdt(g,i,e) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e) = & - - 0.5_pReal & - * sourceState(p)%p(mySource)%dotstate(1:mySizeSourceDotState,c) & - * crystallite_subdt(g,i,e) ! contribution to absolute residuum in state - sourceState(p)%p(mySource)%state (1:mySizeSourceDotState,c) = & - sourceState(p)%p(mySource)%state (1:mySizeSourceDotState,c) & - + sourceState(p)%p(mySource)%dotstate(1:mySizeSourceDotState,c) & - * crystallite_subdt(g,i,e) - enddo - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- STATE JUMP --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- UPDATE DEPENDENT STATES (EULER INTEGRATION) --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - !***dirty way to pass orientations to constitutive_microstructure - call constitutive_microstructure(crystallite_orientation, & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states - enddo; enddo; enddo - !$OMP ENDDO - !$OMP END PARALLEL - endif integrationMode - - - ! --- STRESS INTEGRATION (EULER INTEGRATION) --- - - !$OMP PARALLEL DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e) - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP END PARALLEL DO - - - if (numerics_integrationMode == 1_pInt) then - - !$OMP PARALLEL - ! --- DOT STATE (HEUN METHOD) --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & - crystallite_Fe, & - crystallite_Fp, & - crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) - enddo; enddo; enddo - !$OMP ENDDO - !$OMP DO PRIVATE(p,c,NaN) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) - do mySource = 1_pInt, phase_Nsources(p) - NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) - enddo - if (NaN) then ! NaN occured in any dotState - if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - else ! if broken local... - crystallite_todo(g,i,e) = .false. ! ... skip this one next time - endif - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- ERROR ESTIMATE FOR STATE (HEUN METHOD) --- - - !$OMP SINGLE - relPlasticStateResiduum = 0.0_pReal - relSourceStateResiduum = 0.0_pReal - !$OMP END SINGLE - - !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,converged,p,c,s) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - ! --- contribution of heun step to absolute residui --- - mySizePlasticDotState = plasticState(p)%sizeDotState - plasticStateResiduum(1:mySizePlasticDotState,g,i,e) = & - plasticStateResiduum(1:mySizePlasticDotState,g,i,e) & - + 0.5_pReal * plasticState(p)%dotState(:,c) & - * crystallite_subdt(g,i,e) ! contribution to absolute residuum in state - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e) = & - sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e) & - + 0.5_pReal * sourceState(p)%p(mySource)%dotState(:,c) & - * crystallite_subdt(g,i,e) ! contribution to absolute residuum in state - enddo - !$OMP FLUSH(plasticStateResiduum) - !$OMP FLUSH(sourceStateResiduum) - - ! --- relative residui --- - forall (s = 1_pInt:mySizePlasticDotState, abs(plasticState(p)%dotState(s,c)) > 0.0_pReal) & - relPlasticStateResiduum(s,g,i,e) = & - plasticStateResiduum(s,g,i,e) / plasticState(p)%dotState(s,c) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - forall (s = 1_pInt:mySizeSourceDotState,abs(sourceState(p)%p(mySource)%dotState(s,c)) > 0.0_pReal) & - relSourceStateResiduum(s,mySource,g,i,e) = & - sourceStateResiduum(s,mySource,g,i,e) / sourceState(p)%p(mySource)%dotState(s,c) - enddo - !$OMP FLUSH(relPlasticStateResiduum) - !$OMP FLUSH(relSourceStateResiduum) - -#ifndef _OPENMP - - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i .and. g == debug_g)& - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i8,1x,i2,1x,i3,/)') '<< CRYST >> updateState at el ip g ',e,i,g - write(6,'(a,/,(12x,12(f12.1,1x)),/)') '<< CRYST >> absolute residuum tolerance', & - plasticStateResiduum(1:mySizePlasticDotState,g,i,e) / plasticState(p)%aTolState(1:mySizePlasticDotState) - write(6,'(a,/,(12x,12(f12.1,1x)),/)') '<< CRYST >> relative residuum tolerance', & - relPlasticStateResiduum(1:mySizePlasticDotState,g,i,e) / rTol_crystalliteState - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> dotState', plasticState(p)%dotState(1:mySizePlasticDotState,c) & - - 2.0_pReal * plasticStateResiduum(1:mySizePlasticDotState,g,i,e) / crystallite_subdt(g,i,e) ! calculate former dotstate from higher order solution and state residuum - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state', plasticState(p)%state(1:mySizePlasticDotState,c) - endif -#endif - - ! --- converged ? --- - converged = all(abs(relPlasticStateResiduum(1:mySizePlasticDotState,g,i,e)) < & - rTol_crystalliteState .or. & - abs(plasticStateResiduum(1:mySizePlasticDotState,g,i,e)) < & - plasticState(p)%aTolState(1:mySizePlasticDotState)) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - converged = converged .and. & - all(abs(relSourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e)) < & - rTol_crystalliteState .or. & - abs(sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e)) < & - sourceState(p)%p(mySource)%aTolState(1:mySizeSourceDotState)) - enddo - if (converged) then - crystallite_converged(g,i,e) = .true. ! ... converged per definitionem - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionState) - debug_StateLoopDistribution(2,numerics_integrationMode) = & - debug_StateLoopDistribution(2,numerics_integrationMode) + 1_pInt - !$OMP END CRITICAL (distributionState) - endif - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - !$OMP END PARALLEL - - elseif (numerics_integrationMode > 1) then ! stiffness calculation - - !$OMP PARALLEL DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - crystallite_converged(g,i,e) = .true. ! ... converged per definitionem - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionState) - debug_StateLoopDistribution(2,numerics_integrationMode) = & - debug_StateLoopDistribution(2,numerics_integrationMode) + 1_pInt - !$OMP END CRITICAL (distributionState) - endif - endif - enddo; enddo; enddo - !$OMP END PARALLEL DO - - endif - - - - ! --- NONLOCAL CONVERGENCE CHECK --- - - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i8,a,i2,/)') '<< CRYST >> ', count(crystallite_converged(:,:,:)), ' grains converged' - if ((.not. singleRun) .and. any(.not. crystallite_converged .and. .not. crystallite_localPlasticity)) & ! any non-local not yet converged (or broken)... - crystallite_converged = crystallite_converged .and. crystallite_localPlasticity ! ...restart all non-local as not converged - - -end subroutine crystallite_integrateStateAdaptiveEuler - - -!-------------------------------------------------------------------------------------------------- -!> @brief integrate stress, and state with 1st order explicit Euler method -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_integrateStateEuler() - use prec, only: & - prec_isNaN - use debug, only: & - debug_level, & - debug_crystallite, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_g, & - debug_StateLoopDistribution - use numerics, only: & - numerics_integrationMode, & - numerics_timeSyncing - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP - use mesh, only: & - mesh_element, & - mesh_NcpElems - use material, only: & - plasticState, & - sourceState, & - phaseAt, phasememberAt, & - phase_Nsources, & - homogenization_Ngrains - use constitutive, only: & - constitutive_collectDotState, & - constitutive_microstructure - - implicit none - - integer(pInt) :: & - e, & ! element index in element loop - i, & ! integration point index in ip loop - g, & ! grain index in grain loop - p, & ! phase loop - c, & - mySource, & - mySizePlasticDotState, & - mySizeSourceDotState - integer(pInt), dimension(2) :: & - eIter ! bounds for element iteration - integer(pInt), dimension(2,mesh_NcpElems) :: & - iIter, & ! bounds for ip iteration - gIter ! bounds for grain iteration - logical :: & - NaN, & - singleRun ! flag indicating computation for single (g,i,e) triple - - -eIter = FEsolving_execElem(1:2) - do e = eIter(1),eIter(2) - iIter(1:2,e) = FEsolving_execIP(1:2,e) - gIter(1:2,e) = [ 1_pInt,homogenization_Ngrains(mesh_element(3,e))] - enddo - - singleRun = (eIter(1) == eIter(2) .and. iIter(1,eIter(1)) == iIter(2,eIter(2))) - - if (numerics_integrationMode == 1_pInt) then - !$OMP PARALLEL - - ! --- DOT STATE --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) & - call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & - crystallite_Fe, & - crystallite_Fp, & - crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) - enddo; enddo; enddo - !$OMP ENDDO - !$OMP DO PRIVATE(p,c,NaN) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then - c = phasememberAt(g,i,e) - p = phaseAt(g,i,e) - NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) - do mySource = 1_pInt, phase_Nsources(p) - NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) - enddo - if (NaN) then ! NaN occured in any dotState - if (.not. crystallite_localPlasticity(g,i,e) .and. .not. numerics_timeSyncing) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - else ! if broken local... - crystallite_todo(g,i,e) = .false. ! ... skip this one next time - endif - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- UPDATE STATE --- - - !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,c) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - mySizePlasticDotState = plasticState(p)%sizeDotState - plasticState(p)%state( 1:mySizePlasticDotState,c) = & - plasticState(p)%state( 1:mySizePlasticDotState,c) & - + plasticState(p)%dotState(1:mySizePlasticDotState,c) & - * crystallite_subdt(g,i,e) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceState(p)%p(mySource)%state( 1:mySizeSourceDotState,c) = & - sourceState(p)%p(mySource)%state( 1:mySizeSourceDotState,c) & - + sourceState(p)%p(mySource)%dotState(1:mySizeSourceDotState,c) & - * crystallite_subdt(g,i,e) - enddo - -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i .and. g == debug_g) & - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - write(6,'(a,i8,1x,i2,1x,i3,/)') '<< CRYST >> update state at el ip g ',e,i,g - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> dotState', plasticState(p)%dotState(1:mySizePlasticDotState,c) - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state', plasticState(p)%state (1:mySizePlasticDotState,c) - endif -#endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- STATE JUMP --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e) & ! if broken non-local... - .and. .not. numerics_timeSyncing) then - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- UPDATE DEPENDENT STATES --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) & - !***dirty way to pass orientations to constitutive_microstructure - call constitutive_microstructure(crystallite_orientation, & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states - enddo; enddo; enddo - !$OMP ENDDO - !$OMP END PARALLEL - endif - - - !$OMP PARALLEL - ! --- STRESS INTEGRATION --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e) - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e) & ! if broken non-local... - .and. .not. numerics_timeSyncing) then - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - - ! --- SET CONVERGENCE FLAG --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then - crystallite_converged(g,i,e) = .true. ! if still "to do" then converged per definitionem - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionState) - debug_StateLoopDistribution(1,numerics_integrationMode) = & - debug_StateLoopDistribution(1,numerics_integrationMode) + 1_pInt - !$OMP END CRITICAL (distributionState) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP END PARALLEL - - - ! --- CHECK NON-LOCAL CONVERGENCE --- - - if (.not. singleRun) then ! if not requesting Integration of just a single IP - if (any(.not. crystallite_converged .and. .not. crystallite_localPlasticity) & ! any non-local not yet converged (or broken)... - .and. .not. numerics_timeSyncing) & - crystallite_converged = crystallite_converged .and. crystallite_localPlasticity ! ...restart all non-local as not converged - endif - -end subroutine crystallite_integrateStateEuler - - -!-------------------------------------------------------------------------------------------------- -!> @brief integrate stress, state with adaptive 1st order explicit Euler method -!> using Fixed Point Iteration to adapt the stepsize -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_integrateStateFPI() - use prec, only: & - prec_isNaN - use debug, only: & - debug_e, & - debug_i, & - debug_g, & - debug_level,& - debug_crystallite, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_StateLoopDistribution - use numerics, only: & - nState, & - numerics_integrationMode, & - rTol_crystalliteState - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP - use mesh, only: & - mesh_element, & - mesh_NcpElems - use material, only: & - plasticState, & - sourceState, & - phaseAt, phasememberAt, & - phase_Nsources, & - homogenization_Ngrains - use constitutive, only: & - constitutive_collectDotState, & - constitutive_microstructure, & - constitutive_plasticity_maxSizeDotState, & - constitutive_source_maxSizeDotState - - implicit none - - integer(pInt) :: & - NiterationState, & !< number of iterations in state loop - e, & !< element index in element loop - i, & !< integration point index in ip loop - g, & !< grain index in grain loop - p, & - c, & - mySource, & - mySizePlasticDotState, & ! size of dot states - mySizeSourceDotState - integer(pInt), dimension(2) :: & - eIter ! bounds for element iteration - integer(pInt), dimension(2,mesh_NcpElems) :: & - iIter, & ! bounds for ip iteration - gIter ! bounds for grain iteration - real(pReal) :: & - dot_prod12, & - dot_prod22, & - plasticStateDamper, & ! damper for integration of state - sourceStateDamper - real(pReal), dimension(constitutive_plasticity_maxSizeDotState) :: & - plasticStateResiduum, & - tempPlasticState - real(pReal), dimension(constitutive_source_maxSizeDotState, maxval(phase_Nsources)) :: & - sourceStateResiduum, & ! residuum from evolution in micrstructure - tempSourceState - logical :: & - converged, & - NaN, & - singleRun, & ! flag indicating computation for single (g,i,e) triple - doneWithIntegration - - eIter = FEsolving_execElem(1:2) - do e = eIter(1),eIter(2) - iIter(1:2,e) = FEsolving_execIP(1:2,e) - gIter(1:2,e) = [ 1_pInt,homogenization_Ngrains(mesh_element(3,e))] - enddo - - singleRun = (eIter(1) == eIter(2) .and. iIter(1,eIter(1)) == iIter(2,eIter(2))) - -!-------------------------------------------------------------------------------------------------- -! initialize dotState - if (.not. singleRun) then - forall(p = 1_pInt:size(plasticState)) - plasticState(p)%previousDotState = 0.0_pReal - plasticState(p)%previousDotState2 = 0.0_pReal - end forall - do p = 1_pInt, size(sourceState); do mySource = 1_pInt, phase_Nsources(p) - sourceState(p)%p(mySource)%previousDotState = 0.0_pReal - sourceState(p)%p(mySource)%previousDotState2 = 0.0_pReal - enddo; enddo - else - e = eIter(1) - i = iIter(1,e) - do g = gIter(1,e), gIter(2,e) - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - plasticState(p)%previousDotState (:,c) = 0.0_pReal - plasticState(p)%previousDotState2(:,c) = 0.0_pReal - do mySource = 1_pInt, phase_Nsources(p) - sourceState(p)%p(mySource)%previousDotState (:,c) = 0.0_pReal - sourceState(p)%p(mySource)%previousDotState2(:,c) = 0.0_pReal - enddo - enddo - endif - - ! --+>> PREGUESS FOR STATE <<+-- - - ! --- DOT STATES --- - - !$OMP PARALLEL - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) & - call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & - crystallite_Fe, & - crystallite_Fp, & - crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) - enddo; enddo; enddo - - !$OMP ENDDO - !$OMP DO PRIVATE(p,c,NaN) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) - do mySource = 1_pInt, phase_Nsources(p) - NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) - enddo - if (NaN) then ! NaN occured in any dotState - if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken is a non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals done (and broken) - !$OMP END CRITICAL (checkTodo) - else ! broken one was local... - crystallite_todo(g,i,e) = .false. ! ... done (and broken) - endif - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - ! --- UPDATE STATE --- - - !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,c) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e)) then - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - mySizePlasticDotState = plasticState(p)%sizeDotState - plasticState(p)%state(1:mySizePlasticDotState,c) = & - plasticState(p)%subState0(1:mySizePlasticDotState,c) & - + plasticState(p)%dotState (1:mySizePlasticDotState,c) & - * crystallite_subdt(g,i,e) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceState(p)%p(mySource)%state(1:mySizeSourceDotState,c) = & - sourceState(p)%p(mySource)%subState0(1:mySizeSourceDotState,c) & - + sourceState(p)%p(mySource)%dotState (1:mySizeSourceDotState,c) & - * crystallite_subdt(g,i,e) - enddo - endif - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP END PARALLEL - - ! --+>> STATE LOOP <<+-- - - NiterationState = 0_pInt - doneWithIntegration = .false. - crystalliteLooping: do while (.not. doneWithIntegration .and. NiterationState < nState) - NiterationState = NiterationState + 1_pInt - - !$OMP PARALLEL - - ! --- UPDATE DEPENDENT STATES --- - - !$OMP DO PRIVATE(p,c) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) & - !***dirty way to pass orientations to constitutive_micrsotructure - call constitutive_microstructure(crystallite_orientation, & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - plasticState(p)%previousDotState2(:,c) = plasticState(p)%previousDotState(:,c) - plasticState(p)%previousDotState (:,c) = plasticState(p)%dotState(:,c) - do mySource = 1_pInt, phase_Nsources(p) - sourceState(p)%p(mySource)%previousDotState2(:,c) = sourceState(p)%p(mySource)%previousDotState(:,c) - sourceState(p)%p(mySource)%previousDotState (:,c) = sourceState(p)%p(mySource)%dotState(:,c) - enddo - enddo; enddo; enddo - !$OMP ENDDO - - ! --- STRESS INTEGRATION --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then - crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e) - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ... then all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP SINGLE - !$OMP CRITICAL (write2out) - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i8,a)') '<< CRYST >> ', count(crystallite_todo(:,:,:)),' grains todo after stress integration' - !$OMP END CRITICAL (write2out) - !$OMP END SINGLE - - - ! --- DOT STATE --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) & - call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & - crystallite_Fe, & - crystallite_Fp, & - crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) - enddo; enddo; enddo - !$OMP ENDDO - - !$OMP DO PRIVATE(p,c) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) - do mySource = 1_pInt, phase_Nsources(p) - NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) - enddo - if (NaN) then ! NaN occured in any dotState - crystallite_todo(g,i,e) = .false. ! ... skip me next time - if (.not. crystallite_localPlasticity(g,i,e)) then ! if me is non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - - endif - - enddo; enddo; enddo - !$OMP ENDDO - - ! --- UPDATE STATE --- - - !$OMP DO PRIVATE(dot_prod12,dot_prod22, & - !$OMP& mySizePlasticDotState,mySizeSourceDotState, & - !$OMP& plasticStateResiduum,sourceStateResiduum, & - !$OMP& plasticStatedamper,sourceStateDamper, & - !$OMP& tempPlasticState,tempSourceState,converged,p,c) - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then - - p = phaseAt(g,i,e) - c = phasememberAt(g,i,e) - dot_prod12 = dot_product( plasticState(p)%dotState (:,c) & - - plasticState(p)%previousDotState (:,c), & - plasticState(p)%previousDotState (:,c) & - - plasticState(p)%previousDotState2(:,c)) - dot_prod22 = dot_product( plasticState(p)%previousDotState (:,c) & - - plasticState(p)%previousDotState2(:,c), & - plasticState(p)%previousDotState (:,c) & - - plasticState(p)%previousDotState2(:,c)) - if ( dot_prod22 > 0.0_pReal & - .and. ( dot_prod12 < 0.0_pReal & - .or. dot_product(plasticState(p)%dotState(:,c), & - plasticState(p)%previousDotState(:,c)) < 0.0_pReal) ) then - plasticStateDamper = 0.75_pReal + 0.25_pReal * tanh(2.0_pReal + 4.0_pReal * dot_prod12 / dot_prod22) - else - plasticStateDamper = 1.0_pReal - endif - ! --- get residui --- - - mySizePlasticDotState = plasticState(p)%sizeDotState - plasticStateResiduum(1:mySizePlasticDotState) = & - plasticState(p)%state(1:mySizePlasticDotState,c) & - - plasticState(p)%subState0(1:mySizePlasticDotState,c) & - - ( plasticState(p)%dotState(1:mySizePlasticDotState,c) * plasticStateDamper & - + plasticState(p)%previousDotState(1:mySizePlasticDotState,c) & - * (1.0_pReal - plasticStateDamper)) * crystallite_subdt(g,i,e) - - ! --- correct state with residuum --- - tempPlasticState(1:mySizePlasticDotState) = & - plasticState(p)%state(1:mySizePlasticDotState,c) & - - plasticStateResiduum(1:mySizePlasticDotState) ! need to copy to local variable, since we cant flush a pointer in openmp - - ! --- store corrected dotState --- (cannot do this before state update, because not sure how to flush pointers in openmp) - - plasticState(p)%dotState(:,c) = plasticState(p)%dotState(:,c) * plasticStateDamper & - + plasticState(p)%previousDotState(:,c) & - * (1.0_pReal - plasticStateDamper) - - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - dot_prod12 = dot_product( sourceState(p)%p(mySource)%dotState (:,c) & - - sourceState(p)%p(mySource)%previousDotState (:,c), & - sourceState(p)%p(mySource)%previousDotState (:,c) & - - sourceState(p)%p(mySource)%previousDotState2(:,c)) - dot_prod22 = dot_product( sourceState(p)%p(mySource)%previousDotState (:,c) & - - sourceState(p)%p(mySource)%previousDotState2(:,c), & - sourceState(p)%p(mySource)%previousDotState (:,c) & - - sourceState(p)%p(mySource)%previousDotState2(:,c)) - - if ( dot_prod22 > 0.0_pReal & - .and. ( dot_prod12 < 0.0_pReal & - .or. dot_product(sourceState(p)%p(mySource)%dotState(:,c), & - sourceState(p)%p(mySource)%previousDotState(:,c)) < 0.0_pReal) ) then - sourceStateDamper = 0.75_pReal + 0.25_pReal * tanh(2.0_pReal + 4.0_pReal * dot_prod12 / dot_prod22) - else - sourceStateDamper = 1.0_pReal - endif - ! --- get residui --- - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceStateResiduum(1:mySizeSourceDotState,mySource) = & - sourceState(p)%p(mySource)%state(1:mySizeSourceDotState,c) & - - sourceState(p)%p(mySource)%subState0(1:mySizeSourceDotState,c) & - - ( sourceState(p)%p(mySource)%dotState(1:mySizeSourceDotState,c) * sourceStateDamper & - + sourceState(p)%p(mySource)%previousDotState(1:mySizeSourceDotState,c) & - * (1.0_pReal - sourceStateDamper)) * crystallite_subdt(g,i,e) - - ! --- correct state with residuum --- - tempSourceState(1:mySizeSourceDotState,mySource) = & - sourceState(p)%p(mySource)%state(1:mySizeSourceDotState,c) & - - sourceStateResiduum(1:mySizeSourceDotState,mySource) ! need to copy to local variable, since we cant flush a pointer in openmp - - ! --- store corrected dotState --- (cannot do this before state update, because not sure how to flush pointers in openmp) - sourceState(p)%p(mySource)%dotState(:,c) = & - sourceState(p)%p(mySource)%dotState(:,c) * sourceStateDamper & - + sourceState(p)%p(mySource)%previousDotState(:,c) & - * (1.0_pReal - sourceStateDamper) - enddo - -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i .and. g == debug_g) & - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i8,1x,i2,1x,i3,/)') '<< CRYST >> update state at el ip g ',e,i,g - write(6,'(a,f6.1,/)') '<< CRYST >> plasticstatedamper ',plasticStatedamper - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> plastic state residuum',plasticStateResiduum(1:mySizePlasticDotState) - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state',tempPlasticState(1:mySizePlasticDotState) - endif -#endif - - ! --- converged ? --- - converged = all( abs(plasticStateResiduum(1:mySizePlasticDotState)) < & - plasticState(p)%aTolState(1:mySizePlasticDotState) & - .or. abs(plasticStateResiduum(1:mySizePlasticDotState)) < & - rTol_crystalliteState * abs(tempPlasticState(1:mySizePlasticDotState))) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - converged = converged .and. & - all( abs(sourceStateResiduum(1:mySizeSourceDotState,mySource)) < & - sourceState(p)%p(mySource)%aTolState(1:mySizeSourceDotState) & - .or. abs(sourceStateResiduum(1:mySizeSourceDotState,mySource)) < & - rTol_crystalliteState * abs(tempSourceState(1:mySizeSourceDotState,mySource))) - enddo - if (converged) then - crystallite_converged(g,i,e) = .true. ! ... converged per definition - - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionState) - debug_StateLoopDistribution(NiterationState,numerics_integrationMode) = & - debug_StateLoopDistribution(NiterationState,numerics_integrationMode) + 1_pInt - !$OMP END CRITICAL (distributionState) - endif - endif - plasticState(p)%state(1:mySizePlasticDotState,c) = & - tempPlasticState(1:mySizePlasticDotState) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState - sourceState(p)%p(mySource)%state(1:mySizeSourceDotState,c) = & - tempSourceState(1:mySizeSourceDotState,mySource) - enddo - endif - enddo; enddo; enddo - !$OMP ENDDO - ! --- STATE JUMP --- - - !$OMP DO - do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - !$OMP FLUSH(crystallite_todo) - if (crystallite_todo(g,i,e) .and. crystallite_converged(g,i,e)) then ! converged and still alive... - crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) - !$OMP FLUSH(crystallite_todo) - if (.not. crystallite_todo(g,i,e)) then ! if state jump fails, then convergence is broken - crystallite_converged(g,i,e) = .false. - if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... - !$OMP CRITICAL (checkTodo) - crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped - !$OMP END CRITICAL (checkTodo) - endif - endif - endif - enddo; enddo; enddo - !$OMP ENDDO - !$OMP END PARALLEL - - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & - write(6,'(a,i8,a,i2,/)') '<< CRYST >> ', count(crystallite_converged(:,:,:)), & - ' grains converged after state integration #', NiterationState - - - ! --- NON-LOCAL CONVERGENCE CHECK --- - - if (.not. singleRun) then ! if not requesting Integration of just a single IP - if (any(.not. crystallite_converged .and. .not. crystallite_localPlasticity)) & ! any non-local not yet converged (or broken)... - crystallite_converged = crystallite_converged .and. crystallite_localPlasticity ! ...restart all non-local as not converged - endif - - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) then - write(6,'(a,i8,a)') '<< CRYST >> ', count(crystallite_converged(:,:,:)), & - ' grains converged after non-local check' - write(6,'(a,i8,a,i2,/)') '<< CRYST >> ', count(crystallite_todo(:,:,:)), & - ' grains todo after state integration #', NiterationState - endif - ! --- CHECK IF DONE WITH INTEGRATION --- - - doneWithIntegration = .true. - elemLoop: do e = eIter(1),eIter(2) - do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains - if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then - doneWithIntegration = .false. - exit elemLoop - endif - enddo; enddo - enddo elemLoop - - enddo crystalliteLooping -end subroutine crystallite_integrateStateFPI - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates a jump in the state according to the current state and the current stress -!> returns true, if state jump was successfull or not needed. false indicates NaN in delta state -!-------------------------------------------------------------------------------------------------- -logical function crystallite_stateJump(ipc,ip,el) - use prec, only: & - prec_isNaN - use debug, only: & - debug_level, & - debug_crystallite, & - debug_levelExtensive, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_g - use material, only: & - plasticState, & - sourceState, & - phase_Nsources, & - phaseAt, phasememberAt - use constitutive, only: & - constitutive_collectDeltaState - - implicit none - integer(pInt), intent(in):: & - el, & ! element index - ip, & ! integration point index - ipc ! grain index - - integer(pInt) :: & - c, & - p, & - mySource, & - mySizePlasticDeltaState, & - mySizeSourceDeltaState - - c= phasememberAt(ipc,ip,el) - p = phaseAt(ipc,ip,el) - call constitutive_collectDeltaState(crystallite_Tstar_v(1:6,ipc,ip,el), crystallite_Fe(1:3,1:3,ipc,ip,el), ipc,ip,el) - mySizePlasticDeltaState = plasticState(p)%sizeDeltaState - if( any(prec_isNaN(plasticState(p)%deltaState(:,c)))) then ! NaN occured in deltaState - crystallite_stateJump = .false. - return - endif - plasticState(p)%state(1:mySizePlasticDeltaState,c) = plasticState(p)%state(1:mySizePlasticDeltaState,c) + & - plasticState(p)%deltaState(1:mySizePlasticDeltaState,c) - do mySource = 1_pInt, phase_Nsources(p) - mySizeSourceDeltaState = sourceState(p)%p(mySource)%sizeDeltaState - if( any(prec_isNaN(sourceState(p)%p(mySource)%deltaState(:,c)))) then ! NaN occured in deltaState - crystallite_stateJump = .false. - return - endif - sourceState(p)%p(mySource)%state(1:mySizeSourceDeltaState,c) = & - sourceState(p)%p(mySource)%state(1:mySizeSourceDeltaState,c) + & - sourceState(p)%p(mySource)%deltaState(1:mySizeSourceDeltaState,c) - enddo - -#ifndef _OPENMP - if (any(plasticState(p)%deltaState(1:mySizePlasticDeltaState,c) /= 0.0_pReal) & - .and. iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i8,1x,i2,1x,i3, /)') '<< CRYST >> update state at el ip ipc ',el,ip,ipc - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> deltaState', plasticState(p)%deltaState(1:mySizePlasticDeltaState,c) - write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state', plasticState(p)%state (1:mySizePlasticDeltaState,c) - endif -#endif - - crystallite_stateJump = .true. - -end function crystallite_stateJump - - -!-------------------------------------------------------------------------------------------------- -!> @brief Map 2nd order tensor to reference config -!-------------------------------------------------------------------------------------------------- -function crystallite_push33ToRef(ipc,ip,el, tensor33) - use math, only: & - math_mul33x33, & - math_inv33, & - math_transpose33, & - math_EulerToR - use material, only: & - material_EulerAngles - - implicit none - real(pReal), dimension(3,3) :: crystallite_push33ToRef - real(pReal), dimension(3,3), intent(in) :: tensor33 - real(pReal), dimension(3,3) :: T - integer(pInt), intent(in):: & - el, & ! element index - ip, & ! integration point index - ipc ! grain index - - T = math_mul33x33(math_EulerToR(material_EulerAngles(1:3,ipc,ip,el)), & - math_transpose33(math_inv33(crystallite_subF(1:3,1:3,ipc,ip,el)))) - crystallite_push33ToRef = math_mul33x33(math_transpose33(T),math_mul33x33(tensor33,T)) - -end function crystallite_push33ToRef - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculation of stress (P) with time integration based on a residuum in Lp and -!> intermediate acceleration of the Newton-Raphson correction -!-------------------------------------------------------------------------------------------------- -logical function crystallite_integrateStress(& - ipc,& ! grain number - ip,& ! integration point number - el,& ! element number - timeFraction & - ) - use prec, only: pLongInt, & - tol_math_check, & - prec_isNaN - use numerics, only: nStress, & - aTol_crystalliteStress, & - rTol_crystalliteStress, & - iJacoLpresiduum, & - numerics_integrationMode - use debug, only: debug_level, & - debug_crystallite, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_g, & - debug_cumLpCalls, & - debug_cumLpTicks, & - debug_StressLoopLpDistribution, & - debug_StressLoopLiDistribution - use constitutive, only: constitutive_LpAndItsTangent, & - constitutive_LiAndItsTangent, & - constitutive_TandItsTangent - use math, only: math_mul33x33, & - math_mul33xx33, & - math_mul3333xx3333, & - math_mul66x6, & - math_mul99x99, & - math_transpose33, & - math_inv33, & - math_invert, & - math_det33, & - math_I3, & - math_identity2nd, & - math_Mandel66to3333, & - math_Mandel6to33, & - math_Mandel33to6, & - math_Plain3333to99, & - math_Plain33to9, & - math_Plain9to33, & - math_Plain99to3333 - use mesh, only: mesh_element - - implicit none - integer(pInt), intent(in):: el, & ! element index - ip, & ! integration point index - ipc ! grain index - real(pReal), optional, intent(in) :: timeFraction ! fraction of timestep - - !*** local variables ***! - real(pReal), dimension(3,3):: Fg_new, & ! deformation gradient at end of timestep - Fp_current, & ! plastic deformation gradient at start of timestep - Fi_current, & ! intermediate deformation gradient at start of timestep - Fp_new, & ! plastic deformation gradient at end of timestep - Fe_new, & ! elastic deformation gradient at end of timestep - invFp_new, & ! inverse of Fp_new - Fi_new, & ! gradient of intermediate deformation stages - invFi_new, & - invFp_current, & ! inverse of Fp_current - invFi_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 - 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 - Tstar, & ! 2nd Piola-Kirchhoff Stress in plastic (lattice) configuration - A, & - B, & - Fe, & ! elastic deformation gradient - temp_33 - real(pReal), dimension(6):: Tstar_v ! 2nd Piola-Kirchhoff Stress in Mandel-Notation - real(pReal), dimension(9):: work ! needed for matrix inversion by LAPACK - integer(pInt), dimension(9) :: ipiv ! needed for matrix inversion by LAPACK - real(pReal), dimension(9,9) :: dRLp_dLp, & ! partial derivative of residuum (Jacobian for NEwton-Raphson scheme) - dRLp_dLp2, & ! working copy of dRdLp - dRLi_dLi ! partial derivative of residuumI (Jacobian for NEwton-Raphson scheme) - real(pReal), dimension(3,3,3,3):: dT_dFe3333, & ! partial derivative of 2nd Piola-Kirchhoff stress - dT_dFi3333, & - dFe_dLp3333, & ! partial derivative of elastic deformation gradient - dFe_dLi3333, & - dFi_dLi3333, & - dLp_dFi3333, & - dLi_dFi3333, & - dLp_dT3333, & - dLi_dT3333 - real(pReal) detInvFi, & ! determinant of InvFi - steplengthLp0, & - steplengthLp, & - steplengthLi0, & - steplengthLi, & - dt, & ! time increment - aTolLp, & - aTolLi - integer(pInt) 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 - integer(pLongInt) tick, & - tock, & - tickrate, & - maxticks - - external :: & -#if(FLOAT==8) - dgesv -#elif(FLOAT==4) - sgesv -#endif - - !* be pessimistic - crystallite_integrateStress = .false. -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i8,1x,i2,1x,i3)') '<< CRYST >> integrateStress at el ip ipc ',el,ip,ipc - endif -#endif - - - !* only integrate over fraction of timestep? - - if (present(timeFraction)) then - dt = crystallite_subdt(ipc,ip,el) * timeFraction - Fg_new = 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) - Fg_new = crystallite_subF(1:3,1:3,ipc,ip,el) - endif - - - !* feed local variables - - Fp_current = crystallite_subFp0(1:3,1:3,ipc,ip,el) ! "Fp_current" is only used as temp var here... - Lpguess = crystallite_Lp (1:3,1:3,ipc,ip,el) ! ... and take it as first guess - Fi_current = crystallite_subFi0(1:3,1:3,ipc,ip,el) ! intermediate configuration, assume decomposition as F = Fe Fi Fp - Liguess = crystallite_Li (1:3,1:3,ipc,ip,el) ! ... and take it as first guess - Liguess_old = Liguess - - - !* inversion of Fp_current... - - invFp_current = math_inv33(Fp_current) - if (all(abs(invFp_current) <= tiny(0.0_pReal))) then ! math_inv33 returns zero when failed, avoid floating point comparison -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3)') '<< CRYST >> integrateStress failed on inversion of Fp_current at el (elFE) ip g ',& - el,'(',mesh_element(1,el),')',ip,ipc - if (iand(debug_level(debug_crystallite), debug_levelExtensive) > 0_pInt) & - write(6,'(/,a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Fp_current',math_transpose33(Fp_current(1:3,1:3)) - endif -#endif - return - endif - A = math_mul33x33(Fg_new,invFp_current) ! intermediate tensor needed later to calculate dFe_dLp - - !* inversion of Fi_current... - - invFi_current = math_inv33(Fi_current) - if (all(abs(invFi_current) <= tiny(0.0_pReal))) then ! math_inv33 returns zero when failed, avoid floating point comparison -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3)') '<< CRYST >> integrateStress failed on inversion of Fi_current at el (elFE) ip ipc ',& - el,'(',mesh_element(1,el),')',ip,ipc - if (iand(debug_level(debug_crystallite), debug_levelExtensive) > 0_pInt) & - write(6,'(/,a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Fp_current',math_transpose33(Fi_current(1:3,1:3)) - endif -#endif - return - endif - - !* start LpLoop with normal step length - - NiterationStressLi = 0_pInt - jacoCounterLi = 0_pInt - steplengthLi0 = 1.0_pReal - steplengthLi = steplengthLi0 - residuumLi_old = 0.0_pReal - - LiLoop: do - NiterationStressLi = NiterationStressLi + 1_pInt - IloopsExeced: if (NiterationStressLi > nStress) then -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) & - write(6,'(a,i3,a,i8,1x,a,i8,a,1x,i2,1x,i3,/)') '<< CRYST >> integrateStress reached inelastic loop limit',nStress, & - ' at el (elFE) ip ipc ', el,mesh_element(1,el),ip,ipc -#endif - return - endif IloopsExeced - - invFi_new = math_mul33x33(invFi_current,math_I3 - dt*Liguess) - Fi_new = math_inv33(invFi_new) - detInvFi = math_det33(invFi_new) - - NiterationStressLp = 0_pInt - jacoCounterLp = 0_pInt - steplengthLp0 = 1.0_pReal - steplengthLp = steplengthLp0 - residuumLp_old = 0.0_pReal - Lpguess_old = Lpguess - - LpLoop: do ! inner stress integration loop for consistency with Fi - NiterationStressLp = NiterationStressLp + 1_pInt - loopsExeced: if (NiterationStressLp > nStress) then -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) & - write(6,'(a,i3,a,i8,1x,a,i8,a,1x,i2,1x,i3,/)') '<< CRYST >> integrateStress reached loop limit',nStress, & - ' at el (elFE) ip ipc ', el,mesh_element(1,el),ip,ipc -#endif - return - endif loopsExeced - - !* calculate (elastic) 2nd Piola--Kirchhoff stress tensor and its tangent from constitutive law - - B = math_I3 - dt*Lpguess - Fe = math_mul33x33(math_mul33x33(A,B), invFi_new) ! current elastic deformation tensor - call constitutive_TandItsTangent(Tstar, dT_dFe3333, dT_dFi3333, Fe, Fi_new, ipc, ip, el) ! call constitutive law to calculate 2nd Piola-Kirchhoff stress and its derivative in unloaded configuration - Tstar_v = math_Mandel33to6(Tstar) - - !* calculate plastic velocity gradient and its tangent from constitutive law - - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - call system_clock(count=tick,count_rate=tickrate,count_max=maxticks) - endif - - call constitutive_LpAndItsTangent(Lp_constitutive, dLp_dT3333, dLp_dFi3333, & - Tstar_v, Fi_new, ipc, ip, el) - - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - call system_clock(count=tock,count_rate=tickrate,count_max=maxticks) - !$OMP CRITICAL (debugTimingLpTangent) - debug_cumLpCalls = debug_cumLpCalls + 1_pInt - debug_cumLpTicks = debug_cumLpTicks + tock-tick - !$OMP FLUSH (debug_cumLpTicks) - if (tock < tick) debug_cumLpTicks = debug_cumLpTicks + maxticks - !$OMP END CRITICAL (debugTimingLpTangent) - endif - -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i3,/)') '<< CRYST >> stress iteration ', NiterationStressLp - write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Lp_constitutive', math_transpose33(Lp_constitutive) - write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Lpguess', math_transpose33(Lpguess) - endif -#endif - - - !* update current residuum and check for convergence of loop - - aTolLp = max(rTol_crystalliteStress * max(norm2(Lpguess),norm2(Lp_constitutive)), & ! absolute tolerance from largest acceptable relative error - aTol_crystalliteStress) ! minimum lower cutoff - residuumLp = Lpguess - Lp_constitutive - - if (any(prec_isNaN(residuumLp))) then ! NaN in residuum... -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) & - write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3,a,i3,a)') '<< CRYST >> integrateStress encountered NaN at el (elFE) ip ipc ', & - el,mesh_element(1,el),ip,ipc, & - ' ; iteration ', NiterationStressLp,& - ' >> returning..!' -#endif - return ! ...me = .false. to inform integrator about problem - elseif (norm2(residuumLp) < aTolLp) then ! converged if below absolute tolerance - exit LpLoop ! ...leave iteration loop - elseif ( NiterationStressLp == 1_pInt & - .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 = steplengthLp0 ! ...proceed with normal step length (calculate new search direction) - else ! not converged and residuum not improved... - steplengthLp = 0.5_pReal * steplengthLp ! ...try with smaller step length in same direction - Lpguess = Lpguess_old + steplengthLp * deltaLp - cycle LpLoop - endif - - - !* calculate Jacobian for correction term - - if (mod(jacoCounterLp, iJacoLpresiduum) == 0_pInt) then - dFe_dLp3333 = 0.0_pReal - forall(o=1_pInt:3_pInt,p=1_pInt:3_pInt) & - dFe_dLp3333(o,1:3,p,1:3) = A(o,p)*math_transpose33(invFi_new) ! dFe_dLp(i,j,k,l) = -dt * A(i,k) invFi(l,j) - dFe_dLp3333 = - dt * dFe_dLp3333 - dRLp_dLp = math_identity2nd(9_pInt) & - - math_Plain3333to99(math_mul3333xx3333(math_mul3333xx3333(dLp_dT3333,dT_dFe3333),dFe_dLp3333)) - dRLp_dLp2 = dRLp_dLp ! will be overwritten in first call to LAPACK routine - work = math_plain33to9(residuumLp) -#if(FLOAT==8) - call dgesv(9,1,dRLp_dLp2,9,ipiv,work,9,ierr) ! solve dRLp/dLp * delta Lp = -res for delta Lp -#elif(FLOAT==4) - call sgesv(9,1,dRLp_dLp2,9,ipiv,work,9,ierr) ! solve dRLp/dLp * delta Lp = -res for delta Lp -#endif - if (ierr /= 0_pInt) then -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3,a,i3)') '<< CRYST >> integrateStress failed on dR/dLp inversion at el ip ipc ', & - el,mesh_element(1,el),ip,ipc - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g)& - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - write(6,*) - write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dR_dLp',transpose(dRLp_dLp) - write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dFe_dLp',transpose(math_Plain3333to99(dFe_dLp3333)) - write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dT_dFe_constitutive',transpose(math_Plain3333to99(dT_dFe3333)) - write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dLp_dT_constitutive',transpose(math_Plain3333to99(dLp_dT3333)) - write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> A',math_transpose33(A) - write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> B',math_transpose33(B) - write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Lp_constitutive',math_transpose33(Lp_constitutive) - write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Lpguess',math_transpose33(Lpguess) - endif - endif -#endif - return - endif - deltaLp = - math_plain9to33(work) - endif - jacoCounterLp = jacoCounterLp + 1_pInt ! increase counter for jaco update - - Lpguess = Lpguess + steplengthLp * deltaLp - - enddo LpLoop - - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionStress) - debug_StressLoopLpDistribution(NiterationStressLp,numerics_integrationMode) = & - debug_StressLoopLpDistribution(NiterationStressLp,numerics_integrationMode) + 1_pInt - !$OMP END CRITICAL (distributionStress) - endif - - !* calculate intermediate velocity gradient and its tangent from constitutive law - - call constitutive_LiAndItsTangent(Li_constitutive, dLi_dT3333, dLi_dFi3333, & - Tstar_v, Fi_new, ipc, ip, el) - -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Li_constitutive', math_transpose33(Li_constitutive) - write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Liguess', math_transpose33(Liguess) - endif -#endif - !* update current residuum and check for convergence of loop - - aTolLi = max(rTol_crystalliteStress * max(norm2(Liguess),norm2(Li_constitutive)), & ! absolute tolerance from largest acceptable relative error - aTol_crystalliteStress) ! minimum lower cutoff - residuumLi = Liguess - Li_constitutive - if (any(prec_isNaN(residuumLi))) then ! NaN in residuum... - return ! ...me = .false. to inform integrator about problem - elseif (norm2(residuumLi) < aTolLi) then ! converged if below absolute tolerance - exit LiLoop ! ...leave iteration loop - elseif ( NiterationStressLi == 1_pInt & - .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 = steplengthLi0 ! ...proceed with normal step length (calculate new search direction) - else ! not converged and residuum not improved... - steplengthLi = 0.5_pReal * steplengthLi ! ...try with smaller step length in same direction - Liguess = Liguess_old + steplengthLi * deltaLi - cycle LiLoop - endif - - !* calculate Jacobian for correction term - - if (mod(jacoCounterLi, iJacoLpresiduum) == 0_pInt) then - temp_33 = math_mul33x33(math_mul33x33(A,B),invFi_current) - dFe_dLi3333 = 0.0_pReal - dFi_dLi3333 = 0.0_pReal - forall(o=1_pInt:3_pInt,p=1_pInt:3_pInt) - dFe_dLi3333(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_dLi3333(1:3,o,1:3,p) = -dt*math_I3(o,p)*invFi_current - end forall - forall(o=1_pInt:3_pInt,p=1_pInt:3_pInt) & - dFi_dLi3333(1:3,1:3,o,p) = math_mul33x33(math_mul33x33(Fi_new,dFi_dLi3333(1:3,1:3,o,p)),Fi_new) - - dRLi_dLi = math_identity2nd(9_pInt) & - - math_Plain3333to99(math_mul3333xx3333(dLi_dT3333, math_mul3333xx3333(dT_dFe3333, dFe_dLi3333) + & - math_mul3333xx3333(dT_dFi3333, dFi_dLi3333))) & - - math_Plain3333to99(math_mul3333xx3333(dLi_dFi3333, dFi_dLi3333)) - work = math_plain33to9(residuumLi) -#if(FLOAT==8) - call dgesv(9,1,dRLi_dLi,9,ipiv,work,9,ierr) ! solve dRLi/dLp * delta Li = -res for delta Li -#elif(FLOAT==4) - call sgesv(9,1,dRLi_dLi,9,ipiv,work,9,ierr) ! solve dRLi/dLp * delta Li = -res for delta Li -#endif - if (ierr /= 0_pInt) then -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3,a,i3)') '<< CRYST >> integrateStress failed on dR/dLi inversion at el ip ipc ', & - el,mesh_element(1,el),ip,ipc - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g)& - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - write(6,*) - write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dR_dLi',transpose(dRLi_dLi) - write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dFe_dLi',transpose(math_Plain3333to99(dFe_dLi3333)) - write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dT_dFi_constitutive',transpose(math_Plain3333to99(dT_dFi3333)) - write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dLi_dT_constitutive',transpose(math_Plain3333to99(dLi_dT3333)) - write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Li_constitutive',math_transpose33(Li_constitutive) - write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Liguess',math_transpose33(Liguess) - endif - endif -#endif - return - endif - - deltaLi = - math_plain9to33(work) - endif - jacoCounterLi = jacoCounterLi + 1_pInt ! increase counter for jaco update - - Liguess = Liguess + steplengthLi * deltaLi - enddo LiLoop - - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionStress) - debug_StressLoopLiDistribution(NiterationStressLi,numerics_integrationMode) = & - debug_StressLoopLiDistribution(NiterationStressLi,numerics_integrationMode) + 1_pInt - !$OMP END CRITICAL (distributionStress) - endif - - !* calculate new plastic and elastic deformation gradient - - invFp_new = math_mul33x33(invFp_current,B) - invFp_new = invFp_new / math_det33(invFp_new)**(1.0_pReal/3.0_pReal) ! regularize by det - Fp_new = math_inv33(invFp_new) - if (all(abs(Fp_new)<= tiny(0.0_pReal))) then ! math_inv33 returns zero when failed, avoid floating point comparison -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then - write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3,a,i3)') '<< CRYST >> integrateStress failed on invFp_new inversion at el ip ipc ',& - el,mesh_element(1,el),ip,ipc, ' ; iteration ', NiterationStressLp - if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) & - write(6,'(/,a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> invFp_new',math_transpose33(invFp_new) - endif -#endif - return - endif - Fe_new = math_mul33x33(math_mul33x33(Fg_new,invFp_new),invFi_new) ! calc resulting Fe - - !* calculate 1st Piola-Kirchhoff stress - - crystallite_P(1:3,1:3,ipc,ip,el) = math_mul33x33(math_mul33x33(Fg_new,invFp_new), & - math_mul33x33(math_Mandel6to33(Tstar_v), & - math_transpose33(invFp_new))) - - !* store local values in global variables - - crystallite_Lp(1:3,1:3,ipc,ip,el) = Lpguess - crystallite_Li(1:3,1:3,ipc,ip,el) = Liguess - crystallite_Tstar_v(1:6,ipc,ip,el) = Tstar_v - crystallite_Fp(1:3,1:3,ipc,ip,el) = Fp_new - crystallite_Fi(1:3,1:3,ipc,ip,el) = Fi_new - crystallite_Fe(1:3,1:3,ipc,ip,el) = Fe_new - crystallite_invFp(1:3,1:3,ipc,ip,el) = invFp_new - crystallite_invFi(1:3,1:3,ipc,ip,el) = invFi_new - - !* set return flag to true - - crystallite_integrateStress = .true. -#ifndef _OPENMP - if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & - .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> P / MPa',math_transpose33(crystallite_P(1:3,1:3,ipc,ip,el))*1.0e-6_pReal - write(6,'(a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Cauchy / MPa', & - math_mul33x33(crystallite_P(1:3,1:3,ipc,ip,el), math_transpose33(Fg_new)) * 1.0e-6_pReal / math_det33(Fg_new) - write(6,'(a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Fe Lp Fe^-1', & - math_transpose33(math_mul33x33(Fe_new, math_mul33x33(crystallite_Lp(1:3,1:3,ipc,ip,el), math_inv33(Fe_new)))) ! transpose to get correct print out order - write(6,'(a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Fp',math_transpose33(crystallite_Fp(1:3,1:3,ipc,ip,el)) - write(6,'(a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Fi',math_transpose33(crystallite_Fi(1:3,1:3,ipc,ip,el)) - endif -#endif - -end function crystallite_integrateStress - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates orientations and disorientations (in case of single grain ips) -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_orientations - use math, only: & - math_rotationalPart33, & - math_RtoQ, & - math_qConj - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP - use material, only: & - material_phase, & - homogenization_Ngrains, & - plasticState - use mesh, only: & - mesh_element, & - mesh_ipNeighborhood, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype - use lattice, only: & - lattice_qDisorientation, & - lattice_structure - use plastic_nonlocal, only: & - plastic_nonlocal_updateCompatibility - - - implicit none - integer(pInt) & - c, & !< counter in integration point component loop - i, & !< counter in integration point loop - e, & !< counter in element loop - n, & !< counter in neighbor loop - neighboring_e, & !< neighbor element - neighboring_i, & !< neighbor integration point - myPhase, & ! phase - neighboringPhase - real(pReal), dimension(4) :: & - orientation - - ! --- CALCULATE ORIENTATION AND LATTICE ROTATION --- - - !$OMP PARALLEL DO PRIVATE(orientation) - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - do c = 1_pInt,homogenization_Ngrains(mesh_element(3,e)) -! somehow this subroutine is not threadsafe, so need critical statement here; not clear, what exactly the problem is - !$OMP CRITICAL (polarDecomp) - orientation = math_RtoQ(transpose(math_rotationalPart33(crystallite_Fe(1:3,1:3,c,i,e)))) ! rotational part from polar decomposition as quaternion - !$OMP END CRITICAL (polarDecomp) - crystallite_rotation(1:4,c,i,e) = lattice_qDisorientation(crystallite_orientation0(1:4,c,i,e), & ! active rotation from ori0 - orientation) ! to current orientation (with no symmetry) - crystallite_orientation(1:4,c,i,e) = orientation - enddo; enddo; enddo - !$OMP END PARALLEL DO - - - ! --- UPDATE SOME ADDITIONAL VARIABLES THAT ARE NEEDED FOR NONLOCAL MATERIAL --- - ! --- we use crystallite_orientation from above, so need a separate loop - - !$OMP PARALLEL DO PRIVATE(myPhase,neighboring_e,neighboring_i,neighboringPhase) - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - myPhase = material_phase(1,i,e) ! get my phase (non-local models make no sense with more than one grain per material point) - if (plasticState(myPhase)%nonLocal) then ! if nonlocal model - ! --- calculate disorientation between me and my neighbor --- - - do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) ! loop through my neighbors - neighboring_e = mesh_ipNeighborhood(1,n,i,e) - neighboring_i = mesh_ipNeighborhood(2,n,i,e) - if (neighboring_e > 0 .and. neighboring_i > 0) then ! if neighbor exists - neighboringPhase = material_phase(1,neighboring_i,neighboring_e) ! get my neighbor's phase - if (plasticState(neighboringPhase)%nonLocal) then ! neighbor got also nonlocal plasticity - if (lattice_structure(myPhase) == lattice_structure(neighboringPhase)) then ! if my neighbor has same crystal structure like me - crystallite_disorientation(:,n,1,i,e) = & - lattice_qDisorientation( crystallite_orientation(1:4,1,i,e), & - crystallite_orientation(1:4,1,neighboring_i,neighboring_e), & - lattice_structure(myPhase)) ! calculate disorientation for given symmetry - else ! for neighbor with different phase - crystallite_disorientation(:,n,1,i,e) = [0.0_pReal, 1.0_pReal, 0.0_pReal, 0.0_pReal] ! 180 degree rotation about 100 axis - endif - else ! for neighbor with local plasticity - crystallite_disorientation(:,n,1,i,e) = [-1.0_pReal, 0.0_pReal, 0.0_pReal, 0.0_pReal] ! homomorphic identity - endif - else ! no existing neighbor - crystallite_disorientation(:,n,1,i,e) = [-1.0_pReal, 0.0_pReal, 0.0_pReal, 0.0_pReal] ! homomorphic identity - endif - enddo - - - ! --- calculate compatibility and transmissivity between me and my neighbor --- - - call plastic_nonlocal_updateCompatibility(crystallite_orientation,i,e) - - endif - enddo; enddo - !$OMP END PARALLEL DO - -end subroutine crystallite_orientations - -!-------------------------------------------------------------------------------------------------- -!> @brief return results of particular grain -!-------------------------------------------------------------------------------------------------- -function crystallite_postResults(ipc, ip, el) - use math, only: & - math_qToEuler, & - math_qToEulerAxisAngle, & - math_mul33x33, & - math_transpose33, & - math_det33, & - math_I3, & - inDeg, & - math_Mandel6to33, & - math_qMul, & - math_qConj - use mesh, only: & - mesh_element, & - mesh_ipVolume, & - mesh_maxNipNeighbors, & - mesh_ipNeighborhood, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype - use material, only: & - plasticState, & - sourceState, & - microstructure_crystallite, & - crystallite_Noutput, & - material_phase, & - material_texture, & - homogenization_Ngrains - use constitutive, only: & - constitutive_homogenizedC, & - constitutive_postResults - - implicit none - integer(pInt), intent(in):: & - el, & !< element index - ip, & !< integration point index - ipc !< grain index - - real(pReal), dimension(1+crystallite_sizePostResults(microstructure_crystallite(mesh_element(4,el))) + & - 1+plasticState(material_phase(ipc,ip,el))%sizePostResults + & - sum(sourceState(material_phase(ipc,ip,el))%p(:)%sizePostResults)) :: & - crystallite_postResults - real(pReal), dimension(3,3) :: & - Ee - real(pReal), dimension(4) :: & - rotation - real(pReal) :: & - detF - integer(pInt) :: & - o, & - c, & - crystID, & - mySize, & - n - - - crystID = microstructure_crystallite(mesh_element(4,el)) - - crystallite_postResults = 0.0_pReal - c = 0_pInt - crystallite_postResults(c+1) = real(crystallite_sizePostResults(crystID),pReal) ! size of results from cryst - c = c + 1_pInt - - do o = 1_pInt,crystallite_Noutput(crystID) - mySize = 0_pInt - select case(crystallite_outputID(o,crystID)) - case (phase_ID) - mySize = 1_pInt - crystallite_postResults(c+1) = real(material_phase(ipc,ip,el),pReal) ! phaseID of grain - case (texture_ID) - mySize = 1_pInt - crystallite_postResults(c+1) = real(material_texture(ipc,ip,el),pReal) ! textureID of grain - case (volume_ID) - mySize = 1_pInt - detF = math_det33(crystallite_partionedF(1:3,1:3,ipc,ip,el)) ! V_current = det(F) * V_reference - crystallite_postResults(c+1) = detF * mesh_ipVolume(ip,el) & - / homogenization_Ngrains(mesh_element(3,el)) ! grain volume (not fraction but absolute) - case (orientation_ID) - mySize = 4_pInt - crystallite_postResults(c+1:c+mySize) = crystallite_orientation(1:4,ipc,ip,el) ! grain orientation as quaternion - case (eulerangles_ID) - mySize = 3_pInt - crystallite_postResults(c+1:c+mySize) = inDeg & - * math_qToEuler(crystallite_orientation(1:4,ipc,ip,el)) ! grain orientation as Euler angles in degree - case (grainrotation_ID) - mySize = 4_pInt - crystallite_postResults(c+1:c+mySize) = & - math_qToEulerAxisAngle(crystallite_rotation(1:4,ipc,ip,el)) ! grain rotation away from initial orientation as axis-angle in sample reference coordinates - crystallite_postResults(c+4) = inDeg * crystallite_postResults(c+4) ! angle in degree - case (grainrotationx_ID) - mySize = 1_pInt - rotation = math_qToEulerAxisAngle(crystallite_rotation(1:4,ipc,ip,el)) ! grain rotation away from initial orientation as axis-angle in sample reference coordinates - crystallite_postResults(c+1) = inDeg * rotation(1) * rotation(4) ! angle in degree - case (grainrotationy_ID) - mySize = 1_pInt - rotation = math_qToEulerAxisAngle(crystallite_rotation(1:4,ipc,ip,el)) ! grain rotation away from initial orientation as axis-angle in sample reference coordinates - crystallite_postResults(c+1) = inDeg * rotation(2) * rotation(4) ! angle in degree - case (grainrotationz_ID) - mySize = 1_pInt - rotation = math_qToEulerAxisAngle(crystallite_rotation(1:4,ipc,ip,el)) ! grain rotation away from initial orientation as axis-angle in sample reference coordinates - crystallite_postResults(c+1) = inDeg * rotation(3) * rotation(4) ! angle in degree - -! remark: tensor output is of the form 11,12,13, 21,22,23, 31,32,33 -! thus row index i is slow, while column index j is fast. reminder: "row is slow" - - case (defgrad_ID) - mySize = 9_pInt - crystallite_postResults(c+1:c+mySize) = & - reshape(math_transpose33(crystallite_partionedF(1:3,1:3,ipc,ip,el)),[mySize]) - case (e_ID) - mySize = 9_pInt - crystallite_postResults(c+1:c+mySize) = 0.5_pReal * reshape((math_mul33x33( & - math_transpose33(crystallite_partionedF(1:3,1:3,ipc,ip,el)), & - crystallite_partionedF(1:3,1:3,ipc,ip,el)) - math_I3),[mySize]) - case (fe_ID) - mySize = 9_pInt - crystallite_postResults(c+1:c+mySize) = & - reshape(math_transpose33(crystallite_Fe(1:3,1:3,ipc,ip,el)),[mySize]) - case (ee_ID) - Ee = 0.5_pReal *(math_mul33x33(math_transpose33(crystallite_Fe(1:3,1:3,ipc,ip,el)), & - crystallite_Fe(1:3,1:3,ipc,ip,el)) - math_I3) - mySize = 9_pInt - crystallite_postResults(c+1:c+mySize) = reshape(Ee,[mySize]) - case (fp_ID) - mySize = 9_pInt - crystallite_postResults(c+1:c+mySize) = & - reshape(math_transpose33(crystallite_Fp(1:3,1:3,ipc,ip,el)),[mySize]) - case (fi_ID) - mySize = 9_pInt - crystallite_postResults(c+1:c+mySize) = & - reshape(math_transpose33(crystallite_Fi(1:3,1:3,ipc,ip,el)),[mySize]) - case (lp_ID) - mySize = 9_pInt - crystallite_postResults(c+1:c+mySize) = & - reshape(math_transpose33(crystallite_Lp(1:3,1:3,ipc,ip,el)),[mySize]) - case (li_ID) - mySize = 9_pInt - crystallite_postResults(c+1:c+mySize) = & - reshape(math_transpose33(crystallite_Li(1:3,1:3,ipc,ip,el)),[mySize]) - case (p_ID) - mySize = 9_pInt - crystallite_postResults(c+1:c+mySize) = & - reshape(math_transpose33(crystallite_P(1:3,1:3,ipc,ip,el)),[mySize]) - case (s_ID) - mySize = 9_pInt - crystallite_postResults(c+1:c+mySize) = & - reshape(math_Mandel6to33(crystallite_Tstar_v(1:6,ipc,ip,el)),[mySize]) - case (elasmatrix_ID) - mySize = 36_pInt - crystallite_postResults(c+1:c+mySize) = reshape(constitutive_homogenizedC(ipc,ip,el),[mySize]) - case(neighboringelement_ID) - mySize = mesh_maxNipNeighbors - crystallite_postResults(c+1:c+mySize) = 0.0_pReal - forall (n = 1_pInt:FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) & - crystallite_postResults(c+n) = real(mesh_ipNeighborhood(1,n,ip,el),pReal) - case(neighboringip_ID) - mySize = mesh_maxNipNeighbors - crystallite_postResults(c+1:c+mySize) = 0.0_pReal - forall (n = 1_pInt:FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) & - crystallite_postResults(c+n) = real(mesh_ipNeighborhood(2,n,ip,el),pReal) - end select - c = c + mySize - enddo - - crystallite_postResults(c+1) = real(plasticState(material_phase(ipc,ip,el))%sizePostResults,pReal) ! size of constitutive results - c = c + 1_pInt - if (size(crystallite_postResults)-c > 0_pInt) & - crystallite_postResults(c+1:size(crystallite_postResults)) = & - constitutive_postResults(crystallite_Tstar_v(1:6,ipc,ip,el), crystallite_Fe, & - ipc, ip, el) - -end function crystallite_postResults - -end module crystallite diff --git a/code/damage_local.f90 b/code/damage_local.f90 deleted file mode 100644 index 196382c13..000000000 --- a/code/damage_local.f90 +++ /dev/null @@ -1,327 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for locally evolving damage field -!-------------------------------------------------------------------------------------------------- -module damage_local - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - damage_local_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - damage_local_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - damage_local_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - damage_local_Noutput !< number of outputs per instance of this damage - - enum, bind(c) - enumerator :: undefined_ID, & - damage_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - damage_local_outputID !< ID of each post result output - - public :: & - damage_local_init, & - damage_local_updateState, & - damage_local_postResults - private :: & - damage_local_getSourceAndItsTangent - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine damage_local_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - damage_type, & - damage_typeInstance, & - homogenization_Noutput, & - DAMAGE_local_label, & - DAMAGE_local_ID, & - material_homog, & - mappingHomogenization, & - damageState, & - damageMapping, & - damage, & - damage_initialPhi, & - material_partHomogenization - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,homog,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_local_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(damage_type == DAMAGE_local_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(damage_local_sizePostResults(maxNinstance), source=0_pInt) - allocate(damage_local_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(damage_local_output (maxval(homogenization_Noutput),maxNinstance)) - damage_local_output = '' - allocate(damage_local_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(damage_local_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - homog = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - homog = homog + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (homog > 0_pInt ) then; if (damage_type(homog) == DAMAGE_local_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = damage_typeInstance(homog) ! which instance of my damage is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('damage') - damage_local_Noutput(instance) = damage_local_Noutput(instance) + 1_pInt - damage_local_outputID(damage_local_Noutput(instance),instance) = damage_ID - damage_local_output(damage_local_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingFile - - initializeInstances: do homog = 1_pInt, size(damage_type) - - myhomog: if (damage_type(homog) == DAMAGE_local_ID) then - NofMyHomog = count(material_homog == homog) - instance = damage_typeInstance(homog) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,damage_local_Noutput(instance) - select case(damage_local_outputID(o,instance)) - case(damage_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - damage_local_sizePostResult(o,instance) = mySize - damage_local_sizePostResults(instance) = damage_local_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 1_pInt - damageState(homog)%sizeState = sizeState - damageState(homog)%sizePostResults = damage_local_sizePostResults(instance) - allocate(damageState(homog)%state0 (sizeState,NofMyHomog), source=damage_initialPhi(homog)) - allocate(damageState(homog)%subState0(sizeState,NofMyHomog), source=damage_initialPhi(homog)) - allocate(damageState(homog)%state (sizeState,NofMyHomog), source=damage_initialPhi(homog)) - - nullify(damageMapping(homog)%p) - damageMapping(homog)%p => mappingHomogenization(1,:,:) - deallocate(damage(homog)%p) - damage(homog)%p => damageState(homog)%state(1,:) - - endif myhomog - enddo initializeInstances - - -end subroutine damage_local_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates local change in damage field -!-------------------------------------------------------------------------------------------------- -function damage_local_updateState(subdt, ip, el) - use numerics, only: & - residualStiffness, & - err_damage_tolAbs, & - err_damage_tolRel - use material, only: & - mappingHomogenization, & - damageState - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - subdt - logical, dimension(2) :: & - damage_local_updateState - integer(pInt) :: & - homog, & - offset - real(pReal) :: & - phi, phiDot, dPhiDot_dPhi - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - phi = damageState(homog)%subState0(1,offset) - call damage_local_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) - phi = max(residualStiffness,min(1.0_pReal,phi + subdt*phiDot)) - - damage_local_updateState = [ abs(phi - damageState(homog)%state(1,offset)) & - <= err_damage_tolAbs & - .or. abs(phi - damageState(homog)%state(1,offset)) & - <= err_damage_tolRel*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) - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - phase_source, & - phase_Nsources, & - SOURCE_damage_isoBrittle_ID, & - SOURCE_damage_isoDuctile_ID, & - SOURCE_damage_anisoBrittle_ID, & - SOURCE_damage_anisoDuctile_ID - use source_damage_isoBrittle, only: & - source_damage_isobrittle_getRateAndItsTangent - use source_damage_isoDuctile, only: & - source_damage_isoductile_getRateAndItsTangent - use source_damage_anisoBrittle, only: & - source_damage_anisobrittle_getRateAndItsTangent - use source_damage_anisoDuctile, only: & - source_damage_anisoductile_getRateAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - integer(pInt) :: & - phase, & - grain, & - source - real(pReal) :: & - phiDot, dPhiDot_dPhi, localphiDot, dLocalphiDot_dPhi - - phiDot = 0.0_pReal - dPhiDot_dPhi = 0.0_pReal - do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) - phase = phaseAt(grain,ip,el) - do source = 1, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_damage_isoBrittle_ID) - call source_damage_isobrittle_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_isoDuctile_ID) - call source_damage_isoductile_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_anisoBrittle_ID) - call source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_anisoDuctile_ID) - call source_damage_anisoductile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case default - localphiDot = 0.0_pReal - dLocalphiDot_dPhi = 0.0_pReal - - end select - phiDot = phiDot + localphiDot - dPhiDot_dPhi = dPhiDot_dPhi + dLocalphiDot_dPhi - enddo - enddo - - phiDot = phiDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - dPhiDot_dPhi = dPhiDot_dPhi/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - -end subroutine damage_local_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of damage results -!-------------------------------------------------------------------------------------------------- -function damage_local_postResults(ip,el) - use material, only: & - mappingHomogenization, & - damage_typeInstance, & - damageMapping, & - damage - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(damage_local_sizePostResults(damage_typeInstance(mappingHomogenization(2,ip,el)))) :: & - damage_local_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = damageMapping(homog)%p(ip,el) - instance = damage_typeInstance(homog) - - c = 0_pInt - damage_local_postResults = 0.0_pReal - - do o = 1_pInt,damage_local_Noutput(instance) - select case(damage_local_outputID(o,instance)) - - case (damage_ID) - damage_local_postResults(c+1_pInt) = damage(homog)%p(offset) - c = c + 1 - end select - enddo -end function damage_local_postResults - -end module damage_local diff --git a/code/damage_none.f90 b/code/damage_none.f90 deleted file mode 100644 index 956ba5cc8..000000000 --- a/code/damage_none.f90 +++ /dev/null @@ -1,60 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for constant damage field -!-------------------------------------------------------------------------------------------------- -module damage_none - - implicit none - private - - public :: & - damage_none_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine damage_none_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_none_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (damage_type(homog) == DAMAGE_none_ID) then - NofMyHomog = count(material_homog == homog) - damageState(homog)%sizeState = 0_pInt - damageState(homog)%sizePostResults = 0_pInt - allocate(damageState(homog)%state0 (0_pInt,NofMyHomog)) - allocate(damageState(homog)%subState0(0_pInt,NofMyHomog)) - allocate(damageState(homog)%state (0_pInt,NofMyHomog)) - - deallocate(damage(homog)%p) - allocate (damage(homog)%p(1), source=damage_initialPhi(homog)) - - endif myhomog - enddo initializeInstances - - -end subroutine damage_none_init - -end module damage_none diff --git a/code/damage_nonlocal.f90 b/code/damage_nonlocal.f90 deleted file mode 100644 index 311570781..000000000 --- a/code/damage_nonlocal.f90 +++ /dev/null @@ -1,380 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for non-locally evolving damage field -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module damage_nonlocal - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - damage_nonlocal_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - damage_nonlocal_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - damage_nonlocal_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - damage_nonlocal_Noutput !< number of outputs per instance of this damage - - enum, bind(c) - enumerator :: undefined_ID, & - damage_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - damage_nonlocal_outputID !< ID of each post result output - - - public :: & - damage_nonlocal_init, & - damage_nonlocal_getSourceAndItsTangent, & - damage_nonlocal_getDiffusion33, & - damage_nonlocal_getMobility, & - damage_nonlocal_putNonLocalDamage, & - damage_nonlocal_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine damage_nonlocal_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - damage_type, & - damage_typeInstance, & - homogenization_Noutput, & - DAMAGE_nonlocal_label, & - DAMAGE_nonlocal_ID, & - material_homog, & - mappingHomogenization, & - damageState, & - damageMapping, & - damage, & - damage_initialPhi, & - material_partHomogenization - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_nonlocal_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(damage_type == DAMAGE_nonlocal_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(damage_nonlocal_sizePostResults(maxNinstance), source=0_pInt) - allocate(damage_nonlocal_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(damage_nonlocal_output (maxval(homogenization_Noutput),maxNinstance)) - damage_nonlocal_output = '' - allocate(damage_nonlocal_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(damage_nonlocal_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (damage_type(section) == DAMAGE_nonlocal_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = damage_typeInstance(section) ! which instance of my damage is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('damage') - damage_nonlocal_Noutput(instance) = damage_nonlocal_Noutput(instance) + 1_pInt - damage_nonlocal_outputID(damage_nonlocal_Noutput(instance),instance) = damage_ID - damage_nonlocal_output(damage_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingFile - - initializeInstances: do section = 1_pInt, size(damage_type) - if (damage_type(section) == DAMAGE_nonlocal_ID) then - NofMyHomog=count(material_homog==section) - instance = damage_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,damage_nonlocal_Noutput(instance) - select case(damage_nonlocal_outputID(o,instance)) - case(damage_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - damage_nonlocal_sizePostResult(o,instance) = mySize - damage_nonlocal_sizePostResults(instance) = damage_nonlocal_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 0_pInt - damageState(section)%sizeState = sizeState - damageState(section)%sizePostResults = damage_nonlocal_sizePostResults(instance) - allocate(damageState(section)%state0 (sizeState,NofMyHomog)) - allocate(damageState(section)%subState0(sizeState,NofMyHomog)) - allocate(damageState(section)%state (sizeState,NofMyHomog)) - - nullify(damageMapping(section)%p) - damageMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(damage(section)%p) - allocate(damage(section)%p(NofMyHomog), source=damage_initialPhi(section)) - - endif - - enddo initializeInstances -end subroutine damage_nonlocal_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates homogenized damage driving forces -!-------------------------------------------------------------------------------------------------- -subroutine damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - phase_source, & - phase_Nsources, & - SOURCE_damage_isoBrittle_ID, & - SOURCE_damage_isoDuctile_ID, & - SOURCE_damage_anisoBrittle_ID, & - SOURCE_damage_anisoDuctile_ID - use source_damage_isoBrittle, only: & - source_damage_isobrittle_getRateAndItsTangent - use source_damage_isoDuctile, only: & - source_damage_isoductile_getRateAndItsTangent - use source_damage_anisoBrittle, only: & - source_damage_anisobrittle_getRateAndItsTangent - use source_damage_anisoDuctile, only: & - source_damage_anisoductile_getRateAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - integer(pInt) :: & - phase, & - grain, & - source - real(pReal) :: & - phiDot, dPhiDot_dPhi, localphiDot, dLocalphiDot_dPhi - - phiDot = 0.0_pReal - dPhiDot_dPhi = 0.0_pReal - do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) - phase = phaseAt(grain,ip,el) - do source = 1_pInt, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_damage_isoBrittle_ID) - call source_damage_isobrittle_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_isoDuctile_ID) - call source_damage_isoductile_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_anisoBrittle_ID) - call source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case (SOURCE_damage_anisoDuctile_ID) - call source_damage_anisoductile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) - - case default - localphiDot = 0.0_pReal - dLocalphiDot_dPhi = 0.0_pReal - - end select - phiDot = phiDot + localphiDot - dPhiDot_dPhi = dPhiDot_dPhi + dLocalphiDot_dPhi - enddo - enddo - - phiDot = phiDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - dPhiDot_dPhi = dPhiDot_dPhi/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - -end subroutine damage_nonlocal_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized non local damage diffusion tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function damage_nonlocal_getDiffusion33(ip,el) - use numerics, only: & - charLength - use lattice, only: & - lattice_DamageDiffusion33 - use material, only: & - homogenization_Ngrains, & - material_phase, & - mappingHomogenization - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - damage_nonlocal_getDiffusion33 - integer(pInt) :: & - homog, & - grain - - homog = mappingHomogenization(2,ip,el) - damage_nonlocal_getDiffusion33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(homog) - damage_nonlocal_getDiffusion33 = damage_nonlocal_getDiffusion33 + & - crystallite_push33ToRef(grain,ip,el,lattice_DamageDiffusion33(1:3,1:3,material_phase(grain,ip,el))) - enddo - - damage_nonlocal_getDiffusion33 = & - charLength*charLength* & - damage_nonlocal_getDiffusion33/ & - homogenization_Ngrains(homog) - -end function damage_nonlocal_getDiffusion33 - -!-------------------------------------------------------------------------------------------------- -!> @brief Returns homogenized nonlocal damage mobility -!-------------------------------------------------------------------------------------------------- -real(pReal) function damage_nonlocal_getMobility(ip,el) - use mesh, only: & - mesh_element - use lattice, only: & - lattice_damageMobility - use material, only: & - material_phase, & - homogenization_Ngrains - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - integer(pInt) :: & - ipc - - damage_nonlocal_getMobility = 0.0_pReal - - do ipc = 1, homogenization_Ngrains(mesh_element(3,el)) - damage_nonlocal_getMobility = damage_nonlocal_getMobility + lattice_DamageMobility(material_phase(ipc,ip,el)) - enddo - - damage_nonlocal_getMobility = damage_nonlocal_getMobility /homogenization_Ngrains(mesh_element(3,el)) - -end function damage_nonlocal_getMobility - -!-------------------------------------------------------------------------------------------------- -!> @brief updated nonlocal damage field with solution from damage phase field PDE -!-------------------------------------------------------------------------------------------------- -subroutine damage_nonlocal_putNonLocalDamage(phi,ip,el) - use material, only: & - material_homog, & - damageMapping, & - damage - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - integer(pInt) :: & - homog, & - offset - - homog = material_homog(ip,el) - offset = damageMapping(homog)%p(ip,el) - damage(homog)%p(offset) = phi - -end subroutine damage_nonlocal_putNonLocalDamage - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of damage results -!-------------------------------------------------------------------------------------------------- -function damage_nonlocal_postResults(ip,el) - use material, only: & - mappingHomogenization, & - damage_typeInstance, & - damage - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(damage_nonlocal_sizePostResults(damage_typeInstance(mappingHomogenization(2,ip,el)))) :: & - damage_nonlocal_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - instance = damage_typeInstance(homog) - - c = 0_pInt - damage_nonlocal_postResults = 0.0_pReal - - do o = 1_pInt,damage_nonlocal_Noutput(instance) - select case(damage_nonlocal_outputID(o,instance)) - - case (damage_ID) - damage_nonlocal_postResults(c+1_pInt) = damage(homog)%p(offset) - c = c + 1 - end select - enddo -end function damage_nonlocal_postResults - -end module damage_nonlocal diff --git a/code/damask.core.pyf b/code/damask.core.pyf deleted file mode 100644 index e6396ee1d..000000000 --- a/code/damask.core.pyf +++ /dev/null @@ -1,126 +0,0 @@ -! $Id$ -! -*- f90 -*- -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! Note: the syntax of this file is case sensitive. -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! This file was auto-generated with f2py (version:2_5972). -! See http://cens.ioc.ee/projects/f2py2e/ -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! The auto-generated file is quite heavily corrected -! For modifying, notice the following hints: -! - if the dimension of an array depend on a array that is itself an input, use the C-Syntax: (1) becomes [0] etc. -! - be sure that the precision defined is integer, real*8, and complex*16 -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -python module core ! in - interface ! in :core - - module prec - subroutine prec_init - end subroutine prec_init - end module prec - - module damask_interface ! in :damask_interface:DAMASK_spectral_interface.f90 - subroutine DAMASK_interface_init(loadcaseParameterIn,geometryParameterIn) ! in :damask_interface:DAMASK_spectral_interface.f90 - character(len=1024), intent(in) :: loadcaseParameterIn - character(len=1024), intent(in) :: geometryParameterIn - end subroutine DAMASK_interface_init - end module damask_interface - - module io - subroutine IO_init - end subroutine IO_init - end module io - - module numerics - subroutine numerics_init - end subroutine numerics_init - end module numerics - - module debug - subroutine debug_init - end subroutine debug_init - end module debug - - module math ! in :math:math.f90 - subroutine math_init - end subroutine math_init - - function math_tensorAvg(field) ! in :math:math.f90 - ! input variables - real*8 dimension(:,:,:,:,:), intent(in), :: field - ! function definition - real*8 dimension(3,3), :: math_tensorAvg - end function math_tensorAvg - - end module math - - module fesolving - subroutine FE_init - end subroutine FE_init - end module fesolving - - module mesh ! in :mesh:mesh.f90 - subroutine mesh_init(ip,element) - integer, parameter :: ip = 1 - integer, parameter :: element = 1 - end subroutine mesh_init - - function mesh_nodesAroundCentres(gDim,Favg,centres) ! in :mesh:mesh.f90 - real*8, dimension(:,:,:,:), intent(in) :: centres - real*8, dimension(3), intent(in) :: gDim - real*8, dimension(3,3), intent(in) :: Favg - real*8, dimension(3,size(centres,2)+1,size(centres,3)+1,size(centres,4)+1), depend(centres) :: mesh_nodesAroundCentres - real*8, dimension(3,size(centres,2)+1,size(centres,3)+1,size(centres,4)+1), depend(centres) :: wrappedCentres - end function mesh_nodesAroundCentres - - function mesh_deformedCoordsFFT(gDim,F,FavgIn,scalingIn) ! in :mesh:mesh.f90 - real*8, dimension(:,:,:,:,:), intent(in) :: F - real*8, dimension(3), intent(in) :: gDim - real*8, dimension(3,3), intent(in), optional :: FavgIn = -1.0 - real*8, dimension(3), intent(in), optional :: scalingIn = -1.0 - real*8, dimension(3,size(F,3),size(F,4),size(F,5)), depend(F) :: mesh_deformedCoordsFFT - end function mesh_deformedCoordsFFT - - function mesh_volumeMismatch(gDim,F,nodes) ! in :mesh:mesh.f90 - real*8, dimension(:,:,:,:,:), intent(in) :: F - real*8, dimension(:,:,:,:), intent(in) :: nodes - real*8, dimension(3), intent(in) :: gDim - real*8, dimension(size(F,3),size(F,4),size(F,5)), depend(F) :: mesh_volumeMismatch - end function mesh_volumeMismatch - - function mesh_shapeMismatch(gDim,F,nodes,centres) ! in :mesh:mesh.f90 - real*8, dimension(:,:,:,:,:), intent(in) :: F - real*8, dimension(:,:,:,:), intent(in) :: nodes - real*8, dimension(:,:,:,:), intent(in) :: centres - real*8, dimension(3), intent(in) :: gDim - real*8, dimension(size(F,3),size(F,4),size(F,5)), depend(F) :: mesh_shapeMismatch - end function mesh_shapeMismatch - - function mesh_init_postprocessing(filepath) ! in :mesh:mesh.f90 - character(len=*), intent(in) :: filepath - end function mesh_init_postprocessing - - function mesh_build_cellnodes(nodes,Ncellnodes) ! in :mesh:mesh.f90 - integer, intent(in) :: Ncellnodes - real*8, dimension(3,:), intent(in) :: nodes - real*8, dimension(3,Ncellnodes), depend(Ncellnodes) :: mesh_build_cellnodes - end function mesh_build_cellnodes - - function mesh_get_Ncellnodes() ! in :mesh:mesh.f90 - integer :: mesh_get_Ncellnodes - end function mesh_get_Ncellnodes - - function mesh_get_unitlength() ! in :mesh:mesh.f90 - real*8 :: mesh_get_unitlength - end function mesh_get_unitlength - - function mesh_get_nodeAtIP(elemtypeFE,ip) ! in :mesh:mesh.f90 - character(len=*), intent(in) :: elemtypeFE - integer, intent(in) :: ip - integer :: mesh_get_nodeAtIP - end function mesh_get_nodeAtIP - - end module mesh - end interface -end python module core - diff --git a/code/damask_hdf5.f90 b/code/damask_hdf5.f90 deleted file mode 100644 index 34479f9b3..000000000 --- a/code/damask_hdf5.f90 +++ /dev/null @@ -1,16 +0,0 @@ -module HDF5_io - use prec - use IO - use hdf5 - -contains - -subroutine HDF5_init(filename, total_inc, total_time) - integer(pInt), intent(in) :: total_inc - real(pReal), intent(in) :: total_time - - write(6,*) 'pretend to write something' - -end subroutine HDF5_init - -end module HDF5_io \ No newline at end of file diff --git a/code/debug.f90 b/code/debug.f90 deleted file mode 100644 index 2a9c6d800..000000000 --- a/code/debug.f90 +++ /dev/null @@ -1,476 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @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 Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Reading in and interpretating the debugging settings for the various modules -!-------------------------------------------------------------------------------------------------- -module debug - use prec, only: & - pInt, & - pReal, & - pLongInt - - implicit none - private - integer(pInt), parameter, public :: & - debug_LEVELSELECTIVE = 2_pInt**0_pInt, & - debug_LEVELBASIC = 2_pInt**1_pInt, & - debug_LEVELEXTENSIVE = 2_pInt**2_pInt - integer(pInt), parameter, private :: & - debug_MAXGENERAL = debug_LEVELEXTENSIVE ! must be set to the last bitcode used by (potentially) all debug types - integer(pInt), parameter, public :: & - debug_SPECTRALRESTART = debug_MAXGENERAL*2_pInt**1_pInt, & - debug_SPECTRALFFTW = debug_MAXGENERAL*2_pInt**2_pInt, & - debug_SPECTRALDIVERGENCE = debug_MAXGENERAL*2_pInt**3_pInt, & - debug_SPECTRALROTATION = debug_MAXGENERAL*2_pInt**4_pInt, & - debug_SPECTRALPETSC = debug_MAXGENERAL*2_pInt**5_pInt - - integer(pInt), parameter, public :: & - debug_DEBUG = 1_pInt, & - debug_MATH = 2_pInt, & - debug_FESOLVING = 3_pInt, & - debug_MESH = 4_pInt, & !< stores debug level for mesh part of DAMASK bitwise coded - debug_MATERIAL = 5_pInt, & !< stores debug level for material part of DAMASK bitwise coded - debug_LATTICE = 6_pInt, & !< stores debug level for lattice part of DAMASK bitwise coded - debug_CONSTITUTIVE = 7_pInt, & !< stores debug level for constitutive part of DAMASK bitwise coded - debug_CRYSTALLITE = 8_pInt, & - debug_HOMOGENIZATION = 9_pInt, & - debug_CPFEM = 10_pInt, & - debug_SPECTRAL = 11_pInt, & - debug_MARC = 12_pInt, & - debug_ABAQUS = 13_pInt - integer(pInt), parameter, private :: & - debug_MAXNTYPE = debug_ABAQUS !< must be set to the maximum defined debug type - - integer(pInt),protected, dimension(debug_maxNtype+2_pInt), public :: & ! specific ones, and 2 for "all" and "other" - debug_level = 0_pInt - - integer(pInt), public :: & - debug_cumLpCalls = 0_pInt, & !< total number of calls to LpAndItsTangent - debug_cumDeltaStateCalls = 0_pInt, & !< total number of calls to deltaState - debug_cumDotStateCalls = 0_pInt !< total number of calls to dotState - - integer(pInt), protected, public :: & - debug_e = 1_pInt, & - debug_i = 1_pInt, & - debug_g = 1_pInt - - integer(pLongInt), public :: & - debug_cumLpTicks = 0_pLongInt, & !< total cpu ticks spent in LpAndItsTangent - debug_cumDeltaStateTicks = 0_pLongInt, & !< total cpu ticks spent in deltaState - debug_cumDotStateTicks = 0_pLongInt !< total cpu ticks spent in dotState - - integer(pInt), dimension(2), public :: & - debug_stressMaxLocation = 0_pInt, & - debug_stressMinLocation = 0_pInt, & - debug_jacobianMaxLocation = 0_pInt, & - debug_jacobianMinLocation = 0_pInt - - integer(pInt), dimension(:), allocatable, public :: & - debug_CrystalliteLoopDistribution, & !< distribution of crystallite cutbacks - debug_MaterialpointStateLoopDistribution, & - debug_MaterialpointLoopDistribution - - integer(pInt), dimension(:,:), allocatable, public :: & - debug_StressLoopLiDistribution, & !< distribution of stress iterations until convergence - debug_StressLoopLpDistribution, & !< distribution of stress iterations until convergence - debug_StateLoopDistribution !< distribution of state iterations until convergence - - real(pReal), public :: & - debug_stressMax = -huge(1.0_pReal), & - debug_stressMin = huge(1.0_pReal), & - debug_jacobianMax = -huge(1.0_pReal), & - debug_jacobianMin = huge(1.0_pReal) - - character(len=64), parameter, private :: & - debug_CONFIGFILE = 'debug.config' !< name of configuration file - -#ifdef PETSc - character(len=1024), parameter, public :: & - PETSCDEBUG = ' -snes_view -snes_monitor ' -#endif - public :: debug_init, & - debug_reset, & - debug_info - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads in parameters from debug.config and allocates arrays -!-------------------------------------------------------------------------------------------------- -subroutine debug_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use numerics, only: & - worldrank, & - nStress, & - nState, & - nCryst, & - nMPstate, & - nHomog - use IO, only: & - IO_read, & - IO_error, & - IO_open_file_stat, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_lc, & - IO_floatValue, & - IO_intValue, & - IO_timeStamp, & - IO_EOF - - implicit none - integer(pInt), parameter :: FILEUNIT = 300_pInt - - integer(pInt) :: i, what - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=65536) :: tag, line - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- debug init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - if (allocated(debug_StressLoopLpDistribution)) & - deallocate(debug_StressLoopLpDistribution) - allocate(debug_StressLoopLpDistribution(nStress+1,2)) - debug_StressLoopLpDistribution = 0_pInt - if (allocated(debug_StressLoopLiDistribution)) & - deallocate(debug_StressLoopLiDistribution) - allocate(debug_StressLoopLiDistribution(nStress+1,2)) - debug_StressLoopLiDistribution = 0_pInt - if (allocated(debug_StateLoopDistribution)) & - deallocate(debug_StateLoopDistribution) - allocate(debug_StateLoopDistribution(nState+1,2)) - debug_StateLoopDistribution = 0_pInt - if (allocated(debug_CrystalliteLoopDistribution)) & - deallocate(debug_CrystalliteLoopDistribution) - allocate(debug_CrystalliteLoopDistribution(nCryst+1)) - debug_CrystalliteLoopDistribution = 0_pInt - if (allocated(debug_MaterialpointStateLoopDistribution)) & - deallocate(debug_MaterialpointStateLoopDistribution) - allocate(debug_MaterialpointStateLoopDistribution(nMPstate)) - debug_MaterialpointStateLoopDistribution = 0_pInt - if (allocated(debug_MaterialpointLoopDistribution)) & - deallocate(debug_MaterialpointLoopDistribution) - allocate(debug_MaterialpointLoopDistribution(nHomog+1)) - debug_MaterialpointLoopDistribution = 0_pInt - -!-------------------------------------------------------------------------------------------------- -! try to open the config file - - line = '' - fileExists: if(IO_open_file_stat(FILEUNIT,debug_configFile)) then - do while (trim(line) /= IO_EOF) ! read thru sections of phase part - line = IO_read(FILEUNIT) - if (IO_isBlank(line)) cycle ! skip empty lines - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('element','e','el') - debug_e = IO_intValue(line,chunkPos,2_pInt) - case ('integrationpoint','i','ip') - debug_i = IO_intValue(line,chunkPos,2_pInt) - case ('grain','g','gr') - debug_g = IO_intValue(line,chunkPos,2_pInt) - end select - - what = 0_pInt - select case(tag) - case ('debug') - what = debug_DEBUG - case ('math') - what = debug_MATH - case ('fesolving', 'fe') - what = debug_FESOLVING - case ('mesh') - what = debug_MESH - case ('material') - what = debug_MATERIAL - case ('lattice') - what = debug_LATTICE - case ('constitutive') - what = debug_CONSTITUTIVE - case ('crystallite') - what = debug_CRYSTALLITE - case ('homogenization') - what = debug_HOMOGENIZATION - case ('cpfem') - what = debug_CPFEM - case ('spectral') - what = debug_SPECTRAL - case ('marc') - what = debug_MARC - case ('abaqus') - what = debug_ABAQUS - case ('all') - what = debug_MAXNTYPE + 1_pInt - case ('other') - what = debug_MAXNTYPE + 2_pInt - end select - if (what /= 0) then - do i = 2_pInt, chunkPos(1) - select case(IO_lc(IO_stringValue(line,chunkPos,i))) - case('basic') - debug_level(what) = ior(debug_level(what), debug_LEVELBASIC) - case('extensive') - debug_level(what) = ior(debug_level(what), debug_LEVELEXTENSIVE) - case('selective') - debug_level(what) = ior(debug_level(what), debug_LEVELSELECTIVE) - case('restart') - debug_level(what) = ior(debug_level(what), debug_SPECTRALRESTART) - case('fft','fftw') - debug_level(what) = ior(debug_level(what), debug_SPECTRALFFTW) - case('divergence') - debug_level(what) = ior(debug_level(what), debug_SPECTRALDIVERGENCE) - case('rotation') - debug_level(what) = ior(debug_level(what), debug_SPECTRALROTATION) - case('petsc') - debug_level(what) = ior(debug_level(what), debug_SPECTRALPETSC) - end select - enddo - endif - enddo - close(FILEUNIT) - - do i = 1_pInt, debug_maxNtype - if (debug_level(i) == 0) & - debug_level(i) = ior(debug_level(i), debug_level(debug_MAXNTYPE + 2_pInt)) ! fill undefined debug types with levels specified by "other" - - debug_level(i) = ior(debug_level(i), debug_level(debug_MAXNTYPE + 1_pInt)) ! fill all debug types with levels specified by "all" - enddo - - if (iand(debug_level(debug_debug),debug_LEVELBASIC) /= 0) & - write(6,'(a,/)') ' using values from config file' - else fileExists - if (iand(debug_level(debug_debug),debug_LEVELBASIC) /= 0) & - write(6,'(a,/)') ' using standard values' - endif fileExists - -!-------------------------------------------------------------------------------------------------- -! output switched on (debug level for debug must be extensive) - if (iand(debug_level(debug_debug),debug_LEVELEXTENSIVE) /= 0) then - do i = 1_pInt, debug_MAXNTYPE - select case(i) - case (debug_DEBUG) - tag = ' Debug' - case (debug_MATH) - tag = ' Math' - case (debug_FESOLVING) - tag = ' FEsolving' - case (debug_MESH) - tag = ' Mesh' - case (debug_MATERIAL) - tag = ' Material' - case (debug_LATTICE) - tag = ' Lattice' - case (debug_CONSTITUTIVE) - tag = ' Constitutive' - case (debug_CRYSTALLITE) - tag = ' Crystallite' - case (debug_HOMOGENIZATION) - tag = ' Homogenizaiton' - case (debug_CPFEM) - tag = ' CPFEM' - case (debug_SPECTRAL) - tag = ' Spectral solver' - case (debug_MARC) - tag = ' MSC.MARC FEM solver' - case (debug_ABAQUS) - tag = ' ABAQUS FEM solver' - end select - - if(debug_level(i) /= 0) then - write(6,'(3a)') ' debug level for ', trim(tag), ':' - if(iand(debug_level(i),debug_LEVELBASIC) /= 0) write(6,'(a)') ' basic' - if(iand(debug_level(i),debug_LEVELEXTENSIVE) /= 0) write(6,'(a)') ' extensive' - if(iand(debug_level(i),debug_LEVELSELECTIVE) /= 0) then - write(6,'(a)') ' selective on:' - write(6,'(a24,1x,i8)') ' element: ',debug_e - write(6,'(a24,1x,i8)') ' ip: ',debug_i - write(6,'(a24,1x,i8)') ' grain: ',debug_g - endif - if(iand(debug_level(i),debug_SPECTRALRESTART) /= 0) write(6,'(a)') ' restart' - if(iand(debug_level(i),debug_SPECTRALFFTW) /= 0) write(6,'(a)') ' FFTW' - if(iand(debug_level(i),debug_SPECTRALDIVERGENCE)/= 0) write(6,'(a)') ' divergence' - if(iand(debug_level(i),debug_SPECTRALROTATION) /= 0) write(6,'(a)') ' rotation' - if(iand(debug_level(i),debug_SPECTRALPETSC) /= 0) write(6,'(a)') ' PETSc' - endif - enddo - endif - -end subroutine debug_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief resets all debug values -!-------------------------------------------------------------------------------------------------- -subroutine debug_reset - - implicit none - - debug_StressLoopLpDistribution = 0_pInt - debug_StressLoopLiDistribution = 0_pInt - debug_StateLoopDistribution = 0_pInt - debug_CrystalliteLoopDistribution = 0_pInt - debug_MaterialpointStateLoopDistribution = 0_pInt - debug_MaterialpointLoopDistribution = 0_pInt - debug_cumLpTicks = 0_pLongInt - debug_cumDeltaStateTicks = 0_pLongInt - debug_cumDotStateTicks = 0_pLongInt - debug_cumLpCalls = 0_pInt - debug_cumDeltaStateCalls = 0_pInt - debug_cumDotStateCalls = 0_pInt - debug_stressMaxLocation = 0_pInt - debug_stressMinLocation = 0_pInt - debug_jacobianMaxLocation = 0_pInt - debug_jacobianMinLocation = 0_pInt - debug_stressMax = -huge(1.0_pReal) - debug_stressMin = huge(1.0_pReal) - debug_jacobianMax = -huge(1.0_pReal) - debug_jacobianMin = huge(1.0_pReal) - -end subroutine debug_reset - - -!-------------------------------------------------------------------------------------------------- -!> @brief writes debug statements to standard out -!-------------------------------------------------------------------------------------------------- -subroutine debug_info - use numerics, only: & - nStress, & - nState, & - nCryst, & - nMPstate, & - nHomog - - implicit none - integer(pInt) :: j,integral - integer(pLongInt) :: tickrate - character(len=1) :: exceed - - call system_clock(count_rate=tickrate) - - !$OMP CRITICAL (write2out) - debugOutputCryst: if (iand(debug_level(debug_CRYSTALLITE),debug_LEVELBASIC) /= 0) then - write(6,'(/,a,/)') ' DEBUG Info (from previous cycle)' - write(6,'(a33,1x,i12)') 'total calls to LpAndItsTangent :',debug_cumLpCalls - if (debug_cumLpCalls > 0_pInt) then - write(6,'(a33,1x,f12.3)') 'total CPU time/s :',& - real(debug_cumLpTicks,pReal)/real(tickrate,pReal) - write(6,'(a33,1x,f12.6)') 'avg CPU time/microsecs per call :',& - real(debug_cumLpTicks,pReal)*1.0e6_pReal/real(tickrate*debug_cumLpCalls,pReal) - endif - write(6,'(/,a33,1x,i12)') 'total calls to collectDotState :',debug_cumDotStateCalls - if (debug_cumdotStateCalls > 0_pInt) then - write(6,'(a33,1x,f12.3)') 'total CPU time/s :',& - real(debug_cumDotStateTicks,pReal)/real(tickrate,pReal) - write(6,'(a33,1x,f12.6)') 'avg CPU time/microsecs per call :',& - real(debug_cumDotStateTicks,pReal)*1.0e6_pReal/real(tickrate*debug_cumDotStateCalls,pReal) - endif - write(6,'(/,a33,1x,i12)') 'total calls to collectDeltaState:',debug_cumDeltaStateCalls - if (debug_cumDeltaStateCalls > 0_pInt) then - write(6,'(a33,1x,f12.3)') 'total CPU time/s :',& - real(debug_cumDeltaStateTicks,pReal)/real(tickrate,pReal) - write(6,'(a33,1x,f12.6)') 'avg CPU time/microsecs per call :',& - real(debug_cumDeltaStateTicks,pReal)*1.0e6_pReal/real(tickrate*debug_cumDeltaStateCalls,pReal) - endif - - integral = 0_pInt - write(6,'(3/,a)') 'distribution_StressLoopLp : stress stiffness' - do j=1_pInt,nStress+1_pInt - if (any(debug_StressLoopLpDistribution(j,:) /= 0_pInt )) then - integral = integral + j*(debug_StressLoopLpDistribution(j,1) + debug_StressLoopLpDistribution(j,2)) - exceed = ' ' - if (j > nStress) exceed = '+' ! last entry gets "+" - write(6,'(i25,a1,i10,1x,i10)') min(nStress,j),exceed,debug_StressLoopLpDistribution(j,1),& - debug_StressLoopLpDistribution(j,2) - endif - enddo - write(6,'(a15,i10,2(1x,i10))') ' total',integral,sum(debug_StressLoopLpDistribution(:,1)), & - sum(debug_StressLoopLpDistribution(:,2)) - - integral = 0_pInt - write(6,'(3/,a)') 'distribution_StressLoopLi : stress stiffness' - do j=1_pInt,nStress+1_pInt - if (any(debug_StressLoopLiDistribution(j,:) /= 0_pInt )) then - integral = integral + j*(debug_StressLoopLiDistribution(j,1) + debug_StressLoopLiDistribution(j,2)) - exceed = ' ' - if (j > nStress) exceed = '+' ! last entry gets "+" - write(6,'(i25,a1,i10,1x,i10)') min(nStress,j),exceed,debug_StressLoopLiDistribution(j,1),& - debug_StressLoopLiDistribution(j,2) - endif - enddo - write(6,'(a15,i10,2(1x,i10))') ' total',integral,sum(debug_StressLoopLiDistribution(:,1)), & - sum(debug_StressLoopLiDistribution(:,2)) - - integral = 0_pInt - write(6,'(2/,a)') 'distribution_CrystalliteStateLoop :' - do j=1_pInt,nState+1_pInt - if (any(debug_StateLoopDistribution(j,:) /= 0)) then - integral = integral + j*(debug_StateLoopDistribution(j,1) + debug_StateLoopDistribution(j,2)) - exceed = ' ' - if (j > nState) exceed = '+' ! last entry gets "+" - write(6,'(i25,a1,i10,1x,i10)') min(nState,j),exceed,debug_StateLoopDistribution(j,1),& - debug_StateLoopDistribution(j,2) - endif - enddo - write(6,'(a15,i10,2(1x,i10))') ' total',integral,sum(debug_StateLoopDistribution(:,1)), & - sum(debug_StateLoopDistribution(:,2)) - - integral = 0_pInt - write(6,'(2/,a)') 'distribution_CrystalliteCutbackLoop :' - do j=1_pInt,nCryst+1_pInt - if (debug_CrystalliteLoopDistribution(j) /= 0) then - integral = integral + j*debug_CrystalliteLoopDistribution(j) - exceed = ' ' - if (j > nCryst) exceed = '+' - write(6,'(i25,a1,i10)') min(nCryst,j),exceed,debug_CrystalliteLoopDistribution(j) - endif - enddo - write(6,'(a15,i10,1x,i10)') ' total',integral,sum(debug_CrystalliteLoopDistribution) - endif debugOutputCryst - - debugOutputHomog: if (iand(debug_level(debug_HOMOGENIZATION),debug_LEVELBASIC) /= 0) then - integral = 0_pInt - write(6,'(2/,a)') 'distribution_MaterialpointStateLoop :' - do j=1_pInt,nMPstate - if (debug_MaterialpointStateLoopDistribution(j) /= 0) then - integral = integral + j*debug_MaterialpointStateLoopDistribution(j) - write(6,'(i25,1x,i10)') j,debug_MaterialpointStateLoopDistribution(j) - endif - enddo - write(6,'(a15,i10,1x,i10)') ' total',integral,sum(debug_MaterialpointStateLoopDistribution) - - integral = 0_pInt - write(6,'(2/,a)') 'distribution_MaterialpointCutbackLoop :' - do j=1_pInt,nHomog+1_pInt - if (debug_MaterialpointLoopDistribution(j) /= 0) then - integral = integral + j*debug_MaterialpointLoopDistribution(j) - exceed = ' ' - if (j > nHomog) exceed = '+' - write(6,'(i25,a1,i10)') min(nHomog,j),exceed,debug_MaterialpointLoopDistribution(j) - endif - enddo - write(6,'(a15,i10,1x,i10)') ' total',integral,sum(debug_MaterialpointLoopDistribution) - endif debugOutputHomog - - debugOutputCPFEM: if (iand(debug_level(debug_CPFEM),debug_LEVELBASIC) /= 0) then - write(6,'(2/,a,/)') ' Extreme values of returned stress and jacobian' - write(6,'(a39)') ' value el ip' - write(6,'(a14,1x,e12.3,1x,i6,1x,i4)') ' stress min :', debug_stressMin, debug_stressMinLocation - write(6,'(a14,1x,e12.3,1x,i6,1x,i4)') ' max :', debug_stressMax, debug_stressMaxLocation - write(6,'(a14,1x,e12.3,1x,i6,1x,i4)') ' jacobian min :', debug_jacobianMin, debug_jacobianMinLocation - write(6,'(a14,1x,e12.3,1x,i6,1x,i4,/)') ' max :', debug_jacobianMax, debug_jacobianMaxLocation - endif debugOutputCPFEM - !$OMP END CRITICAL (write2out) - -end subroutine debug_info - -end module debug diff --git a/code/homogenization.f90 b/code/homogenization.f90 deleted file mode 100644 index 00186ff06..000000000 --- a/code/homogenization.f90 +++ /dev/null @@ -1,1396 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Denny Tjahjanto, Max-Planck-Institut für Eisenforschung GmbH -!> @brief homogenization manager, organizing deformation partitioning and stress homogenization -!-------------------------------------------------------------------------------------------------- -module homogenization - use prec, only: & -#ifdef FEM - tOutputData, & -#endif - pInt, & - pReal - -!-------------------------------------------------------------------------------------------------- -! General variables for the homogenization at a material point - implicit none - private - real(pReal), dimension(:,:,:,:), allocatable, public :: & - materialpoint_F0, & !< def grad of IP at start of FE increment - materialpoint_F, & !< def grad of IP to be reached at end of FE increment - materialpoint_P !< first P--K stress of IP - real(pReal), dimension(:,:,:,:,:,:), allocatable, public :: & - materialpoint_dPdF !< tangent of first P--K stress at IP -#ifdef FEM - type(tOutputData), dimension(:), allocatable, public :: & - homogOutput - type(tOutputData), dimension(:,:), allocatable, public :: & - crystalliteOutput, & - phaseOutput -#else - real(pReal), dimension(:,:,:), allocatable, public :: & - materialpoint_results !< results array of material point -#endif - integer(pInt), public, protected :: & - materialpoint_sizeResults, & - homogenization_maxSizePostResults, & - thermal_maxSizePostResults, & - damage_maxSizePostResults, & - vacancyflux_maxSizePostResults, & - porosity_maxSizePostResults, & - hydrogenflux_maxSizePostResults - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - materialpoint_subF0, & !< def grad of IP at beginning of homogenization increment - materialpoint_subF !< def grad of IP to be reached at end of homog inc - real(pReal), dimension(:,:), allocatable, private :: & - materialpoint_subFrac, & - materialpoint_subStep, & - materialpoint_subdt - logical, dimension(:,:), allocatable, private :: & - materialpoint_requested, & - materialpoint_converged - logical, dimension(:,:,:), allocatable, private :: & - materialpoint_doneAndHappy - - public :: & - homogenization_init, & - materialpoint_stressAndItsTangent, & - materialpoint_postResults - private :: & - homogenization_partitionDeformation, & - homogenization_updateState, & - homogenization_averageStressAndItsTangent, & - homogenization_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_init -#ifdef HDF - use hdf5, only: & - HID_T - use IO, only : & - HDF5_mappingHomogenization -#endif - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use math, only: & - math_I3 - use debug, only: & - debug_level, & - debug_homogenization, & - debug_levelBasic, & - debug_e, & - debug_g - use mesh, only: & - mesh_maxNips, & - mesh_NcpElems, & - mesh_element, & - FE_Nips, & - FE_geomtype -#ifdef FEM - use crystallite, only: & - crystallite_sizePostResults -#else - use constitutive, only: & - constitutive_plasticity_maxSizePostResults, & - constitutive_source_maxSizePostResults - use crystallite, only: & - crystallite_maxSizePostResults -#endif - use material - use homogenization_none - use homogenization_isostrain - use homogenization_RGC - use thermal_isothermal - use thermal_adiabatic - use thermal_conduction - use damage_none - use damage_local - use damage_nonlocal - use vacancyflux_isoconc - use vacancyflux_isochempot - use vacancyflux_cahnhilliard - use porosity_none - use porosity_phasefield - use hydrogenflux_isoconc - use hydrogenflux_cahnhilliard - use IO - use numerics, only: & - worldrank - - implicit none - integer(pInt), parameter :: FILEUNIT = 200_pInt - integer(pInt) :: e,i,p - integer(pInt), dimension(:,:), pointer :: thisSize - integer(pInt), dimension(:) , pointer :: thisNoutput - character(len=64), dimension(:,:), pointer :: thisOutput - character(len=32) :: outputName !< name of output, intermediate fix until HDF5 output is ready - logical :: knownHomogenization, knownThermal, knownDamage, knownVacancyflux, knownPorosity, knownHydrogenflux -#ifdef HDF - integer(pInt), dimension(:,:), allocatable :: mapping - integer(pInt), dimension(:), allocatable :: InstancePosition - allocate(mapping(mesh_ncpelems,4),source=0_pInt) - allocate(InstancePosition(material_Nhomogenization),source=0_pInt) -#endif - - -!-------------------------------------------------------------------------------------------------- -! open material.config - if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... - call IO_open_file(FILEUNIT,material_configFile) ! ... open material.config file - -!-------------------------------------------------------------------------------------------------- -! parse homogenization from config file - if (any(homogenization_type == HOMOGENIZATION_NONE_ID)) & - call homogenization_none_init() - if (any(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID)) & - call homogenization_isostrain_init(FILEUNIT) - if (any(homogenization_type == HOMOGENIZATION_RGC_ID)) & - call homogenization_RGC_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse thermal from config file - call IO_checkAndRewind(FILEUNIT) - if (any(thermal_type == THERMAL_isothermal_ID)) & - call thermal_isothermal_init() - if (any(thermal_type == THERMAL_adiabatic_ID)) & - call thermal_adiabatic_init(FILEUNIT) - if (any(thermal_type == THERMAL_conduction_ID)) & - call thermal_conduction_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse damage from config file - call IO_checkAndRewind(FILEUNIT) - if (any(damage_type == DAMAGE_none_ID)) & - call damage_none_init() - if (any(damage_type == DAMAGE_local_ID)) & - call damage_local_init(FILEUNIT) - if (any(damage_type == DAMAGE_nonlocal_ID)) & - call damage_nonlocal_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse vacancy transport from config file - call IO_checkAndRewind(FILEUNIT) - if (any(vacancyflux_type == VACANCYFLUX_isoconc_ID)) & - call vacancyflux_isoconc_init() - if (any(vacancyflux_type == VACANCYFLUX_isochempot_ID)) & - call vacancyflux_isochempot_init(FILEUNIT) - if (any(vacancyflux_type == VACANCYFLUX_cahnhilliard_ID)) & - call vacancyflux_cahnhilliard_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse porosity from config file - call IO_checkAndRewind(FILEUNIT) - if (any(porosity_type == POROSITY_none_ID)) & - call porosity_none_init() - if (any(porosity_type == POROSITY_phasefield_ID)) & - call porosity_phasefield_init(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! parse hydrogen transport from config file - call IO_checkAndRewind(FILEUNIT) - if (any(hydrogenflux_type == HYDROGENFLUX_isoconc_ID)) & - call hydrogenflux_isoconc_init() - if (any(hydrogenflux_type == HYDROGENFLUX_cahnhilliard_ID)) & - call hydrogenflux_cahnhilliard_init(FILEUNIT) - close(FILEUNIT) - -!-------------------------------------------------------------------------------------------------- -! write description file for homogenization output - mainProcess2: if (worldrank == 0) then - call IO_write_jobFile(FILEUNIT,'outputHomogenization') - do p = 1,material_Nhomogenization - if (any(material_homog == p)) then - i = homogenization_typeInstance(p) ! which instance of this homogenization type - knownHomogenization = .true. ! assume valid - select case(homogenization_type(p)) ! split per homogenization type - case (HOMOGENIZATION_NONE_ID) - outputName = HOMOGENIZATION_NONE_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (HOMOGENIZATION_ISOSTRAIN_ID) - outputName = HOMOGENIZATION_ISOSTRAIN_label - thisNoutput => homogenization_isostrain_Noutput - thisOutput => homogenization_isostrain_output - thisSize => homogenization_isostrain_sizePostResult - case (HOMOGENIZATION_RGC_ID) - outputName = HOMOGENIZATION_RGC_label - thisNoutput => homogenization_RGC_Noutput - thisOutput => homogenization_RGC_output - thisSize => homogenization_RGC_sizePostResult - case default - knownHomogenization = .false. - end select - write(FILEUNIT,'(/,a,/)') '['//trim(homogenization_name(p))//']' - if (knownHomogenization) then - write(FILEUNIT,'(a)') '(type)'//char(9)//trim(outputName) - write(FILEUNIT,'(a,i4)') '(ngrains)'//char(9),homogenization_Ngrains(p) - if (homogenization_type(p) /= HOMOGENIZATION_NONE_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - i = thermal_typeInstance(p) ! which instance of this thermal type - knownThermal = .true. ! assume valid - select case(thermal_type(p)) ! split per thermal type - case (THERMAL_isothermal_ID) - outputName = THERMAL_isothermal_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (THERMAL_adiabatic_ID) - outputName = THERMAL_adiabatic_label - thisNoutput => thermal_adiabatic_Noutput - thisOutput => thermal_adiabatic_output - thisSize => thermal_adiabatic_sizePostResult - case (THERMAL_conduction_ID) - outputName = THERMAL_conduction_label - thisNoutput => thermal_conduction_Noutput - thisOutput => thermal_conduction_output - thisSize => thermal_conduction_sizePostResult - case default - knownThermal = .false. - end select - if (knownThermal) then - write(FILEUNIT,'(a)') '(thermal)'//char(9)//trim(outputName) - if (thermal_type(p) /= THERMAL_isothermal_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - i = damage_typeInstance(p) ! which instance of this damage type - knownDamage = .true. ! assume valid - select case(damage_type(p)) ! split per damage type - case (DAMAGE_none_ID) - outputName = DAMAGE_none_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (DAMAGE_local_ID) - outputName = DAMAGE_local_label - thisNoutput => damage_local_Noutput - thisOutput => damage_local_output - thisSize => damage_local_sizePostResult - case (DAMAGE_nonlocal_ID) - outputName = DAMAGE_nonlocal_label - thisNoutput => damage_nonlocal_Noutput - thisOutput => damage_nonlocal_output - thisSize => damage_nonlocal_sizePostResult - case default - knownDamage = .false. - end select - if (knownDamage) then - write(FILEUNIT,'(a)') '(damage)'//char(9)//trim(outputName) - if (damage_type(p) /= DAMAGE_none_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - i = vacancyflux_typeInstance(p) ! which instance of this vacancy flux type - knownVacancyflux = .true. ! assume valid - select case(vacancyflux_type(p)) ! split per vacancy flux type - case (VACANCYFLUX_isoconc_ID) - outputName = VACANCYFLUX_isoconc_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (VACANCYFLUX_isochempot_ID) - outputName = VACANCYFLUX_isochempot_label - thisNoutput => vacancyflux_isochempot_Noutput - thisOutput => vacancyflux_isochempot_output - thisSize => vacancyflux_isochempot_sizePostResult - case (VACANCYFLUX_cahnhilliard_ID) - outputName = VACANCYFLUX_cahnhilliard_label - thisNoutput => vacancyflux_cahnhilliard_Noutput - thisOutput => vacancyflux_cahnhilliard_output - thisSize => vacancyflux_cahnhilliard_sizePostResult - case default - knownVacancyflux = .false. - end select - if (knownVacancyflux) then - write(FILEUNIT,'(a)') '(vacancyflux)'//char(9)//trim(outputName) - if (vacancyflux_type(p) /= VACANCYFLUX_isoconc_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - i = porosity_typeInstance(p) ! which instance of this porosity type - knownPorosity = .true. ! assume valid - select case(porosity_type(p)) ! split per porosity type - case (POROSITY_none_ID) - outputName = POROSITY_none_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (POROSITY_phasefield_ID) - outputName = POROSITY_phasefield_label - thisNoutput => porosity_phasefield_Noutput - thisOutput => porosity_phasefield_output - thisSize => porosity_phasefield_sizePostResult - case default - knownPorosity = .false. - end select - if (knownPorosity) then - write(FILEUNIT,'(a)') '(porosity)'//char(9)//trim(outputName) - if (porosity_type(p) /= POROSITY_none_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - i = hydrogenflux_typeInstance(p) ! which instance of this hydrogen flux type - knownHydrogenflux = .true. ! assume valid - select case(hydrogenflux_type(p)) ! split per hydrogen flux type - case (HYDROGENFLUX_isoconc_ID) - outputName = HYDROGENFLUX_isoconc_label - thisNoutput => null() - thisOutput => null() - thisSize => null() - case (HYDROGENFLUX_cahnhilliard_ID) - outputName = HYDROGENFLUX_cahnhilliard_label - thisNoutput => hydrogenflux_cahnhilliard_Noutput - thisOutput => hydrogenflux_cahnhilliard_output - thisSize => hydrogenflux_cahnhilliard_sizePostResult - case default - knownHydrogenflux = .false. - end select - if (knownHydrogenflux) then - write(FILEUNIT,'(a)') '(hydrogenflux)'//char(9)//trim(outputName) - if (hydrogenflux_type(p) /= HYDROGENFLUX_isoconc_ID) then - do e = 1,thisNoutput(i) - write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) - enddo - endif - endif - endif - enddo - close(FILEUNIT) - endif mainProcess2 - -!-------------------------------------------------------------------------------------------------- -! allocate and initialize global variables - allocate(materialpoint_dPdF(3,3,3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_F0(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - materialpoint_F0 = spread(spread(math_I3,3,mesh_maxNips),4,mesh_NcpElems) ! initialize to identity - allocate(materialpoint_F(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - materialpoint_F = materialpoint_F0 ! initialize to identity - allocate(materialpoint_subF0(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_subF(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_P(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_subFrac(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_subStep(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_subdt(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(materialpoint_requested(mesh_maxNips,mesh_NcpElems), source=.false.) - allocate(materialpoint_converged(mesh_maxNips,mesh_NcpElems), source=.true.) - allocate(materialpoint_doneAndHappy(2,mesh_maxNips,mesh_NcpElems), source=.true.) - -!-------------------------------------------------------------------------------------------------- -! allocate and initialize global state and postresutls variables -#ifdef HDF - elementLooping: do e = 1,mesh_NcpElems - myInstance = homogenization_typeInstance(mesh_element(3,e)) - IpLooping: do i = 1,FE_Nips(FE_geomtype(mesh_element(2,e))) - InstancePosition(myInstance) = InstancePosition(myInstance)+1_pInt - mapping(e,1:4) = [instancePosition(myinstance),myinstance,e,i] - enddo IpLooping - enddo elementLooping - call HDF5_mappingHomogenization(mapping) -#endif - - homogenization_maxSizePostResults = 0_pInt - thermal_maxSizePostResults = 0_pInt - damage_maxSizePostResults = 0_pInt - vacancyflux_maxSizePostResults = 0_pInt - porosity_maxSizePostResults = 0_pInt - hydrogenflux_maxSizePostResults = 0_pInt - do p = 1,material_Nhomogenization - homogenization_maxSizePostResults = max(homogenization_maxSizePostResults,homogState (p)%sizePostResults) - thermal_maxSizePostResults = max(thermal_maxSizePostResults, thermalState (p)%sizePostResults) - damage_maxSizePostResults = max(damage_maxSizePostResults ,damageState (p)%sizePostResults) - vacancyflux_maxSizePostResults = max(vacancyflux_maxSizePostResults ,vacancyfluxState (p)%sizePostResults) - porosity_maxSizePostResults = max(porosity_maxSizePostResults ,porosityState (p)%sizePostResults) - hydrogenflux_maxSizePostResults = max(hydrogenflux_maxSizePostResults ,hydrogenfluxState(p)%sizePostResults) - enddo - -#ifdef FEM - allocate(homogOutput (material_Nhomogenization )) - allocate(crystalliteOutput(material_Ncrystallite, homogenization_maxNgrains)) - allocate(phaseOutput (material_Nphase, homogenization_maxNgrains)) - do p = 1, material_Nhomogenization - homogOutput(p)%sizeResults = homogState (p)%sizePostResults + & - thermalState (p)%sizePostResults + & - damageState (p)%sizePostResults + & - vacancyfluxState (p)%sizePostResults + & - porosityState (p)%sizePostResults + & - hydrogenfluxState(p)%sizePostResults - homogOutput(p)%sizeIpCells = count(material_homog==p) - allocate(homogOutput(p)%output(homogOutput(p)%sizeResults,homogOutput(p)%sizeIpCells)) - enddo - do p = 1, material_Ncrystallite; do e = 1, homogenization_maxNgrains - crystalliteOutput(p,e)%sizeResults = crystallite_sizePostResults(p) - crystalliteOutput(p,e)%sizeIpCells = count(microstructure_crystallite(mesh_element(4,:)) == p .and. & - homogenization_Ngrains (mesh_element(3,:)) >= e)*mesh_maxNips - allocate(crystalliteOutput(p,e)%output(crystalliteOutput(p,e)%sizeResults,crystalliteOutput(p,e)%sizeIpCells)) - enddo; enddo - do p = 1, material_Nphase; do e = 1, homogenization_maxNgrains - phaseOutput(p,e)%sizeResults = plasticState (p)%sizePostResults + & - sum(sourceState (p)%p(:)%sizePostResults) - phaseOutput(p,e)%sizeIpCells = count(material_phase(e,:,:) == p) - allocate(phaseOutput(p,e)%output(phaseOutput(p,e)%sizeResults,phaseOutput(p,e)%sizeIpCells)) - enddo; enddo -#else - materialpoint_sizeResults = 1 & ! grain count - + 1 + homogenization_maxSizePostResults & ! homogSize & homogResult - + thermal_maxSizePostResults & - + damage_maxSizePostResults & - + vacancyflux_maxSizePostResults & - + porosity_maxSizePostResults & - + hydrogenflux_maxSizePostResults & - + homogenization_maxNgrains * (1 + crystallite_maxSizePostResults & ! crystallite size & crystallite results - + 1 + constitutive_plasticity_maxSizePostResults & ! constitutive size & constitutive results - + constitutive_source_maxSizePostResults) - allocate(materialpoint_results(materialpoint_sizeResults,mesh_maxNips,mesh_NcpElems)) -#endif - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- homogenization init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then -#ifdef TODO - write(6,'(a32,1x,7(i8,1x))') 'homogenization_state0: ', shape(homogenization_state0) - write(6,'(a32,1x,7(i8,1x))') 'homogenization_subState0: ', shape(homogenization_subState0) - write(6,'(a32,1x,7(i8,1x))') 'homogenization_state: ', shape(homogenization_state) -#endif - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_dPdF: ', shape(materialpoint_dPdF) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_F0: ', shape(materialpoint_F0) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_F: ', shape(materialpoint_F) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subF0: ', shape(materialpoint_subF0) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subF: ', shape(materialpoint_subF) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_P: ', shape(materialpoint_P) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subFrac: ', shape(materialpoint_subFrac) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subStep: ', shape(materialpoint_subStep) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subdt: ', shape(materialpoint_subdt) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_requested: ', shape(materialpoint_requested) - write(6,'(a32,1x,7(i8,1x))') 'materialpoint_converged: ', shape(materialpoint_converged) - write(6,'(a32,1x,7(i8,1x),/)') 'materialpoint_doneAndHappy: ', shape(materialpoint_doneAndHappy) -#ifndef FEM - write(6,'(a32,1x,7(i8,1x),/)') 'materialpoint_results: ', shape(materialpoint_results) -#endif - write(6,'(a32,1x,7(i8,1x))') 'maxSizePostResults: ', homogenization_maxSizePostResults - endif - flush(6) - - if (debug_g < 1 .or. debug_g > homogenization_Ngrains(mesh_element(3,debug_e))) & - call IO_error(602_pInt,ext_msg='component (grain)') - -end subroutine homogenization_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief parallelized calculation of stress and corresponding tangent at material points -!-------------------------------------------------------------------------------------------------- -subroutine materialpoint_stressAndItsTangent(updateJaco,dt) - use numerics, only: & - subStepMinHomog, & - subStepSizeHomog, & - stepIncreaseHomog, & - nHomog, & - nMPstate - use math, only: & - math_transpose33 - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP, & - terminallyIll - use mesh, only: & - mesh_element - use material, only: & - plasticState, & - sourceState, & - homogState, & - thermalState, & - damageState, & - vacancyfluxState, & - porosityState, & - hydrogenfluxState, & - phase_Nsources, & - mappingHomogenization, & - phaseAt, phasememberAt, & - homogenization_Ngrains - use crystallite, only: & - crystallite_F0, & - crystallite_Fp0, & - crystallite_Fp, & - crystallite_Fi0, & - crystallite_Fi, & - crystallite_Lp0, & - crystallite_Lp, & - crystallite_Li0, & - crystallite_Li, & - crystallite_dPdF, & - crystallite_dPdF0, & - crystallite_Tstar0_v, & - crystallite_Tstar_v, & - crystallite_partionedF0, & - crystallite_partionedF, & - crystallite_partionedFp0, & - crystallite_partionedLp0, & - crystallite_partionedFi0, & - crystallite_partionedLi0, & - crystallite_partioneddPdF0, & - crystallite_partionedTstar0_v, & - crystallite_dt, & - crystallite_requested, & - crystallite_converged, & - crystallite_stressAndItsTangent, & - crystallite_orientations - use debug, only: & - debug_level, & - debug_homogenization, & - debug_levelBasic, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_MaterialpointLoopDistribution, & - debug_MaterialpointStateLoopDistribution - - implicit none - real(pReal), intent(in) :: dt !< time increment - logical, intent(in) :: updateJaco !< initiating Jacobian update - integer(pInt) :: & - NiterationHomog, & - NiterationMPstate, & - g, & !< grain number - i, & !< integration point number - e, & !< element number - mySource, & - myNgrains - -!-------------------------------------------------------------------------------------------------- -! initialize to starting condition - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(/a,i5,1x,i2)') '<< HOMOG >> Material Point start at el ip ', debug_e, debug_i - - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< HOMOG >> F0', & - math_transpose33(materialpoint_F0(1:3,1:3,debug_i,debug_e)) - write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< HOMOG >> F', & - math_transpose33(materialpoint_F(1:3,1:3,debug_i,debug_e)) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! initialize restoration points of ... - do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Ngrains(mesh_element(3,e)) - do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do g = 1,myNgrains - - plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) = & - plasticState (phaseAt(g,i,e))%state0( :,phasememberAt(g,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) - sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) = & - sourceState(phaseAt(g,i,e))%p(mySource)%state0( :,phasememberAt(g,i,e)) - enddo - - crystallite_partionedFp0(1:3,1:3,g,i,e) = crystallite_Fp0(1:3,1:3,g,i,e) ! ...plastic def grads - crystallite_partionedLp0(1:3,1:3,g,i,e) = crystallite_Lp0(1:3,1:3,g,i,e) ! ...plastic velocity grads - crystallite_partionedFi0(1:3,1:3,g,i,e) = crystallite_Fi0(1:3,1:3,g,i,e) ! ...intermediate def grads - crystallite_partionedLi0(1:3,1:3,g,i,e) = crystallite_Li0(1:3,1:3,g,i,e) ! ...intermediate velocity grads - crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,g,i,e) = crystallite_dPdF0(1:3,1:3,1:3,1:3,g,i,e) ! ...stiffness - crystallite_partionedF0(1:3,1:3,g,i,e) = crystallite_F0(1:3,1:3,g,i,e) ! ...def grads - crystallite_partionedTstar0_v(1:6,g,i,e) = crystallite_Tstar0_v(1:6,g,i,e) ! ...2nd PK stress - - enddo; enddo - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e)) - materialpoint_subF0(1:3,1:3,i,e) = materialpoint_F0(1:3,1:3,i,e) ! ...def grad - materialpoint_subFrac(i,e) = 0.0_pReal - materialpoint_subStep(i,e) = 1.0_pReal/subStepSizeHomog ! <> - materialpoint_converged(i,e) = .false. ! pretend failed step of twice the required size - materialpoint_requested(i,e) = .true. ! everybody requires calculation - endforall - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - homogState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal homogenization state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - thermalState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal thermal state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - damageState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal damage state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - vacancyfluxState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal vacancy transport state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - porosityState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal porosity state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - hydrogenfluxState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal hydrogen transport state - enddo - NiterationHomog = 0_pInt - - cutBackLooping: do while (.not. terminallyIll .and. & - any(materialpoint_subStep(:,FEsolving_execELem(1):FEsolving_execElem(2)) > subStepMinHomog)) - - !$OMP PARALLEL DO PRIVATE(myNgrains) - elementLooping1: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Ngrains(mesh_element(3,e)) - IpLooping1: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - - converged: if ( materialpoint_converged(i,e) ) then -#ifndef _OPENMP - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i) & - .or. .not. iand(debug_level(debug_homogenization),debug_levelSelective) /= 0_pInt)) then - write(6,'(a,1x,f12.8,1x,a,1x,f12.8,1x,a,i8,1x,i2/)') '<< HOMOG >> winding forward from', & - materialpoint_subFrac(i,e), 'to current materialpoint_subFrac', & - materialpoint_subFrac(i,e)+materialpoint_subStep(i,e),'in materialpoint_stressAndItsTangent at el ip',e,i - endif -#endif - -!--------------------------------------------------------------------------------------------------- -! calculate new subStep and new subFrac - materialpoint_subFrac(i,e) = materialpoint_subFrac(i,e) + materialpoint_subStep(i,e) - !$OMP FLUSH(materialpoint_subFrac) - materialpoint_subStep(i,e) = min(1.0_pReal-materialpoint_subFrac(i,e), & - stepIncreaseHomog*materialpoint_subStep(i,e)) ! introduce flexibility for step increase/acceleration - !$OMP FLUSH(materialpoint_subStep) - - steppingNeeded: if (materialpoint_subStep(i,e) > subStepMinHomog) then - - ! wind forward grain starting point of... - crystallite_partionedF0(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedF(1:3,1:3,1:myNgrains,i,e) ! ...def grads - - crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) = & - crystallite_Fp(1:3,1:3,1:myNgrains,i,e) ! ...plastic def grads - - crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) = & - crystallite_Lp(1:3,1:3,1:myNgrains,i,e) ! ...plastic velocity grads - - crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) = & - crystallite_Fi(1:3,1:3,1:myNgrains,i,e) ! ...intermediate def grads - - crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) = & - crystallite_Li(1:3,1:3,1:myNgrains,i,e) ! ...intermediate velocity grads - - crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,1:myNgrains,i,e) = & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:myNgrains,i,e) ! ...stiffness - - crystallite_partionedTstar0_v(1:6,1:myNgrains,i,e) = & - crystallite_Tstar_v(1:6,1:myNgrains,i,e) ! ...2nd PK stress - - do g = 1,myNgrains - plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) = & - plasticState (phaseAt(g,i,e))%state( :,phasememberAt(g,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) - sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) = & - sourceState(phaseAt(g,i,e))%p(mySource)%state( :,phasememberAt(g,i,e)) - enddo - enddo - - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - homogState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal homogenization state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - thermalState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal thermal state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - damageState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal damage state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - vacancyfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal vacancy transport state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - porosityState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal porosity state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & - hydrogenfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal hydrogen transport state - materialpoint_subF0(1:3,1:3,i,e) = materialpoint_subF(1:3,1:3,i,e) ! ...def grad - !$OMP FLUSH(materialpoint_subF0) - elseif (materialpoint_requested(i,e)) then steppingNeeded ! already at final time (??) - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionHomog) - debug_MaterialpointLoopDistribution(min(nHomog+1,NiterationHomog)) = & - debug_MaterialpointLoopDistribution(min(nHomog+1,NiterationHomog)) + 1 - !$OMP END CRITICAL (distributionHomog) - endif - endif steppingNeeded - - else converged - if ( (myNgrains == 1_pInt .and. materialpoint_subStep(i,e) <= 1.0 ) .or. & ! single grain already tried internal subStepping in crystallite - subStepSizeHomog * materialpoint_subStep(i,e) <= subStepMinHomog ) then ! would require too small subStep - ! cutback makes no sense - !$OMP FLUSH(terminallyIll) - if (.not. terminallyIll) then ! so first signals terminally ill... - !$OMP CRITICAL (write2out) - write(6,*) 'Integration point ', i,' at element ', e, ' terminally ill' - !$OMP END CRITICAL (write2out) - endif - !$OMP CRITICAL (setTerminallyIll) - terminallyIll = .true. ! ...and kills all others - !$OMP END CRITICAL (setTerminallyIll) - else ! cutback makes sense - materialpoint_subStep(i,e) = subStepSizeHomog * materialpoint_subStep(i,e) ! crystallite had severe trouble, so do a significant cutback - !$OMP FLUSH(materialpoint_subStep) - -#ifndef _OPENMP - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt & - .and. ((e == debug_e .and. i == debug_i) & - .or. .not. iand(debug_level(debug_homogenization), debug_levelSelective) /= 0_pInt)) then - write(6,'(a,1x,f12.8,a,i8,1x,i2/)') & - '<< HOMOG >> cutback step in materialpoint_stressAndItsTangent with new materialpoint_subStep:',& - materialpoint_subStep(i,e),' at el ip',e,i - endif -#endif - -!-------------------------------------------------------------------------------------------------- -! restore... - crystallite_Fp(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) ! ...plastic def grads - crystallite_Lp(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) ! ...plastic velocity grads - crystallite_Fi(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) ! ...intermediate def grads - crystallite_Li(1:3,1:3,1:myNgrains,i,e) = & - crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) ! ...intermediate velocity grads - crystallite_dPdF(1:3,1:3,1:3,1:3,1:myNgrains,i,e) = & - crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,1:myNgrains,i,e) ! ...stiffness - crystallite_Tstar_v(1:6,1:myNgrains,i,e) = & - crystallite_partionedTstar0_v(1:6,1:myNgrains,i,e) ! ...2nd PK stress - do g = 1, myNgrains - plasticState (phaseAt(g,i,e))%state( :,phasememberAt(g,i,e)) = & - plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) - do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) - sourceState(phaseAt(g,i,e))%p(mySource)%state( :,phasememberAt(g,i,e)) = & - sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) - enddo - enddo - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - homogState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal homogenization state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - thermalState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal thermal state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - damageState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal damage state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - vacancyfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal vacancy transport state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - porosityState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal porosity state - forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & - hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & - hydrogenfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & - hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal hydrogen transport state - endif - endif converged - - if (materialpoint_subStep(i,e) > subStepMinHomog) then - materialpoint_requested(i,e) = .true. - materialpoint_subF(1:3,1:3,i,e) = materialpoint_subF0(1:3,1:3,i,e) + & - materialpoint_subStep(i,e) * (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) - materialpoint_subdt(i,e) = materialpoint_subStep(i,e) * dt - materialpoint_doneAndHappy(1:2,i,e) = [.false.,.true.] - endif - enddo IpLooping1 - enddo elementLooping1 - !$OMP END PARALLEL DO - - NiterationMPstate = 0_pInt - - convergenceLooping: do while (.not. terminallyIll .and. & - any( materialpoint_requested(:,FEsolving_execELem(1):FEsolving_execElem(2)) & - .and. .not. materialpoint_doneAndHappy(1,:,FEsolving_execELem(1):FEsolving_execElem(2)) & - ) .and. & - NiterationMPstate < nMPstate) - NiterationMPstate = NiterationMPstate + 1 - -!-------------------------------------------------------------------------------------------------- -! deformation partitioning -! based on materialpoint_subF0,.._subF,crystallite_partionedF0, and homogenization_state, -! results in crystallite_partionedF - !$OMP PARALLEL DO PRIVATE(myNgrains) - elementLooping2: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Ngrains(mesh_element(3,e)) - IpLooping2: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if ( materialpoint_requested(i,e) .and. & ! process requested but... - .not. materialpoint_doneAndHappy(1,i,e)) then ! ...not yet done material points - call homogenization_partitionDeformation(i,e) ! partition deformation onto constituents - crystallite_dt(1:myNgrains,i,e) = materialpoint_subdt(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 -! based on crystallite_partionedF0,.._partionedF -! incrementing by crystallite_dt - call crystallite_stressAndItsTangent(updateJaco) ! request stress and tangent calculation for constituent grains - -!-------------------------------------------------------------------------------------------------- -! state update - !$OMP PARALLEL DO - elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) - IpLooping3: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - if ( materialpoint_requested(i,e) .and. & - .not. materialpoint_doneAndHappy(1,i,e)) then - if (.not. all(crystallite_converged(:,i,e))) then - materialpoint_doneAndHappy(1:2,i,e) = [.true.,.false.] - materialpoint_converged(i,e) = .false. - else - materialpoint_doneAndHappy(1:2,i,e) = homogenization_updateState(i,e) - materialpoint_converged(i,e) = all(materialpoint_doneAndHappy(1:2,i,e)) ! converged if done and happy - endif - !$OMP FLUSH(materialpoint_converged) - if (materialpoint_converged(i,e)) then - if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (distributionMPState) - debug_MaterialpointStateLoopdistribution(NiterationMPstate) = & - debug_MaterialpointStateLoopdistribution(NiterationMPstate) + 1_pInt - !$OMP END CRITICAL (distributionMPState) - endif - endif - endif - enddo IpLooping3 - enddo elementLooping3 - !$OMP END PARALLEL DO - - enddo convergenceLooping - - NiterationHomog = NiterationHomog + 1_pInt - - enddo cutBackLooping - - 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,e),FEsolving_execIP(2,e) - call homogenization_averageStressAndItsTangent(i,e) - enddo IpLooping4 - enddo elementLooping4 - !$OMP END PARALLEL DO - else - !$OMP CRITICAL (write2out) - write(6,'(/,a,/)') '<< HOMOG >> Material Point terminally ill' - !$OMP END CRITICAL (write2out) - endif - -end subroutine materialpoint_stressAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief parallelized calculation of result array at material points -!-------------------------------------------------------------------------------------------------- -subroutine materialpoint_postResults - use FEsolving, only: & - FEsolving_execElem, & - FEsolving_execIP - use mesh, only: & - mesh_element - use material, only: & - mappingHomogenization, & -#ifdef FEM - phaseAt, phasememberAt, & - homogenization_maxNgrains, & - material_Ncrystallite, & - material_Nphase, & -#else - homogState, & - thermalState, & - damageState, & - vacancyfluxState, & - porosityState, & - hydrogenfluxState, & -#endif - plasticState, & - sourceState, & - material_phase, & - homogenization_Ngrains, & - microstructure_crystallite - use constitutive, only: & -#ifdef FEM - constitutive_plasticity_maxSizePostResults, & - constitutive_source_maxSizePostResults, & -#endif - constitutive_postResults - use crystallite, only: & -#ifdef FEM - crystallite_maxSizePostResults, & -#endif - crystallite_sizePostResults, & - crystallite_postResults - - implicit none - integer(pInt) :: & - thePos, & - theSize, & - myNgrains, & - myCrystallite, & - g, & !< grain number - i, & !< integration point number - e !< element number -#ifdef FEM - integer(pInt) :: & - myHomog, & - myPhase, & - crystalliteCtr(material_Ncrystallite, homogenization_maxNgrains), & - phaseCtr (material_Nphase, homogenization_maxNgrains) - real(pReal), dimension(1+crystallite_maxSizePostResults + & - 1+constitutive_plasticity_maxSizePostResults + & - constitutive_source_maxSizePostResults) :: & - crystalliteResults - - - - crystalliteCtr = 0_pInt; phaseCtr = 0_pInt - elementLooping: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Ngrains(mesh_element(3,e)) - myCrystallite = microstructure_crystallite(mesh_element(4,e)) - IpLooping: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - myHomog = mappingHomogenization(2,i,e) - thePos = mappingHomogenization(1,i,e) - homogOutput(myHomog)%output(1: & - homogOutput(myHomog)%sizeResults, & - thePos) = homogenization_postResults(i,e) - - grainLooping :do g = 1,myNgrains - myPhase = phaseAt(g,i,e) - crystalliteResults(1:1+crystallite_sizePostResults(myCrystallite) + & - 1+plasticState(myPhase)%sizePostResults + & - sum(sourceState(myPhase)%p(:)%sizePostResults)) = crystallite_postResults(g,i,e) - if (microstructure_crystallite(mesh_element(4,e)) == myCrystallite .and. & - homogenization_Ngrains (mesh_element(3,e)) >= g) then - crystalliteCtr(myCrystallite,g) = crystalliteCtr(myCrystallite,g) + 1_pInt - crystalliteOutput(myCrystallite,g)% & - output(1:crystalliteOutput(myCrystallite,g)%sizeResults,crystalliteCtr(myCrystallite,g)) = & - crystalliteResults(2:1+crystalliteOutput(myCrystallite,g)%sizeResults) - endif - if (material_phase(g,i,e) == myPhase) then - phaseCtr(myPhase,g) = phaseCtr(myPhase,g) + 1_pInt - phaseOutput(myPhase,g)% & - output(1:phaseOutput(myPhase,g)%sizeResults,phaseCtr(myPhase,g)) = & - crystalliteResults(3 + crystalliteOutput(myCrystallite,g)%sizeResults: & - 1 + crystalliteOutput(myCrystallite,g)%sizeResults + & - 1 + plasticState (myphase)%sizePostResults + & - sum(sourceState(myphase)%p(:)%sizePostResults)) - endif - enddo grainLooping - enddo IpLooping - enddo elementLooping -#else - - !$OMP PARALLEL DO PRIVATE(myNgrains,myCrystallite,thePos,theSize) - elementLooping: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Ngrains(mesh_element(3,e)) - myCrystallite = microstructure_crystallite(mesh_element(4,e)) - IpLooping: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) - thePos = 0_pInt - - theSize = homogState (mappingHomogenization(2,i,e))%sizePostResults & - + thermalState (mappingHomogenization(2,i,e))%sizePostResults & - + damageState (mappingHomogenization(2,i,e))%sizePostResults & - + vacancyfluxState (mappingHomogenization(2,i,e))%sizePostResults & - + porosityState (mappingHomogenization(2,i,e))%sizePostResults & - + hydrogenfluxState(mappingHomogenization(2,i,e))%sizePostResults - materialpoint_results(thePos+1,i,e) = real(theSize,pReal) ! tell size of homogenization results - thePos = thePos + 1_pInt - - if (theSize > 0_pInt) then ! any homogenization results to mention? - materialpoint_results(thePos+1:thePos+theSize,i,e) = homogenization_postResults(i,e) ! tell homogenization results - thePos = thePos + theSize - endif - - materialpoint_results(thePos+1,i,e) = real(myNgrains,pReal) ! tell number of grains at materialpoint - thePos = thePos + 1_pInt - - grainLooping :do g = 1,myNgrains - theSize = 1 + crystallite_sizePostResults(myCrystallite) + & - 1 + plasticState (material_phase(g,i,e))%sizePostResults + & !ToDo - sum(sourceState(material_phase(g,i,e))%p(:)%sizePostResults) - materialpoint_results(thePos+1:thePos+theSize,i,e) = crystallite_postResults(g,i,e) ! tell crystallite results - thePos = thePos + theSize - enddo grainLooping - enddo IpLooping - enddo elementLooping - !$OMP END PARALLEL DO -#endif - -end subroutine materialpoint_postResults - - -!-------------------------------------------------------------------------------------------------- -!> @brief partition material point def grad onto constituents -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_partitionDeformation(ip,el) - use mesh, only: & - mesh_element - use material, only: & - homogenization_type, & - homogenization_maxNgrains, & - HOMOGENIZATION_NONE_ID, & - HOMOGENIZATION_ISOSTRAIN_ID, & - HOMOGENIZATION_RGC_ID - use crystallite, only: & - crystallite_partionedF - use homogenization_isostrain, only: & - homogenization_isostrain_partitionDeformation - use homogenization_RGC, only: & - homogenization_RGC_partitionDeformation - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element number - - chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) - - case (HOMOGENIZATION_NONE_ID) chosenHomogenization - crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el) = 0.0_pReal - crystallite_partionedF(1:3,1:3,1:1,ip,el) = & - spread(materialpoint_subF(1:3,1:3,ip,el),3,1) - - case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization - call homogenization_isostrain_partitionDeformation(& - crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - materialpoint_subF(1:3,1:3,ip,el),& - el) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - call homogenization_RGC_partitionDeformation(& - crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - materialpoint_subF(1:3,1:3,ip,el),& - ip, & - el) - end select chosenHomogenization - -end subroutine homogenization_partitionDeformation - - -!-------------------------------------------------------------------------------------------------- -!> @brief update the internal state of the homogenization scheme and tell whether "done" and -!> "happy" with result -!-------------------------------------------------------------------------------------------------- -function homogenization_updateState(ip,el) - use mesh, only: & - mesh_element - use material, only: & - homogenization_type, & - thermal_type, & - damage_type, & - vacancyflux_type, & - homogenization_maxNgrains, & - HOMOGENIZATION_RGC_ID, & - THERMAL_adiabatic_ID, & - DAMAGE_local_ID, & - VACANCYFLUX_isochempot_ID - use crystallite, only: & - crystallite_P, & - crystallite_dPdF, & - crystallite_partionedF,& - crystallite_partionedF0 - use homogenization_RGC, only: & - homogenization_RGC_updateState - use thermal_adiabatic, only: & - thermal_adiabatic_updateState - use damage_local, only: & - damage_local_updateState - use vacancyflux_isochempot, only: & - vacancyflux_isochempot_updateState - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element number - logical, dimension(2) :: homogenization_updateState - - homogenization_updateState = .true. - chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - homogenization_updateState = & - homogenization_updateState .and. & - homogenization_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - crystallite_partionedF0(1:3,1:3,1:homogenization_maxNgrains,ip,el),& - materialpoint_subF(1:3,1:3,ip,el),& - materialpoint_subdt(ip,el), & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & - ip, & - el) - end select chosenHomogenization - - chosenThermal: select case (thermal_type(mesh_element(3,el))) - case (THERMAL_adiabatic_ID) chosenThermal - homogenization_updateState = & - homogenization_updateState .and. & - thermal_adiabatic_updateState(materialpoint_subdt(ip,el), & - ip, & - el) - end select chosenThermal - - chosenDamage: select case (damage_type(mesh_element(3,el))) - case (DAMAGE_local_ID) chosenDamage - homogenization_updateState = & - homogenization_updateState .and. & - damage_local_updateState(materialpoint_subdt(ip,el), & - ip, & - el) - end select chosenDamage - - chosenVacancyflux: select case (vacancyflux_type(mesh_element(3,el))) - case (VACANCYFLUX_isochempot_ID) chosenVacancyflux - homogenization_updateState = & - homogenization_updateState .and. & - vacancyflux_isochempot_updateState(materialpoint_subdt(ip,el), & - ip, & - el) - end select chosenVacancyflux - -end function homogenization_updateState - - -!-------------------------------------------------------------------------------------------------- -!> @brief derive average stress and stiffness from constituent quantities -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_averageStressAndItsTangent(ip,el) - use mesh, only: & - mesh_element - use material, only: & - homogenization_type, & - homogenization_maxNgrains, & - HOMOGENIZATION_NONE_ID, & - HOMOGENIZATION_ISOSTRAIN_ID, & - HOMOGENIZATION_RGC_ID - use crystallite, only: & - crystallite_P,crystallite_dPdF - use homogenization_isostrain, only: & - homogenization_isostrain_averageStressAndItsTangent - use homogenization_RGC, only: & - homogenization_RGC_averageStressAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element number - - chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) - case (HOMOGENIZATION_NONE_ID) chosenHomogenization - materialpoint_P(1:3,1:3,ip,el) = sum(crystallite_P(1:3,1:3,1:1,ip,el),3) - materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el) & - = sum(crystallite_dPdF(1:3,1:3,1:3,1:3,1:1,ip,el),5) - - case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization - call homogenization_isostrain_averageStressAndItsTangent(& - materialpoint_P(1:3,1:3,ip,el), & - materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& - crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & - el) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - call homogenization_RGC_averageStressAndItsTangent(& - materialpoint_P(1:3,1:3,ip,el), & - materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& - crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & - crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & - el) - end select chosenHomogenization - -end subroutine homogenization_averageStressAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of homogenization results for post file inclusion. call only, -!> if homogenization_sizePostResults(i,e) > 0 !! -!-------------------------------------------------------------------------------------------------- -function homogenization_postResults(ip,el) - use mesh, only: & - mesh_element - use material, only: & - mappingHomogenization, & - homogState, & - thermalState, & - damageState, & - vacancyfluxState, & - porosityState, & - hydrogenfluxState, & - homogenization_type, & - thermal_type, & - damage_type, & - vacancyflux_type, & - porosity_type, & - hydrogenflux_type, & - HOMOGENIZATION_NONE_ID, & - HOMOGENIZATION_ISOSTRAIN_ID, & - HOMOGENIZATION_RGC_ID, & - THERMAL_isothermal_ID, & - THERMAL_adiabatic_ID, & - THERMAL_conduction_ID, & - DAMAGE_none_ID, & - DAMAGE_local_ID, & - DAMAGE_nonlocal_ID, & - VACANCYFLUX_isoconc_ID, & - VACANCYFLUX_isochempot_ID, & - VACANCYFLUX_cahnhilliard_ID, & - POROSITY_none_ID, & - POROSITY_phasefield_ID, & - HYDROGENFLUX_isoconc_ID, & - HYDROGENFLUX_cahnhilliard_ID - use homogenization_isostrain, only: & - homogenization_isostrain_postResults - use homogenization_RGC, only: & - homogenization_RGC_postResults - use thermal_adiabatic, only: & - thermal_adiabatic_postResults - use thermal_conduction, only: & - thermal_conduction_postResults - use damage_local, only: & - damage_local_postResults - use damage_nonlocal, only: & - damage_nonlocal_postResults - use vacancyflux_isochempot, only: & - vacancyflux_isochempot_postResults - use vacancyflux_cahnhilliard, only: & - vacancyflux_cahnhilliard_postResults - use porosity_phasefield, only: & - porosity_phasefield_postResults - use hydrogenflux_cahnhilliard, only: & - hydrogenflux_cahnhilliard_postResults - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element number - real(pReal), dimension( homogState (mappingHomogenization(2,ip,el))%sizePostResults & - + thermalState (mappingHomogenization(2,ip,el))%sizePostResults & - + damageState (mappingHomogenization(2,ip,el))%sizePostResults & - + vacancyfluxState (mappingHomogenization(2,ip,el))%sizePostResults & - + porosityState (mappingHomogenization(2,ip,el))%sizePostResults & - + hydrogenfluxState(mappingHomogenization(2,ip,el))%sizePostResults) :: & - homogenization_postResults - integer(pInt) :: & - startPos, endPos - - homogenization_postResults = 0.0_pReal - - startPos = 1_pInt - endPos = homogState(mappingHomogenization(2,ip,el))%sizePostResults - chosenHomogenization: select case (homogenization_type(mesh_element(3,el))) - case (HOMOGENIZATION_NONE_ID) chosenHomogenization - - case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization - homogenization_postResults(startPos:endPos) = & - homogenization_isostrain_postResults(& - ip, & - el, & - materialpoint_P(1:3,1:3,ip,el), & - materialpoint_F(1:3,1:3,ip,el)) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - homogenization_postResults(startPos:endPos) = & - homogenization_RGC_postResults(& - ip, & - el, & - materialpoint_P(1:3,1:3,ip,el), & - materialpoint_F(1:3,1:3,ip,el)) - end select chosenHomogenization - - startPos = endPos + 1_pInt - endPos = endPos + thermalState(mappingHomogenization(2,ip,el))%sizePostResults - chosenThermal: select case (thermal_type(mesh_element(3,el))) - case (THERMAL_isothermal_ID) chosenThermal - - case (THERMAL_adiabatic_ID) chosenThermal - homogenization_postResults(startPos:endPos) = & - thermal_adiabatic_postResults(ip, el) - case (THERMAL_conduction_ID) chosenThermal - homogenization_postResults(startPos:endPos) = & - thermal_conduction_postResults(ip, el) - end select chosenThermal - - startPos = endPos + 1_pInt - endPos = endPos + damageState(mappingHomogenization(2,ip,el))%sizePostResults - chosenDamage: select case (damage_type(mesh_element(3,el))) - case (DAMAGE_none_ID) chosenDamage - - case (DAMAGE_local_ID) chosenDamage - homogenization_postResults(startPos:endPos) = & - damage_local_postResults(ip, el) - - case (DAMAGE_nonlocal_ID) chosenDamage - homogenization_postResults(startPos:endPos) = & - damage_nonlocal_postResults(ip, el) - end select chosenDamage - - startPos = endPos + 1_pInt - endPos = endPos + vacancyfluxState(mappingHomogenization(2,ip,el))%sizePostResults - chosenVacancyflux: select case (vacancyflux_type(mesh_element(3,el))) - case (VACANCYFLUX_isoconc_ID) chosenVacancyflux - - case (VACANCYFLUX_isochempot_ID) chosenVacancyflux - homogenization_postResults(startPos:endPos) = & - vacancyflux_isochempot_postResults(ip, el) - case (VACANCYFLUX_cahnhilliard_ID) chosenVacancyflux - homogenization_postResults(startPos:endPos) = & - vacancyflux_cahnhilliard_postResults(ip, el) - end select chosenVacancyflux - - startPos = endPos + 1_pInt - endPos = endPos + porosityState(mappingHomogenization(2,ip,el))%sizePostResults - chosenPorosity: select case (porosity_type(mesh_element(3,el))) - case (POROSITY_none_ID) chosenPorosity - - case (POROSITY_phasefield_ID) chosenPorosity - homogenization_postResults(startPos:endPos) = & - porosity_phasefield_postResults(ip, el) - end select chosenPorosity - - startPos = endPos + 1_pInt - endPos = endPos + hydrogenfluxState(mappingHomogenization(2,ip,el))%sizePostResults - chosenHydrogenflux: select case (hydrogenflux_type(mesh_element(3,el))) - case (HYDROGENFLUX_isoconc_ID) chosenHydrogenflux - - case (HYDROGENFLUX_cahnhilliard_ID) chosenHydrogenflux - homogenization_postResults(startPos:endPos) = & - hydrogenflux_cahnhilliard_postResults(ip, el) - end select chosenHydrogenflux - -end function homogenization_postResults - -end module homogenization diff --git a/code/homogenization_RGC.f90 b/code/homogenization_RGC.f90 deleted file mode 100644 index 323ca2934..000000000 --- a/code/homogenization_RGC.f90 +++ /dev/null @@ -1,1558 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Denny Tjahjanto, 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 -!> @brief Relaxed grain cluster (RGC) homogenization scheme -!> Ngrains is defined as p x q x r (cluster) -!-------------------------------------------------------------------------------------------------- -module homogenization_RGC - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public :: & - homogenization_RGC_sizeState, & - homogenization_RGC_sizePostResults - integer(pInt), dimension(:,:), allocatable,target, public :: & - homogenization_RGC_sizePostResult - character(len=64), dimension(:,:), allocatable,target, public :: & - homogenization_RGC_output ! name of each post result output - integer(pInt), dimension(:), allocatable,target, public :: & - homogenization_RGC_Noutput !< number of outputs per homog instance - integer(pInt), dimension(:,:), allocatable, private :: & - homogenization_RGC_Ngrains - real(pReal), dimension(:,:), allocatable, private :: & - homogenization_RGC_dAlpha, & - homogenization_RGC_angles - real(pReal), dimension(:,:,:,:), allocatable, private :: & - homogenization_RGC_orientation - real(pReal), dimension(:), allocatable, private :: & - homogenization_RGC_xiAlpha, & - homogenization_RGC_ciAlpha - enum, bind(c) - enumerator :: undefined_ID, & - constitutivework_ID, & - penaltyenergy_ID, & - volumediscrepancy_ID, & - averagerelaxrate_ID,& - maximumrelaxrate_ID,& - ipcoords_ID,& - magnitudemismatch_ID,& - avgdefgrad_ID,& - avgfirstpiola_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - homogenization_RGC_outputID !< ID of each post result output - - public :: & - homogenization_RGC_init, & - homogenization_RGC_partitionDeformation, & - homogenization_RGC_averageStressAndItsTangent, & - homogenization_RGC_updateState, & - homogenization_RGC_postResults - private :: & - homogenization_RGC_stressPenalty, & - homogenization_RGC_volumePenalty, & - homogenization_RGC_grainDeformation, & - homogenization_RGC_surfaceCorrection, & - homogenization_RGC_equivalentModuli, & - homogenization_RGC_relaxationVector, & - homogenization_RGC_interfaceNormal, & - homogenization_RGC_getInterface, & - homogenization_RGC_grain1to3, & - homogenization_RGC_grain3to1, & - homogenization_RGC_interface4to1, & - homogenization_RGC_interface1to4 - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use debug, only: & - debug_level, & - debug_homogenization, & - debug_levelBasic, & - debug_levelExtensive - use math, only: & - math_Mandel3333to66,& - math_Voigt66to3333, & - math_I3, & - math_sampleRandomOri,& - math_EulerToR,& - INRAD - use mesh, only: & - mesh_maxNips, & - mesh_NcpElems,& - mesh_element, & - FE_Nips, & - FE_geomtype - use IO - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit !< file pointer to material configuration - integer(pInt), allocatable, dimension(:) :: chunkPos - integer :: & - homog, & - NofMyHomog, & - o, & - instance, & - sizeHState - integer(pInt) :: section=0_pInt, maxNinstance, i,j,e, mySize, myInstance - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_RGC_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(homogenization_type == HOMOGENIZATION_RGC_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_HOMOGENIZATION),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - allocate(homogenization_RGC_sizeState(maxNinstance), source=0_pInt) - allocate(homogenization_RGC_sizePostResults(maxNinstance), source=0_pInt) - allocate(homogenization_RGC_Noutput(maxNinstance), source=0_pInt) - allocate(homogenization_RGC_Ngrains(3,maxNinstance), source=0_pInt) - allocate(homogenization_RGC_ciAlpha(maxNinstance), source=0.0_pReal) - allocate(homogenization_RGC_xiAlpha(maxNinstance), source=0.0_pReal) - allocate(homogenization_RGC_dAlpha(3,maxNinstance), source=0.0_pReal) - allocate(homogenization_RGC_angles(3,maxNinstance), source=400.0_pReal) - allocate(homogenization_RGC_output(maxval(homogenization_Noutput),maxNinstance)) - homogenization_RGC_output='' - allocate(homogenization_RGC_outputID(maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(homogenization_RGC_sizePostResult(maxval(homogenization_Noutput),maxNinstance),& - source=0_pInt) - allocate(homogenization_RGC_orientation(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - homogenization_RGC_orientation = spread(spread(math_I3,3,mesh_maxNips),4,mesh_NcpElems) ! initialize to identity - - rewind(fileUnit) - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>'))/=material_partHomogenization) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homogenization part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - cycle - endif - if (section > 0_pInt ) then ! do not short-circuit here (.and. with next if-statement). It's not safe in Fortran - if (homogenization_type(section) == HOMOGENIZATION_RGC_ID) then ! one of my sections - i = homogenization_typeInstance(section) ! which instance of my type is present homogenization - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case('constitutivework') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = constitutivework_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('penaltyenergy') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = penaltyenergy_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('volumediscrepancy') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = volumediscrepancy_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('averagerelaxrate') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = averagerelaxrate_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('maximumrelaxrate') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = maximumrelaxrate_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('magnitudemismatch') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = magnitudemismatch_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('ipcoords') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = ipcoords_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('avgdefgrad','avgf') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = avgdefgrad_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('avgp','avgfirstpiola','avg1stpiola') - homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt - homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = avgfirstpiola_ID - homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - - end select - case ('clustersize') - homogenization_RGC_Ngrains(1,i) = IO_intValue(line,chunkPos,2_pInt) - homogenization_RGC_Ngrains(2,i) = IO_intValue(line,chunkPos,3_pInt) - homogenization_RGC_Ngrains(3,i) = IO_intValue(line,chunkPos,4_pInt) - if (homogenization_Ngrains(section) /= product(homogenization_RGC_Ngrains(1:3,i))) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//HOMOGENIZATION_RGC_label//')') - case ('scalingparameter') - homogenization_RGC_xiAlpha(i) = IO_floatValue(line,chunkPos,2_pInt) - case ('overproportionality') - homogenization_RGC_ciAlpha(i) = IO_floatValue(line,chunkPos,2_pInt) - case ('grainsize') - homogenization_RGC_dAlpha(1,i) = IO_floatValue(line,chunkPos,2_pInt) - homogenization_RGC_dAlpha(2,i) = IO_floatValue(line,chunkPos,3_pInt) - homogenization_RGC_dAlpha(3,i) = IO_floatValue(line,chunkPos,4_pInt) - case ('clusterorientation') - homogenization_RGC_angles(1,i) = IO_floatValue(line,chunkPos,2_pInt) - homogenization_RGC_angles(2,i) = IO_floatValue(line,chunkPos,3_pInt) - homogenization_RGC_angles(3,i) = IO_floatValue(line,chunkPos,4_pInt) - - end select - endif - endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! * assigning cluster orientations - elementLooping: do e = 1_pInt,mesh_NcpElems - if (homogenization_type(mesh_element(3,e)) == HOMOGENIZATION_RGC_ID) then - myInstance = homogenization_typeInstance(mesh_element(3,e)) - if (all (homogenization_RGC_angles(1:3,myInstance) >= 399.9_pReal)) then - homogenization_RGC_orientation(1:3,1:3,1,e) = math_EulerToR(math_sampleRandomOri()) - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - if (microstructure_elemhomo(mesh_element(4,e))) then - homogenization_RGC_orientation(1:3,1:3,i,e) = homogenization_RGC_orientation(1:3,1:3,1,e) - else - homogenization_RGC_orientation(1:3,1:3,i,e) = math_EulerToR(math_sampleRandomOri()) - endif - enddo - else - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - homogenization_RGC_orientation(1:3,1:3,i,e) = & - math_EulerToR(homogenization_RGC_angles(1:3,myInstance)*inRad) - enddo - endif - endif - enddo elementLooping - - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - do i = 1_pInt,maxNinstance - write(6,'(a15,1x,i4,/)') 'instance: ', i - write(6,'(a25,3(1x,i8))') 'cluster size: ',(homogenization_RGC_Ngrains(j,i),j=1_pInt,3_pInt) - write(6,'(a25,1x,e10.3)') 'scaling parameter: ', homogenization_RGC_xiAlpha(i) - write(6,'(a25,1x,e10.3)') 'over-proportionality: ', homogenization_RGC_ciAlpha(i) - write(6,'(a25,3(1x,e10.3))') 'grain size: ',(homogenization_RGC_dAlpha(j,i),j=1_pInt,3_pInt) - write(6,'(a25,3(1x,e10.3))') 'cluster orientation: ',(homogenization_RGC_angles(j,i),j=1_pInt,3_pInt) - enddo - endif -!-------------------------------------------------------------------------------------------------- - initializeInstances: do homog = 1_pInt, material_Nhomogenization - myHomog: if (homogenization_type(homog) == HOMOGENIZATION_RGC_ID) then - NofMyHomog = count(material_homog == homog) - instance = homogenization_typeInstance(homog) - -! * Determine size of postResults array - outputsLoop: do o = 1_pInt, homogenization_RGC_Noutput(instance) - select case(homogenization_RGC_outputID(o,instance)) - case(constitutivework_ID,penaltyenergy_ID,volumediscrepancy_ID, & - averagerelaxrate_ID,maximumrelaxrate_ID) - mySize = 1_pInt - case(ipcoords_ID,magnitudemismatch_ID) - mySize = 3_pInt - case(avgdefgrad_ID,avgfirstpiola_ID) - mySize = 9_pInt - case default - mySize = 0_pInt - end select - - outputFound: if (mySize > 0_pInt) then - homogenization_RGC_sizePostResult(o,instance) = mySize - homogenization_RGC_sizePostResults(instance) = & - homogenization_RGC_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop - - sizeHState = & - 3_pInt*(homogenization_RGC_Ngrains(1,instance)-1_pInt)* & - homogenization_RGC_Ngrains(2,instance)*homogenization_RGC_Ngrains(3,instance) & - + 3_pInt*homogenization_RGC_Ngrains(1,instance)*(homogenization_RGC_Ngrains(2,instance)-1_pInt)* & - homogenization_RGC_Ngrains(3,instance) & - + 3_pInt*homogenization_RGC_Ngrains(1,instance)*homogenization_RGC_Ngrains(2,instance)* & - (homogenization_RGC_Ngrains(3,instance)-1_pInt) & - + 8_pInt ! (1) Average constitutive work, (2-4) Overall mismatch, (5) Average penalty energy, - ! (6) Volume discrepancy, (7) Avg relaxation rate component, (8) Max relaxation rate component - -! allocate state arrays - homogState(homog)%sizeState = sizeHState - homogState(homog)%sizePostResults = homogenization_RGC_sizePostResults(instance) - allocate(homogState(homog)%state0 (sizeHState,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%subState0(sizeHState,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%state (sizeHState,NofMyHomog), source=0.0_pReal) - - endif myHomog - enddo initializeInstances - - - -end subroutine homogenization_RGC_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief partitions the deformation gradient onto the constituents -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_partitionDeformation(F,avgF,ip,el) - use debug, only: & - debug_level, & - debug_homogenization, & - debug_levelExtensive - use mesh, only: & - mesh_element - use material, only: & - homogenization_maxNgrains, & - homogenization_Ngrains,& - homogenization_typeInstance - - implicit none - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned F per grain - real(pReal), dimension (3,3), intent(in) :: avgF !< averaged F - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension (3) :: aVect,nVect - integer(pInt), dimension (4) :: intFace - integer(pInt), dimension (3) :: iGrain3 - integer(pInt) :: homID, iGrain,iFace,i,j - integer(pInt), parameter :: nFace = 6_pInt - -!-------------------------------------------------------------------------------------------------- -! compute the deformation gradient of individual grains due to relaxations - homID = homogenization_typeInstance(mesh_element(3,el)) - F = 0.0_pReal - do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) - iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) - do iFace = 1_pInt,nFace - intFace = homogenization_RGC_getInterface(iFace,iGrain3) ! identifying 6 interfaces of each grain - - aVect = homogenization_RGC_relaxationVector(intFace,homID, ip, el) ! get the relaxation vectors for each interface from global relaxation vector array - - nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the normal of each interface - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) & - 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 - -!-------------------------------------------------------------------------------------------------- -! debugging the grain deformation gradients - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a32,1x,i3)')'Deformation gradient of grain: ',iGrain - do i = 1_pInt,3_pInt - write(6,'(1x,3(e15.8,1x))')(F(i,j,iGrain), j = 1_pInt,3_pInt) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - - enddo - -end subroutine homogenization_RGC_partitionDeformation - - -!-------------------------------------------------------------------------------------------------- -!> @brief update the internal state of the homogenization scheme and tell whether "done" and -! "happy" with result -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) - use debug, only: & - debug_level, & - debug_homogenization,& - debug_levelExtensive, & - debug_e, & - debug_i - use math, only: & - math_invert - use mesh, only: & - mesh_element - use material, only: & - homogenization_maxNgrains, & - homogenization_typeInstance, & - homogState, & - mappingHomogenization, & - homogenization_Ngrains - use numerics, only: & - absTol_RGC, & - relTol_RGC, & - absMax_RGC, & - relMax_RGC, & - pPert_RGC, & - maxdRelax_RGC, & - viscPower_RGC, & - viscModus_RGC, & - refRelaxRate_RGC - - implicit none - - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: & - P,& !< array of P - F,& !< array of F - F0 !< array of initial F - real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffness - real(pReal), dimension (3,3), intent(in) :: avgF !< average F - real(pReal), intent(in) :: dt !< time increment - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - logical, dimension(2) :: homogenization_RGC_updateState - integer(pInt), dimension (4) :: intFaceN,intFaceP,faceID - integer(pInt), dimension (3) :: nGDim,iGr3N,iGr3P,stresLoc - integer(pInt), dimension (2) :: residLoc - integer(pInt) homID,iNum,i,j,nIntFaceTot,iGrN,iGrP,iMun,iFace,k,l,ipert,iGrain,nGrain - real(pReal), dimension (3,3,homogenization_maxNgrains) :: R,pF,pR,D,pD - real(pReal), dimension (3,homogenization_maxNgrains) :: NN,pNN - real(pReal), dimension (3) :: normP,normN,mornP,mornN - real(pReal) :: residMax,stresMax,constitutiveWork,penaltyEnergy,volDiscrep - logical error - - integer(pInt), parameter :: nFace = 6_pInt - - real(pReal), dimension(:,:), allocatable :: tract,jmatrix,jnverse,smatrix,pmatrix,rmatrix - real(pReal), dimension(:), allocatable :: resid,relax,p_relax,p_resid,drelax - - if(abs(dt) < tiny(0.0_pReal)) then ! zero time step - homogenization_RGC_updateState = .true. ! pretend everything is fine and return - return - endif - -!-------------------------------------------------------------------------------------------------- -! get the dimension of the cluster (grains and interfaces) - homID = homogenization_typeInstance(mesh_element(3,el)) - nGDim = homogenization_RGC_Ngrains(1:3,homID) - nGrain = homogenization_Ngrains(mesh_element(3,el)) - nIntFaceTot = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) + nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) & - + nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) - -!-------------------------------------------------------------------------------------------------- -! allocate the size of the global relaxation arrays/jacobian matrices depending on the size of the cluster - allocate(resid(3_pInt*nIntFaceTot), source=0.0_pReal) - allocate(tract(nIntFaceTot,3), source=0.0_pReal) - allocate(relax(3_pInt*nIntFaceTot)); relax= homogState(mappingHomogenization(2,ip,el))% & - state(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) - allocate(drelax(3_pInt*nIntFaceTot)); drelax= homogState(mappingHomogenization(2,ip,el))% & - state(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) - & - homogState(mappingHomogenization(2,ip,el))% & - state0(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) -!-------------------------------------------------------------------------------------------------- -! debugging the obtained state - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Obtained state: ' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,2(e15.8,1x))')homogState(mappingHomogenization(2,ip,el))%state(i,mappingHomogenization(1,ip,el)) - enddo - write(6,*)' ' - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! computing interface mismatch and stress penalty tensor for all interfaces of all grains - call homogenization_RGC_stressPenalty(R,NN,avgF,F,ip,el,homID) - -!-------------------------------------------------------------------------------------------------- -! calculating volume discrepancy and stress penalty related to overall volume discrepancy - call homogenization_RGC_volumePenalty(D,volDiscrep,F,avgF,ip,el) - -!-------------------------------------------------------------------------------------------------- -! debugging the mismatch, stress and penalties of grains - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - do iGrain = 1_pInt,nGrain - write(6,'(1x,a30,1x,i3,1x,a4,3(1x,e15.8))')'Mismatch magnitude of grain(',iGrain,') :',& - NN(1,iGrain),NN(2,iGrain),NN(3,iGrain) - write(6,'(/,1x,a30,1x,i3)')'Stress and penalties of grain: ',iGrain - do i = 1_pInt,3_pInt - write(6,'(1x,3(e15.8,1x),1x,3(e15.8,1x),1x,3(e15.8,1x))')(P(i,j,iGrain), j = 1_pInt,3_pInt), & - (R(i,j,iGrain), j = 1_pInt,3_pInt), & - (D(i,j,iGrain), j = 1_pInt,3_pInt) - enddo - write(6,*)' ' - enddo - !$OMP END CRITICAL (write2out) - endif - -!------------------------------------------------------------------------------------------------ -! computing the residual stress from the balance of traction at all (interior) interfaces - do iNum = 1_pInt,nIntFaceTot - faceID = homogenization_RGC_interface1to4(iNum,homID) ! identifying the interface ID in local coordinate system (4-dimensional index) - -!-------------------------------------------------------------------------------------------------- -! identify the left/bottom/back grain (-|N) - iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate system (3-dimensional index) - iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) - intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) - normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the interface normal - -!-------------------------------------------------------------------------------------------------- -! identify the right/up/front grain (+|P) - iGr3P = iGr3N - iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate system (3-dimensional index) - iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) - intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) - normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the interface normal - -!-------------------------------------------------------------------------------------------------- -! compute the residual of traction at the interface (in local system, 4-dimensional index) - do i = 1_pInt,3_pInt - tract(iNum,i) = sign(viscModus_RGC*(abs(drelax(i+3*(iNum-1_pInt)))/(refRelaxRate_RGC*dt))**viscPower_RGC, & - drelax(i+3*(iNum-1_pInt))) ! contribution from the relaxation viscosity - do j = 1_pInt,3_pInt - tract(iNum,i) = tract(iNum,i) + (P(i,j,iGrP) + R(i,j,iGrP) + D(i,j,iGrP))*normP(j) & ! contribution from material stress P, mismatch penalty R, and volume penalty D projected into the interface - + (P(i,j,iGrN) + R(i,j,iGrN) + D(i,j,iGrN))*normN(j) - resid(i+3_pInt*(iNum-1_pInt)) = tract(iNum,i) ! translate the local residual into global 1-dimensional residual array - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! debugging the residual stress - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30,1x,i3)')'Traction at interface: ',iNum - write(6,'(1x,3(e15.8,1x))')(tract(iNum,j), j = 1_pInt,3_pInt) - write(6,*)' ' - !$OMP END CRITICAL (write2out) - endif - enddo - -!-------------------------------------------------------------------------------------------------- -! convergence check for stress residual - stresMax = maxval(abs(P)) ! get the maximum of first Piola-Kirchhoff (material) stress - stresLoc = int(maxloc(abs(P)),pInt) ! get the location of the maximum stress - residMax = maxval(abs(tract)) ! get the maximum of the residual - residLoc = int(maxloc(abs(tract)),pInt) ! get the position of the maximum residual - -!-------------------------------------------------------------------------------------------------- -! Debugging the convergent criteria - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a)')' ' - write(6,'(1x,a,1x,i2,1x,i4)')'RGC residual check ...',ip,el - write(6,'(1x,a15,1x,e15.8,1x,a7,i3,1x,a12,i2,i2)')'Max stress: ',stresMax, & - '@ grain',stresLoc(3),'in component',stresLoc(1),stresLoc(2) - write(6,'(1x,a15,1x,e15.8,1x,a7,i3,1x,a12,i2)')'Max residual: ',residMax, & - '@ iface',residLoc(1),'in direction',residLoc(2) - flush(6) - !$OMP END CRITICAL (write2out) - endif - - homogenization_RGC_updateState = .false. - -!-------------------------------------------------------------------------------------------------- -! If convergence reached => done and happy - if (residMax < relTol_RGC*stresMax .or. residMax < absTol_RGC) then - homogenization_RGC_updateState = .true. - - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a55,/)')'... done and happy' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! compute/update the state for postResult, i.e., all energy densities computed by time-integration - constitutiveWork = homogState(mappingHomogenization(2,ip,el))%state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) - penaltyEnergy = homogState(mappingHomogenization(2,ip,el))%state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) - do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) ! time-integration loop for the calculating the work and energy - do i = 1_pInt,3_pInt - do j = 1_pInt,3_pInt - constitutiveWork = constitutiveWork + P(i,j,iGrain)*(F(i,j,iGrain) - F0(i,j,iGrain))/real(nGrain,pReal) - penaltyEnergy = penaltyEnergy + R(i,j,iGrain)*(F(i,j,iGrain) - F0(i,j,iGrain))/real(nGrain,pReal) - enddo - enddo - enddo - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) = constitutiveWork ! the bulk mechanical/constitutive work - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+2,mappingHomogenization(1,ip,el)) = sum(NN(1,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e1-direction - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+3,mappingHomogenization(1,ip,el)) = sum(NN(2,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e2-direction - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+4,mappingHomogenization(1,ip,el)) = sum(NN(3,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e3-direction - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) = penaltyEnergy ! the overall penalty energy - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+6,mappingHomogenization(1,ip,el)) = volDiscrep ! the overall volume discrepancy - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+7,mappingHomogenization(1,ip,el)) = & - sum(abs(drelax))/dt/real(3_pInt*nIntFaceTot,pReal) ! the average rate of relaxation vectors - homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+8,mappingHomogenization(1,ip,el)) = maxval(abs(drelax))/dt ! the maximum rate of relaxation vectors - - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30,1x,e15.8)') 'Constitutive work: ',constitutiveWork - write(6,'(1x,a30,3(1x,e15.8))')'Magnitude mismatch: ',sum(NN(1,:))/real(nGrain,pReal), & - sum(NN(2,:))/real(nGrain,pReal), & - sum(NN(3,:))/real(nGrain,pReal) - write(6,'(1x,a30,1x,e15.8)') 'Penalty energy: ',penaltyEnergy - write(6,'(1x,a30,1x,e15.8,/)') 'Volume discrepancy: ',volDiscrep - write(6,'(1x,a30,1x,e15.8)') 'Maximum relaxation rate: ',maxval(abs(drelax))/dt - write(6,'(1x,a30,1x,e15.8,/)') 'Average relaxation rate: ',sum(abs(drelax))/dt/real(3_pInt*nIntFaceTot,pReal) - flush(6) - !$OMP END CRITICAL (write2out) - endif - - deallocate(tract,resid,relax,drelax) - return - -!-------------------------------------------------------------------------------------------------- -! if residual blows-up => done but unhappy - elseif (residMax > relMax_RGC*stresMax .or. residMax > absMax_RGC) then ! try to restart when residual blows up exceeding maximum bound - homogenization_RGC_updateState = [.true.,.false.] ! with direct cut-back - - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a55,/)')'... broken' - flush(6) - !$OMP END CRITICAL (write2out) - endif - - deallocate(tract,resid,relax,drelax) - return - else ! proceed with computing the Jacobian and state update - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a55,/)')'... not yet done' - flush(6) - !$OMP END CRITICAL (write2out) - endif - - endif - -!--------------------------------------------------------------------------------------------------- -! construct the global Jacobian matrix for updating the global relaxation vector array when -! convergence is not yet reached ... - -!-------------------------------------------------------------------------------------------------- -! ... of the constitutive stress tangent, assembled from dPdF or material constitutive model "smatrix" - allocate(smatrix(3*nIntFaceTot,3*nIntFaceTot), source=0.0_pReal) - do iNum = 1_pInt,nIntFaceTot - faceID = homogenization_RGC_interface1to4(iNum,homID) ! assembling of local dPdF into global Jacobian matrix - -!-------------------------------------------------------------------------------------------------- -! identify the left/bottom/back grain (-|N) - iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate sytem - iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate into global grain ID - intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) ! identifying the connecting interface in local coordinate system - normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the interface normal - do iFace = 1_pInt,nFace - intFaceN = homogenization_RGC_getInterface(iFace,iGr3N) ! identifying all interfaces that influence relaxation of the above interface - mornN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get normal of the interfaces - iMun = homogenization_RGC_interface4to1(intFaceN,homID) ! translate the interfaces ID into local 4-dimensional index - if (iMun > 0) then ! get the corresponding tangent - do i=1_pInt,3_pInt; do j=1_pInt,3_pInt; do k=1_pInt,3_pInt; do l=1_pInt,3_pInt - smatrix(3*(iNum-1)+i,3*(iMun-1)+j) = smatrix(3*(iNum-1)+i,3*(iMun-1)+j) + dPdF(i,k,j,l,iGrN)*normN(k)*mornN(l) - enddo;enddo;enddo;enddo -! projecting the material tangent dPdF into the interface -! to obtain the Jacobian matrix contribution of dPdF - endif - enddo - -!-------------------------------------------------------------------------------------------------- -! identify the right/up/front grain (+|P) - iGr3P = iGr3N - iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate sytem - iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate into global grain ID - intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) ! identifying the connecting interface in local coordinate system - normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the interface normal - do iFace = 1_pInt,nFace - intFaceP = homogenization_RGC_getInterface(iFace,iGr3P) ! identifying all interfaces that influence relaxation of the above interface - mornP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get normal of the interfaces - iMun = homogenization_RGC_interface4to1(intFaceP,homID) ! translate the interfaces ID into local 4-dimensional index - if (iMun > 0_pInt) then ! get the corresponding tangent - do i=1_pInt,3_pInt; do j=1_pInt,3_pInt; do k=1_pInt,3_pInt; do l=1_pInt,3_pInt - smatrix(3*(iNum-1)+i,3*(iMun-1)+j) = smatrix(3*(iNum-1)+i,3*(iMun-1)+j) + dPdF(i,k,j,l,iGrP)*normP(k)*mornP(l) - enddo;enddo;enddo;enddo - endif - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! debugging the global Jacobian matrix of stress tangent - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Jacobian matrix of stress' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,100(e11.4,1x))')(smatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! ... of the stress penalty tangent (mismatch penalty and volume penalty, computed using numerical -! perturbation method) "pmatrix" - allocate(pmatrix(3*nIntFaceTot,3*nIntFaceTot), source=0.0_pReal) - allocate(p_relax(3*nIntFaceTot), source=0.0_pReal) - allocate(p_resid(3*nIntFaceTot), source=0.0_pReal) - do ipert = 1_pInt,3_pInt*nIntFaceTot - p_relax = relax - p_relax(ipert) = relax(ipert) + pPert_RGC ! perturb the relaxation vector - homogState(mappingHomogenization(2,ip,el))%state(1:3*nIntFaceTot,mappingHomogenization(1,ip,el)) = p_relax - call homogenization_RGC_grainDeformation(pF,avgF,ip,el) ! compute the grains deformation from perturbed state - call homogenization_RGC_stressPenalty(pR,pNN,avgF,pF,ip,el,homID) ! compute stress penalty due to interface mismatch from perturbed state - call homogenization_RGC_volumePenalty(pD,volDiscrep,pF,avgF,ip,el) ! compute stress penalty due to volume discrepancy from perturbed state - -!-------------------------------------------------------------------------------------------------- -! computing the global stress residual array from the perturbed state - p_resid = 0.0_pReal - do iNum = 1_pInt,nIntFaceTot - faceID = homogenization_RGC_interface1to4(iNum,homID) ! identifying the interface ID in local coordinate system (4-dimensional index) - -!-------------------------------------------------------------------------------------------------- -! identify the left/bottom/back grain (-|N) - iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate system (3-dimensional index) - iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) - intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) ! identifying the interface ID of the grain - normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the corresponding interface normal - -!-------------------------------------------------------------------------------------------------- -! identify the right/up/front grain (+|P) - iGr3P = iGr3N - iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate system (3-dimensional index) - iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) - intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) ! identifying the interface ID of the grain - normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the corresponding normal - -!-------------------------------------------------------------------------------------------------- -! compute the residual stress (contribution of mismatch and volume penalties) from perturbed state -! at all interfaces - do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt - p_resid(i+3*(iNum-1)) = p_resid(i+3*(iNum-1)) + (pR(i,j,iGrP) - R(i,j,iGrP))*normP(j) & - + (pR(i,j,iGrN) - R(i,j,iGrN))*normN(j) & - + (pD(i,j,iGrP) - D(i,j,iGrP))*normP(j) & - + (pD(i,j,iGrN) - D(i,j,iGrN))*normN(j) - enddo; enddo - enddo - pmatrix(:,ipert) = p_resid/pPert_RGC - enddo - -!-------------------------------------------------------------------------------------------------- -! debugging the global Jacobian matrix of penalty tangent - if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Jacobian matrix of penalty' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,100(e11.4,1x))')(pmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! ... of the numerical viscosity traction "rmatrix" - allocate(rmatrix(3*nIntFaceTot,3*nIntFaceTot),source=0.0_pReal) - forall (i=1_pInt:3_pInt*nIntFaceTot) & - rmatrix(i,i) = viscModus_RGC*viscPower_RGC/(refRelaxRate_RGC*dt)* & ! tangent due to numerical viscosity traction appears - (abs(drelax(i))/(refRelaxRate_RGC*dt))**(viscPower_RGC - 1.0_pReal) ! only in the main diagonal term - - - -!-------------------------------------------------------------------------------------------------- -! debugging the global Jacobian matrix of numerical viscosity tangent - if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Jacobian matrix of penalty' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,100(e11.4,1x))')(rmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! The overall Jacobian matrix summarizing contributions of smatrix, pmatrix, rmatrix - allocate(jmatrix(3*nIntFaceTot,3*nIntFaceTot)); jmatrix = smatrix + pmatrix + rmatrix - - if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Jacobian matrix (total)' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,100(e11.4,1x))')(jmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! computing the update of the state variable (relaxation vectors) using the Jacobian matrix - allocate(jnverse(3_pInt*nIntFaceTot,3_pInt*nIntFaceTot),source=0.0_pReal) - call math_invert(size(jmatrix,1),jmatrix,jnverse,error) ! Compute the inverse of the overall Jacobian matrix - -!-------------------------------------------------------------------------------------------------- -! debugging the inverse Jacobian matrix - if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Jacobian inverse' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,100(e11.4,1x))')(jnverse(i,j), j = 1_pInt,3_pInt*nIntFaceTot) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! calculate the state update (global relaxation vectors) for the next Newton-Raphson iteration - drelax = 0.0_pReal - do i = 1_pInt,3_pInt*nIntFaceTot - do j = 1_pInt,3_pInt*nIntFaceTot - drelax(i) = drelax(i) - jnverse(i,j)*resid(j) ! Calculate the correction for the state variable - enddo - enddo - relax = relax + drelax ! Updateing the state variable for the next iteration - homogState(mappingHomogenization(2,ip,el))%state(1:3*nIntFaceTot,mappingHomogenization(1,ip,el)) = relax - if (any(abs(drelax) > maxdRelax_RGC)) then ! Forcing cutback when the incremental change of relaxation vector becomes too large - homogenization_RGC_updateState = [.true.,.false.] - !$OMP CRITICAL (write2out) - write(6,'(1x,a,1x,i3,1x,a,1x,i3,1x,a)')'RGC_updateState: ip',ip,'| el',el,'enforces cutback' - write(6,'(1x,a,1x,e15.8)')'due to large relaxation change =',maxval(abs(drelax)) - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! debugging the return state - if (iand(debug_homogenization, debug_levelExtensive) > 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30)')'Returned state: ' - do i = 1_pInt,3_pInt*nIntFaceTot - write(6,'(1x,2(e15.8,1x))')homogState(mappingHomogenization(2,ip,el))%state(i,mappingHomogenization(1,ip,el)) - enddo - write(6,*)' ' - flush(6) - !$OMP END CRITICAL (write2out) - endif - - deallocate(tract,resid,jmatrix,jnverse,relax,drelax,pmatrix,smatrix,p_relax,p_resid) - -end function homogenization_RGC_updateState - - -!-------------------------------------------------------------------------------------------------- -!> @brief derive average stress and stiffness from constituent quantities -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,el) - use debug, only: & - debug_level, & - debug_homogenization,& - debug_levelExtensive - use mesh, only: mesh_element - use material, only: & - homogenization_maxNgrains, & - homogenization_Ngrains, & - homogenization_typeInstance - use math, only: math_Plain3333to99 - - implicit none - 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 (3,3,homogenization_maxNgrains), intent(in) :: P !< array of current grain stresses - real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffnesses - integer(pInt), intent(in) :: el !< element number - real(pReal), dimension (9,9) :: dPdF99 - - integer(pInt) :: homID, i, j, Ngrains, iGrain - - homID = homogenization_typeInstance(mesh_element(3,el)) - Ngrains = homogenization_Ngrains(mesh_element(3,el)) - -!-------------------------------------------------------------------------------------------------- -! debugging the grain tangent - if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then - !$OMP CRITICAL (write2out) - do iGrain = 1_pInt,Ngrains - dPdF99 = math_Plain3333to99(dPdF(1:3,1:3,1:3,1:3,iGrain)) - write(6,'(1x,a30,1x,i3)')'Stress tangent of grain: ',iGrain - do i = 1_pInt,9_pInt - write(6,'(1x,(e15.8,1x))') (dPdF99(i,j), j = 1_pInt,9_pInt) - enddo - write(6,*)' ' - enddo - flush(6) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! computing the average first Piola-Kirchhoff stress P and the average tangent dPdF - avgP = sum(P,3)/real(Ngrains,pReal) - dAvgPdAvgF = sum(dPdF,5)/real(Ngrains,pReal) - -end subroutine homogenization_RGC_averageStressAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of homogenization results for post file inclusion -!-------------------------------------------------------------------------------------------------- -pure function homogenization_RGC_postResults(ip,el,avgP,avgF) - use mesh, only: & - mesh_element, & - mesh_ipCoordinates - use material, only: & - homogenization_typeInstance,& - homogState, & - mappingHomogenization, & - homogenization_Noutput - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3), intent(in) :: & - avgP, & !< average stress at material point - avgF !< average deformation gradient at material point - - integer(pInt) homID,o,c,nIntFaceTot - real(pReal), dimension(homogenization_RGC_sizePostResults(homogenization_typeInstance(mesh_element(3,el)))) :: & - homogenization_RGC_postResults - - homID = homogenization_typeInstance(mesh_element(3,el)) - nIntFaceTot=(homogenization_RGC_Ngrains(1,homID)-1_pInt)*homogenization_RGC_Ngrains(2,homID)*homogenization_RGC_Ngrains(3,homID)& - + homogenization_RGC_Ngrains(1,homID)*(homogenization_RGC_Ngrains(2,homID)-1_pInt)*homogenization_RGC_Ngrains(3,homID)& - + homogenization_RGC_Ngrains(1,homID)*homogenization_RGC_Ngrains(2,homID)*(homogenization_RGC_Ngrains(3,homID)-1_pInt) - - c = 0_pInt - homogenization_RGC_postResults = 0.0_pReal - do o = 1_pInt,homogenization_Noutput(mesh_element(3,el)) - select case(homogenization_RGC_outputID(o,homID)) - case (avgdefgrad_ID) - homogenization_RGC_postResults(c+1_pInt:c+9_pInt) = reshape(avgF,[9]) - c = c + 9_pInt - case (avgfirstpiola_ID) - homogenization_RGC_postResults(c+1_pInt:c+9_pInt) = reshape(avgP,[9]) - c = c + 9_pInt - case (ipcoords_ID) - homogenization_RGC_postResults(c+1_pInt:c+3_pInt) = mesh_ipCoordinates(1:3,ip,el) ! current ip coordinates - c = c + 3_pInt - case (constitutivework_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) - c = c + 1_pInt - case (magnitudemismatch_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+2,mappingHomogenization(1,ip,el)) - homogenization_RGC_postResults(c+2) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+3,mappingHomogenization(1,ip,el)) - homogenization_RGC_postResults(c+3) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+4,mappingHomogenization(1,ip,el)) - c = c + 3_pInt - case (penaltyenergy_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) - c = c + 1_pInt - case (volumediscrepancy_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+6,mappingHomogenization(1,ip,el)) - c = c + 1_pInt - case (averagerelaxrate_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+7,mappingHomogenization(1,ip,el)) - c = c + 1_pInt - case (maximumrelaxrate_ID) - homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & - state(3*nIntFaceTot+8,mappingHomogenization(1,ip,el)) - c = c + 1_pInt - end select - enddo - -end function homogenization_RGC_postResults - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate stress-like penalty due to deformation mismatch -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_stressPenalty(rPen,nMis,avgF,fDef,ip,el,homID) - use debug, only: & - debug_level, & - debug_homogenization,& - debug_levelExtensive, & - debug_e, & - debug_i - use mesh, only: & - mesh_element - use constitutive, only: & - constitutive_homogenizedC - use math, only: & - math_civita - use material, only: & - homogenization_maxNgrains,& - homogenization_Ngrains - use numerics, only: & - xSmoo_RGC - - implicit none - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: rPen !< stress-like penalty - real(pReal), dimension (3,homogenization_maxNgrains), intent(out) :: nMis !< total amount of mismatch - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: fDef !< deformation gradients - real(pReal), dimension (3,3), intent(in) :: avgF !< initial effective stretch tensor - integer(pInt), intent(in) :: ip,el - integer(pInt), dimension (4) :: intFace - integer(pInt), dimension (3) :: iGrain3,iGNghb3,nGDim - real(pReal), dimension (3,3) :: gDef,nDef - real(pReal), dimension (3) :: nVect,surfCorr - real(pReal), dimension (2) :: Gmoduli - integer(pInt) :: homID,iGrain,iGNghb,iFace,i,j,k,l - real(pReal) :: muGrain,muGNghb,nDefNorm,bgGrain,bgGNghb - - integer(pInt), parameter :: nFace = 6_pInt - real(pReal), parameter :: nDefToler = 1.0e-10_pReal - - nGDim = homogenization_RGC_Ngrains(1:3,homID) - rPen = 0.0_pReal - nMis = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! get the correction factor the modulus of penalty stress representing the evolution of area of -! the interfaces due to deformations - surfCorr = homogenization_RGC_surfaceCorrection(avgF,ip,el) - -!-------------------------------------------------------------------------------------------------- -! debugging the surface correction factor - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a20,2(1x,i3))')'Correction factor: ',ip,el - write(6,'(1x,3(e11.4,1x))')(surfCorr(i), i = 1,3) - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! computing the mismatch and penalty stress tensor of all grains - do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) - Gmoduli = homogenization_RGC_equivalentModuli(iGrain,ip,el) - muGrain = Gmoduli(1) ! collecting the equivalent shear modulus of grain - bgGrain = Gmoduli(2) ! and the lengthh of Burgers vector - iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) ! get the grain ID in local 3-dimensional index (x,y,z)-position - -!* Looping over all six interfaces of each grain - do iFace = 1_pInt,nFace - intFace = homogenization_RGC_getInterface(iFace,iGrain3) ! get the 4-dimensional index of the interface in local numbering system of the grain - nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the interface normal - iGNghb3 = iGrain3 ! identify the neighboring grain across the interface - iGNghb3(abs(intFace(1))) = iGNghb3(abs(intFace(1))) + int(real(intFace(1),pReal)/real(abs(intFace(1)),pReal),pInt) - if (iGNghb3(1) < 1) iGNghb3(1) = nGDim(1) ! with periodicity along e1 direction - if (iGNghb3(1) > nGDim(1)) iGNghb3(1) = 1_pInt - if (iGNghb3(2) < 1) iGNghb3(2) = nGDim(2) ! with periodicity along e2 direction - if (iGNghb3(2) > nGDim(2)) iGNghb3(2) = 1_pInt - if (iGNghb3(3) < 1) iGNghb3(3) = nGDim(3) ! with periodicity along e3 direction - if (iGNghb3(3) > nGDim(3)) iGNghb3(3) = 1_pInt - iGNghb = homogenization_RGC_grain3to1(iGNghb3,homID) ! get the ID of the neighboring grain - Gmoduli = homogenization_RGC_equivalentModuli(iGNghb,ip,el) ! collecting the shear modulus and Burgers vector of the neighbor - muGNghb = Gmoduli(1) - bgGNghb = Gmoduli(2) - gDef = 0.5_pReal*(fDef(1:3,1:3,iGNghb) - fDef(1:3,1:3,iGrain)) ! compute the difference/jump in deformation gradeint across the neighbor - -!-------------------------------------------------------------------------------------------------- -! compute the mismatch tensor of all interfaces - nDefNorm = 0.0_pReal - nDef = 0.0_pReal - do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt - do k = 1_pInt,3_pInt; do l = 1_pInt,3_pInt - nDef(i,j) = nDef(i,j) - nVect(k)*gDef(i,l)*math_civita(j,k,l) ! compute the interface mismatch tensor from the jump of deformation gradient - enddo; enddo - nDefNorm = nDefNorm + nDef(i,j)*nDef(i,j) ! compute the norm of the mismatch tensor - 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) - -!-------------------------------------------------------------------------------------------------- -! debuggin the mismatch tensor - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a20,i2,1x,a20,1x,i3)')'Mismatch to face: ',intFace(1),'neighbor grain: ',iGNghb - do i = 1,3 - write(6,'(1x,3(e11.4,1x))')(nDef(i,j), j = 1,3) - enddo - write(6,'(1x,a20,e11.4)')'with magnitude: ',nDefNorm - !$OMP END CRITICAL (write2out) - endif - -!-------------------------------------------------------------------------------------------------- -! compute the stress penalty of all interfaces - do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt - do k = 1_pInt,3_pInt; do l = 1_pInt,3_pInt - rPen(i,j,iGrain) = rPen(i,j,iGrain) + 0.5_pReal*(muGrain*bgGrain + muGNghb*bgGNghb)*homogenization_RGC_xiAlpha(homID) & - *surfCorr(abs(intFace(1)))/homogenization_RGC_dAlpha(abs(intFace(1)),homID) & - *cosh(homogenization_RGC_ciAlpha(homID)*nDefNorm) & - *0.5_pReal*nVect(l)*nDef(i,k)/nDefNorm*math_civita(k,l,j) & - *tanh(nDefNorm/xSmoo_RGC) - enddo; enddo - enddo; enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! debugging the stress-like penalty - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a20,i2)')'Penalty of grain: ',iGrain - do i = 1,3 - write(6,'(1x,3(e11.4,1x))')(rPen(i,j,iGrain), j = 1,3) - enddo - !$OMP END CRITICAL (write2out) - endif - - enddo - -end subroutine homogenization_RGC_stressPenalty - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate stress-like penalty due to volume discrepancy -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_volumePenalty(vPen,vDiscrep,fDef,fAvg,ip,el) - use debug, only: & - debug_level, & - debug_homogenization,& - debug_levelExtensive, & - debug_e, & - debug_i - use mesh, only: & - mesh_element - use math, only: & - math_det33, & - math_inv33 - use material, only: & - homogenization_maxNgrains,& - homogenization_Ngrains - use numerics, only: & - maxVolDiscr_RGC,& - volDiscrMod_RGC,& - volDiscrPow_RGC - - implicit none - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: vPen ! stress-like penalty due to volume - real(pReal), intent(out) :: vDiscrep ! total volume discrepancy - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: fDef ! deformation gradients - real(pReal), dimension (3,3), intent(in) :: fAvg ! overall deformation gradient - integer(pInt), intent(in) :: ip,& ! integration point - el - real(pReal), dimension (homogenization_maxNgrains) :: gVol - integer(pInt) :: iGrain,nGrain,i,j - - nGrain = homogenization_Ngrains(mesh_element(3,el)) - -!-------------------------------------------------------------------------------------------------- -! compute the volumes of grains and of cluster - vDiscrep = math_det33(fAvg) ! compute the volume of the cluster - do iGrain = 1_pInt,nGrain - gVol(iGrain) = math_det33(fDef(1:3,1:3,iGrain)) ! compute the volume of individual grains - vDiscrep = vDiscrep - gVol(iGrain)/real(nGrain,pReal) ! calculate the difference/dicrepancy between - ! the volume of the cluster and the the total volume of grains - enddo - -!-------------------------------------------------------------------------------------------------- -! calculate the stress and penalty due to volume discrepancy - vPen = 0.0_pReal - do iGrain = 1_pInt,nGrain - vPen(:,:,iGrain) = -1.0_pReal/real(nGrain,pReal)*volDiscrMod_RGC*volDiscrPow_RGC/maxVolDiscr_RGC* & - sign((abs(vDiscrep)/maxVolDiscr_RGC)**(volDiscrPow_RGC - 1.0),vDiscrep)* & - gVol(iGrain)*transpose(math_inv33(fDef(:,:,iGrain))) - -!-------------------------------------------------------------------------------------------------- -! debugging the stress-like penalty - if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & - .and. debug_e == el .and. debug_i == ip) then - !$OMP CRITICAL (write2out) - write(6,'(1x,a30,i2)')'Volume penalty of grain: ',iGrain - do i = 1,3 - write(6,'(1x,3(e11.4,1x))')(vPen(i,j,iGrain), j = 1,3) - enddo - !$OMP END CRITICAL (write2out) - endif - enddo - -end subroutine homogenization_RGC_volumePenalty - - -!-------------------------------------------------------------------------------------------------- -!> @brief compute the correction factor accouted for surface evolution (area change) due to -! deformation -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_surfaceCorrection(avgF,ip,el) - use math, only: & - math_invert33, & - math_mul33x33 - - implicit none - real(pReal), dimension(3) :: homogenization_RGC_surfaceCorrection - real(pReal), dimension(3,3), intent(in) :: avgF !< average F - integer(pInt), intent(in) :: ip,& !< integration point number - el !< element number - real(pReal), dimension(3,3) :: invC,avgC - real(pReal), dimension(3) :: nVect - real(pReal) :: detF - integer(pInt), dimension(4) :: intFace - integer(pInt) :: i,j,iBase - logical :: error - - avgC = math_mul33x33(transpose(avgF),avgF) - call math_invert33(avgC,invC,detF,error) - homogenization_RGC_surfaceCorrection = 0.0_pReal - do iBase = 1_pInt,3_pInt - intFace = [iBase,1_pInt,1_pInt,1_pInt] - nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the normal of the interface - do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt - homogenization_RGC_surfaceCorrection(iBase) = & ! compute the component of (the inverse of) the stretch in the direction of the normal - homogenization_RGC_surfaceCorrection(iBase) + invC(i,j)*nVect(i)*nVect(j) - enddo; enddo - homogenization_RGC_surfaceCorrection(iBase) = & ! get the surface correction factor (area contraction/enlargement) - sqrt(homogenization_RGC_surfaceCorrection(iBase))*detF - enddo - -end function homogenization_RGC_surfaceCorrection - - -!-------------------------------------------------------------------------------------------------- -!> @brief compute the equivalent shear and bulk moduli from the elasticity tensor -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_equivalentModuli(grainID,ip,el) - use constitutive, only: & - constitutive_homogenizedC - - implicit none - integer(pInt), intent(in) :: & - grainID,& - ip, & !< integration point number - el !< element number - real(pReal), dimension (6,6) :: elasTens - real(pReal), dimension(2) :: homogenization_RGC_equivalentModuli - 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 - homogenization_RGC_equivalentModuli(1) = 0.2_pReal*(cEquiv_11 - cEquiv_12) + 0.6_pReal*cEquiv_44 - -!-------------------------------------------------------------------------------------------------- -! obtain the length of Burgers vector (could be model dependend) - homogenization_RGC_equivalentModuli(2) = 2.5e-10_pReal - -end function homogenization_RGC_equivalentModuli - - -!-------------------------------------------------------------------------------------------------- -!> @brief collect relaxation vectors of an interface -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_relaxationVector(intFace,homID, ip, el) - use material, only: & - homogState, & - mappingHomogenization - - implicit none - integer(pInt), intent(in) :: ip, el - real(pReal), dimension (3) :: homogenization_RGC_relaxationVector - integer(pInt), dimension (4), intent(in) :: intFace !< set of interface ID in 4D array (normal and position) - integer(pInt), dimension (3) :: nGDim - integer(pInt) :: & - iNum, & - homID !< homogenization ID - -!-------------------------------------------------------------------------------------------------- -! collect the interface relaxation vector from the global state array - homogenization_RGC_relaxationVector = 0.0_pReal - nGDim = homogenization_RGC_Ngrains(1:3,homID) - iNum = homogenization_RGC_interface4to1(intFace,homID) ! identify the position of the interface in global state array - if (iNum > 0_pInt) homogenization_RGC_relaxationVector = homogState(mappingHomogenization(2,ip,el))% & - state((3*iNum-2):(3*iNum),mappingHomogenization(1,ip,el)) ! get the corresponding entries - -end function homogenization_RGC_relaxationVector - - -!-------------------------------------------------------------------------------------------------- -!> @brief identify the normal of an interface -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_interfaceNormal(intFace,ip,el) - use debug, only: & - debug_homogenization,& - debug_levelExtensive - use math, only: & - math_mul33x3 - - implicit none - real(pReal), dimension (3) :: homogenization_RGC_interfaceNormal - integer(pInt), dimension (4), intent(in) :: intFace !< interface ID in 4D array (normal and position) - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - integer(pInt) :: nPos - -!-------------------------------------------------------------------------------------------------- -! get the normal of the interface, identified from the value of intFace(1) - homogenization_RGC_interfaceNormal = 0.0_pReal - nPos = abs(intFace(1)) ! identify the position of the interface in global state array - homogenization_RGC_interfaceNormal(nPos) = real(intFace(1)/abs(intFace(1)),pReal) ! get the normal vector w.r.t. cluster axis - - homogenization_RGC_interfaceNormal = & - math_mul33x3(homogenization_RGC_orientation(1:3,1:3,ip,el),homogenization_RGC_interfaceNormal) - ! map the normal vector into sample coordinate system (basis) - -end function homogenization_RGC_interfaceNormal - - -!-------------------------------------------------------------------------------------------------- -!> @brief collect six faces of a grain in 4D (normal and position) -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_getInterface(iFace,iGrain3) - - implicit none - integer(pInt), dimension (4) :: homogenization_RGC_getInterface - integer(pInt), dimension (3), intent(in) :: iGrain3 !< grain ID in 3D array - integer(pInt), intent(in) :: iFace !< face index (1..6) mapped like (-e1,-e2,-e3,+e1,+e2,+e3) or iDir = (-1,-2,-3,1,2,3) - integer(pInt) :: iDir - -!* Direction of interface normal - iDir = (int(real(iFace-1_pInt,pReal)/2.0_pReal,pInt)+1_pInt)*(-1_pInt)**iFace - homogenization_RGC_getInterface(1) = iDir - -!-------------------------------------------------------------------------------------------------- -! identify the interface position by the direction of its normal - homogenization_RGC_getInterface(2:4) = iGrain3 - if (iDir < 0_pInt) & ! to have a correlation with coordinate/position in real space - homogenization_RGC_getInterface(1_pInt-iDir) = homogenization_RGC_getInterface(1_pInt-iDir)-1_pInt - -end function homogenization_RGC_getInterface - -!-------------------------------------------------------------------------------------------------- -!> @brief map grain ID from in 1D (global array) to in 3D (local position) -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_grain1to3(grain1,homID) - - implicit none - integer(pInt), dimension (3) :: homogenization_RGC_grain1to3 - integer(pInt), intent(in) :: & - grain1,& !< grain ID in 1D array - homID !< homogenization ID - integer(pInt), dimension (3) :: nGDim - -!-------------------------------------------------------------------------------------------------- -! get the grain position - nGDim = homogenization_RGC_Ngrains(1:3,homID) - homogenization_RGC_grain1to3(3) = 1_pInt+(grain1-1_pInt)/(nGDim(1)*nGDim(2)) - homogenization_RGC_grain1to3(2) = 1_pInt+mod((grain1-1_pInt)/nGDim(1),nGDim(2)) - homogenization_RGC_grain1to3(1) = 1_pInt+mod((grain1-1_pInt),nGDim(1)) - -end function homogenization_RGC_grain1to3 - - -!-------------------------------------------------------------------------------------------------- -!> @brief map grain ID from in 3D (local position) to in 1D (global array) -!-------------------------------------------------------------------------------------------------- -pure function homogenization_RGC_grain3to1(grain3,homID) - - implicit none - integer(pInt), dimension (3), intent(in) :: grain3 !< grain ID in 3D array (pos.x,pos.y,pos.z) - integer(pInt) :: homogenization_RGC_grain3to1 - integer(pInt), dimension (3) :: nGDim - integer(pInt), intent(in) :: homID ! homogenization ID - -!-------------------------------------------------------------------------------------------------- -! get the grain ID - nGDim = homogenization_RGC_Ngrains(1:3,homID) - homogenization_RGC_grain3to1 = grain3(1) + nGDim(1)*(grain3(2)-1_pInt) + nGDim(1)*nGDim(2)*(grain3(3)-1_pInt) - -end function homogenization_RGC_grain3to1 - - -!-------------------------------------------------------------------------------------------------- -!> @brief maps interface ID from 4D (normal and local position) into 1D (global array) -!-------------------------------------------------------------------------------------------------- -integer(pInt) pure function homogenization_RGC_interface4to1(iFace4D, homID) - - implicit none - integer(pInt), dimension (4), intent(in) :: iFace4D !< interface ID in 4D array (n.dir,pos.x,pos.y,pos.z) - integer(pInt), dimension (3) :: nGDim,nIntFace - integer(pInt), intent(in) :: homID !< homogenization ID - - nGDim = homogenization_RGC_Ngrains(1:3,homID) - -!-------------------------------------------------------------------------------------------------- -! compute the total number of interfaces, which ... - nIntFace(1) = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) ! ... normal //e1 - nIntFace(2) = nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) ! ... normal //e2 - nIntFace(3) = nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) ! ... normal //e3 - - homogenization_RGC_interface4to1 = -1_pInt - -!-------------------------------------------------------------------------------------------------- -! get the corresponding interface ID in 1D global array - if (abs(iFace4D(1)) == 1_pInt) then ! interface with normal //e1 - homogenization_RGC_interface4to1 = iFace4D(3) + nGDim(2)*(iFace4D(4)-1_pInt) & - + nGDim(2)*nGDim(3)*(iFace4D(2)-1_pInt) - if ((iFace4D(2) == 0_pInt) .or. (iFace4D(2) == nGDim(1))) homogenization_RGC_interface4to1 = 0_pInt - elseif (abs(iFace4D(1)) == 2_pInt) then ! interface with normal //e2 - homogenization_RGC_interface4to1 = iFace4D(4) + nGDim(3)*(iFace4D(2)-1_pInt) & - + nGDim(3)*nGDim(1)*(iFace4D(3)-1_pInt) + nIntFace(1) - if ((iFace4D(3) == 0_pInt) .or. (iFace4D(3) == nGDim(2))) homogenization_RGC_interface4to1 = 0_pInt - elseif (abs(iFace4D(1)) == 3_pInt) then ! interface with normal //e3 - homogenization_RGC_interface4to1 = iFace4D(2) + nGDim(1)*(iFace4D(3)-1_pInt) & - + nGDim(1)*nGDim(2)*(iFace4D(4)-1_pInt) + nIntFace(1) + nIntFace(2) - if ((iFace4D(4) == 0_pInt) .or. (iFace4D(4) == nGDim(3))) homogenization_RGC_interface4to1 = 0_pInt - endif - -end function homogenization_RGC_interface4to1 - - -!-------------------------------------------------------------------------------------------------- -!> @brief maps interface ID from 1D (global array) into 4D (normal and local position) -!-------------------------------------------------------------------------------------------------- -function homogenization_RGC_interface1to4(iFace1D, homID) - - implicit none - integer(pInt), dimension (4) :: homogenization_RGC_interface1to4 - integer(pInt), intent(in) :: iFace1D !< interface ID in 1D array - integer(pInt), dimension (3) :: nGDim,nIntFace - integer(pInt), intent(in) :: homID !< homogenization ID - - nGDim = homogenization_RGC_Ngrains(:,homID) - -!-------------------------------------------------------------------------------------------------- -! compute the total number of interfaces, which ... - nIntFace(1) = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) ! ... normal //e1 - nIntFace(2) = nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) ! ... normal //e2 - nIntFace(3) = nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) ! ... normal //e3 - -!-------------------------------------------------------------------------------------------------- -! get the corresponding interface ID in 4D (normal and local position) - if (iFace1D > 0 .and. iFace1D <= nIntFace(1)) then ! interface with normal //e1 - homogenization_RGC_interface1to4(1) = 1_pInt - homogenization_RGC_interface1to4(3) = mod((iFace1D-1_pInt),nGDim(2))+1_pInt - homogenization_RGC_interface1to4(4) = mod(& - int(& - real(iFace1D-1_pInt,pReal)/& - real(nGDim(2),pReal)& - ,pInt)& - ,nGDim(3))+1_pInt - homogenization_RGC_interface1to4(2) = int(& - real(iFace1D-1_pInt,pReal)/& - real(nGDim(2),pReal)/& - real(nGDim(3),pReal)& - ,pInt)+1_pInt - elseif (iFace1D > nIntFace(1) .and. iFace1D <= (nIntFace(2) + nIntFace(1))) then ! interface with normal //e2 - homogenization_RGC_interface1to4(1) = 2_pInt - homogenization_RGC_interface1to4(4) = mod((iFace1D-nIntFace(1)-1_pInt),nGDim(3))+1_pInt - homogenization_RGC_interface1to4(2) = mod(& - int(& - real(iFace1D-nIntFace(1)-1_pInt,pReal)/& - real(nGDim(3),pReal)& - ,pInt)& - ,nGDim(1))+1_pInt - homogenization_RGC_interface1to4(3) = int(& - real(iFace1D-nIntFace(1)-1_pInt,pReal)/& - real(nGDim(3),pReal)/& - real(nGDim(1),pReal)& - ,pInt)+1_pInt - elseif (iFace1D > nIntFace(2) + nIntFace(1) .and. iFace1D <= (nIntFace(3) + nIntFace(2) + nIntFace(1))) then ! interface with normal //e3 - homogenization_RGC_interface1to4(1) = 3_pInt - homogenization_RGC_interface1to4(2) = mod((iFace1D-nIntFace(2)-nIntFace(1)-1_pInt),nGDim(1))+1_pInt - homogenization_RGC_interface1to4(3) = mod(& - int(& - real(iFace1D-nIntFace(2)-nIntFace(1)-1_pInt,pReal)/& - real(nGDim(1),pReal)& - ,pInt)& - ,nGDim(2))+1_pInt - homogenization_RGC_interface1to4(4) = int(& - real(iFace1D-nIntFace(2)-nIntFace(1)-1_pInt,pReal)/& - real(nGDim(1),pReal)/& - real(nGDim(2),pReal)& - ,pInt)+1_pInt - endif - -end function homogenization_RGC_interface1to4 - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculating the grain deformation gradient (the same with -! homogenization_RGC_partionDeformation, but used only for perturbation scheme) -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_RGC_grainDeformation(F, avgF, ip, el) - use mesh, only: & - mesh_element - use material, only: & - homogenization_maxNgrains,& - homogenization_Ngrains, & - homogenization_typeInstance - - implicit none - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned F per grain - real(pReal), dimension (3,3), intent(in) :: avgF !< - integer(pInt), intent(in) :: & - el, & !< element number - ip !< integration point number - real(pReal), dimension (3) :: aVect,nVect - integer(pInt), dimension (4) :: intFace - integer(pInt), dimension (3) :: iGrain3 - integer(pInt) :: homID, iGrain,iFace,i,j - integer(pInt), parameter :: nFace = 6_pInt - -!-------------------------------------------------------------------------------------------------- -! compute the deformation gradient of individual grains due to relaxations - homID = homogenization_typeInstance(mesh_element(3,el)) - F = 0.0_pReal - do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) - iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) - do iFace = 1_pInt,nFace - intFace = homogenization_RGC_getInterface(iFace,iGrain3) - aVect = homogenization_RGC_relaxationVector(intFace,homID, ip, el) - nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) & - F(i,j,iGrain) = F(i,j,iGrain) + aVect(i)*nVect(j) ! effective relaxations - enddo - F(1:3,1:3,iGrain) = F(1:3,1:3,iGrain) + avgF ! relaxed deformation gradient - enddo - -end subroutine homogenization_RGC_grainDeformation - -end module homogenization_RGC diff --git a/code/homogenization_isostrain.f90 b/code/homogenization_isostrain.f90 deleted file mode 100644 index 083107d9f..000000000 --- a/code/homogenization_isostrain.f90 +++ /dev/null @@ -1,317 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Isostrain (full constraint Taylor assuption) homogenization scheme -!-------------------------------------------------------------------------------------------------- -module homogenization_isostrain - use prec, only: & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - homogenization_isostrain_sizePostResults - integer(pInt), dimension(:,:), allocatable, target, public :: & - homogenization_isostrain_sizePostResult - - character(len=64), dimension(:,:), allocatable, target, public :: & - homogenization_isostrain_output !< name of each post result output - integer(pInt), dimension(:), allocatable, target, public :: & - homogenization_isostrain_Noutput !< number of outputs per homog instance - integer(pInt), dimension(:), allocatable, private :: & - homogenization_isostrain_Ngrains - enum, bind(c) - enumerator :: undefined_ID, & - nconstituents_ID, & - ipcoords_ID, & - avgdefgrad_ID, & - avgfirstpiola_ID - end enum - enum, bind(c) - enumerator :: parallel_ID, & - average_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - homogenization_isostrain_outputID !< ID of each post result output - integer(kind(average_ID)), dimension(:), allocatable, private :: & - homogenization_isostrain_mapping !< mapping type - - - public :: & - homogenization_isostrain_init, & - homogenization_isostrain_partitionDeformation, & - homogenization_isostrain_averageStressAndItsTangent, & - homogenization_isostrain_postResults - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_isostrain_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal - use debug, only: & - debug_HOMOGENIZATION, & - debug_level, & - debug_levelBasic - use IO - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - section = 0_pInt, i, mySize, o - integer :: & - maxNinstance, & - homog, & - instance - integer :: & - NofMyHomog ! no pInt (stores a system dependen value from 'count' - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_ISOSTRAIN_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = count(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID) - if (maxNinstance == 0) return - - if (iand(debug_level(debug_HOMOGENIZATION),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - allocate(homogenization_isostrain_sizePostResults(maxNinstance), source=0_pInt) - allocate(homogenization_isostrain_sizePostResult(maxval(homogenization_Noutput),maxNinstance), & - source=0_pInt) - allocate(homogenization_isostrain_Noutput(maxNinstance), source=0_pInt) - allocate(homogenization_isostrain_Ngrains(maxNinstance), source=0_pInt) - allocate(homogenization_isostrain_mapping(maxNinstance), source=average_ID) - allocate(homogenization_isostrain_output(maxval(homogenization_Noutput),maxNinstance)) - homogenization_isostrain_output = '' - allocate(homogenization_isostrain_outputID(maxval(homogenization_Noutput),maxNinstance), & - source=undefined_ID) - - rewind(fileUnit) - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homogenization part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - cycle - endif - if (section > 0_pInt ) then ! do not short-circuit here (.and. with next if-statement). It's not safe in Fortran - if (homogenization_type(section) == HOMOGENIZATION_ISOSTRAIN_ID) then ! one of my sections - i = homogenization_typeInstance(section) ! which instance of my type is present homogenization - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case('nconstituents','ngrains') - homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt - homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = nconstituents_ID - homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('ipcoords') - homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt - homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = ipcoords_ID - homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('avgdefgrad','avgf') - homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt - homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = avgdefgrad_ID - homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case('avgp','avgfirstpiola','avg1stpiola') - homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt - homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = avgfirstpiola_ID - homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - - end select - case ('nconstituents','ngrains') - homogenization_isostrain_Ngrains(i) = IO_intValue(line,chunkPos,2_pInt) - case ('mapping') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('parallel','sum') - homogenization_isostrain_mapping(i) = parallel_ID - case ('average','mean','avg') - homogenization_isostrain_mapping(i) = average_ID - case default - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//HOMOGENIZATION_isostrain_label//')') - end select - - end select - endif - endif - enddo parsingFile - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - myHomog: if (homogenization_type(homog) == HOMOGENIZATION_ISOSTRAIN_ID) then - NofMyHomog = count(material_homog == homog) - instance = homogenization_typeInstance(homog) - -! * Determine size of postResults array - outputsLoop: do o = 1_pInt, homogenization_isostrain_Noutput(instance) - select case(homogenization_isostrain_outputID(o,instance)) - case(nconstituents_ID) - mySize = 1_pInt - case(ipcoords_ID) - mySize = 3_pInt - case(avgdefgrad_ID, avgfirstpiola_ID) - mySize = 9_pInt - case default - mySize = 0_pInt - end select - - outputFound: if (mySize > 0_pInt) then - homogenization_isostrain_sizePostResult(o,instance) = mySize - homogenization_isostrain_sizePostResults(instance) = & - homogenization_isostrain_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop - -! allocate state arrays - homogState(homog)%sizeState = 0_pInt - homogState(homog)%sizePostResults = homogenization_isostrain_sizePostResults(instance) - allocate(homogState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) - - endif myHomog - enddo initializeInstances - -end subroutine homogenization_isostrain_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief partitions the deformation gradient onto the constituents -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_isostrain_partitionDeformation(F,avgF,el) - use prec, only: & - pReal - use mesh, only: & - mesh_element - use material, only: & - homogenization_maxNgrains, & - homogenization_Ngrains - - implicit none - real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned def grad per grain - real(pReal), dimension (3,3), intent(in) :: avgF !< my average def grad - integer(pInt), intent(in) :: & - el !< element number - F=0.0_pReal - F(1:3,1:3,1:homogenization_Ngrains(mesh_element(3,el)))= & - spread(avgF,3,homogenization_Ngrains(mesh_element(3,el))) - -end subroutine homogenization_isostrain_partitionDeformation - - -!-------------------------------------------------------------------------------------------------- -!> @brief derive average stress and stiffness from constituent quantities -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_isostrain_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,el) - use prec, only: & - pReal - use mesh, only: & - mesh_element - use material, only: & - homogenization_maxNgrains, & - homogenization_Ngrains, & - homogenization_typeInstance - - implicit none - 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 (3,3,homogenization_maxNgrains), intent(in) :: P !< array of current grain stresses - real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffnesses - integer(pInt), intent(in) :: el !< element number - integer(pInt) :: & - homID, & - Ngrains - - homID = homogenization_typeInstance(mesh_element(3,el)) - Ngrains = homogenization_Ngrains(mesh_element(3,el)) - - select case (homogenization_isostrain_mapping(homID)) - case (parallel_ID) - avgP = sum(P,3) - dAvgPdAvgF = sum(dPdF,5) - case (average_ID) - avgP = sum(P,3) /real(Ngrains,pReal) - dAvgPdAvgF = sum(dPdF,5)/real(Ngrains,pReal) - end select - -end subroutine homogenization_isostrain_averageStressAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of homogenization results for post file inclusion -!-------------------------------------------------------------------------------------------------- -pure function homogenization_isostrain_postResults(ip,el,avgP,avgF) - use prec, only: & - pReal - use mesh, only: & - mesh_element, & - mesh_ipCoordinates - use material, only: & - homogenization_typeInstance, & - homogenization_Noutput - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3), intent(in) :: & - avgP, & !< average stress at material point - avgF !< average deformation gradient at material point - real(pReal), dimension(homogenization_isostrain_sizePostResults & - (homogenization_typeInstance(mesh_element(3,el)))) :: & - homogenization_isostrain_postResults - - integer(pInt) :: & - homID, & - o, c - - c = 0_pInt - homID = homogenization_typeInstance(mesh_element(3,el)) - homogenization_isostrain_postResults = 0.0_pReal - - do o = 1_pInt,homogenization_Noutput(mesh_element(3,el)) - select case(homogenization_isostrain_outputID(o,homID)) - case (nconstituents_ID) - homogenization_isostrain_postResults(c+1_pInt) = real(homogenization_isostrain_Ngrains(homID),pReal) - c = c + 1_pInt - case (avgdefgrad_ID) - homogenization_isostrain_postResults(c+1_pInt:c+9_pInt) = reshape(avgF,[9]) - c = c + 9_pInt - case (avgfirstpiola_ID) - homogenization_isostrain_postResults(c+1_pInt:c+9_pInt) = reshape(avgP,[9]) - c = c + 9_pInt - case (ipcoords_ID) - homogenization_isostrain_postResults(c+1_pInt:c+3_pInt) = mesh_ipCoordinates(1:3,ip,el) ! current ip coordinates - c = c + 3_pInt - end select - enddo - -end function homogenization_isostrain_postResults - -end module homogenization_isostrain diff --git a/code/homogenization_none.f90 b/code/homogenization_none.f90 deleted file mode 100644 index 59e483c27..000000000 --- a/code/homogenization_none.f90 +++ /dev/null @@ -1,60 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief dummy homogenization homogenization scheme -!-------------------------------------------------------------------------------------------------- -module homogenization_none - - implicit none - private - - public :: & - homogenization_none_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine homogenization_none_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_NONE_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (homogenization_type(homog) == HOMOGENIZATION_none_ID) then - NofMyHomog = count(material_homog == homog) - homogState(homog)%sizeState = 0_pInt - homogState(homog)%sizePostResults = 0_pInt - allocate(homogState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) - allocate(homogState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) - - endif myhomog - enddo initializeInstances - - -end subroutine homogenization_none_init - -end module homogenization_none diff --git a/code/hydrogenflux_cahnhilliard.f90 b/code/hydrogenflux_cahnhilliard.f90 deleted file mode 100644 index d8cb71edc..000000000 --- a/code/hydrogenflux_cahnhilliard.f90 +++ /dev/null @@ -1,513 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for conservative transport of solute hydrogen -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module hydrogenflux_cahnhilliard - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - hydrogenflux_cahnhilliard_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - hydrogenflux_cahnhilliard_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - hydrogenflux_cahnhilliard_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - hydrogenflux_cahnhilliard_Noutput !< number of outputs per instance of this damage - - real(pReal), parameter, private :: & - kB = 1.3806488e-23_pReal !< Boltzmann constant in J/Kelvin - - enum, bind(c) - enumerator :: undefined_ID, & - hydrogenConc_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - hydrogenflux_cahnhilliard_outputID !< ID of each post result output - - - public :: & - hydrogenflux_cahnhilliard_init, & - hydrogenflux_cahnhilliard_getMobility33, & - hydrogenflux_cahnhilliard_getDiffusion33, & - hydrogenflux_cahnhilliard_getFormationEnergy, & - hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent, & - hydrogenflux_cahnhilliard_getChemPotAndItsTangent, & - hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate, & - hydrogenflux_cahnhilliard_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine hydrogenflux_cahnhilliard_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - hydrogenflux_type, & - hydrogenflux_typeInstance, & - homogenization_Noutput, & - HYDROGENFLUX_cahnhilliard_label, & - HYDROGENFLUX_cahnhilliard_ID, & - material_homog, & - mappingHomogenization, & - hydrogenfluxState, & - hydrogenfluxMapping, & - hydrogenConc, & - hydrogenConcRate, & - hydrogenflux_initialCh, & - material_partHomogenization, & - material_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- hydrogenflux_'//HYDROGENFLUX_cahnhilliard_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(hydrogenflux_type == HYDROGENFLUX_cahnhilliard_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(hydrogenflux_cahnhilliard_sizePostResults(maxNinstance), source=0_pInt) - allocate(hydrogenflux_cahnhilliard_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(hydrogenflux_cahnhilliard_output (maxval(homogenization_Noutput),maxNinstance)) - hydrogenflux_cahnhilliard_output = '' - allocate(hydrogenflux_cahnhilliard_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(hydrogenflux_cahnhilliard_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (hydrogenflux_type(section) == HYDROGENFLUX_cahnhilliard_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = hydrogenflux_typeInstance(section) ! which instance of my hydrogenflux is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('hydrogenconc') - hydrogenflux_cahnhilliard_Noutput(instance) = hydrogenflux_cahnhilliard_Noutput(instance) + 1_pInt - hydrogenflux_cahnhilliard_outputID(hydrogenflux_cahnhilliard_Noutput(instance),instance) = hydrogenConc_ID - hydrogenflux_cahnhilliard_output(hydrogenflux_cahnhilliard_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingHomog - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - initializeInstances: do section = 1_pInt, size(hydrogenflux_type) - if (hydrogenflux_type(section) == HYDROGENFLUX_cahnhilliard_ID) then - NofMyHomog=count(material_homog==section) - instance = hydrogenflux_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,hydrogenflux_cahnhilliard_Noutput(instance) - select case(hydrogenflux_cahnhilliard_outputID(o,instance)) - case(hydrogenConc_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - hydrogenflux_cahnhilliard_sizePostResult(o,instance) = mySize - hydrogenflux_cahnhilliard_sizePostResults(instance) = hydrogenflux_cahnhilliard_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 0_pInt - hydrogenfluxState(section)%sizeState = sizeState - hydrogenfluxState(section)%sizePostResults = hydrogenflux_cahnhilliard_sizePostResults(instance) - allocate(hydrogenfluxState(section)%state0 (sizeState,NofMyHomog)) - allocate(hydrogenfluxState(section)%subState0(sizeState,NofMyHomog)) - allocate(hydrogenfluxState(section)%state (sizeState,NofMyHomog)) - - nullify(hydrogenfluxMapping(section)%p) - hydrogenfluxMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(hydrogenConc (section)%p) - deallocate(hydrogenConcRate(section)%p) - allocate (hydrogenConc (section)%p(NofMyHomog), source=hydrogenflux_initialCh(section)) - allocate (hydrogenConcRate(section)%p(NofMyHomog), source=0.0_pReal) - - endif - - enddo initializeInstances - -end subroutine hydrogenflux_cahnhilliard_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized solute mobility tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function hydrogenflux_cahnhilliard_getMobility33(ip,el) - use lattice, only: & - lattice_hydrogenfluxMobility33 - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - hydrogenflux_cahnhilliard_getMobility33 - integer(pInt) :: & - grain - - hydrogenflux_cahnhilliard_getMobility33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - hydrogenflux_cahnhilliard_getMobility33 = hydrogenflux_cahnhilliard_getMobility33 + & - crystallite_push33ToRef(grain,ip,el,lattice_hydrogenfluxMobility33(:,:,material_phase(grain,ip,el))) - enddo - - hydrogenflux_cahnhilliard_getMobility33 = & - hydrogenflux_cahnhilliard_getMobility33/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function hydrogenflux_cahnhilliard_getMobility33 - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized solute nonlocal diffusion tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function hydrogenflux_cahnhilliard_getDiffusion33(ip,el) - use lattice, only: & - lattice_hydrogenfluxDiffusion33 - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - hydrogenflux_cahnhilliard_getDiffusion33 - integer(pInt) :: & - grain - - hydrogenflux_cahnhilliard_getDiffusion33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - hydrogenflux_cahnhilliard_getDiffusion33 = hydrogenflux_cahnhilliard_getDiffusion33 + & - crystallite_push33ToRef(grain,ip,el,lattice_hydrogenfluxDiffusion33(:,:,material_phase(grain,ip,el))) - enddo - - hydrogenflux_cahnhilliard_getDiffusion33 = & - hydrogenflux_cahnhilliard_getDiffusion33/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function hydrogenflux_cahnhilliard_getDiffusion33 - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized solution energy -!-------------------------------------------------------------------------------------------------- -function hydrogenflux_cahnhilliard_getFormationEnergy(ip,el) - use lattice, only: & - lattice_hydrogenFormationEnergy, & - lattice_hydrogenVol, & - lattice_hydrogenSurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - hydrogenflux_cahnhilliard_getFormationEnergy - integer(pInt) :: & - grain - - hydrogenflux_cahnhilliard_getFormationEnergy = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - hydrogenflux_cahnhilliard_getFormationEnergy = hydrogenflux_cahnhilliard_getFormationEnergy + & - lattice_hydrogenFormationEnergy(material_phase(grain,ip,el))/ & - lattice_hydrogenVol(material_phase(grain,ip,el))/ & - lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) - enddo - - hydrogenflux_cahnhilliard_getFormationEnergy = & - hydrogenflux_cahnhilliard_getFormationEnergy/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function hydrogenflux_cahnhilliard_getFormationEnergy - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized hydrogen entropy coefficient -!-------------------------------------------------------------------------------------------------- -function hydrogenflux_cahnhilliard_getEntropicCoeff(ip,el) - use lattice, only: & - lattice_hydrogenVol, & - lattice_hydrogenSurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_homog, & - material_phase, & - temperature, & - thermalMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - hydrogenflux_cahnhilliard_getEntropicCoeff - integer(pInt) :: & - grain - - hydrogenflux_cahnhilliard_getEntropicCoeff = 0.0_pReal - do grain = 1, homogenization_Ngrains(material_homog(ip,el)) - hydrogenflux_cahnhilliard_getEntropicCoeff = hydrogenflux_cahnhilliard_getEntropicCoeff + & - kB/ & - lattice_hydrogenVol(material_phase(grain,ip,el))/ & - lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) - enddo - - hydrogenflux_cahnhilliard_getEntropicCoeff = & - hydrogenflux_cahnhilliard_getEntropicCoeff* & - temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))/ & - homogenization_Ngrains(material_homog(ip,el)) - -end function hydrogenflux_cahnhilliard_getEntropicCoeff - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized kinematic contribution to chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCh, Ch, ip, el) - use lattice, only: & - lattice_hydrogenSurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_homog, & - phase_kinematics, & - phase_Nkinematics, & - material_phase, & - KINEMATICS_hydrogen_strain_ID - use crystallite, only: & - crystallite_Tstar_v, & - crystallite_Fi0, & - crystallite_Fi - use kinematics_hydrogen_strain, only: & - kinematics_hydrogen_strain_ChemPotAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Ch - real(pReal), intent(out) :: & - KPot, dKPot_dCh - real(pReal) :: & - my_KPot, my_dKPot_dCh - integer(pInt) :: & - grain, kinematics - - KPot = 0.0_pReal - dKPot_dCh = 0.0_pReal - do grain = 1_pInt,homogenization_Ngrains(material_homog(ip,el)) - do kinematics = 1_pInt, phase_Nkinematics(material_phase(grain,ip,el)) - select case (phase_kinematics(kinematics,material_phase(grain,ip,el))) - case (KINEMATICS_hydrogen_strain_ID) - call kinematics_hydrogen_strain_ChemPotAndItsTangent(my_KPot, my_dKPot_dCh, & - crystallite_Tstar_v(1:6,grain,ip,el), & - crystallite_Fi0(1:3,1:3,grain,ip,el), & - crystallite_Fi (1:3,1:3,grain,ip,el), & - grain,ip, el) - - case default - my_KPot = 0.0_pReal - my_dKPot_dCh = 0.0_pReal - - end select - KPot = KPot + my_KPot/lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) - dKPot_dCh = dKPot_dCh + my_dKPot_dCh/lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) - enddo - enddo - - KPot = KPot/homogenization_Ngrains(material_homog(ip,el)) - dKPot_dCh = dKPot_dCh/homogenization_Ngrains(material_homog(ip,el)) - -end subroutine hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine hydrogenflux_cahnhilliard_getChemPotAndItsTangent(ChemPot,dChemPot_dCh,Ch,ip,el) - use numerics, only: & - hydrogenBoundPenalty, & - hydrogenPolyOrder - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Ch - real(pReal), intent(out) :: & - ChemPot, & - dChemPot_dCh - real(pReal) :: & - kBT, KPot, dKPot_dCh - integer(pInt) :: & - o - - ChemPot = hydrogenflux_cahnhilliard_getFormationEnergy(ip,el) - dChemPot_dCh = 0.0_pReal - kBT = hydrogenflux_cahnhilliard_getEntropicCoeff(ip,el) - do o = 1_pInt, hydrogenPolyOrder - ChemPot = ChemPot + kBT*((2.0_pReal*Ch - 1.0_pReal)**real(2_pInt*o-1_pInt,pReal))/ & - real(2_pInt*o-1_pInt,pReal) - dChemPot_dCh = dChemPot_dCh + 2.0_pReal*kBT*(2.0_pReal*Ch - 1.0_pReal)**real(2_pInt*o-2_pInt,pReal) - enddo - - call hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCh, Ch, ip, el) - ChemPot = ChemPot + KPot - dChemPot_dCh = dChemPot_dCh + dKPot_dCh - - if (Ch < 0.0_pReal) then - ChemPot = ChemPot - 3.0_pReal*hydrogenBoundPenalty*Ch*Ch - dChemPot_dCh = dChemPot_dCh - 6.0_pReal*hydrogenBoundPenalty*Ch - elseif (Ch > 1.0_pReal) then - ChemPot = ChemPot + 3.0_pReal*hydrogenBoundPenalty*(1.0_pReal - Ch)*(1.0_pReal - Ch) - dChemPot_dCh = dChemPot_dCh - 6.0_pReal*hydrogenBoundPenalty*(1.0_pReal - Ch) - endif - -end subroutine hydrogenflux_cahnhilliard_getChemPotAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief updates hydrogen concentration with solution from Cahn-Hilliard PDE for solute transport -!-------------------------------------------------------------------------------------------------- -subroutine hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate(Ch,Chdot,ip,el) - use material, only: & - mappingHomogenization, & - hydrogenConc, & - hydrogenConcRate, & - hydrogenfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Ch, & - Chdot - integer(pInt) :: & - homog, & - offset - - homog = mappingHomogenization(2,ip,el) - offset = hydrogenfluxMapping(homog)%p(ip,el) - hydrogenConc (homog)%p(offset) = Ch - hydrogenConcRate(homog)%p(offset) = Chdot - -end subroutine hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of hydrogen transport results -!-------------------------------------------------------------------------------------------------- -function hydrogenflux_cahnhilliard_postResults(ip,el) - use material, only: & - mappingHomogenization, & - hydrogenflux_typeInstance, & - hydrogenConc, & - hydrogenfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(hydrogenflux_cahnhilliard_sizePostResults(hydrogenflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & - hydrogenflux_cahnhilliard_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = hydrogenfluxMapping(homog)%p(ip,el) - instance = hydrogenflux_typeInstance(homog) - - c = 0_pInt - hydrogenflux_cahnhilliard_postResults = 0.0_pReal - - do o = 1_pInt,hydrogenflux_cahnhilliard_Noutput(instance) - select case(hydrogenflux_cahnhilliard_outputID(o,instance)) - - case (hydrogenConc_ID) - hydrogenflux_cahnhilliard_postResults(c+1_pInt) = hydrogenConc(homog)%p(offset) - c = c + 1 - end select - enddo -end function hydrogenflux_cahnhilliard_postResults - -end module hydrogenflux_cahnhilliard diff --git a/code/hydrogenflux_isoconc.f90 b/code/hydrogenflux_isoconc.f90 deleted file mode 100644 index 74759d4c3..000000000 --- a/code/hydrogenflux_isoconc.f90 +++ /dev/null @@ -1,63 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for constant hydrogen concentration -!-------------------------------------------------------------------------------------------------- -module hydrogenflux_isoconc - - implicit none - private - - public :: & - hydrogenflux_isoconc_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine hydrogenflux_isoconc_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- hydrogenflux_'//HYDROGENFLUX_isoconc_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (hydrogenflux_type(homog) == HYDROGENFLUX_isoconc_ID) then - NofMyHomog = count(material_homog == homog) - hydrogenfluxState(homog)%sizeState = 0_pInt - hydrogenfluxState(homog)%sizePostResults = 0_pInt - allocate(hydrogenfluxState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) - allocate(hydrogenfluxState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) - allocate(hydrogenfluxState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) - - deallocate(hydrogenConc (homog)%p) - deallocate(hydrogenConcRate(homog)%p) - allocate (hydrogenConc (homog)%p(1), source=hydrogenflux_initialCh(homog)) - allocate (hydrogenConcRate(homog)%p(1), source=0.0_pReal) - - endif myhomog - enddo initializeInstances - - -end subroutine hydrogenflux_isoconc_init - -end module hydrogenflux_isoconc diff --git a/code/kinematics_cleavage_opening.f90 b/code/kinematics_cleavage_opening.f90 deleted file mode 100644 index 945e2d08a..000000000 --- a/code/kinematics_cleavage_opening.f90 +++ /dev/null @@ -1,303 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from opening of cleavage planes -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_cleavage_opening - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_cleavage_opening_sizePostResults, & !< cumulative size of post results - kinematics_cleavage_opening_offset, & !< which kinematics is my current damage mechanism? - kinematics_cleavage_opening_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_cleavage_opening_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_cleavage_opening_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_cleavage_opening_Noutput !< number of outputs per instance of this damage - - integer(pInt), dimension(:), allocatable, private :: & - kinematics_cleavage_opening_totalNcleavage !< total number of cleavage systems - - integer(pInt), dimension(:,:), allocatable, private :: & - kinematics_cleavage_opening_Ncleavage !< number of cleavage systems per family - - real(pReal), dimension(:), allocatable, private :: & - kinematics_cleavage_opening_sdot_0, & - kinematics_cleavage_opening_N - - real(pReal), dimension(:,:), allocatable, private :: & - kinematics_cleavage_opening_critDisp, & - kinematics_cleavage_opening_critLoad - - public :: & - kinematics_cleavage_opening_init, & - kinematics_cleavage_opening_LiAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_cleavage_opening_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_cleavage_opening_label, & - KINEMATICS_cleavage_opening_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - use lattice, only: & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_cleavage_opening_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_cleavage_opening_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_cleavage_opening_offset(material_Nphase), source=0_pInt) - allocate(kinematics_cleavage_opening_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_cleavage_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_cleavage_opening_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_cleavage_opening_ID) & - kinematics_cleavage_opening_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_cleavage_opening_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_output(maxval(phase_Noutput),maxNinstance)) - kinematics_cleavage_opening_output = '' - allocate(kinematics_cleavage_opening_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(kinematics_cleavage_opening_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(kinematics_cleavage_opening_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_totalNcleavage(maxNinstance), source=0_pInt) - allocate(kinematics_cleavage_opening_sdot_0(maxNinstance), source=0.0_pReal) - allocate(kinematics_cleavage_opening_N(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_cleavage_opening_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('anisobrittle_sdot0') - kinematics_cleavage_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisobrittle_ratesensitivity') - kinematics_cleavage_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('ncleavage') ! - Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_CleavageFamilies - kinematics_cleavage_opening_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticaldisplacement') - do j = 1_pInt, Nchunks_CleavageFamilies - kinematics_cleavage_opening_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticalload') - do j = 1_pInt, Nchunks_CleavageFamilies - kinematics_cleavage_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then - instance = kinematics_cleavage_opening_instance(phase) - kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & - min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested - kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance)) - kinematics_cleavage_opening_totalNcleavage(instance) = sum(kinematics_cleavage_opening_Ncleavage(:,instance)) ! how many cleavage systems altogether - if (kinematics_cleavage_opening_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_cleavage_opening_LABEL//')') - if (any(kinematics_cleavage_opening_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//KINEMATICS_cleavage_opening_LABEL//')') - if (any(kinematics_cleavage_opening_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//KINEMATICS_cleavage_opening_LABEL//')') - if (kinematics_cleavage_opening_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_cleavage_opening_LABEL//')') - endif myPhase - enddo sanityChecks - -end subroutine kinematics_cleavage_opening_init - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) - use prec, only: & - tol_math_check - use material, only: & - phaseAt, phasememberAt, & - material_homog, & - damage, & - damageMapping - use lattice, only: & - lattice_Scleavage, & - lattice_Scleavage_v, & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola-Kirchhoff stress - real(pReal), intent(out), dimension(3,3) :: & - Ld !< damage velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) - integer(pInt) :: & - phase, & - constituent, & - instance, & - homog, damageOffset, & - f, i, index_myFamily, k, l, m, n - real(pReal) :: & - traction_d, traction_t, traction_n, traction_crit, & - udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = kinematics_cleavage_opening_instance(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - Ld = 0.0_pReal - dLd_dTstar3333 = 0.0_pReal - do f = 1_pInt,lattice_maxNcleavageFamily - index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family - do i = 1_pInt,kinematics_cleavage_opening_Ncleavage(f,instance) ! process each (active) cleavage system in family - traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) - traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) - traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) - traction_crit = kinematics_cleavage_opening_critLoad(f,instance)* & - damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) - udotd = & - sign(1.0_pReal,traction_d)* & - kinematics_cleavage_opening_sdot_0(instance)* & - (max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) - if (abs(udotd) > tol_math_check) then - Ld = Ld + udotd*lattice_Scleavage(1:3,1:3,1,index_myFamily+i,phase) - dudotd_dt = sign(1.0_pReal,traction_d)*udotd*kinematics_cleavage_opening_N(instance)/ & - max(0.0_pReal, abs(traction_d) - traction_crit) - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotd_dt*lattice_Scleavage(k,l,1,index_myFamily+i,phase)* & - lattice_Scleavage(m,n,1,index_myFamily+i,phase) - endif - - udott = & - sign(1.0_pReal,traction_t)* & - kinematics_cleavage_opening_sdot_0(instance)* & - (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) - if (abs(udott) > tol_math_check) then - Ld = Ld + udott*lattice_Scleavage(1:3,1:3,2,index_myFamily+i,phase) - dudott_dt = sign(1.0_pReal,traction_t)*udott*kinematics_cleavage_opening_N(instance)/ & - max(0.0_pReal, abs(traction_t) - traction_crit) - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudott_dt*lattice_Scleavage(k,l,2,index_myFamily+i,phase)* & - lattice_Scleavage(m,n,2,index_myFamily+i,phase) - endif - - udotn = & - sign(1.0_pReal,traction_n)* & - kinematics_cleavage_opening_sdot_0(instance)* & - (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) - if (abs(udotn) > tol_math_check) then - Ld = Ld + udotn*lattice_Scleavage(1:3,1:3,3,index_myFamily+i,phase) - dudotn_dt = sign(1.0_pReal,traction_n)*udotn*kinematics_cleavage_opening_N(instance)/ & - max(0.0_pReal, abs(traction_n) - traction_crit) - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotn_dt*lattice_Scleavage(k,l,3,index_myFamily+i,phase)* & - lattice_Scleavage(m,n,3,index_myFamily+i,phase) - endif - - enddo - enddo - -end subroutine kinematics_cleavage_opening_LiAndItsTangent - -end module kinematics_cleavage_opening diff --git a/code/kinematics_hydrogen_strain.f90 b/code/kinematics_hydrogen_strain.f90 deleted file mode 100644 index ceb3b1ef3..000000000 --- a/code/kinematics_hydrogen_strain.f90 +++ /dev/null @@ -1,264 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from interstitial hydrogen -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_hydrogen_strain - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_hydrogen_strain_sizePostResults, & !< cumulative size of post results - kinematics_hydrogen_strain_offset, & !< which kinematics is my current damage mechanism? - kinematics_hydrogen_strain_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_hydrogen_strain_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_hydrogen_strain_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_hydrogen_strain_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - kinematics_hydrogen_strain_coeff - - public :: & - kinematics_hydrogen_strain_init, & - kinematics_hydrogen_strain_initialStrain, & - kinematics_hydrogen_strain_LiAndItsTangent, & - kinematics_hydrogen_strain_ChemPotAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_hydrogen_strain_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_hydrogen_strain_label, & - KINEMATICS_hydrogen_strain_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_hydrogen_strain_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_hydrogen_strain_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_hydrogen_strain_offset(material_Nphase), source=0_pInt) - allocate(kinematics_hydrogen_strain_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_hydrogen_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_hydrogen_strain_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_hydrogen_strain_ID) & - kinematics_hydrogen_strain_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_hydrogen_strain_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_hydrogen_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_hydrogen_strain_output(maxval(phase_Noutput),maxNinstance)) - kinematics_hydrogen_strain_output = '' - allocate(kinematics_hydrogen_strain_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_hydrogen_strain_coeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_hydrogen_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_hydrogen_strain_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('hydrogen_strain_coeff') - kinematics_hydrogen_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - -end subroutine kinematics_hydrogen_strain_init - -!-------------------------------------------------------------------------------------------------- -!> @brief report initial hydrogen strain based on current hydrogen conc deviation from -!> equillibrium (0) -!-------------------------------------------------------------------------------------------------- -pure function kinematics_hydrogen_strain_initialStrain(ipc, ip, el) - use math, only: & - math_I3 - use material, only: & - material_phase, & - material_homog, & - hydrogenConc, & - hydrogenfluxMapping - use lattice, only: & - lattice_equilibriumHydrogenConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - kinematics_hydrogen_strain_initialStrain !< initial thermal strain (should be small strain, though) - integer(pInt) :: & - phase, & - homog, offset, instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_hydrogen_strain_instance(phase) - homog = material_homog(ip,el) - offset = hydrogenfluxMapping(homog)%p(ip,el) - - kinematics_hydrogen_strain_initialStrain = & - (hydrogenConc(homog)%p(offset) - lattice_equilibriumHydrogenConcentration(phase)) * & - kinematics_hydrogen_strain_coeff(instance)* math_I3 - -end function kinematics_hydrogen_strain_initialStrain - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_hydrogen_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - hydrogenConc, & - hydrogenConcRate, & - hydrogenfluxMapping - use math, only: & - math_I3 - use lattice, only: & - lattice_equilibriumHydrogenConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out), dimension(3,3) :: & - Li !< thermal velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) - integer(pInt) :: & - phase, & - instance, & - homog, offset - real(pReal) :: & - Ch, ChEq, ChDot - - phase = material_phase(ipc,ip,el) - instance = kinematics_hydrogen_strain_instance(phase) - homog = material_homog(ip,el) - offset = hydrogenfluxMapping(homog)%p(ip,el) - Ch = hydrogenConc(homog)%p(offset) - ChDot = hydrogenConcRate(homog)%p(offset) - ChEq = lattice_equilibriumHydrogenConcentration(phase) - - Li = ChDot*math_I3* & - kinematics_hydrogen_strain_coeff(instance)/ & - (1.0_pReal + kinematics_hydrogen_strain_coeff(instance)*(Ch - ChEq)) - dLi_dTstar3333 = 0.0_pReal - -end subroutine kinematics_hydrogen_strain_LiAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the kinematic contribution to hydrogen chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCh, Tstar_v, Fi0, Fi, ipc, ip, el) - use material, only: & - material_phase - use math, only: & - math_inv33, & - math_mul33x33, & - math_Mandel6to33, & - math_transpose33 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v - real(pReal), intent(in), dimension(3,3) :: & - Fi0, Fi - real(pReal), intent(out) :: & - ChemPot, dChemPot_dCh - integer(pInt) :: & - phase, & - instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_hydrogen_strain_instance(phase) - - ChemPot = -kinematics_hydrogen_strain_coeff(instance)* & - sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & - math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) - dChemPot_dCh = 0.0_pReal - -end subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent - -end module kinematics_hydrogen_strain diff --git a/code/kinematics_slipplane_opening.f90 b/code/kinematics_slipplane_opening.f90 deleted file mode 100644 index 8b49e1cf3..000000000 --- a/code/kinematics_slipplane_opening.f90 +++ /dev/null @@ -1,323 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from opening of slip planes -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_slipplane_opening - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_slipplane_opening_sizePostResults, & !< cumulative size of post results - kinematics_slipplane_opening_offset, & !< which kinematics is my current damage mechanism? - kinematics_slipplane_opening_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_slipplane_opening_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_slipplane_opening_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_slipplane_opening_Noutput !< number of outputs per instance of this damage - - integer(pInt), dimension(:), allocatable, private :: & - kinematics_slipplane_opening_totalNslip !< total number of slip systems - - integer(pInt), dimension(:,:), allocatable, private :: & - kinematics_slipplane_opening_Nslip !< number of slip systems per family - - real(pReal), dimension(:), allocatable, private :: & - kinematics_slipplane_opening_sdot_0, & - kinematics_slipplane_opening_N - - real(pReal), dimension(:,:), allocatable, private :: & - kinematics_slipplane_opening_critPlasticStrain, & - kinematics_slipplane_opening_critLoad - - public :: & - kinematics_slipplane_opening_init, & - kinematics_slipplane_opening_LiAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_slipplane_opening_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_slipplane_opening_label, & - KINEMATICS_slipplane_opening_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - use lattice, only: & - lattice_maxNslipFamily, & - lattice_NslipSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_slipplane_opening_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_slipplane_opening_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_slipplane_opening_offset(material_Nphase), source=0_pInt) - allocate(kinematics_slipplane_opening_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_slipplane_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_slipplane_opening_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_slipplane_opening_ID) & - kinematics_slipplane_opening_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_slipplane_opening_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_slipplane_opening_output(maxval(phase_Noutput),maxNinstance)) - kinematics_slipplane_opening_output = '' - allocate(kinematics_slipplane_opening_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(kinematics_slipplane_opening_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(kinematics_slipplane_opening_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_totalNslip(maxNinstance), source=0_pInt) - allocate(kinematics_slipplane_opening_N(maxNinstance), source=0.0_pReal) - allocate(kinematics_slipplane_opening_sdot_0(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_slipplane_opening_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('nslip') ! - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - kinematics_slipplane_opening_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_sdot0') - kinematics_slipplane_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalplasticstrain') - do j = 1_pInt, Nchunks_SlipFamilies - kinematics_slipplane_opening_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_ratesensitivity') - kinematics_slipplane_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalload') - do j = 1_pInt, Nchunks_SlipFamilies - kinematics_slipplane_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then - instance = kinematics_slipplane_opening_instance(phase) - kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested - kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance)) - kinematics_slipplane_opening_totalNslip(instance) = sum(kinematics_slipplane_opening_Nslip(:,instance)) - if (kinematics_slipplane_opening_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_slipplane_opening_LABEL//')') - if (any(kinematics_slipplane_opening_critPlasticStrain(:,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//KINEMATICS_slipplane_opening_LABEL//')') - if (kinematics_slipplane_opening_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_slipplane_opening_LABEL//')') - endif myPhase - enddo sanityChecks - - -end subroutine kinematics_slipplane_opening_init - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) - use prec, only: & - tol_math_check - use lattice, only: & - lattice_maxNslipFamily, & - lattice_NslipSystem, & - lattice_sd, & - lattice_st, & - lattice_sn - use material, only: & - phaseAt, phasememberAt, & - material_homog, & - damage, & - damageMapping - use math, only: & - math_Plain3333to99, & - math_I3, & - math_identity4th, & - math_symmetric33, & - math_Mandel33to6, & - math_tensorproduct33, & - math_det33, & - math_mul33x33 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola-Kirchhoff stress - real(pReal), intent(out), dimension(3,3) :: & - Ld !< damage velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) - real(pReal), dimension(3,3) :: & - projection_d, projection_t, projection_n !< projection modes 3x3 tensor - real(pReal), dimension(6) :: & - projection_d_v, projection_t_v, projection_n_v !< projection modes 3x3 vector - integer(pInt) :: & - phase, & - constituent, & - instance, & - homog, damageOffset, & - f, i, index_myFamily, k, l, m, n - real(pReal) :: & - traction_d, traction_t, traction_n, traction_crit, & - udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = kinematics_slipplane_opening_instance(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - Ld = 0.0_pReal - dLd_dTstar3333 = 0.0_pReal - do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,phase)) ! at which index starts my family - do i = 1_pInt,kinematics_slipplane_opening_Nslip(f,instance) ! process each (active) slip system in family - projection_d = math_tensorproduct33(lattice_sd(1:3,index_myFamily+i,phase),& - lattice_sn(1:3,index_myFamily+i,phase)) - projection_t = math_tensorproduct33(lattice_st(1:3,index_myFamily+i,phase),& - lattice_sn(1:3,index_myFamily+i,phase)) - projection_n = math_tensorproduct33(lattice_sn(1:3,index_myFamily+i,phase),& - lattice_sn(1:3,index_myFamily+i,phase)) - - projection_d_v(1:6) = math_Mandel33to6(math_symmetric33(projection_d(1:3,1:3))) - projection_t_v(1:6) = math_Mandel33to6(math_symmetric33(projection_t(1:3,1:3))) - projection_n_v(1:6) = math_Mandel33to6(math_symmetric33(projection_n(1:3,1:3))) - - traction_d = dot_product(Tstar_v,projection_d_v(1:6)) - traction_t = dot_product(Tstar_v,projection_t_v(1:6)) - traction_n = dot_product(Tstar_v,projection_n_v(1:6)) - - traction_crit = kinematics_slipplane_opening_critLoad(f,instance)* & - damage(homog)%p(damageOffset) ! degrading critical load carrying capacity by damage - - udotd = & - sign(1.0_pReal,traction_d)* & - kinematics_slipplane_opening_sdot_0(instance)* & - (abs(traction_d)/traction_crit - & - abs(traction_d)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) - if (abs(udotd) > tol_math_check) then - Ld = Ld + udotd*projection_d - dudotd_dt = udotd*kinematics_slipplane_opening_N(instance)/traction_d - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotd_dt*projection_d(k,l)*projection_d(m,n) - endif - - udott = & - sign(1.0_pReal,traction_t)* & - kinematics_slipplane_opening_sdot_0(instance)* & - (abs(traction_t)/traction_crit - & - abs(traction_t)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) - if (abs(udott) > tol_math_check) then - Ld = Ld + udott*projection_t - dudott_dt = udott*kinematics_slipplane_opening_N(instance)/traction_t - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudott_dt*projection_t(k,l)*projection_t(m,n) - endif - udotn = & - kinematics_slipplane_opening_sdot_0(instance)* & - (max(0.0_pReal,traction_n)/traction_crit - & - max(0.0_pReal,traction_n)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) - if (abs(udotn) > tol_math_check) then - Ld = Ld + udotn*projection_n - dudotn_dt = udotn*kinematics_slipplane_opening_N(instance)/traction_n - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & - dudotn_dt*projection_n(k,l)*projection_n(m,n) - endif - enddo - enddo - -end subroutine kinematics_slipplane_opening_LiAndItsTangent - -end module kinematics_slipplane_opening diff --git a/code/kinematics_thermal_expansion.f90 b/code/kinematics_thermal_expansion.f90 deleted file mode 100644 index b99c499f3..000000000 --- a/code/kinematics_thermal_expansion.f90 +++ /dev/null @@ -1,228 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from thermal expansion -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_thermal_expansion - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_thermal_expansion_sizePostResults, & !< cumulative size of post results - kinematics_thermal_expansion_offset, & !< which kinematics is my current damage mechanism? - kinematics_thermal_expansion_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_thermal_expansion_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_thermal_expansion_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_thermal_expansion_Noutput !< number of outputs per instance of this damage - -! enum, bind(c) ! ToDo kinematics need state machinery to deal with sizePostResult -! enumerator :: undefined_ID, & ! possible remedy is to decouple having state vars from having output -! thermalexpansionrate_ID ! which means to separate user-defined types tState + tOutput... -! end enum - public :: & - kinematics_thermal_expansion_init, & - kinematics_thermal_expansion_initialStrain, & - kinematics_thermal_expansion_LiAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_thermal_expansion_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_thermal_expansion_label, & - KINEMATICS_thermal_expansion_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - character(len=65536) :: & - tag = '', & - output = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_thermal_expansion_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_thermal_expansion_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_thermal_expansion_offset(material_Nphase), source=0_pInt) - allocate(kinematics_thermal_expansion_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_thermal_expansion_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_thermal_expansion_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_thermal_expansion_ID) & - kinematics_thermal_expansion_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_thermal_expansion_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_thermal_expansion_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_thermal_expansion_output(maxval(phase_Noutput),maxNinstance)) - kinematics_thermal_expansion_output = '' - allocate(kinematics_thermal_expansion_Noutput(maxNinstance), source=0_pInt) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_thermal_expansion_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_thermal_expansion_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key... - select case(tag) -! case ('(output)') -! output = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) ! ...and corresponding output -! select case(output) -! case ('thermalexpansionrate') -! kinematics_thermal_expansion_Noutput(instance) = kinematics_thermal_expansion_Noutput(instance) + 1_pInt -! kinematics_thermal_expansion_outputID(kinematics_thermal_expansion_Noutput(instance),instance) = & -! thermalexpansionrate_ID -! kinematics_thermal_expansion_output(kinematics_thermal_expansion_Noutput(instance),instance) = output -! ToDo add sizePostResult loop afterwards... - - end select - endif; endif - enddo parsingFile - -end subroutine kinematics_thermal_expansion_init - -!-------------------------------------------------------------------------------------------------- -!> @brief report initial thermal strain based on current temperature deviation from reference -!-------------------------------------------------------------------------------------------------- -pure function kinematics_thermal_expansion_initialStrain(ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - temperature, & - thermalMapping - use lattice, only: & - lattice_thermalExpansion33, & - lattice_referenceTemperature - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - kinematics_thermal_expansion_initialStrain !< initial thermal strain (should be small strain, though) - integer(pInt) :: & - phase, & - homog, offset - - phase = material_phase(ipc,ip,el) - homog = material_homog(ip,el) - offset = thermalMapping(homog)%p(ip,el) - - kinematics_thermal_expansion_initialStrain = & - (temperature(homog)%p(offset) - lattice_referenceTemperature(phase)) * & - lattice_thermalExpansion33(1:3,1:3,phase) - -end function kinematics_thermal_expansion_initialStrain - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - temperature, & - temperatureRate, & - thermalMapping - use lattice, only: & - lattice_thermalExpansion33, & - lattice_referenceTemperature - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out), dimension(3,3) :: & - Li !< thermal velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor defined to be zero) - integer(pInt) :: & - phase, & - homog, offset - real(pReal) :: & - T, TRef, TDot - - phase = material_phase(ipc,ip,el) - homog = material_homog(ip,el) - offset = thermalMapping(homog)%p(ip,el) - T = temperature(homog)%p(offset) - TDot = temperatureRate(homog)%p(offset) - TRef = lattice_referenceTemperature(phase) - - Li = TDot* & - lattice_thermalExpansion33(1:3,1:3,phase)/ & - (1.0_pReal + lattice_thermalExpansion33(1:3,1:3,phase)*(T - TRef)) - dLi_dTstar3333 = 0.0_pReal - -end subroutine kinematics_thermal_expansion_LiAndItsTangent - -end module kinematics_thermal_expansion diff --git a/code/kinematics_vacancy_strain.f90 b/code/kinematics_vacancy_strain.f90 deleted file mode 100644 index 899bccd9f..000000000 --- a/code/kinematics_vacancy_strain.f90 +++ /dev/null @@ -1,265 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating kinematics resulting from vacancy point defects -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module kinematics_vacancy_strain - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - kinematics_vacancy_strain_sizePostResults, & !< cumulative size of post results - kinematics_vacancy_strain_offset, & !< which kinematics is my current damage mechanism? - kinematics_vacancy_strain_instance !< instance of damage kinematics mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - kinematics_vacancy_strain_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - kinematics_vacancy_strain_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - kinematics_vacancy_strain_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - kinematics_vacancy_strain_coeff - - public :: & - kinematics_vacancy_strain_init, & - kinematics_vacancy_strain_initialStrain, & - kinematics_vacancy_strain_LiAndItsTangent, & - kinematics_vacancy_strain_ChemPotAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_vacancy_strain_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_kinematics, & - phase_Nkinematics, & - phase_Noutput, & - KINEMATICS_vacancy_strain_label, & - KINEMATICS_vacancy_strain_ID, & - material_Nphase, & - MATERIAL_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,kinematics - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_vacancy_strain_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_kinematics == KINEMATICS_vacancy_strain_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(kinematics_vacancy_strain_offset(material_Nphase), source=0_pInt) - allocate(kinematics_vacancy_strain_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - kinematics_vacancy_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_vacancy_strain_ID) - do kinematics = 1, phase_Nkinematics(phase) - if (phase_kinematics(kinematics,phase) == kinematics_vacancy_strain_ID) & - kinematics_vacancy_strain_offset(phase) = kinematics - enddo - enddo - - allocate(kinematics_vacancy_strain_sizePostResults(maxNinstance), source=0_pInt) - allocate(kinematics_vacancy_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(kinematics_vacancy_strain_output(maxval(phase_Noutput),maxNinstance)) - kinematics_vacancy_strain_output = '' - allocate(kinematics_vacancy_strain_Noutput(maxNinstance), source=0_pInt) - allocate(kinematics_vacancy_strain_coeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_vacancy_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = kinematics_vacancy_strain_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('vacancy_strain_coeff') - kinematics_vacancy_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - -end subroutine kinematics_vacancy_strain_init - -!-------------------------------------------------------------------------------------------------- -!> @brief report initial vacancy strain based on current vacancy conc deviation from equillibrium -!-------------------------------------------------------------------------------------------------- -pure function kinematics_vacancy_strain_initialStrain(ipc, ip, el) - use math, only: & - math_I3 - use material, only: & - material_phase, & - material_homog, & - vacancyConc, & - vacancyfluxMapping - use lattice, only: & - lattice_equilibriumVacancyConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - kinematics_vacancy_strain_initialStrain !< initial thermal strain (should be small strain, though) - integer(pInt) :: & - phase, & - homog, offset, instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_vacancy_strain_instance(phase) - homog = material_homog(ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - - kinematics_vacancy_strain_initialStrain = & - (vacancyConc(homog)%p(offset) - lattice_equilibriumVacancyConcentration(phase)) * & - kinematics_vacancy_strain_coeff(instance)* math_I3 - -end function kinematics_vacancy_strain_initialStrain - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the constitutive equation for calculating the velocity gradient -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_vacancy_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) - use material, only: & - material_phase, & - material_homog, & - vacancyConc, & - vacancyConcRate, & - vacancyfluxMapping - use math, only: & - math_I3 - use lattice, only: & - lattice_equilibriumVacancyConcentration - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out), dimension(3,3) :: & - Li !< thermal velocity gradient - real(pReal), intent(out), dimension(3,3,3,3) :: & - dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) - integer(pInt) :: & - phase, & - instance, & - homog, offset - real(pReal) :: & - Cv, CvEq, CvDot - - phase = material_phase(ipc,ip,el) - instance = kinematics_vacancy_strain_instance(phase) - homog = material_homog(ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - - Cv = vacancyConc(homog)%p(offset) - CvDot = vacancyConcRate(homog)%p(offset) - CvEq = lattice_equilibriumvacancyConcentration(phase) - - Li = CvDot*math_I3* & - kinematics_vacancy_strain_coeff(instance)/ & - (1.0_pReal + kinematics_vacancy_strain_coeff(instance)*(Cv - CvEq)) - - dLi_dTstar3333 = 0.0_pReal - -end subroutine kinematics_vacancy_strain_LiAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief contains the kinematic contribution to vacancy chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine kinematics_vacancy_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCv, Tstar_v, Fi0, Fi, ipc, ip, el) - use material, only: & - material_phase - use math, only: & - math_inv33, & - math_mul33x33, & - math_Mandel6to33, & - math_transpose33 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v - real(pReal), intent(in), dimension(3,3) :: & - Fi0, Fi - real(pReal), intent(out) :: & - ChemPot, dChemPot_dCv - integer(pInt) :: & - phase, & - instance - - phase = material_phase(ipc,ip,el) - instance = kinematics_vacancy_strain_instance(phase) - - ChemPot = -kinematics_vacancy_strain_coeff(instance)* & - sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & - math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) - dChemPot_dCv = 0.0_pReal - -end subroutine kinematics_vacancy_strain_ChemPotAndItsTangent - -end module kinematics_vacancy_strain diff --git a/code/lattice.f90 b/code/lattice.f90 deleted file mode 100644 index 8e87ba2a9..000000000 --- a/code/lattice.f90 +++ /dev/null @@ -1,2239 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief defines lattice structure definitions, slip and twin system definitions, Schimd matrix -!> calculation and non-Schmid behavior -!-------------------------------------------------------------------------------------------------- -module lattice - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), parameter, public :: & - LATTICE_maxNslipFamily = 13_pInt, & !< max # of slip system families over lattice structures - LATTICE_maxNtwinFamily = 4_pInt, & !< max # of twin system families over lattice structures - LATTICE_maxNtransFamily = 2_pInt, & !< max # of transformation system families over lattice structures - LATTICE_maxNcleavageFamily = 3_pInt, & !< max # of transformation system families over lattice structures - LATTICE_maxNslip = 52_pInt, & !< max # of slip systems over lattice structures - LATTICE_maxNtwin = 24_pInt, & !< max # of twin systems over lattice structures - LATTICE_maxNinteraction = 182_pInt, & !< max # of interaction types (in hardening matrix part) - LATTICE_maxNnonSchmid = 6_pInt, & !< max # of non schmid contributions over lattice structures - LATTICE_maxNtrans = 12_pInt, & !< max # of transformations over lattice structures - LATTICE_maxNcleavage = 9_pInt !< max # of cleavage over lattice structures - - integer(pInt), allocatable, dimension(:,:), protected, public :: & - lattice_NslipSystem, & !< total # of slip systems in each family - lattice_NtwinSystem, & !< total # of twin systems in each family - lattice_NtransSystem, & !< total # of transformation systems in each family - lattice_NcleavageSystem !< total # of transformation systems in each family - - integer(pInt), allocatable, dimension(:,:,:), protected, public :: & - lattice_interactionSlipSlip, & !< Slip--slip interaction type - lattice_interactionSlipTwin, & !< Slip--twin interaction type - lattice_interactionTwinSlip, & !< Twin--slip interaction type - lattice_interactionTwinTwin, & !< Twin--twin interaction type - lattice_interactionSlipTrans, & !< Slip--trans interaction type - lattice_interactionTransSlip, & !< Trans--slip interaction type - lattice_interactionTransTrans !< Trans--trans interaction type - - real(pReal), allocatable, dimension(:,:,:,:,:), protected, public :: & - lattice_Sslip, & !< Schmid and non-Schmid matrices - lattice_Scleavage !< Schmid matrices for cleavage systems - - real(pReal), allocatable, dimension(:,:,:,:), protected, public :: & - lattice_Sslip_v, & !< Mandel notation of lattice_Sslip - lattice_Scleavage_v !< Mandel notation of lattice_Scleavege - - real(pReal), allocatable, dimension(:,:,:), protected, public :: & - lattice_sn, & !< normal direction of slip system - lattice_sd, & !< slip direction of slip system - lattice_st !< sd x sn - -! rotation and Schmid matrices, normal, shear direction and d x n of twin systems - real(pReal), allocatable, dimension(:,:,:,:), protected, public :: & - lattice_Stwin, & - lattice_Qtwin - - real(pReal), allocatable, dimension(:,:,:), protected, public :: & - lattice_Stwin_v, & - lattice_tn, & - lattice_td, & - lattice_tt - - real(pReal), allocatable, dimension(:,:,:), protected, public :: & - lattice_Strans_v, & !< Eigendeformation tensor in vector form - lattice_projectionTrans !< Matrix for projection of slip to fault-band (twin) systems for strain-induced martensite nucleation - - real(pReal), allocatable, dimension(:,:,:,:), protected, public :: & - lattice_Qtrans, & !< Total rotation: Q = R*B - lattice_Strans !< Eigendeformation tensor for phase transformation - - real(pReal), allocatable, dimension(:,:), protected, public :: & - lattice_shearTwin, & !< characteristic twin shear - lattice_shearTrans !< characteristic transformation shear - - integer(pInt), allocatable, dimension(:), protected, public :: & - lattice_NnonSchmid !< total # of non-Schmid contributions for each structure - -!-------------------------------------------------------------------------------------------------- -! fcc - integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & - LATTICE_fcc_NslipSystem = int([12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],pInt) !< total # of slip systems per family for fcc - - integer(pInt), dimension(LATTICE_maxNtwinFamily), parameter, public :: & - LATTICE_fcc_NtwinSystem = int([12, 0, 0, 0],pInt) !< total # of twin systems per family for fcc - - integer(pInt), dimension(LATTICE_maxNtransFamily), parameter, public :: & - LATTICE_fcc_NtransSystem = int([12, 0],pInt) !< total # of transformation systems per family for fcc - - integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & - LATTICE_fcc_NcleavageSystem = int([3, 4, 0],pInt) !< total # of cleavage systems per family for fcc - - integer(pInt), parameter, private :: & - LATTICE_fcc_Nslip = 12_pInt, & ! sum(lattice_fcc_NslipSystem), & !< total # of slip systems for fcc - LATTICE_fcc_Ntwin = 12_pInt, & ! sum(lattice_fcc_NtwinSystem) !< total # of twin systems for fcc - LATTICE_fcc_NnonSchmid = 0_pInt, & !< total # of non-Schmid contributions for fcc - LATTICE_fcc_Ntrans = 12_pInt, & !< total # of transformations for fcc - LATTICE_fcc_Ncleavage = 7_pInt !< total # of cleavage systems for fcc - - real(pReal), dimension(3+3,LATTICE_fcc_Nslip), parameter, private :: & - LATTICE_fcc_systemSlip = reshape(real([& - ! Slip direction Plane normal - 0, 1,-1, 1, 1, 1, & - -1, 0, 1, 1, 1, 1, & - 1,-1, 0, 1, 1, 1, & - 0,-1,-1, -1,-1, 1, & - 1, 0, 1, -1,-1, 1, & - -1, 1, 0, -1,-1, 1, & - 0,-1, 1, 1,-1,-1, & - -1, 0,-1, 1,-1,-1, & - 1, 1, 0, 1,-1,-1, & - 0, 1, 1, -1, 1,-1, & - 1, 0,-1, -1, 1,-1, & - -1,-1, 0, -1, 1,-1 & - ],pReal),[ 3_pInt + 3_pInt,LATTICE_fcc_Nslip]) !< Slip system <110>{111} directions. Sorted according to Eisenlohr & Hantcherli - - real(pReal), dimension(3+3,LATTICE_fcc_Ntwin), parameter, private :: & - LATTICE_fcc_systemTwin = reshape(real( [& - -2, 1, 1, 1, 1, 1, & - 1,-2, 1, 1, 1, 1, & - 1, 1,-2, 1, 1, 1, & - 2,-1, 1, -1,-1, 1, & - -1, 2, 1, -1,-1, 1, & - -1,-1,-2, -1,-1, 1, & - -2,-1,-1, 1,-1,-1, & - 1, 2,-1, 1,-1,-1, & - 1,-1, 2, 1,-1,-1, & - 2, 1,-1, -1, 1,-1, & - -1,-2,-1, -1, 1,-1, & - -1, 1, 2, -1, 1,-1 & - ],pReal),[ 3_pInt + 3_pInt,LATTICE_fcc_Ntwin]) !< Twin system <112>{111} directions. Sorted according to Eisenlohr & Hantcherli - - real(pReal), dimension(3+3,LATTICE_fcc_Ntrans), parameter, private :: & - LATTICE_fccTohex_systemTrans = reshape(real( [& - -2, 1, 1, 1, 1, 1, & - 1,-2, 1, 1, 1, 1, & - 1, 1,-2, 1, 1, 1, & - 2,-1, 1, -1,-1, 1, & - -1, 2, 1, -1,-1, 1, & - -1,-1,-2, -1,-1, 1, & - -2,-1,-1, 1,-1,-1, & - 1, 2,-1, 1,-1,-1, & - 1,-1, 2, 1,-1,-1, & - 2, 1,-1, -1, 1,-1, & - -1,-2,-1, -1, 1,-1, & - -1, 1, 2, -1, 1,-1 & - ],pReal),[ 3_pInt + 3_pInt,LATTICE_fcc_Ntrans]) - - real(pReal), dimension(LATTICE_fcc_Ntwin), parameter, private :: & - LATTICE_fcc_shearTwin = 0.5_pReal*sqrt(2.0_pReal) !< Twin system <112>{111} ??? Sorted according to Eisenlohr & Hantcherli - - integer(pInt), dimension(2_pInt,LATTICE_fcc_Ntwin), parameter, public :: & - LATTICE_fcc_twinNucleationSlipPair = reshape(int( [& - 2,3, & - 1,3, & - 1,2, & - 5,6, & - 4,6, & - 4,5, & - 8,9, & - 7,9, & - 7,8, & - 11,12, & - 10,12, & - 10,11 & - ],pInt),[2_pInt,LATTICE_fcc_Ntwin]) - - integer(pInt), dimension(LATTICE_fcc_Nslip,lattice_fcc_Nslip), parameter, public :: & - LATTICE_fcc_interactionSlipSlip = reshape(int( [& - 1,2,2,4,6,5,3,5,5,4,5,6, & ! ---> slip - 2,1,2,6,4,5,5,4,6,5,3,5, & ! | - 2,2,1,5,5,3,5,6,4,6,5,4, & ! | - 4,6,5,1,2,2,4,5,6,3,5,5, & ! v slip - 6,4,5,2,1,2,5,3,5,5,4,6, & - 5,5,3,2,2,1,6,5,4,5,6,4, & - 3,5,5,4,5,6,1,2,2,4,6,5, & - 5,4,6,5,3,5,2,1,2,6,4,5, & - 5,6,4,6,5,4,2,2,1,5,5,3, & - 4,5,6,3,5,5,4,6,5,1,2,2, & - 5,3,5,5,4,6,6,4,5,2,1,2, & - 6,5,4,5,6,4,5,5,3,2,2,1 & - ],pInt),[LATTICE_fcc_Nslip,LATTICE_fcc_Nslip],order=[2,1]) !< Slip--slip interaction types for fcc - !< 1: self interaction - !< 2: coplanar interaction - !< 3: collinear interaction - !< 4: Hirth locks - !< 5: glissile junctions - !< 6: Lomer locks - integer(pInt), dimension(LATTICE_fcc_Nslip,LATTICE_fcc_Ntwin), parameter, public :: & - LATTICE_fcc_interactionSlipTwin = reshape(int( [& - 1,1,1,3,3,3,2,2,2,3,3,3, & ! ---> twin - 1,1,1,3,3,3,3,3,3,2,2,2, & ! | - 1,1,1,2,2,2,3,3,3,3,3,3, & ! | - 3,3,3,1,1,1,3,3,3,2,2,2, & ! v slip - 3,3,3,1,1,1,2,2,2,3,3,3, & - 2,2,2,1,1,1,3,3,3,3,3,3, & - 2,2,2,3,3,3,1,1,1,3,3,3, & - 3,3,3,2,2,2,1,1,1,3,3,3, & - 3,3,3,3,3,3,1,1,1,2,2,2, & - 3,3,3,2,2,2,3,3,3,1,1,1, & - 2,2,2,3,3,3,3,3,3,1,1,1, & - 3,3,3,3,3,3,2,2,2,1,1,1 & - ],pInt),[LATTICE_fcc_Nslip,LATTICE_fcc_Ntwin],order=[2,1]) !< Slip--twin interaction types for fcc - !< 1: coplanar interaction - !< 2: screw trace between slip system and twin habit plane (easy cross slip) - !< 3: other interaction - integer(pInt), dimension(LATTICE_fcc_Ntwin,LATTICE_fcc_Nslip), parameter, public :: & - LATTICE_fcc_interactionTwinSlip = 1_pInt !< Twin--Slip interaction types for fcc - - integer(pInt), dimension(LATTICE_fcc_Ntwin,LATTICE_fcc_Ntwin), parameter,public :: & - LATTICE_fcc_interactionTwinTwin = reshape(int( [& - 1,1,1,2,2,2,2,2,2,2,2,2, & ! ---> twin - 1,1,1,2,2,2,2,2,2,2,2,2, & ! | - 1,1,1,2,2,2,2,2,2,2,2,2, & ! | - 2,2,2,1,1,1,2,2,2,2,2,2, & ! v twin - 2,2,2,1,1,1,2,2,2,2,2,2, & - 2,2,2,1,1,1,2,2,2,2,2,2, & - 2,2,2,2,2,2,1,1,1,2,2,2, & - 2,2,2,2,2,2,1,1,1,2,2,2, & - 2,2,2,2,2,2,1,1,1,2,2,2, & - 2,2,2,2,2,2,2,2,2,1,1,1, & - 2,2,2,2,2,2,2,2,2,1,1,1, & - 2,2,2,2,2,2,2,2,2,1,1,1 & - ],pInt),[lattice_fcc_Ntwin,lattice_fcc_Ntwin],order=[2,1]) !< Twin--twin interaction types for fcc - - integer(pInt), dimension(LATTICE_fcc_Nslip,LATTICE_fcc_Ntrans), parameter, public :: & - LATTICE_fccTohex_interactionSlipTrans = reshape(int( [& - 1,1,1,3,3,3,2,2,2,3,3,3, & ! ---> trans - 1,1,1,3,3,3,3,3,3,2,2,2, & ! | - 1,1,1,2,2,2,3,3,3,3,3,3, & ! | - 3,3,3,1,1,1,3,3,3,2,2,2, & ! v slip - 3,3,3,1,1,1,2,2,2,3,3,3, & - 2,2,2,1,1,1,3,3,3,3,3,3, & - 2,2,2,3,3,3,1,1,1,3,3,3, & - 3,3,3,2,2,2,1,1,1,3,3,3, & - 3,3,3,3,3,3,1,1,1,2,2,2, & - 3,3,3,2,2,2,3,3,3,1,1,1, & - 2,2,2,3,3,3,3,3,3,1,1,1, & - 3,3,3,3,3,3,2,2,2,1,1,1 & - ],pInt),[LATTICE_fcc_Nslip,LATTICE_fcc_Ntrans],order=[2,1]) !< Slip--trans interaction types for fcc - - integer(pInt), dimension(LATTICE_fcc_Ntrans,LATTICE_fcc_Nslip), parameter, public :: & - LATTICE_fccTohex_interactionTransSlip = 1_pInt !< Trans--Slip interaction types for fcc - - integer(pInt), dimension(LATTICE_fcc_Ntrans,LATTICE_fcc_Ntrans), parameter,public :: & - LATTICE_fccTohex_interactionTransTrans = reshape(int( [& - 1,1,1,2,2,2,2,2,2,2,2,2, & ! ---> trans - 1,1,1,2,2,2,2,2,2,2,2,2, & ! | - 1,1,1,2,2,2,2,2,2,2,2,2, & ! | - 2,2,2,1,1,1,2,2,2,2,2,2, & ! v trans - 2,2,2,1,1,1,2,2,2,2,2,2, & - 2,2,2,1,1,1,2,2,2,2,2,2, & - 2,2,2,2,2,2,1,1,1,2,2,2, & - 2,2,2,2,2,2,1,1,1,2,2,2, & - 2,2,2,2,2,2,1,1,1,2,2,2, & - 2,2,2,2,2,2,2,2,2,1,1,1, & - 2,2,2,2,2,2,2,2,2,1,1,1, & - 2,2,2,2,2,2,2,2,2,1,1,1 & - ],pInt),[LATTICE_fcc_Ntrans,LATTICE_fcc_Ntrans],order=[2,1]) !< Trans--trans interaction types for fcc - - real(pReal), dimension(LATTICE_fcc_Ntrans), parameter, private :: & - LATTICE_fccTohex_shearTrans = sqrt(2.0_pReal)/4.0_pReal - - real(pReal), dimension(4,LATTICE_fcc_Ntrans), parameter, private :: & - LATTICE_fccTobcc_systemTrans = reshape([& - 0.0, 1.0, 0.0, 10.26, & ! Pitsch OR (Ma & Hartmaier 2014, Table 3) - 0.0, 1.0, 0.0, -10.26, & - 0.0, 0.0, 1.0, 10.26, & - 0.0, 0.0, 1.0, -10.26, & - 1.0, 0.0, 0.0, 10.26, & - 1.0, 0.0, 0.0, -10.26, & - 0.0, 0.0, 1.0, 10.26, & - 0.0, 0.0, 1.0, -10.26, & - 1.0, 0.0, 0.0, 10.26, & - 1.0, 0.0, 0.0, -10.26, & - 0.0, 1.0, 0.0, 10.26, & - 0.0, 1.0, 0.0, -10.26 & - ],[ 4_pInt,LATTICE_fcc_Ntrans]) - - integer(pInt), dimension(9,LATTICE_fcc_Ntrans), parameter, private :: & - LATTICE_fccTobcc_bainVariant = reshape(int( [& - 1, 0, 0, 0, 1, 0, 0, 0, 1, & ! Pitsch OR (Ma & Hartmaier 2014, Table 3) - 1, 0, 0, 0, 1, 0, 0, 0, 1, & - 1, 0, 0, 0, 1, 0, 0, 0, 1, & - 1, 0, 0, 0, 1, 0, 0, 0, 1, & - 0, 1, 0, 1, 0, 0, 0, 0, 1, & - 0, 1, 0, 1, 0, 0, 0, 0, 1, & - 0, 1, 0, 1, 0, 0, 0, 0, 1, & - 0, 1, 0, 1, 0, 0, 0, 0, 1, & - 0, 0, 1, 1, 0, 0, 0, 1, 0, & - 0, 0, 1, 1, 0, 0, 0, 1, 0, & - 0, 0, 1, 1, 0, 0, 0, 1, 0, & - 0, 0, 1, 1, 0, 0, 0, 1, 0 & - ],pInt),[ 9_pInt, LATTICE_fcc_Ntrans]) - - real(pReal), dimension(4,LATTICE_fcc_Ntrans), parameter, private :: & - LATTICE_fccTobcc_bainRot = reshape([& - 1.0, 0.0, 0.0, 45.0, & ! Rotate fcc austensite to bain variant - 1.0, 0.0, 0.0, 45.0, & - 1.0, 0.0, 0.0, 45.0, & - 1.0, 0.0, 0.0, 45.0, & - 0.0, 1.0, 0.0, 45.0, & - 0.0, 1.0, 0.0, 45.0, & - 0.0, 1.0, 0.0, 45.0, & - 0.0, 1.0, 0.0, 45.0, & - 0.0, 0.0, 1.0, 45.0, & - 0.0, 0.0, 1.0, 45.0, & - 0.0, 0.0, 1.0, 45.0, & - 0.0, 0.0, 1.0, 45.0 & - ],[ 4_pInt,LATTICE_fcc_Ntrans]) - - real(pReal), dimension(LATTICE_fcc_Ntrans,LATTICE_fcc_Ntrans), parameter, private :: & ! Matrix for projection of shear from slip system to fault-band (twin) systems - LATTICE_fccTobcc_projectionTrans = reshape(real([& ! For ns = nt = nr - 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, & - -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, & - 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & - 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, & - 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, & - 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, & - 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, & - 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, & - 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, & - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, & - 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, & - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, 0 & - ],pReal),[LATTICE_fcc_Ntrans,LATTICE_fcc_Ntrans],order=[2,1]) - - real(pReal), parameter, private :: & - LATTICE_fccTobcc_projectionTransFactor = sqrt(3.0_pReal/4.0_pReal) - - real(pReal), parameter, public :: & - LATTICE_fccTobcc_shearCritTrans = 0.0224 - - integer(pInt), dimension(2_pInt,LATTICE_fcc_Ntrans), parameter, public :: & - LATTICE_fccTobcc_transNucleationTwinPair = reshape(int( [& - 4, 7, & - 1, 10, & - 1, 4, & - 7, 10, & - 2, 8, & - 5, 11, & - 8, 11, & - 2, 5, & - 6, 12, & - 3, 9, & - 3, 12, & - 6, 9 & - ],pInt),[2_pInt,LATTICE_fcc_Ntrans]) - - real(pReal), dimension(3+3,LATTICE_fcc_Ncleavage), parameter, private :: & - LATTICE_fcc_systemCleavage = reshape(real([& - ! Cleavage direction Plane normal - 0, 1, 0, 1, 0, 0, & - 0, 0, 1, 0, 1, 0, & - 1, 0, 0, 0, 0, 1, & - 0, 1,-1, 1, 1, 1, & - 0,-1,-1, -1,-1, 1, & - -1, 0,-1, 1,-1,-1, & - 0, 1, 1, -1, 1,-1 & - ],pReal),[ 3_pInt + 3_pInt,LATTICE_fcc_Ncleavage]) - -!-------------------------------------------------------------------------------------------------- -! bcc - integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & - LATTICE_bcc_NslipSystem = int([ 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], pInt) !< total # of slip systems per family for bcc - - integer(pInt), dimension(LATTICE_maxNtwinFamily), parameter, public :: & - LATTICE_bcc_NtwinSystem = int([ 12, 0, 0, 0], pInt) !< total # of twin systems per family for bcc - - integer(pInt), dimension(LATTICE_maxNtransFamily), parameter, public :: & - LATTICE_bcc_NtransSystem = int([0,0],pInt) !< total # of transformation systems per family for bcc - - integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & - LATTICE_bcc_NcleavageSystem = int([3,6,0],pInt) !< total # of cleavage systems per family for bcc - - integer(pInt), parameter, private :: & - LATTICE_bcc_Nslip = 24_pInt, & ! sum(lattice_bcc_NslipSystem), & !< total # of slip systems for bcc - LATTICE_bcc_Ntwin = 12_pInt, & ! sum(lattice_bcc_NtwinSystem) !< total # of twin systems for bcc - LATTICE_bcc_NnonSchmid = 6_pInt, & !< # of non-Schmid contributions for bcc. 6 known non schmid contributions for BCC (A. Koester, A. Ma, A. Hartmaier 2012) - LATTICE_bcc_Ntrans = 0_pInt, & !< total # of transformations for bcc - LATTICE_bcc_Ncleavage = 9_pInt !< total # of cleavage systems for bcc - - - real(pReal), dimension(3+3,LATTICE_bcc_Nslip), parameter, private :: & - LATTICE_bcc_systemSlip = reshape(real([& - ! Slip direction Plane normal - ! Slip system <111>{110} - 1,-1, 1, 0, 1, 1, & - -1,-1, 1, 0, 1, 1, & - 1, 1, 1, 0,-1, 1, & - -1, 1, 1, 0,-1, 1, & - -1, 1, 1, 1, 0, 1, & - -1,-1, 1, 1, 0, 1, & - 1, 1, 1, -1, 0, 1, & - 1,-1, 1, -1, 0, 1, & - -1, 1, 1, 1, 1, 0, & - -1, 1,-1, 1, 1, 0, & - 1, 1, 1, -1, 1, 0, & - 1, 1,-1, -1, 1, 0, & - ! Slip system <111>{112} - -1, 1, 1, 2, 1, 1, & - 1, 1, 1, -2, 1, 1, & - 1, 1,-1, 2,-1, 1, & - 1,-1, 1, 2, 1,-1, & - 1,-1, 1, 1, 2, 1, & - 1, 1,-1, -1, 2, 1, & - 1, 1, 1, 1,-2, 1, & - -1, 1, 1, 1, 2,-1, & - 1, 1,-1, 1, 1, 2, & - 1,-1, 1, -1, 1, 2, & - -1, 1, 1, 1,-1, 2, & - 1, 1, 1, 1, 1,-2 & - ! Slip system <111>{123} - ! 1, 1,-1, 1, 2, 3, & - ! 1,-1, 1, -1, 2, 3, & - ! -1, 1, 1, 1,-2, 3, & - ! 1, 1, 1, 1, 2,-3, & - ! 1,-1, 1, 1, 3, 2, & - ! 1, 1,-1, -1, 3, 2, & - ! 1, 1, 1, 1,-3, 2, & - ! -1, 1, 1, 1, 3,-2, & - ! 1, 1,-1, 2, 1, 3, & - ! 1,-1, 1, -2, 1, 3, & - ! -1, 1, 1, 2,-1, 3, & - ! 1, 1, 1, 2, 1,-3, & - ! 1,-1, 1, 2, 3, 1, & - ! 1, 1,-1, -2, 3, 1, & - ! 1, 1, 1, 2,-3, 1, & - ! -1, 1, 1, 2, 3,-1, & - ! -1, 1, 1, 3, 1, 2, & - ! 1, 1, 1, -3, 1, 2, & - ! 1, 1,-1, 3,-1, 2, & - ! 1,-1, 1, 3, 1,-2, & - ! -1, 1, 1, 3, 2, 1, & - ! 1, 1, 1, -3, 2, 1, & - ! 1, 1,-1, 3,-2, 1, & - ! 1,-1, 1, 3, 2,-1 & - ],pReal),[ 3_pInt + 3_pInt ,LATTICE_bcc_Nslip]) - - real(pReal), dimension(3+3,LATTICE_bcc_Ntwin), parameter, private :: & - LATTICE_bcc_systemTwin = reshape(real([& - ! Twin system <111>{112} - -1, 1, 1, 2, 1, 1, & - 1, 1, 1, -2, 1, 1, & - 1, 1,-1, 2,-1, 1, & - 1,-1, 1, 2, 1,-1, & - 1,-1, 1, 1, 2, 1, & - 1, 1,-1, -1, 2, 1, & - 1, 1, 1, 1,-2, 1, & - -1, 1, 1, 1, 2,-1, & - 1, 1,-1, 1, 1, 2, & - 1,-1, 1, -1, 1, 2, & - -1, 1, 1, 1,-1, 2, & - 1, 1, 1, 1, 1,-2 & - ],pReal),[ 3_pInt + 3_pInt,LATTICE_bcc_Ntwin]) - - real(pReal), dimension(LATTICE_bcc_Ntwin), parameter, private :: & - LATTICE_bcc_shearTwin = 0.5_pReal*sqrt(2.0_pReal) - - integer(pInt), dimension(LATTICE_bcc_Nslip,LATTICE_bcc_Nslip), parameter, public :: & - LATTICE_bcc_interactionSlipSlip = reshape(int( [& - 1,2,6,6,5,4,4,3,4,3,5,4, 6,6,4,3,3,4,6,6,4,3,6,6, & ! ---> slip - 2,1,6,6,4,3,5,4,5,4,4,3, 6,6,3,4,4,3,6,6,3,4,6,6, & ! | - 6,6,1,2,4,5,3,4,4,5,3,4, 4,3,6,6,6,6,3,4,6,6,4,3, & ! | - 6,6,2,1,3,4,4,5,3,4,4,5, 3,4,6,6,6,6,4,3,6,6,3,4, & ! v slip - 5,4,4,3,1,2,6,6,3,4,5,4, 3,6,4,6,6,4,6,3,4,6,3,6, & - 4,3,5,4,2,1,6,6,4,5,4,3, 4,6,3,6,6,3,6,4,3,6,4,6, & - 4,5,3,4,6,6,1,2,5,4,3,4, 6,3,6,4,4,6,3,6,6,4,6,3, & - 3,4,4,5,6,6,2,1,4,3,4,5, 6,4,6,3,3,6,4,6,6,3,6,4, & - 4,5,4,3,3,4,5,4,1,2,6,6, 3,6,6,4,4,6,6,3,6,4,3,6, & - 3,4,5,4,4,5,4,3,2,1,6,6, 4,6,6,3,3,6,6,4,6,3,4,6, & - 5,4,3,4,5,4,3,4,6,6,1,2, 6,3,4,6,6,4,3,6,4,6,6,3, & - 4,3,4,5,4,3,4,5,6,6,2,1, 6,4,3,6,6,3,4,6,3,6,6,4, & - ! - 6,6,4,3,3,4,6,6,3,4,6,6, 1,5,6,6,5,6,6,3,5,6,3,6, & - 6,6,3,4,6,6,3,4,6,6,3,4, 5,1,6,6,6,5,3,6,6,5,6,3, & - 4,3,6,6,4,3,6,6,6,6,4,3, 6,6,1,5,6,3,5,6,3,6,5,6, & - 3,4,6,6,6,6,4,3,4,3,6,6, 6,6,5,1,3,6,6,5,6,3,6,5, & - 3,4,6,6,6,6,4,3,4,3,6,6, 5,6,6,3,1,6,5,6,5,3,6,6, & - 4,3,6,6,4,3,6,6,6,6,4,3, 6,5,3,6,6,1,6,5,3,5,6,6, & - 6,6,3,4,6,6,3,4,6,6,3,4, 6,3,5,6,5,6,1,6,6,6,5,3, & - 6,6,4,3,3,4,6,6,3,4,6,6, 3,6,6,5,6,5,6,1,6,6,3,5, & - 4,3,6,6,4,3,6,6,6,6,4,3, 5,6,3,6,5,3,6,6,1,6,6,5, & - 3,4,6,6,6,6,4,3,4,3,6,6, 6,5,6,3,3,5,6,6,6,1,5,6, & - 6,6,4,3,3,4,6,6,3,4,6,6, 3,6,5,6,6,6,5,3,6,5,1,6, & - 6,6,3,4,6,6,3,4,6,6,3,4, 6,3,6,5,6,6,3,5,5,6,6,1 & - ],pInt),[lattice_bcc_Nslip,lattice_bcc_Nslip],order=[2,1]) !< Slip--slip interaction types for bcc from Queyreau et al. Int J Plast 25 (2009) 361–377 - !< 1: self interaction - !< 2: coplanar interaction - !< 3: collinear interaction - !< 4: mixed-asymmetrical junction - !< 5: mixed-symmetrical junction - !< 6: edge junction - integer(pInt), dimension(LATTICE_bcc_Nslip,LATTICE_bcc_Ntwin), parameter, public :: & - LATTICE_bcc_interactionSlipTwin = reshape(int( [& - 3,3,3,2,2,3,3,3,3,2,3,3, & ! ---> twin - 3,3,2,3,3,2,3,3,2,3,3,3, & ! | - 3,2,3,3,3,3,2,3,3,3,3,2, & ! | - 2,3,3,3,3,3,3,2,3,3,2,3, & ! v slip - 2,3,3,3,3,3,3,2,3,3,2,3, & - 3,3,2,3,3,2,3,3,2,3,3,3, & - 3,2,3,3,3,3,2,3,3,3,3,2, & - 3,3,3,2,2,3,3,3,3,2,3,3, & - 2,3,3,3,3,3,3,2,3,3,2,3, & - 3,3,3,2,2,3,3,3,3,2,3,3, & - 3,2,3,3,3,3,2,3,3,3,3,2, & - 3,3,2,3,3,2,3,3,2,3,3,3, & - ! - 1,3,3,3,3,3,3,2,3,3,2,3, & - 3,1,3,3,3,3,2,3,3,3,3,2, & - 3,3,1,3,3,2,3,3,2,3,3,3, & - 3,3,3,1,2,3,3,3,3,2,3,3, & - 3,3,3,2,1,3,3,3,3,2,3,3, & - 3,3,2,3,3,1,3,3,2,3,3,3, & - 3,2,3,3,3,3,1,3,3,3,3,2, & - 2,3,3,3,3,3,3,1,3,3,2,3, & - 3,3,2,3,3,2,3,3,1,3,3,3, & - 3,3,3,2,2,3,3,3,3,1,3,3, & - 2,3,3,3,3,3,3,2,3,3,1,3, & - 3,2,3,3,3,3,2,3,3,3,3,1 & - ],pInt),[LATTICE_bcc_Nslip,LATTICE_bcc_Ntwin],order=[2,1]) !< Slip--twin interaction types for bcc - !< 1: coplanar interaction - !< 2: screw trace between slip system and twin habit plane (easy cross slip) - !< 3: other interaction - integer(pInt), dimension(LATTICE_bcc_Ntwin,LATTICE_bcc_Nslip), parameter, public :: & - LATTICE_bcc_interactionTwinSlip = 1_pInt !< Twin--slip interaction types for bcc @todo not implemented yet - - integer(pInt), dimension(LATTICE_bcc_Ntwin,LATTICE_bcc_Ntwin), parameter, public :: & - LATTICE_bcc_interactionTwinTwin = reshape(int( [& - 1,3,3,3,3,3,3,2,3,3,2,3, & ! ---> twin - 3,1,3,3,3,3,2,3,3,3,3,2, & ! | - 3,3,1,3,3,2,3,3,2,3,3,3, & ! | - 3,3,3,1,2,3,3,3,3,2,3,3, & ! v twin - 3,3,3,2,1,3,3,3,3,2,3,3, & - 3,3,2,3,3,1,3,3,2,3,3,3, & - 3,2,3,3,3,3,1,3,3,3,3,2, & - 2,3,3,3,3,3,3,1,3,3,2,3, & - 3,3,2,3,3,2,3,3,1,3,3,3, & - 3,3,3,2,2,3,3,3,3,1,3,3, & - 2,3,3,3,3,3,3,2,3,3,1,3, & - 3,2,3,3,3,3,2,3,3,3,3,1 & - ],pInt),[LATTICE_bcc_Ntwin,LATTICE_bcc_Ntwin],order=[2,1]) !< Twin--twin interaction types for bcc - !< 1: self interaction - !< 2: collinear interaction - !< 3: other interaction - real(pReal), dimension(3+3,LATTICE_bcc_Ncleavage), parameter, private :: & - LATTICE_bcc_systemCleavage = reshape(real([& - ! Cleavage direction Plane normal - 0, 1, 0, 1, 0, 0, & - 0, 0, 1, 0, 1, 0, & - 1, 0, 0, 0, 0, 1, & - 1,-1, 1, 0, 1, 1, & - 1, 1, 1, 0,-1, 1, & - -1, 1, 1, 1, 0, 1, & - 1, 1, 1, -1, 0, 1, & - -1, 1, 1, 1, 1, 0, & - 1, 1, 1, -1, 1, 0 & - ],pReal),[ 3_pInt + 3_pInt,LATTICE_bcc_Ncleavage]) - -!-------------------------------------------------------------------------------------------------- -! hex - integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & - lattice_hex_NslipSystem = int([ 3, 3, 3, 6, 12, 6, 0, 0, 0, 0, 0, 0, 0],pInt) !< # of slip systems per family for hex - - integer(pInt), dimension(LATTICE_maxNtwinFamily), parameter, public :: & - lattice_hex_NtwinSystem = int([ 6, 6, 6, 6],pInt) !< # of slip systems per family for hex - - integer(pInt), dimension(LATTICE_maxNtransFamily), parameter, public :: & - LATTICE_hex_NtransSystem = int([0,0],pInt) !< total # of transformation systems per family for hex - - integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & - LATTICE_hex_NcleavageSystem = int([3,0,0],pInt) !< total # of cleavage systems per family for hex - - integer(pInt), parameter , private :: & - LATTICE_hex_Nslip = 33_pInt, & ! sum(lattice_hex_NslipSystem), !< total # of slip systems for hex - LATTICE_hex_Ntwin = 24_pInt, & ! sum(lattice_hex_NtwinSystem) !< total # of twin systems for hex - LATTICE_hex_NnonSchmid = 0_pInt, & !< # of non-Schmid contributions for hex - LATTICE_hex_Ntrans = 0_pInt, & !< total # of transformations for hex - LATTICE_hex_Ncleavage = 3_pInt !< total # of transformations for hex - - real(pReal), dimension(4+4,LATTICE_hex_Nslip), parameter, private :: & - LATTICE_hex_systemSlip = reshape(real([& - ! Slip direction Plane normal - ! Basal systems <11.0>{00.1} (independent of c/a-ratio, Bravais notation (4 coordinate base)) - 2, -1, -1, 0, 0, 0, 0, 1, & - -1, 2, -1, 0, 0, 0, 0, 1, & - -1, -1, 2, 0, 0, 0, 0, 1, & - ! 1st type prismatic systems <11.0>{10.0} (independent of c/a-ratio) - 2, -1, -1, 0, 0, 1, -1, 0, & - -1, 2, -1, 0, -1, 0, 1, 0, & - -1, -1, 2, 0, 1, -1, 0, 0, & - ! 2nd type prismatic systems <10.0>{11.0} -- a slip; plane normals independent of c/a-ratio - 0, 1, -1, 0, 2, -1, -1, 0, & - -1, 0, 1, 0, -1, 2, -1, 0, & - 1, -1, 0, 0, -1, -1, 2, 0, & - ! 1st type 1st order pyramidal systems <11.0>{-11.1} -- plane normals depend on the c/a-ratio - 2, -1, -1, 0, 0, 1, -1, 1, & - -1, 2, -1, 0, -1, 0, 1, 1, & - -1, -1, 2, 0, 1, -1, 0, 1, & - 1, 1, -2, 0, -1, 1, 0, 1, & - -2, 1, 1, 0, 0, -1, 1, 1, & - 1, -2, 1, 0, 1, 0, -1, 1, & - ! pyramidal system: c+a slip <11.3>{-10.1} -- plane normals depend on the c/a-ratio - 2, -1, -1, 3, -1, 1, 0, 1, & - 1, -2, 1, 3, -1, 1, 0, 1, & - -1, -1, 2, 3, 1, 0, -1, 1, & - -2, 1, 1, 3, 1, 0, -1, 1, & - -1, 2, -1, 3, 0, -1, 1, 1, & - 1, 1, -2, 3, 0, -1, 1, 1, & - -2, 1, 1, 3, 1, -1, 0, 1, & - -1, 2, -1, 3, 1, -1, 0, 1, & - 1, 1, -2, 3, -1, 0, 1, 1, & - 2, -1, -1, 3, -1, 0, 1, 1, & - 1, -2, 1, 3, 0, 1, -1, 1, & - -1, -1, 2, 3, 0, 1, -1, 1, & - ! pyramidal system: c+a slip <11.3>{-1-1.2} -- as for hexagonal ice (Castelnau et al. 1996, similar to twin system found below) - 2, -1, -1, 3, -2, 1, 1, 2, & ! sorted according to similar twin system - -1, 2, -1, 3, 1, -2, 1, 2, & ! <11.3>{-1-1.2} shear = 2((c/a)^2-2)/(3 c/a) - -1, -1, 2, 3, 1, 1, -2, 2, & - -2, 1, 1, 3, 2, -1, -1, 2, & - 1, -2, 1, 3, -1, 2, -1, 2, & - 1, 1, -2, 3, -1, -1, 2, 2 & - ],pReal),[ 4_pInt + 4_pInt,LATTICE_hex_Nslip]) !< slip systems for hex sorted by A. Alankar & P. Eisenlohr - - real(pReal), dimension(4+4,LATTICE_hex_Ntwin), parameter, private :: & - LATTICE_hex_systemTwin = reshape(real([& - ! Compression or Tension =f(twinning shear=f(c/a)) for each metal ! (according to Yoo 1981) - 1, -1, 0, 1, -1, 1, 0, 2, & ! <-10.1>{10.2} shear = (3-(c/a)^2)/(sqrt(3) c/a) - -1, 0, 1, 1, 1, 0, -1, 2, & - 0, 1, -1, 1, 0, -1, 1, 2, & - -1, 1, 0, 1, 1, -1, 0, 2, & - 1, 0, -1, 1, -1, 0, 1, 2, & - 0, -1, 1, 1, 0, 1, -1, 2, & -! - 2, -1, -1, 6, -2, 1, 1, 1, & ! <11.6>{-1-1.1} shear = 1/(c/a) - -1, 2, -1, 6, 1, -2, 1, 1, & - -1, -1, 2, 6, 1, 1, -2, 1, & - -2, 1, 1, 6, 2, -1, -1, 1, & - 1, -2, 1, 6, -1, 2, -1, 1, & - 1, 1, -2, 6, -1, -1, 2, 1, & -! - -1, 1, 0, -2, -1, 1, 0, 1, & !! <10.-2>{10.1} shear = (4(c/a)^2-9)/(4 sqrt(3) c/a) - 1, 0, -1, -2, 1, 0, -1, 1, & - 0, -1, 1, -2, 0, -1, 1, 1, & - 1, -1, 0, -2, 1, -1, 0, 1, & - -1, 0, 1, -2, -1, 0, 1, 1, & - 0, 1, -1, -2, 0, 1, -1, 1, & -! - 2, -1, -1, -3, 2, -1, -1, 2, & ! <11.-3>{11.2} shear = 2((c/a)^2-2)/(3 c/a) - -1, 2, -1, -3, -1, 2, -1, 2, & - -1, -1, 2, -3, -1, -1, 2, 2, & - -2, 1, 1, -3, -2, 1, 1, 2, & - 1, -2, 1, -3, 1, -2, 1, 2, & - 1, 1, -2, -3, 1, 1, -2, 2 & - ],pReal),[ 4_pInt + 4_pInt ,LATTICE_hex_Ntwin]) !< twin systems for hex, order follows Prof. Tom Bieler's scheme; but numbering in data was restarted from 1 - - integer(pInt), dimension(LATTICE_hex_Ntwin), parameter, private :: & - LATTICE_hex_shearTwin = reshape(int( [& ! indicator to formula further below - 1, & ! <-10.1>{10.2} - 1, & - 1, & - 1, & - 1, & - 1, & - 2, & ! <11.6>{-1-1.1} - 2, & - 2, & - 2, & - 2, & - 2, & - 3, & ! <10.-2>{10.1} - 3, & - 3, & - 3, & - 3, & - 3, & - 4, & ! <11.-3>{11.2} - 4, & - 4, & - 4, & - 4, & - 4 & - ],pInt),[LATTICE_hex_Ntwin]) - - integer(pInt), dimension(LATTICE_hex_Nslip,LATTICE_hex_Nslip), parameter, public :: & - LATTICE_hex_interactionSlipSlip = reshape(int( [& - 1, 2, 2, 3, 3, 3, 7, 7, 7, 13,13,13,13,13,13, 21,21,21,21,21,21,21,21,21,21,21,21, 31,31,31,31,31,31, & ! ---> slip - 2, 1, 2, 3, 3, 3, 7, 7, 7, 13,13,13,13,13,13, 21,21,21,21,21,21,21,21,21,21,21,21, 31,31,31,31,31,31, & ! | - 2, 2, 1, 3, 3, 3, 7, 7, 7, 13,13,13,13,13,13, 21,21,21,21,21,21,21,21,21,21,21,21, 31,31,31,31,31,31, & ! | - ! v slip - 6, 6, 6, 4, 5, 5, 8, 8, 8, 14,14,14,14,14,14, 22,22,22,22,22,22,22,22,22,22,22,22, 32,32,32,32,32,32, & - 6, 6, 6, 5, 4, 5, 8, 8, 8, 14,14,14,14,14,14, 22,22,22,22,22,22,22,22,22,22,22,22, 32,32,32,32,32,32, & - 6, 6, 6, 5, 5, 4, 8, 8, 8, 14,14,14,14,14,14, 22,22,22,22,22,22,22,22,22,22,22,22, 32,32,32,32,32,32, & - ! - 12,12,12, 11,11,11, 9,10,10, 15,15,15,15,15,15, 23,23,23,23,23,23,23,23,23,23,23,23, 33,33,33,33,33,33, & - 12,12,12, 11,11,11, 10, 9,10, 15,15,15,15,15,15, 23,23,23,23,23,23,23,23,23,23,23,23, 33,33,33,33,33,33, & - 12,12,12, 11,11,11, 10,10, 9, 15,15,15,15,15,15, 23,23,23,23,23,23,23,23,23,23,23,23, 33,33,33,33,33,33, & - ! - 20,20,20, 19,19,19, 18,18,18, 16,17,17,17,17,17, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & - 20,20,20, 19,19,19, 18,18,18, 17,16,17,17,17,17, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & - 20,20,20, 19,19,19, 18,18,18, 17,17,16,17,17,17, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & - 20,20,20, 19,19,19, 18,18,18, 17,17,17,16,17,17, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & - 20,20,20, 19,19,19, 18,18,18, 17,17,17,17,16,17, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & - 20,20,20, 19,19,19, 18,18,18, 17,17,17,17,17,16, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & - ! - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 25,26,26,26,26,26,26,26,26,26,26,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,25,26,26,26,26,26,26,26,26,26,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,25,26,26,26,26,26,26,26,26,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,25,26,26,26,26,26,26,26,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,25,26,26,26,26,26,26,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,25,26,26,26,26,26,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,25,26,26,26,26,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,26,25,26,26,26,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,26,26,25,26,26,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,26,26,26,25,26,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,26,26,26,26,25,26, 35,35,35,35,35,35, & - 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,26,26,26,26,26,25, 35,35,35,35,35,35, & - ! - 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 36,37,37,37,37,37, & - 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 37,36,37,37,37,37, & - 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 37,37,36,37,37,37, & - 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 37,37,37,36,37,37, & - 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 37,37,37,37,36,37, & - 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 37,37,37,37,37,36 & - ! - ],pInt),[LATTICE_hex_Nslip,LATTICE_hex_Nslip],order=[2,1]) !< Slip--slip interaction types for hex (onion peel naming scheme) - - integer(pInt), dimension(LATTICE_hex_Nslip,LATTICE_hex_Ntwin), parameter, public :: & - LATTICE_hex_interactionSlipTwin = reshape(int( [& - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, & ! --> twin - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, & ! | - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, & ! | - ! v - 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, & ! slip - 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, & - 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, & - ! - 9, 9, 9, 9, 9, 9, 10,10,10,10,10,10, 11,11,11,11,11,11, 12,12,12,12,12,12, & - 9, 9, 9, 9, 9, 9, 10,10,10,10,10,10, 11,11,11,11,11,11, 12,12,12,12,12,12, & - 9, 9, 9, 9, 9, 9, 10,10,10,10,10,10, 11,11,11,11,11,11, 12,12,12,12,12,12, & - ! - 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & - 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & - 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & - 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & - 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & - 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & - ! - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & - ! - 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24, & - 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24, & - 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24, & - 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24, & - 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24, & - 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24 & - ! - ],pInt),[LATTICE_hex_Nslip,LATTICE_hex_Ntwin],order=[2,1]) !< Slip--twin interaction types for hex (isotropic, 24 in total) - - integer(pInt), dimension(LATTICE_hex_Ntwin,LATTICE_hex_Nslip), parameter, public :: & - LATTICE_hex_interactionTwinSlip = reshape(int( [& - 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & ! --> slip - 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & ! | - 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & ! | - 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & ! v - 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & ! twin - 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & - ! - 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & - 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & - 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & - 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & - 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & - 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & - ! - 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & - 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & - 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & - 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & - 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & - 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & - ! - 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24, & - 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24, & - 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24, & - 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24, & - 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24, & - 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24 & - ],pInt),[LATTICE_hex_Ntwin,LATTICE_hex_Nslip],order=[2,1]) !< Twin--twin interaction types for hex (isotropic, 20 in total) - - integer(pInt), dimension(LATTICE_hex_Ntwin,LATTICE_hex_Ntwin), parameter, public :: & - LATTICE_hex_interactionTwinTwin = reshape(int( [& - 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & ! ---> twin - 2, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & ! | - 2, 2, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & ! | - 2, 2, 2, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & ! v twin - 2, 2, 2, 2, 1, 2, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & - 2, 2, 2, 2, 2, 1, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & - ! - 6, 6, 6, 6, 6, 6, 4, 5, 5, 5, 5, 5, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & - 6, 6, 6, 6, 6, 6, 5, 4, 5, 5, 5, 5, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & - 6, 6, 6, 6, 6, 6, 5, 5, 4, 5, 5, 5, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & - 6, 6, 6, 6, 6, 6, 5, 5, 5, 4, 5, 5, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & - 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, 5, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & - 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & - ! - 12,12,12,12,12,12, 11,11,11,11,11,11, 9,10,10,10,10,10, 15,15,15,15,15,15, & - 12,12,12,12,12,12, 11,11,11,11,11,11, 10, 9,10,10,10,10, 15,15,15,15,15,15, & - 12,12,12,12,12,12, 11,11,11,11,11,11, 10,10, 9,10,10,10, 15,15,15,15,15,15, & - 12,12,12,12,12,12, 11,11,11,11,11,11, 10,10,10, 9,10,10, 15,15,15,15,15,15, & - 12,12,12,12,12,12, 11,11,11,11,11,11, 10,10,10,10, 9,10, 15,15,15,15,15,15, & - 12,12,12,12,12,12, 11,11,11,11,11,11, 10,10,10,10,10, 9, 15,15,15,15,15,15, & - ! - 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 16,17,17,17,17,17, & - 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,16,17,17,17,17, & - 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,17,16,17,17,17, & - 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,17,17,16,17,17, & - 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,17,17,17,16,17, & - 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,17,17,17,17,16 & - ],pInt),[lattice_hex_Ntwin,lattice_hex_Ntwin],order=[2,1]) !< Twin--slip interaction types for hex (isotropic, 16 in total) - - real(pReal), dimension(4+4,LATTICE_hex_Ncleavage), parameter, private :: & - LATTICE_hex_systemCleavage = reshape(real([& - ! Cleavage direction Plane normal - 2,-1,-1, 0, 0, 0, 0, 1, & - 0, 0, 0, 1, 2,-1,-1, 0, & - 0, 0, 0, 1, 0, 1,-1, 0 & - ],pReal),[ 4_pInt + 4_pInt,LATTICE_hex_Ncleavage]) - - - -!-------------------------------------------------------------------------------------------------- -! bct - integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & - LATTICE_bct_NslipSystem = int([2, 2, 2, 4, 2, 4, 2, 2, 4, 8, 4, 8, 8 ],pInt) !< # of slip systems per family for bct (Sn) Bieler J. Electr Mater 2009 - - integer(pInt), dimension(LATTICE_maxNtwinFamily), parameter, public :: & - LATTICE_bct_NtwinSystem = int([0, 0, 0, 0], pInt) !< total # of twin systems per family for bct-example - - integer(pInt), dimension(LATTICE_maxNtransFamily), parameter, public :: & - LATTICE_bct_NtransSystem = int([0,0],pInt) !< total # of transformation systems per family for bct - - integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & - LATTICE_bct_NcleavageSystem = int([0,0,0],pInt) !< total # of cleavage systems per family for bct - - - integer(pInt), parameter , private :: & - LATTICE_bct_Nslip = 52_pInt, & ! sum(lattice_bct_NslipSystem), !< total # of slip systems for bct - LATTICE_bct_Ntwin = 0_pInt, & ! sum(lattice_bcc_NtwinSystem) !< total # of twin systems for bct - LATTICE_bct_NnonSchmid = 0_pInt, & !< # of non-Schmid contributions for bct - LATTICE_bct_Ntrans = 0_pInt, & !< total # of transformations for bct - LATTICE_bct_Ncleavage = 0_pInt !< total # of transformations for bct - - real(pReal), dimension(3+3,LATTICE_bct_Nslip), parameter, private :: & - LATTICE_bct_systemSlip = reshape(real([& - ! Slip direction Plane normal - ! Slip family 1 {100)<001] (Bravais notation {hkl) @brief Module initialization -!-------------------------------------------------------------------------------------------------- -subroutine lattice_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_open_file,& - IO_open_jobFile_stat, & - IO_countSections, & - IO_error, & - IO_timeStamp, & - IO_EOF, & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue - use material, only: & - material_configfile, & - material_localFileExt, & - material_partPhase - use debug, only: & - debug_level, & - debug_lattice, & - debug_levelBasic - use numerics, only: & - worldrank - - implicit none - integer(pInt), parameter :: FILEUNIT = 200_pInt - integer(pInt) :: Nphases - character(len=65536) :: & - tag = '', & - line = '' - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: section = 0_pInt,i - real(pReal), dimension(:), allocatable :: & - CoverA, & !!!!!!< c/a ratio for low symmetry type lattice - CoverA_trans, & !< c/a ratio for transformed hex type lattice - a_fcc, & !< lattice parameter a for fcc austenite - a_bcc !< lattice paramater a for bcc martensite - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- lattice init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!-------------------------------------------------------------------------------------------------- -! consistency checks - - if (LATTICE_maxNslip /= maxval([LATTICE_fcc_Nslip,LATTICE_bcc_Nslip,LATTICE_hex_Nslip,LATTICE_bct_Nslip])) & - call IO_error(0_pInt,ext_msg = 'LATTICE_maxNslip') - if (LATTICE_maxNtwin /= maxval([LATTICE_fcc_Ntwin,LATTICE_bcc_Ntwin,LATTICE_hex_Ntwin])) & - call IO_error(0_pInt,ext_msg = 'LATTICE_maxNtwin') - if (LATTICE_maxNtrans /= maxval([LATTICE_fcc_Ntrans,LATTICE_bcc_Ntrans,LATTICE_hex_Ntrans])) & - call IO_error(0_pInt,ext_msg = 'LATTICE_maxNtrans') - if (LATTICE_maxNnonSchmid /= maxval([lattice_fcc_NnonSchmid,lattice_bcc_NnonSchmid,& - lattice_hex_NnonSchmid])) call IO_error(0_pInt,ext_msg = 'LATTICE_maxNnonSchmid') - - if (LATTICE_fcc_Nslip /= sum(lattice_fcc_NslipSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_fcc_Nslip') - if (LATTICE_bcc_Nslip /= sum(lattice_bcc_NslipSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_bcc_Nslip') - if (LATTICE_hex_Nslip /= sum(lattice_hex_NslipSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_hex_Nslip') - if (LATTICE_bct_Nslip /= sum(lattice_bct_NslipSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_bct_Nslip') - - if (LATTICE_fcc_Ntwin /= sum(lattice_fcc_NtwinSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_fcc_Ntwin') - if (LATTICE_bcc_Ntwin /= sum(lattice_bcc_NtwinSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_bcc_Ntwin') - if (LATTICE_hex_Ntwin /= sum(lattice_hex_NtwinSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_hex_Ntwin') - if (LATTICE_bct_Ntwin /= sum(lattice_bct_NtwinSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_bct_Ntwin') - - if (LATTICE_fcc_Ntrans /= sum(lattice_fcc_NtransSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_fcc_Ntrans') - if (LATTICE_bcc_Ntrans /= sum(lattice_bcc_NtransSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_bcc_Ntrans') - if (LATTICE_hex_Ntrans /= sum(lattice_hex_NtransSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_hex_Ntrans') - if (LATTICE_bct_Ntrans /= sum(lattice_bct_NtransSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_bct_Ntrans') - - if (LATTICE_fcc_Ncleavage /= sum(lattice_fcc_NcleavageSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_fcc_Ncleavage') - if (LATTICE_bcc_Ncleavage /= sum(lattice_bcc_NcleavageSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_bcc_Ncleavage') - if (LATTICE_hex_Ncleavage /= sum(lattice_hex_NcleavageSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_hex_Ncleavage') - if (LATTICE_bct_Ncleavage /= sum(lattice_bct_NcleavageSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_bct_Ncleavage') - if (LATTICE_iso_Ncleavage /= sum(lattice_iso_NcleavageSystem)) & - call IO_error(0_pInt,ext_msg = 'LATTICE_iso_Ncleavage') - - if (LATTICE_maxNinteraction /= max(& - maxval(lattice_fcc_interactionSlipSlip), & - maxval(lattice_bcc_interactionSlipSlip), & - maxval(lattice_hex_interactionSlipSlip), & - maxval(lattice_bct_interactionSlipSlip), & - ! - maxval(lattice_fcc_interactionSlipTwin), & - maxval(lattice_bcc_interactionSlipTwin), & - maxval(lattice_hex_interactionSlipTwin), & -! maxval(lattice_bct_interactionSlipTwin), & - ! - maxval(lattice_fcc_interactionTwinSlip), & - maxval(lattice_bcc_interactionTwinSlip), & - maxval(lattice_hex_interactionTwinSlip), & -! maxval(lattice_bct_interactionTwinSlip), & - ! - maxval(lattice_fcc_interactionTwinTwin), & - maxval(lattice_bcc_interactionTwinTwin), & - maxval(lattice_hex_interactionTwinTwin))) & -! maxval(lattice_bct_interactionTwinTwin))) & - call IO_error(0_pInt,ext_msg = 'LATTICE_maxNinteraction') - -!-------------------------------------------------------------------------------------------------- -! read from material configuration file - if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... - call IO_open_file(FILEUNIT,material_configFile) ! ... open material.config file - Nphases = IO_countSections(FILEUNIT,material_partPhase) - - if(Nphases<1_pInt) & - call IO_error(160_pInt,Nphases, ext_msg='No phases found') - - if (iand(debug_level(debug_lattice),debug_levelBasic) /= 0_pInt) then - write(6,'(a16,1x,i5)') ' # phases:',Nphases - endif - - allocate(lattice_structure(Nphases),source = LATTICE_undefined_ID) - allocate(trans_lattice_structure(Nphases),source = LATTICE_undefined_ID) - allocate(lattice_C66(6,6,Nphases), source=0.0_pReal) - allocate(lattice_C3333(3,3,3,3,Nphases), source=0.0_pReal) - allocate(lattice_trans_C66(6,6,Nphases), source=0.0_pReal) - allocate(lattice_trans_C3333(3,3,3,3,Nphases), source=0.0_pReal) - allocate(lattice_thermalConductivity33 (3,3,Nphases), source=0.0_pReal) - allocate(lattice_thermalExpansion33 (3,3,Nphases), source=0.0_pReal) - allocate(lattice_damageDiffusion33 (3,3,Nphases), source=0.0_pReal) - allocate(lattice_vacancyfluxDiffusion33 (3,3,Nphases), source=0.0_pReal) - allocate(lattice_vacancyfluxMobility33 (3,3,Nphases), source=0.0_pReal) - allocate(lattice_PorosityDiffusion33 (3,3,Nphases), source=0.0_pReal) - allocate(lattice_hydrogenfluxDiffusion33(3,3,Nphases), source=0.0_pReal) - allocate(lattice_hydrogenfluxMobility33 (3,3,Nphases), source=0.0_pReal) - allocate(lattice_damageMobility ( Nphases), source=0.0_pReal) - allocate(lattice_PorosityMobility ( Nphases), source=0.0_pReal) - allocate(lattice_massDensity ( Nphases), source=0.0_pReal) - allocate(lattice_specificHeat ( Nphases), source=0.0_pReal) - allocate(lattice_vacancyFormationEnergy ( Nphases), source=0.0_pReal) - allocate(lattice_vacancySurfaceEnergy ( Nphases), source=0.0_pReal) - allocate(lattice_vacancyVol ( Nphases), source=0.0_pReal) - allocate(lattice_hydrogenFormationEnergy( Nphases), source=0.0_pReal) - allocate(lattice_hydrogenSurfaceEnergy ( Nphases), source=0.0_pReal) - allocate(lattice_hydrogenVol ( Nphases), source=0.0_pReal) - allocate(lattice_referenceTemperature ( Nphases), source=300.0_pReal) - allocate(lattice_equilibriumVacancyConcentration(Nphases), source=0.0_pReal) - allocate(lattice_equilibriumHydrogenConcentration(Nphases),source=0.0_pReal) - - allocate(lattice_mu(Nphases), source=0.0_pReal) - allocate(lattice_nu(Nphases), source=0.0_pReal) - allocate(lattice_trans_mu(Nphases), source=0.0_pReal) - allocate(lattice_trans_nu(Nphases), source=0.0_pReal) - - allocate(lattice_NnonSchmid(Nphases), source=0_pInt) - allocate(lattice_Sslip(3,3,1+2*lattice_maxNnonSchmid,lattice_maxNslip,Nphases),source=0.0_pReal) - allocate(lattice_Sslip_v(6,1+2*lattice_maxNnonSchmid,lattice_maxNslip,Nphases),source=0.0_pReal) - allocate(lattice_Scleavage(3,3,3,lattice_maxNslip,Nphases),source=0.0_pReal) - allocate(lattice_Scleavage_v(6,3,lattice_maxNslip,Nphases),source=0.0_pReal) - allocate(lattice_sd(3,lattice_maxNslip,Nphases),source=0.0_pReal) - allocate(lattice_st(3,lattice_maxNslip,Nphases),source=0.0_pReal) - allocate(lattice_sn(3,lattice_maxNslip,Nphases),source=0.0_pReal) - - allocate(lattice_Qtwin(3,3,lattice_maxNtwin,Nphases),source=0.0_pReal) - allocate(lattice_Stwin(3,3,lattice_maxNtwin,Nphases),source=0.0_pReal) - allocate(lattice_Stwin_v(6,lattice_maxNtwin,Nphases),source=0.0_pReal) - allocate(lattice_td(3,lattice_maxNtwin,Nphases),source=0.0_pReal) - allocate(lattice_tt(3,lattice_maxNtwin,Nphases),source=0.0_pReal) - allocate(lattice_tn(3,lattice_maxNtwin,Nphases),source=0.0_pReal) - - allocate(lattice_shearTwin(lattice_maxNtwin,Nphases),source=0.0_pReal) - allocate(lattice_shearTrans(lattice_maxNtrans,Nphases),source=0.0_pReal) - - allocate(lattice_Qtrans(3,3,lattice_maxNtrans,Nphases),source=0.0_pReal) - allocate(lattice_Strans(3,3,lattice_maxNtrans,Nphases),source=0.0_pReal) - allocate(lattice_Strans_v(6,lattice_maxNtrans,Nphases),source=0.0_pReal) - allocate(lattice_projectionTrans(lattice_maxNtrans,lattice_maxNtrans,Nphases),source=0.0_pReal) - - allocate(lattice_NslipSystem(lattice_maxNslipFamily,Nphases),source=0_pInt) - allocate(lattice_NtwinSystem(lattice_maxNtwinFamily,Nphases),source=0_pInt) - allocate(lattice_NtransSystem(lattice_maxNtransFamily,Nphases),source=0_pInt) - allocate(lattice_NcleavageSystem(lattice_maxNcleavageFamily,Nphases),source=0_pInt) - - allocate(lattice_interactionSlipSlip(lattice_maxNslip,lattice_maxNslip,Nphases),source=0_pInt) ! other:me - allocate(lattice_interactionSlipTwin(lattice_maxNslip,lattice_maxNtwin,Nphases),source=0_pInt) ! other:me - allocate(lattice_interactionTwinSlip(lattice_maxNtwin,lattice_maxNslip,Nphases),source=0_pInt) ! other:me - allocate(lattice_interactionTwinTwin(lattice_maxNtwin,lattice_maxNtwin,Nphases),source=0_pInt) ! other:me - allocate(lattice_interactionSlipTrans(lattice_maxNslip,lattice_maxNtrans,Nphases),source=0_pInt) ! other:me - allocate(lattice_interactionTransSlip(lattice_maxNtrans,lattice_maxNslip,Nphases),source=0_pInt) ! other:me - allocate(lattice_interactionTransTrans(lattice_maxNtrans,lattice_maxNtrans,Nphases),source=0_pInt) ! other:me - - allocate(CoverA(Nphases),source=0.0_pReal) - allocate(CoverA_trans(Nphases),source=0.0_pReal) - allocate(a_fcc(Nphases),source=0.0_pReal) - allocate(a_bcc(Nphases),source=0.0_pReal) - - rewind(fileUnit) - line = '' ! to have it initialized - section = 0_pInt ! - " - - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - do while (trim(line) /= IO_EOF) ! read through sections of material part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - endif - if (section > 0_pInt) then - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('lattice_structure') - select case(trim(IO_lc(IO_stringValue(line,chunkPos,2_pInt)))) - case('iso','isotropic') - lattice_structure(section) = LATTICE_iso_ID - case('fcc') - lattice_structure(section) = LATTICE_fcc_ID - case('bcc') - lattice_structure(section) = LATTICE_bcc_ID - case('hex','hexagonal') - lattice_structure(section) = LATTICE_hex_ID - case('bct') - lattice_structure(section) = LATTICE_bct_ID - case('ort','orthorhombic') - lattice_structure(section) = LATTICE_ort_ID - case default - call IO_error(130_pInt,ext_msg=trim(IO_lc(IO_stringValue(line,chunkPos,2_pInt)))) - end select - case('trans_lattice_structure') - select case(trim(IO_lc(IO_stringValue(line,chunkPos,2_pInt)))) - case('bcc') - trans_lattice_structure(section) = LATTICE_bcc_ID - case('hex','hexagonal','hcp') - trans_lattice_structure(section) = LATTICE_hex_ID - end select - case ('c11') - lattice_C66(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c12') - lattice_C66(1,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c13') - lattice_C66(1,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c22') - lattice_C66(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c23') - lattice_C66(2,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c33') - lattice_C66(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c44') - lattice_C66(4,4,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c55') - lattice_C66(5,5,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c66') - lattice_C66(6,6,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c11_trans') - lattice_trans_C66(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c12_trans') - lattice_trans_C66(1,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c13_trans') - lattice_trans_C66(1,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c22_trans') - lattice_trans_C66(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c23_trans') - lattice_trans_C66(2,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c33_trans') - lattice_trans_C66(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c44_trans') - lattice_trans_C66(4,4,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c55_trans') - lattice_trans_C66(5,5,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c66_trans') - lattice_trans_C66(6,6,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('covera_ratio','c/a_ratio','c/a') - CoverA(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('c/a_trans','c/a_martensite','c/a_mart') - CoverA_trans(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('a_fcc') - a_fcc(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('a_bcc') - a_bcc(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('thermal_conductivity11') - lattice_thermalConductivity33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('thermal_conductivity22') - lattice_thermalConductivity33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('thermal_conductivity33') - lattice_thermalConductivity33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('thermal_expansion11') - lattice_thermalExpansion33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('thermal_expansion22') - lattice_thermalExpansion33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('thermal_expansion33') - lattice_thermalExpansion33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('specific_heat') - lattice_specificHeat(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancyformationenergy') - lattice_vacancyFormationEnergy(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancysurfaceenergy') - lattice_vacancySurfaceEnergy(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancyvolume') - lattice_vacancyVol(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogenformationenergy') - lattice_hydrogenFormationEnergy(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogensurfaceenergy') - lattice_hydrogenSurfaceEnergy(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogenvolume') - lattice_hydrogenVol(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('mass_density') - lattice_massDensity(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('reference_temperature') - lattice_referenceTemperature(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('damage_diffusion11') - lattice_DamageDiffusion33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('damage_diffusion22') - lattice_DamageDiffusion33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('damage_diffusion33') - lattice_DamageDiffusion33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('damage_mobility') - lattice_DamageMobility(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancyflux_diffusion11') - lattice_vacancyfluxDiffusion33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancyflux_diffusion22') - lattice_vacancyfluxDiffusion33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancyflux_diffusion33') - lattice_vacancyfluxDiffusion33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancyflux_mobility11') - lattice_vacancyfluxMobility33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancyflux_mobility22') - lattice_vacancyfluxMobility33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancyflux_mobility33') - lattice_vacancyfluxMobility33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('porosity_diffusion11') - lattice_PorosityDiffusion33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('porosity_diffusion22') - lattice_PorosityDiffusion33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('porosity_diffusion33') - lattice_PorosityDiffusion33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('porosity_mobility') - lattice_PorosityMobility(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogenflux_diffusion11') - lattice_hydrogenfluxDiffusion33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogenflux_diffusion22') - lattice_hydrogenfluxDiffusion33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogenflux_diffusion33') - lattice_hydrogenfluxDiffusion33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogenflux_mobility11') - lattice_hydrogenfluxMobility33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogenflux_mobility22') - lattice_hydrogenfluxMobility33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogenflux_mobility33') - lattice_hydrogenfluxMobility33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancy_eqcv') - lattice_equilibriumVacancyConcentration(section) = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogen_eqch') - lattice_equilibriumHydrogenConcentration(section) = IO_floatValue(line,chunkPos,2_pInt) - end select - endif - enddo - - do i = 1_pInt,Nphases - if ((CoverA(i) < 1.0_pReal .or. CoverA(i) > 2.0_pReal) & - .and. lattice_structure(i) == LATTICE_hex_ID) call IO_error(131_pInt,el=i) ! checking physical significance of c/a - if ((CoverA(i) > 2.0_pReal) & - .and. lattice_structure(i) == LATTICE_bct_ID) call IO_error(131_pInt,el=i) ! checking physical significance of c/a - call lattice_initializeStructure(i, CoverA(i), CoverA_trans(i), a_fcc(i), a_bcc(i)) - enddo - - deallocate(CoverA,CoverA_trans,a_fcc,a_bcc) - -end subroutine lattice_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief Calculation of Schmid matrices, etc. -!-------------------------------------------------------------------------------------------------- -subroutine lattice_initializeStructure(myPhase,CoverA,CoverA_trans,a_fcc,a_bcc) - use prec, only: & - tol_math_check - use math, only: & - math_crossproduct, & - math_tensorproduct33, & - math_mul33x33, & - math_mul33x3, & - math_transpose33, & - math_trace33, & - math_symmetric33, & - math_Mandel33to6, & - math_Mandel3333to66, & - math_Voigt66to3333, & - math_axisAngleToR, & - INRAD, & - MATH_I3 - use IO, only: & - IO_error, & - IO_warning - - implicit none - integer(pInt), intent(in) :: myPhase - real(pReal), intent(in) :: & - CoverA, & - CoverA_trans, & - a_fcc, & - a_bcc - - real(pReal), dimension(3) :: & - sdU, snU, & - np, nn - real(pReal), dimension(3,3) :: & - sstr, sdtr, sttr - real(pReal), dimension(3,lattice_maxNslip) :: & - sd, sn - real(pReal), dimension(3,3,2,lattice_maxNnonSchmid,lattice_maxNslip) :: & - sns - real(pReal), dimension(3,lattice_maxNtwin) :: & - td, tn - real(pReal), dimension(lattice_maxNtwin) :: & - ts - real(pReal), dimension(lattice_maxNtrans) :: & - trs - real(pReal), dimension(3,lattice_maxNtrans) :: & - xtr, ytr, ztr - real(pReal), dimension(3,3,lattice_maxNtrans) :: & - Rtr, Utr, Btr, Qtr, Str - real(pReal), dimension(3,lattice_maxNcleavage) :: & - cd, cn, ct - integer(pInt) :: & - i,j, & - myNslip = 0_pInt, myNtwin = 0_pInt, myNtrans = 0_pInt, myNcleavage = 0_pInt - real(pReal) :: c11bar, c12bar, c13bar, c14bar, c33bar, c44bar, A, B - - lattice_C66(1:6,1:6,myPhase) = lattice_symmetrizeC66(lattice_structure(myPhase),& - lattice_C66(1:6,1:6,myPhase)) - - lattice_mu(myPhase) = 0.2_pReal *( lattice_C66(1,1,myPhase) & - - lattice_C66(1,2,myPhase) & - + 3.0_pReal*lattice_C66(4,4,myPhase)) ! (C11iso-C12iso)/2 with C11iso=(3*C11+2*C12+4*C44)/5 and C12iso=(C11+4*C12-2*C44)/5 - lattice_nu(myPhase) = ( lattice_C66(1,1,myPhase) & - + 4.0_pReal*lattice_C66(1,2,myPhase) & - - 2.0_pReal*lattice_C66(4,4,myPhase)) & - /( 4.0_pReal*lattice_C66(1,1,myPhase) & - + 6.0_pReal*lattice_C66(1,2,myPhase) & - + 2.0_pReal*lattice_C66(4,4,myPhase))! C12iso/(C11iso+C12iso) with C11iso=(3*C11+2*C12+4*C44)/5 and C12iso=(C11+4*C12-2*C44)/5 - lattice_C3333(1:3,1:3,1:3,1:3,myPhase) = math_Voigt66to3333(lattice_C66(1:6,1:6,myPhase)) ! Literature data is Voigt - lattice_C66(1:6,1:6,myPhase) = math_Mandel3333to66(lattice_C3333(1:3,1:3,1:3,1:3,myPhase)) ! DAMASK uses Mandel - do i = 1_pInt, 6_pInt - if (abs(lattice_C66(i,i,myPhase)) 0.0_pReal) .and. (a_bcc > 0.0_pReal)) then - Utr(1:3,1:3,i) = (a_bcc/a_fcc)*math_tensorproduct33(xtr(1:3,i), xtr(1:3,i)) + & - sqrt(2.0_pReal)*(a_bcc/a_fcc)*math_tensorproduct33(ytr(1:3,i), ytr(1:3,i)) + & - sqrt(2.0_pReal)*(a_bcc/a_fcc)*math_tensorproduct33(ztr(1:3,i), ztr(1:3,i)) - endif - Qtr(1:3,1:3,i) = math_mul33x33(Rtr(1:3,1:3,i), Btr(1:3,1:3,i)) - Str(1:3,1:3,i) = math_mul33x33(Rtr(1:3,1:3,i), Utr(1:3,1:3,i)) - MATH_I3 - enddo - case (LATTICE_hex_ID) - sstr(1:3,1:3) = MATH_I3 - sstr(1,3) = sqrt(2.0_pReal)/4.0_pReal - sdtr(1:3,1:3) = MATH_I3 - if (CoverA_trans > 1.0_pReal .and. CoverA_trans < 2.0_pReal) then - sdtr(3,3) = CoverA_trans/sqrt(8.0_pReal/3.0_pReal) - endif - sttr = math_mul33x33(sdtr, sstr) - do i = 1_pInt,myNtrans - xtr(1:3,i) = lattice_fccTohex_systemTrans(1:3,i)/norm2(lattice_fccTohex_systemTrans(1:3,i)) - ztr(1:3,i) = lattice_fccTohex_systemTrans(4:6,i)/norm2(lattice_fccTohex_systemTrans(4:6,i)) - ytr(1:3,i) = -math_crossproduct(xtr(1:3,i), ztr(1:3,i)) - Rtr(1:3,1,i) = xtr(1:3,i) - Rtr(1:3,2,i) = ytr(1:3,i) - Rtr(1:3,3,i) = ztr(1:3,i) - Qtr(1:3,1:3,i) = Rtr(1:3,1:3,i) - Str(1:3,1:3,i) = math_mul33x33(Rtr(1:3,1:3,i), math_mul33x33(sttr, math_transpose33(Rtr(1:3,1:3,i)))) - Str(1:3,1:3,i) = Str(1:3,1:3,i) - MATH_I3 - trs(i) = lattice_fccTohex_shearTrans(i) - enddo - case default - Qtr = 0.0_pReal - Str = 0.0_pReal - end select - - lattice_NslipSystem(1:lattice_maxNslipFamily,myPhase) = lattice_fcc_NslipSystem - lattice_NtwinSystem(1:lattice_maxNtwinFamily,myPhase) = lattice_fcc_NtwinSystem - lattice_NtransSystem(1:lattice_maxNtransFamily,myPhase) = lattice_fcc_NtransSystem - lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_fcc_NcleavageSystem - lattice_NnonSchmid(myPhase) = lattice_fcc_NnonSchmid - lattice_interactionSlipSlip(1:myNslip,1:myNslip,myPhase) = lattice_fcc_interactionSlipSlip - lattice_interactionSlipTwin(1:myNslip,1:myNtwin,myPhase) = lattice_fcc_interactionSlipTwin - lattice_interactionTwinSlip(1:myNtwin,1:myNslip,myPhase) = lattice_fcc_interactionTwinSlip - lattice_interactionTwinTwin(1:myNtwin,1:myNtwin,myPhase) = lattice_fcc_interactionTwinTwin - lattice_interactionSlipTrans(1:myNslip,1:myNtrans,myPhase) = lattice_fccTohex_interactionSlipTrans - lattice_interactionTransSlip(1:myNtrans,1:myNslip,myPhase) = lattice_fccTohex_interactionTransSlip - lattice_interactionTransTrans(1:myNtrans,1:myNtrans,myPhase) = lattice_fccTohex_interactionTransTrans - lattice_projectionTrans(1:myNtrans,1:myNtrans,myPhase) = LATTICE_fccTobcc_projectionTrans*& - LATTICE_fccTobcc_projectionTransFactor - -!-------------------------------------------------------------------------------------------------- -! bcc - case (LATTICE_bcc_ID) - myNslip = lattice_bcc_Nslip - myNtwin = lattice_bcc_Ntwin - myNtrans = lattice_bcc_Ntrans - myNcleavage = lattice_bcc_Ncleavage - do i = 1_pInt,myNslip ! assign slip system vectors - sd(1:3,i) = lattice_bcc_systemSlip(1:3,i) - sn(1:3,i) = lattice_bcc_systemSlip(4:6,i) - sdU = sd(1:3,i) / norm2(sd(1:3,i)) - snU = sn(1:3,i) / norm2(sn(1:3,i)) - ! "np" and "nn" according to Gröger_etal2008, Acta Materialia 56 (2008) 5412–5425, table 1 (corresponds to their "n1" for positive and negative slip direction respectively) - np = math_mul33x3(math_axisAngleToR(sdU,60.0_pReal*INRAD), snU) - nn = math_mul33x3(math_axisAngleToR(-sdU,60.0_pReal*INRAD), snU) - ! Schmid matrices with non-Schmid contributions according to Koester_etal2012, Acta Materialia 60 (2012) 3894–3901, eq. (17) ("n1" is replaced by either "np" or "nn" according to either positive or negative slip direction) - sns(1:3,1:3,1,1,i) = math_tensorproduct33(sdU, np) - sns(1:3,1:3,2,1,i) = math_tensorproduct33(-sdU, nn) - sns(1:3,1:3,1,2,i) = math_tensorproduct33(math_crossproduct(snU, sdU), snU) - sns(1:3,1:3,2,2,i) = math_tensorproduct33(math_crossproduct(snU, -sdU), snU) - sns(1:3,1:3,1,3,i) = math_tensorproduct33(math_crossproduct(np, sdU), np) - sns(1:3,1:3,2,3,i) = math_tensorproduct33(math_crossproduct(nn, -sdU), nn) - sns(1:3,1:3,1,4,i) = math_tensorproduct33(snU, snU) - sns(1:3,1:3,2,4,i) = math_tensorproduct33(snU, snU) - sns(1:3,1:3,1,5,i) = math_tensorproduct33(math_crossproduct(snU, sdU), math_crossproduct(snU, sdU)) - sns(1:3,1:3,2,5,i) = math_tensorproduct33(math_crossproduct(snU, -sdU), math_crossproduct(snU, -sdU)) - sns(1:3,1:3,1,6,i) = math_tensorproduct33(sdU, sdU) - sns(1:3,1:3,2,6,i) = math_tensorproduct33(-sdU, -sdU) - enddo - do i = 1_pInt,myNtwin ! assign twin system vectors and shears - td(1:3,i) = lattice_bcc_systemTwin(1:3,i) - tn(1:3,i) = lattice_bcc_systemTwin(4:6,i) - ts(i) = lattice_bcc_shearTwin(i) - enddo - do i = 1_pInt, myNcleavage ! assign cleavage system vectors - cd(1:3,i) = lattice_bcc_systemCleavage(1:3,i)/norm2(lattice_bcc_systemCleavage(1:3,i)) - cn(1:3,i) = lattice_bcc_systemCleavage(4:6,i)/norm2(lattice_bcc_systemCleavage(4:6,i)) - ct(1:3,i) = math_crossproduct(cd(1:3,i),cn(1:3,i)) - enddo - lattice_NslipSystem(1:lattice_maxNslipFamily,myPhase) = lattice_bcc_NslipSystem - lattice_NtwinSystem(1:lattice_maxNtwinFamily,myPhase) = lattice_bcc_NtwinSystem - lattice_NtransSystem(1:lattice_maxNtransFamily,myPhase) = lattice_bcc_NtransSystem - lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_bcc_NcleavageSystem - lattice_NnonSchmid(myPhase) = lattice_bcc_NnonSchmid - lattice_interactionSlipSlip(1:myNslip,1:myNslip,myPhase) = lattice_bcc_interactionSlipSlip - lattice_interactionSlipTwin(1:myNslip,1:myNtwin,myPhase) = lattice_bcc_interactionSlipTwin - lattice_interactionTwinSlip(1:myNtwin,1:myNslip,myPhase) = lattice_bcc_interactionTwinSlip - lattice_interactionTwinTwin(1:myNtwin,1:myNtwin,myPhase) = lattice_bcc_interactionTwinTwin - -!-------------------------------------------------------------------------------------------------- -! hex (including conversion from miller-bravais (a1=a2=a3=c) to miller (a, b, c) indices) - case (LATTICE_hex_ID) - myNslip = lattice_hex_Nslip - myNtwin = lattice_hex_Ntwin - myNtrans = lattice_hex_Ntrans - myNcleavage = lattice_hex_Ncleavage - do i = 1_pInt,myNslip ! assign slip system vectors - sd(1,i) = lattice_hex_systemSlip(1,i)*1.5_pReal ! direction [uvtw]->[3u/2 (u+2v)*sqrt(3)/2 w*(c/a)] - sd(2,i) = (lattice_hex_systemSlip(1,i)+2.0_pReal*lattice_hex_systemSlip(2,i))*& - 0.5_pReal*sqrt(3.0_pReal) - sd(3,i) = lattice_hex_systemSlip(4,i)*CoverA - sn(1,i) = lattice_hex_systemSlip(5,i) ! plane (hkil)->(h (h+2k)/sqrt(3) l/(c/a)) - sn(2,i) = (lattice_hex_systemSlip(5,i)+2.0_pReal*lattice_hex_systemSlip(6,i))/sqrt(3.0_pReal) - sn(3,i) = lattice_hex_systemSlip(8,i)/CoverA - enddo - do i = 1_pInt,myNtwin ! assign twin system vectors and shears - td(1,i) = lattice_hex_systemTwin(1,i)*1.5_pReal - td(2,i) = (lattice_hex_systemTwin(1,i)+2.0_pReal*lattice_hex_systemTwin(2,i))*& - 0.5_pReal*sqrt(3.0_pReal) - td(3,i) = lattice_hex_systemTwin(4,i)*CoverA - tn(1,i) = lattice_hex_systemTwin(5,i) - tn(2,i) = (lattice_hex_systemTwin(5,i)+2.0_pReal*lattice_hex_systemTwin(6,i))/sqrt(3.0_pReal) - tn(3,i) = lattice_hex_systemTwin(8,i)/CoverA - select case(lattice_hex_shearTwin(i)) ! from Christian & Mahajan 1995 p.29 - case (1_pInt) ! <-10.1>{10.2} - ts(i) = (3.0_pReal-CoverA*CoverA)/sqrt(3.0_pReal)/CoverA - case (2_pInt) ! <11.6>{-1-1.1} - ts(i) = 1.0_pReal/CoverA - case (3_pInt) ! <10.-2>{10.1} - ts(i) = (4.0_pReal*CoverA*CoverA-9.0_pReal)/4.0_pReal/sqrt(3.0_pReal)/CoverA - case (4_pInt) ! <11.-3>{11.2} - ts(i) = 2.0_pReal*(CoverA*CoverA-2.0_pReal)/3.0_pReal/CoverA - end select - enddo - do i = 1_pInt, myNcleavage ! cleavage system vectors - cd(1,i) = lattice_hex_systemCleavage(1,i)*1.5_pReal ! direction [uvtw]->[3u/2 (u+2v)*sqrt(3)/2 w*(c/a)] - cd(2,i) = (lattice_hex_systemCleavage(1,i)+2.0_pReal*lattice_hex_systemCleavage(2,i))*& - 0.5_pReal*sqrt(3.0_pReal) - cd(3,i) = lattice_hex_systemCleavage(4,i)*CoverA - cd(1:3,1) = cd(1:3,i)/norm2(cd(1:3,i)) - cn(1,i) = lattice_hex_systemCleavage(5,i) ! plane (hkil)->(h (h+2k)/sqrt(3) l/(c/a)) - cn(2,i) = (lattice_hex_systemCleavage(5,i)+2.0_pReal*lattice_hex_systemCleavage(6,i))/sqrt(3.0_pReal) - cn(3,i) = lattice_hex_systemCleavage(8,i)/CoverA - cn(1:3,1) = cn(1:3,i)/norm2(cn(1:3,i)) - ct(1:3,i) = math_crossproduct(cd(1:3,i),cn(1:3,i)) - enddo - lattice_NslipSystem(1:lattice_maxNslipFamily,myPhase) = lattice_hex_NslipSystem - lattice_NtwinSystem(1:lattice_maxNtwinFamily,myPhase) = lattice_hex_NtwinSystem - lattice_NtransSystem(1:lattice_maxNtransFamily,myPhase) = lattice_hex_NtransSystem - lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_hex_NcleavageSystem - lattice_NnonSchmid(myPhase) = lattice_hex_NnonSchmid - lattice_interactionSlipSlip(1:myNslip,1:myNslip,myPhase) = lattice_hex_interactionSlipSlip - lattice_interactionSlipTwin(1:myNslip,1:myNtwin,myPhase) = lattice_hex_interactionSlipTwin - lattice_interactionTwinSlip(1:myNtwin,1:myNslip,myPhase) = lattice_hex_interactionTwinSlip - lattice_interactionTwinTwin(1:myNtwin,1:myNtwin,myPhase) = lattice_hex_interactionTwinTwin - -!-------------------------------------------------------------------------------------------------- -! bct - case (LATTICE_bct_ID) - myNslip = lattice_bct_Nslip - myNtwin = lattice_bct_Ntwin - myNcleavage = lattice_bct_Ncleavage - do i = 1_pInt,myNslip ! assign slip system vectors - sd(1:2,i) = lattice_bct_systemSlip(1:2,i) - sd(3,i) = lattice_bct_systemSlip(3,i)*CoverA - sn(1:2,i) = lattice_bct_systemSlip(4:5,i) - sn(3,i) = lattice_bct_systemSlip(6,i)/CoverA - sdU = sd(1:3,i) / norm2(sd(1:3,i)) - snU = sn(1:3,i) / norm2(sn(1:3,i)) - enddo - lattice_NslipSystem(1:lattice_maxNslipFamily,myPhase) = lattice_bct_NslipSystem - lattice_NtwinSystem(1:lattice_maxNtwinFamily,myPhase) = lattice_bct_NtwinSystem - lattice_NtransSystem(1:lattice_maxNtransFamily,myPhase) = lattice_bct_NtransSystem - lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_bct_NcleavageSystem - lattice_NnonSchmid(myPhase) = lattice_bct_NnonSchmid - lattice_interactionSlipSlip(1:myNslip,1:myNslip,myPhase) = lattice_bct_interactionSlipSlip - -!-------------------------------------------------------------------------------------------------- -! orthorhombic (no crystal plasticity) - case (LATTICE_ort_ID) - myNslip = 0_pInt - myNtwin = 0_pInt - myNtrans = 0_pInt - myNcleavage = lattice_ortho_Ncleavage - do i = 1_pInt, myNcleavage ! assign cleavage system vectors - cd(1:3,i) = lattice_iso_systemCleavage(1:3,i)/norm2(LATTICE_ortho_systemCleavage(1:3,i)) - cn(1:3,i) = lattice_iso_systemCleavage(4:6,i)/norm2(LATTICE_ortho_systemCleavage(4:6,i)) - ct(1:3,i) = math_crossproduct(cd(1:3,i),cn(1:3,i)) - enddo - lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_iso_NcleavageSystem - -!-------------------------------------------------------------------------------------------------- -! isotropic (no crystal plasticity) - case (LATTICE_iso_ID) - myNslip = 0_pInt - myNtwin = 0_pInt - myNtrans = 0_pInt - myNcleavage = lattice_iso_Ncleavage - do i = 1_pInt, myNcleavage ! assign cleavage system vectors - cd(1:3,i) = lattice_iso_systemCleavage(1:3,i)/norm2(lattice_iso_systemCleavage(1:3,i)) - cn(1:3,i) = lattice_iso_systemCleavage(4:6,i)/norm2(lattice_iso_systemCleavage(4:6,i)) - ct(1:3,i) = math_crossproduct(cd(1:3,i),cn(1:3,i)) - enddo - lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_iso_NcleavageSystem - -!-------------------------------------------------------------------------------------------------- -! something went wrong - case default - call IO_error(130_pInt,ext_msg='lattice_initializeStructure') - end select - - - do i = 1_pInt,myNslip ! store slip system vectors and Schmid matrix for my structure - lattice_sd(1:3,i,myPhase) = sd(1:3,i)/norm2(sd(1:3,i)) ! make unit vector - lattice_sn(1:3,i,myPhase) = sn(1:3,i)/norm2(sn(1:3,i)) ! make unit vector - lattice_st(1:3,i,myPhase) = math_crossproduct(lattice_sd(1:3,i,myPhase), & - lattice_sn(1:3,i,myPhase)) - lattice_Sslip(1:3,1:3,1,i,myPhase) = math_tensorproduct33(lattice_sd(1:3,i,myPhase), & - lattice_sn(1:3,i,myPhase)) ! calculate Schmid matrix d \otimes n - do j = 1_pInt,lattice_NnonSchmid(myPhase) - lattice_Sslip(1:3,1:3,2*j ,i,myPhase) = sns(1:3,1:3,1,j,i) - lattice_Sslip(1:3,1:3,2*j+1,i,myPhase) = sns(1:3,1:3,2,j,i) - enddo - do j = 1_pInt,1_pInt+2_pInt*lattice_NnonSchmid(myPhase) - lattice_Sslip_v(1:6,j,i,myPhase) = & - math_Mandel33to6(math_symmetric33(lattice_Sslip(1:3,1:3,j,i,myPhase))) - enddo - if (abs(math_trace33(lattice_Sslip(1:3,1:3,1,i,myPhase))) > tol_math_check) & - call IO_error(0_pInt,myPhase,i,0_pInt,ext_msg = 'dilatational slip Schmid matrix') - enddo - do i = 1_pInt,myNtwin ! store twin system vectors and Schmid plus rotation matrix for my structure - lattice_td(1:3,i,myPhase) = td(1:3,i)/norm2(td(1:3,i)) ! make unit vector - lattice_tn(1:3,i,myPhase) = tn(1:3,i)/norm2(tn(1:3,i)) ! make unit vector - lattice_tt(1:3,i,myPhase) = math_crossproduct(lattice_td(1:3,i,myPhase), & - lattice_tn(1:3,i,myPhase)) - lattice_Stwin(1:3,1:3,i,myPhase) = math_tensorproduct33(lattice_td(1:3,i,myPhase), & - lattice_tn(1:3,i,myPhase)) - lattice_Stwin_v(1:6,i,myPhase) = math_Mandel33to6(math_symmetric33(lattice_Stwin(1:3,1:3,i,myPhase))) - lattice_Qtwin(1:3,1:3,i,myPhase) = math_axisAngleToR(tn(1:3,i),180.0_pReal*INRAD) - lattice_shearTwin(i,myPhase) = ts(i) - if (abs(math_trace33(lattice_Stwin(1:3,1:3,i,myPhase))) > tol_math_check) & - call IO_error(301_pInt,myPhase,ext_msg = 'dilatational twin Schmid matrix') - enddo - do i = 1_pInt,myNtrans - lattice_Qtrans(1:3,1:3,i,myPhase) = Qtr(1:3,1:3,i) - lattice_Strans(1:3,1:3,i,myPhase) = Str(1:3,1:3,i) - lattice_Strans_v(1:6,i,myPhase) = math_Mandel33to6(math_symmetric33(lattice_Strans(1:3,1:3,i,myPhase))) - lattice_shearTrans(i,myPhase) = trs(i) - enddo - do i = 1_pInt,myNcleavage ! store slip system vectors and Schmid matrix for my structure - lattice_Scleavage(1:3,1:3,1,i,myPhase) = math_tensorproduct33(cd(1:3,i),cn(1:3,i)) - lattice_Scleavage(1:3,1:3,2,i,myPhase) = math_tensorproduct33(ct(1:3,i),cn(1:3,i)) - lattice_Scleavage(1:3,1:3,3,i,myPhase) = math_tensorproduct33(cn(1:3,i),cn(1:3,i)) - do j = 1_pInt,3_pInt - lattice_Scleavage_v(1:6,j,i,myPhase) = & - math_Mandel33to6(math_symmetric33(lattice_Scleavage(1:3,1:3,j,i,myPhase))) - enddo - enddo - -end subroutine lattice_initializeStructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief Symmetrizes stiffness matrix according to lattice type -!-------------------------------------------------------------------------------------------------- -pure function lattice_symmetrizeC66(struct,C66) - - implicit none - integer(kind(LATTICE_undefined_ID)), intent(in) :: struct - real(pReal), dimension(6,6), intent(in) :: C66 - real(pReal), dimension(6,6) :: lattice_symmetrizeC66 - integer(pInt) :: j,k - - lattice_symmetrizeC66 = 0.0_pReal - - select case(struct) - case (LATTICE_iso_ID) - forall(k=1_pInt:3_pInt) - forall(j=1_pInt:3_pInt) lattice_symmetrizeC66(k,j) = C66(1,2) - lattice_symmetrizeC66(k,k) = C66(1,1) - lattice_symmetrizeC66(k+3,k+3) = 0.5_pReal*(C66(1,1)-C66(1,2)) - end forall - case (LATTICE_fcc_ID,LATTICE_bcc_ID) - forall(k=1_pInt:3_pInt) - forall(j=1_pInt:3_pInt) lattice_symmetrizeC66(k,j) = C66(1,2) - lattice_symmetrizeC66(k,k) = C66(1,1) - lattice_symmetrizeC66(k+3_pInt,k+3_pInt) = C66(4,4) - end forall - case (LATTICE_hex_ID) - lattice_symmetrizeC66(1,1) = C66(1,1) - lattice_symmetrizeC66(2,2) = C66(1,1) - lattice_symmetrizeC66(3,3) = C66(3,3) - lattice_symmetrizeC66(1,2) = C66(1,2) - lattice_symmetrizeC66(2,1) = C66(1,2) - lattice_symmetrizeC66(1,3) = C66(1,3) - lattice_symmetrizeC66(3,1) = C66(1,3) - lattice_symmetrizeC66(2,3) = C66(1,3) - lattice_symmetrizeC66(3,2) = C66(1,3) - lattice_symmetrizeC66(4,4) = C66(4,4) - lattice_symmetrizeC66(5,5) = C66(4,4) - lattice_symmetrizeC66(6,6) = 0.5_pReal*(C66(1,1)-C66(1,2)) - case (LATTICE_ort_ID) - lattice_symmetrizeC66(1,1) = C66(1,1) - lattice_symmetrizeC66(2,2) = C66(2,2) - lattice_symmetrizeC66(3,3) = C66(3,3) - lattice_symmetrizeC66(1,2) = C66(1,2) - lattice_symmetrizeC66(2,1) = C66(1,2) - lattice_symmetrizeC66(1,3) = C66(1,3) - lattice_symmetrizeC66(3,1) = C66(1,3) - lattice_symmetrizeC66(2,3) = C66(2,3) - lattice_symmetrizeC66(3,2) = C66(2,3) - lattice_symmetrizeC66(4,4) = C66(4,4) - lattice_symmetrizeC66(5,5) = C66(5,5) - lattice_symmetrizeC66(6,6) = C66(6,6) - case (LATTICE_bct_ID) - lattice_symmetrizeC66(1,1) = C66(1,1) - lattice_symmetrizeC66(2,2) = C66(1,1) - lattice_symmetrizeC66(3,3) = C66(3,3) - lattice_symmetrizeC66(1,2) = C66(1,2) - lattice_symmetrizeC66(2,1) = C66(1,2) - lattice_symmetrizeC66(1,3) = C66(1,3) - lattice_symmetrizeC66(3,1) = C66(1,3) - lattice_symmetrizeC66(2,3) = C66(1,3) - lattice_symmetrizeC66(3,2) = C66(1,3) - lattice_symmetrizeC66(4,4) = C66(4,4) - lattice_symmetrizeC66(5,5) = C66(4,4) - lattice_symmetrizeC66(6,6) = C66(6,6) !J. A. Rayne and B. S. Chandrasekhar Phys. Rev. 120, 1658 Erratum Phys. Rev. 122, 1962 - case default - lattice_symmetrizeC66 = C66 - end select - - end function lattice_symmetrizeC66 - -!-------------------------------------------------------------------------------------------------- -!> @brief Symmetrizes 2nd order tensor according to lattice type -!-------------------------------------------------------------------------------------------------- -pure function lattice_symmetrize33(struct,T33) - - implicit none - integer(kind(LATTICE_undefined_ID)), intent(in) :: struct - real(pReal), dimension(3,3), intent(in) :: T33 - real(pReal), dimension(3,3) :: lattice_symmetrize33 - integer(pInt) :: k - - lattice_symmetrize33 = 0.0_pReal - - select case(struct) - case (LATTICE_iso_ID,LATTICE_fcc_ID,LATTICE_bcc_ID) - forall(k=1_pInt:3_pInt) lattice_symmetrize33(k,k) = T33(1,1) - case (LATTICE_hex_ID) - lattice_symmetrize33(1,1) = T33(1,1) - lattice_symmetrize33(2,2) = T33(1,1) - lattice_symmetrize33(3,3) = T33(3,3) - case (LATTICE_ort_ID,lattice_bct_ID) - lattice_symmetrize33(1,1) = T33(1,1) - lattice_symmetrize33(2,2) = T33(2,2) - lattice_symmetrize33(3,3) = T33(3,3) - case default - lattice_symmetrize33 = T33 - end select - - end function lattice_symmetrize33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief figures whether unit quat falls into stereographic standard triangle -!-------------------------------------------------------------------------------------------------- -logical pure function lattice_qInSST(Q, struct) - use prec, only: & - prec_isNaN - use math, only: & - math_qToRodrig - - implicit none - real(pReal), dimension(4), intent(in) :: Q ! orientation - integer(kind(LATTICE_undefined_ID)), intent(in) :: struct ! lattice structure - real(pReal), dimension(3) :: Rodrig ! Rodrigues vector of Q - - Rodrig = math_qToRodrig(Q) - if (any(prec_isNaN(Rodrig))) then - lattice_qInSST = .false. - else - select case (struct) - case (LATTICE_bcc_ID,LATTICE_fcc_ID) - lattice_qInSST = Rodrig(1) > Rodrig(2) .and. & - Rodrig(2) > Rodrig(3) .and. & - Rodrig(3) > 0.0_pReal - case (LATTICE_hex_ID) - lattice_qInSST = Rodrig(1) > sqrt(3.0_pReal)*Rodrig(2) .and. & - Rodrig(2) > 0.0_pReal .and. & - Rodrig(3) > 0.0_pReal - case default - lattice_qInSST = .true. - end select - endif - -end function lattice_qInSST - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the disorientation for 2 unit quaternions -!-------------------------------------------------------------------------------------------------- -pure function lattice_qDisorientation(Q1, Q2, struct) - use prec, only: & - tol_math_check - use math, only: & - math_qMul, & - math_qConj - - implicit none - real(pReal), dimension(4) :: lattice_qDisorientation - real(pReal), dimension(4), intent(in) :: & - Q1, & ! 1st orientation - Q2 ! 2nd orientation - integer(kind(LATTICE_undefined_ID)), optional, intent(in) :: & ! if given, symmetries between the two orientation will be considered - struct - - real(pReal), dimension(4) :: dQ,dQsymA,mis - integer(pInt) :: i,j,k,s,symmetry - integer(kind(LATTICE_undefined_ID)) :: myStruct - -!-------------------------------------------------------------------------------------------------- -! check if a structure with known symmetries is given - if (present(struct)) then - myStruct = struct - select case (struct) - case(LATTICE_fcc_ID,LATTICE_bcc_ID) - symmetry = 1_pInt - case(LATTICE_hex_ID) - symmetry = 2_pInt - case default - symmetry = 0_pInt - end select - else - symmetry = 0_pInt - myStruct = LATTICE_undefined_ID - endif - - -!-------------------------------------------------------------------------------------------------- -! calculate misorientation, for cubic and hexagonal structure find symmetries - dQ = math_qMul(math_qConj(Q1),Q2) - lattice_qDisorientation = dQ - - select case(symmetry) - - case (1_pInt,2_pInt) - s = sum(lattice_NsymOperations(1:symmetry-1_pInt)) - do i = 1_pInt,2_pInt - dQ = math_qConj(dQ) ! switch order of "from -- to" - do j = 1_pInt,lattice_NsymOperations(symmetry) ! run through first crystal's symmetries - dQsymA = math_qMul(lattice_symOperations(1:4,s+j),dQ) ! apply sym - do k = 1_pInt,lattice_NsymOperations(symmetry) ! run through 2nd crystal's symmetries - mis = math_qMul(dQsymA,lattice_symOperations(1:4,s+k)) ! apply sym - if (mis(1) < 0.0_pReal) & ! want positive angle - mis = -mis - if (mis(1)-lattice_qDisorientation(1) > -tol_math_check & - .and. lattice_qInSST(mis,LATTICE_undefined_ID)) lattice_qDisorientation = mis ! found better one - enddo; enddo; enddo - case (0_pInt) - if (lattice_qDisorientation(1) < 0.0_pReal) lattice_qDisorientation = -lattice_qDisorientation ! keep omega within 0 to 180 deg - end select - -end function lattice_qDisorientation - -end module lattice diff --git a/code/libs.f90 b/code/libs.f90 deleted file mode 100644 index 7c109cab6..000000000 --- a/code/libs.f90 +++ /dev/null @@ -1,14 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief dummy source for inclusion of Library files -!-------------------------------------------------------------------------------------------------- -module libs -!nothing in here -end module libs - -#include "../lib/IR_Precision.f90" -#include "../lib/Lib_Base64.f90" -#include "../lib/Lib_VTK_IO.f90" - diff --git a/code/material.f90 b/code/material.f90 deleted file mode 100644 index c1aacf751..000000000 --- a/code/material.f90 +++ /dev/null @@ -1,1615 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Parses material config file, either solverJobName.materialConfig or material.config -!> @details reads the material configuration file, where solverJobName.materialConfig takes -!! precedence over material.config and parses the sections 'homogenization', 'crystallite', -!! 'phase', 'texture', and 'microstucture' -!-------------------------------------------------------------------------------------------------- -module material - use prec, only: & - pReal, & - pInt, & - tState, & - tPlasticState, & - tSourceState, & - tHomogMapping, & - tPhaseMapping, & - p_vec, & - p_intvec - - implicit none - private - character(len=*), parameter, public :: & - ELASTICITY_hooke_label = 'hooke', & - PLASTICITY_none_label = 'none', & - PLASTICITY_isotropic_label = 'isotropic', & - PLASTICITY_j2_label = 'j2', & - PLASTICITY_phenopowerlaw_label = 'phenopowerlaw', & - PLASTICITY_phenoplus_label = 'phenoplus', & - PLASTICITY_dislotwin_label = 'dislotwin', & - PLASTICITY_disloucla_label = 'disloucla', & - PLASTICITY_titanmod_label = 'titanmod', & - PLASTICITY_nonlocal_label = 'nonlocal', & - SOURCE_thermal_dissipation_label = 'thermal_dissipation', & - SOURCE_thermal_externalheat_label = 'thermal_externalheat', & - SOURCE_damage_isoBrittle_label = 'damage_isobrittle', & - SOURCE_damage_isoDuctile_label = 'damage_isoductile', & - SOURCE_damage_anisoBrittle_label = 'damage_anisobrittle', & - SOURCE_damage_anisoDuctile_label = 'damage_anisoductile', & - SOURCE_vacancy_phenoplasticity_label = 'vacancy_phenoplasticity', & - SOURCE_vacancy_irradiation_label = 'vacancy_irradiation', & - SOURCE_vacancy_thermalfluc_label = 'vacancy_thermalfluctuation', & - KINEMATICS_thermal_expansion_label = 'thermal_expansion', & - KINEMATICS_cleavage_opening_label = 'cleavage_opening', & - KINEMATICS_slipplane_opening_label = 'slipplane_opening', & - KINEMATICS_vacancy_strain_label = 'vacancy_strain', & - KINEMATICS_hydrogen_strain_label = 'hydrogen_strain', & - STIFFNESS_DEGRADATION_damage_label = 'damage', & - STIFFNESS_DEGRADATION_porosity_label = 'porosity', & - THERMAL_isothermal_label = 'isothermal', & - THERMAL_adiabatic_label = 'adiabatic', & - THERMAL_conduction_label = 'conduction', & - DAMAGE_none_label = 'none', & - DAMAGE_local_label = 'local', & - DAMAGE_nonlocal_label = 'nonlocal', & - VACANCYFLUX_isoconc_label = 'isoconcentration', & - VACANCYFLUX_isochempot_label = 'isochemicalpotential', & - VACANCYFLUX_cahnhilliard_label = 'cahnhilliard', & - POROSITY_none_label = 'none', & - POROSITY_phasefield_label = 'phasefield', & - HYDROGENFLUX_isoconc_label = 'isoconcentration', & - HYDROGENFLUX_cahnhilliard_label = 'cahnhilliard', & - HOMOGENIZATION_none_label = 'none', & - HOMOGENIZATION_isostrain_label = 'isostrain', & - HOMOGENIZATION_rgc_label = 'rgc' - - - - enum, bind(c) - enumerator :: ELASTICITY_undefined_ID, & - ELASTICITY_hooke_ID - end enum - enum, bind(c) - enumerator :: PLASTICITY_undefined_ID, & - PLASTICITY_none_ID, & - PLASTICITY_isotropic_ID, & - PLASTICITY_j2_ID, & - PLASTICITY_phenopowerlaw_ID, & - PLASTICITY_phenoplus_ID, & - PLASTICITY_dislotwin_ID, & - PLASTICITY_disloucla_ID, & - PLASTICITY_titanmod_ID, & - PLASTICITY_nonlocal_ID - end enum - - enum, bind(c) - enumerator :: 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, & - SOURCE_vacancy_phenoplasticity_ID, & - SOURCE_vacancy_irradiation_ID, & - SOURCE_vacancy_thermalfluc_ID - end enum - - enum, bind(c) - enumerator :: KINEMATICS_undefined_ID, & - KINEMATICS_cleavage_opening_ID, & - KINEMATICS_slipplane_opening_ID, & - KINEMATICS_thermal_expansion_ID, & - KINEMATICS_vacancy_strain_ID, & - KINEMATICS_hydrogen_strain_ID - end enum - - enum, bind(c) - enumerator :: STIFFNESS_DEGRADATION_undefined_ID, & - STIFFNESS_DEGRADATION_damage_ID, & - STIFFNESS_DEGRADATION_porosity_ID - end enum - - enum, bind(c) - enumerator :: THERMAL_isothermal_ID, & - THERMAL_adiabatic_ID, & - THERMAL_conduction_ID - end enum - - enum, bind(c) - enumerator :: DAMAGE_none_ID, & - DAMAGE_local_ID, & - DAMAGE_nonlocal_ID - end enum - - enum, bind(c) - enumerator :: VACANCYFLUX_isoconc_ID, & - VACANCYFLUX_isochempot_ID, & - VACANCYFLUX_cahnhilliard_ID - end enum - - enum, bind(c) - enumerator :: POROSITY_none_ID, & - POROSITY_phasefield_ID - end enum - enum, bind(c) - enumerator :: HYDROGENFLUX_isoconc_ID, & - HYDROGENFLUX_cahnhilliard_ID - end enum - - enum, bind(c) - enumerator :: HOMOGENIZATION_undefined_ID, & - HOMOGENIZATION_none_ID, & - HOMOGENIZATION_isostrain_ID, & - HOMOGENIZATION_rgc_ID - end enum - - character(len=*), parameter, public :: & - MATERIAL_configFile = 'material.config', & !< generic name for material configuration file - MATERIAL_localFileExt = 'materialConfig' !< extension of solver job name depending material configuration file - - character(len=*), parameter, public :: & - MATERIAL_partHomogenization = 'homogenization', & !< keyword for homogenization part - MATERIAL_partCrystallite = 'crystallite', & !< keyword for crystallite part - MATERIAL_partPhase = 'phase' !< keyword for phase part - - integer(kind(ELASTICITY_undefined_ID)), dimension(:), allocatable, public, protected :: & - phase_elasticity !< elasticity of each phase - integer(kind(PLASTICITY_undefined_ID)), dimension(:), allocatable, public, protected :: & - phase_plasticity !< plasticity of each phase - integer(kind(THERMAL_isothermal_ID)), dimension(:), allocatable, public, protected :: & - thermal_type !< thermal transport model - integer(kind(DAMAGE_none_ID)), dimension(:), allocatable, public, protected :: & - damage_type !< nonlocal damage model - integer(kind(VACANCYFLUX_isoconc_ID)), dimension(:), allocatable, public, protected :: & - vacancyflux_type !< vacancy transport model - integer(kind(POROSITY_none_ID)), dimension(:), allocatable, public, protected :: & - porosity_type !< porosity evolution model - integer(kind(HYDROGENFLUX_isoconc_ID)), dimension(:), allocatable, public, protected :: & - hydrogenflux_type !< hydrogen transport model - - integer(kind(SOURCE_undefined_ID)), dimension(:,:), allocatable, public, protected :: & - 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 - - integer(kind(HOMOGENIZATION_undefined_ID)), dimension(:), allocatable, public, protected :: & - homogenization_type !< type of each homogenization - - character(len=64), dimension(:), allocatable, public, protected :: & - phase_name, & !< name of each phase - homogenization_name, & !< name of each homogenization - crystallite_name !< name of each crystallite setting - - integer(pInt), public, protected :: & - homogenization_maxNgrains, & !< max number of grains in any USED homogenization - material_Nphase, & !< number of phases - material_Nhomogenization, & !< number of homogenizations - material_Nmicrostructure, & !< number of microstructures - material_Ncrystallite !< number of crystallite settings - - integer(pInt), dimension(:), allocatable, public, protected :: & - 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_Noutput, & !< number of '(output)' items per phase - phase_elasticityInstance, & !< instance of particular elasticity of each phase - phase_plasticityInstance !< instance of particular plasticity of each phase - - integer(pInt), dimension(:), allocatable, public, protected :: & - crystallite_Noutput !< number of '(output)' items per crystallite setting - - integer(pInt), dimension(:), allocatable, public, protected :: & - homogenization_Ngrains, & !< number of grains in each homogenization - homogenization_Noutput, & !< number of '(output)' items per 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 - vacancyflux_typeInstance, & !< instance of particular type of each vacancy flux - porosity_typeInstance, & !< instance of particular type of each porosity model - hydrogenflux_typeInstance, & !< instance of particular type of each hydrogen flux - microstructure_crystallite !< crystallite setting ID of each microstructure - - real(pReal), dimension(:), allocatable, public, protected :: & - thermal_initialT, & !< initial temperature per each homogenization - damage_initialPhi, & !< initial damage per each homogenization - vacancyflux_initialCv, & !< initial vacancy concentration per each homogenization - porosity_initialPhi, & !< initial posority per each homogenization - hydrogenflux_initialCh !< initial hydrogen concentration per each homogenization - - integer(pInt), dimension(:,:,:), allocatable, public :: & - material_phase !< phase (index) of each grain,IP,element - integer(pInt), dimension(:,:), allocatable, public :: & - material_homog !< homogenization (index) of each IP,element - type(tPlasticState), allocatable, dimension(:), public :: & - plasticState - type(tSourceState), allocatable, dimension(:), public :: & - sourceState - type(tState), allocatable, dimension(:), public :: & - homogState, & - thermalState, & - damageState, & - vacancyfluxState, & - porosityState, & - hydrogenfluxState - - integer(pInt), dimension(:,:,:), allocatable, public, protected :: & - material_texture !< texture (index) of each grain,IP,element - - real(pReal), dimension(:,:,:,:), allocatable, public, protected :: & - material_EulerAngles !< initial orientation of each grain,IP,element - - logical, dimension(:), allocatable, public, protected :: & - microstructure_active, & - microstructure_elemhomo, & !< flag to indicate homogeneous microstructure distribution over element's IPs - phase_localPlasticity !< flags phases with local constitutive law - - - character(len=*), parameter, private :: & - MATERIAL_partMicrostructure = 'microstructure', & !< keyword for microstructure part - MATERIAL_partTexture = 'texture' !< keyword for texture part - - character(len=64), dimension(:), allocatable, private :: & - microstructure_name, & !< name of each microstructure - texture_name !< name of each texture - - character(len=256), dimension(:), allocatable, private :: & - texture_ODFfile !< name of each ODF file - - integer(pInt), private :: & - material_Ntexture, & !< number of textures - microstructure_maxNconstituents, & !< max number of constituents in any phase - texture_maxNgauss, & !< max number of Gauss components in any texture - texture_maxNfiber !< max number of Fiber components in any texture - - integer(pInt), dimension(:), allocatable, private :: & - microstructure_Nconstituents, & !< number of constituents in each microstructure - texture_symmetry, & !< number of symmetric orientations per texture - texture_Ngauss, & !< number of Gauss components per texture - texture_Nfiber !< number of Fiber components per texture - - integer(pInt), dimension(:,:), allocatable, private :: & - microstructure_phase, & !< phase IDs of each microstructure - microstructure_texture !< texture IDs of each microstructure - - real(pReal), dimension(:,:), allocatable, private :: & - microstructure_fraction !< vol fraction of each constituent in microstructure - - real(pReal), dimension(:,:,:), allocatable, private :: & - material_volume, & !< volume of each grain,IP,element - texture_Gauss, & !< data of each Gauss component - texture_Fiber, & !< data of each Fiber component - texture_transformation !< transformation for each texture - - logical, dimension(:), allocatable, private :: & - homogenization_active - - integer(pInt), dimension(:,:,:), allocatable, public :: phaseAt !< phase ID of every material point (ipc,ip,el) - integer(pInt), dimension(:,:,:), allocatable, public :: phasememberAt !< memberID of given phase at every material point (ipc,ip,el) - integer(pInt), dimension(:,:,:), allocatable, public, target :: mappingCrystallite - integer(pInt), dimension(:,:,:), allocatable, public, target :: mappingHomogenization !< mapping from material points to offset in heterogenous state/field - integer(pInt), dimension(:,:), allocatable, public, target :: mappingHomogenizationConst !< mapping from material points to offset in constant state/field - - type(tHomogMapping), allocatable, dimension(:), public :: & - thermalMapping, & !< mapping for thermal state/fields - damageMapping, & !< mapping for damage state/fields - vacancyfluxMapping, & !< mapping for vacancy conc state/fields - porosityMapping, & !< mapping for porosity state/fields - hydrogenfluxMapping !< mapping for hydrogen conc state/fields - - type(p_vec), allocatable, dimension(:), public :: & - temperature, & !< temperature field - damage, & !< damage field - vacancyConc, & !< vacancy conc field - porosity, & !< porosity field - hydrogenConc, & !< hydrogen conc field - temperatureRate, & !< temperature change rate field - vacancyConcRate, & !< vacancy conc change field - hydrogenConcRate !< hydrogen conc change field - - public :: & - material_init, & - ELASTICITY_hooke_ID ,& - PLASTICITY_none_ID, & - PLASTICITY_isotropic_ID, & - PLASTICITY_J2_ID, & - PLASTICITY_phenopowerlaw_ID, & - PLASTICITY_phenoplus_ID, & - PLASTICITY_dislotwin_ID, & - PLASTICITY_disloucla_ID, & - PLASTICITY_titanmod_ID, & - PLASTICITY_nonlocal_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, & - SOURCE_vacancy_phenoplasticity_ID, & - SOURCE_vacancy_irradiation_ID, & - SOURCE_vacancy_thermalfluc_ID, & - KINEMATICS_cleavage_opening_ID, & - KINEMATICS_slipplane_opening_ID, & - KINEMATICS_thermal_expansion_ID, & - KINEMATICS_vacancy_strain_ID, & - KINEMATICS_hydrogen_strain_ID, & - STIFFNESS_DEGRADATION_damage_ID, & - STIFFNESS_DEGRADATION_porosity_ID, & - THERMAL_isothermal_ID, & - THERMAL_adiabatic_ID, & - THERMAL_conduction_ID, & - DAMAGE_none_ID, & - DAMAGE_local_ID, & - DAMAGE_nonlocal_ID, & - VACANCYFLUX_isoconc_ID, & - VACANCYFLUX_isochempot_ID, & - VACANCYFLUX_cahnhilliard_ID, & - POROSITY_none_ID, & - POROSITY_phasefield_ID, & - HYDROGENFLUX_isoconc_ID, & - HYDROGENFLUX_cahnhilliard_ID, & - HOMOGENIZATION_none_ID, & - HOMOGENIZATION_isostrain_ID, & -#ifdef HDF - material_NconstituentsPhase, & -#endif - HOMOGENIZATION_RGC_ID - - private :: & - material_parseHomogenization, & - material_parseMicrostructure, & - material_parseCrystallite, & - material_parsePhase, & - material_parseTexture, & - material_populateGrains - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief parses material configuration file -!> @details figures out if solverJobName.materialConfig is present, if not looks for -!> material.config -!-------------------------------------------------------------------------------------------------- -subroutine material_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_error, & - IO_open_file, & - IO_open_jobFile_stat, & - IO_timeStamp - use debug, only: & - debug_level, & - debug_material, & - debug_levelBasic, & - debug_levelExtensive - use mesh, only: & - mesh_maxNips, & - mesh_NcpElems, & - mesh_element, & - FE_Nips, & - FE_geomtype - use numerics, only: & - worldrank - - implicit none - integer(pInt), parameter :: FILEUNIT = 200_pInt - integer(pInt) :: m,c,h, myDebug, myPhase, myHomog - integer(pInt) :: & - g, & !< grain number - i, & !< integration point number - e, & !< element number - phase - integer(pInt), dimension(:), allocatable :: ConstitutivePosition - integer(pInt), dimension(:), allocatable :: CrystallitePosition - integer(pInt), dimension(:), allocatable :: HomogenizationPosition - - myDebug = debug_level(debug_material) - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- material init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... - call IO_open_file(FILEUNIT,material_configFile) ! ...open material.config file - call material_parseHomogenization(FILEUNIT,material_partHomogenization) - if (iand(myDebug,debug_levelBasic) /= 0_pInt) write(6,'(a)') ' Homogenization parsed'; flush(6) - call material_parseMicrostructure(FILEUNIT,material_partMicrostructure) - if (iand(myDebug,debug_levelBasic) /= 0_pInt) write(6,'(a)') ' Microstructure parsed'; flush(6) - call material_parseCrystallite(FILEUNIT,material_partCrystallite) - if (iand(myDebug,debug_levelBasic) /= 0_pInt) write(6,'(a)') ' Crystallite parsed'; flush(6) - call material_parseTexture(FILEUNIT,material_partTexture) - if (iand(myDebug,debug_levelBasic) /= 0_pInt) write(6,'(a)') ' Texture parsed'; flush(6) - call material_parsePhase(FILEUNIT,material_partPhase) - if (iand(myDebug,debug_levelBasic) /= 0_pInt) write(6,'(a)') ' Phase parsed'; flush(6) - close(FILEUNIT) - - allocate(plasticState (material_Nphase)) - allocate(sourceState (material_Nphase)) - do myPhase = 1,material_Nphase - allocate(sourceState(myPhase)%p(phase_Nsources(myPhase))) - enddo - - allocate(homogState (material_Nhomogenization)) - allocate(thermalState (material_Nhomogenization)) - allocate(damageState (material_Nhomogenization)) - allocate(vacancyfluxState (material_Nhomogenization)) - allocate(porosityState (material_Nhomogenization)) - allocate(hydrogenfluxState (material_Nhomogenization)) - - allocate(thermalMapping (material_Nhomogenization)) - allocate(damageMapping (material_Nhomogenization)) - allocate(vacancyfluxMapping (material_Nhomogenization)) - allocate(porosityMapping (material_Nhomogenization)) - allocate(hydrogenfluxMapping(material_Nhomogenization)) - - allocate(temperature (material_Nhomogenization)) - allocate(damage (material_Nhomogenization)) - allocate(vacancyConc (material_Nhomogenization)) - allocate(porosity (material_Nhomogenization)) - allocate(hydrogenConc (material_Nhomogenization)) - - allocate(temperatureRate (material_Nhomogenization)) - allocate(vacancyConcRate (material_Nhomogenization)) - allocate(hydrogenConcRate (material_Nhomogenization)) - - do m = 1_pInt,material_Nmicrostructure - if(microstructure_crystallite(m) < 1_pInt .or. & - microstructure_crystallite(m) > material_Ncrystallite) & - call IO_error(150_pInt,m,ext_msg='crystallite') - if(minval(microstructure_phase(1:microstructure_Nconstituents(m),m)) < 1_pInt .or. & - maxval(microstructure_phase(1:microstructure_Nconstituents(m),m)) > material_Nphase) & - call IO_error(150_pInt,m,ext_msg='phase') - if(minval(microstructure_texture(1:microstructure_Nconstituents(m),m)) < 1_pInt .or. & - maxval(microstructure_texture(1:microstructure_Nconstituents(m),m)) > material_Ntexture) & - call IO_error(150_pInt,m,ext_msg='texture') - if(microstructure_Nconstituents(m) < 1_pInt) & - call IO_error(151_pInt,m) - enddo - - debugOut: if (iand(myDebug,debug_levelExtensive) /= 0_pInt) then - write(6,'(/,a,/)') ' MATERIAL configuration' - write(6,'(a32,1x,a16,1x,a6)') 'homogenization ','type ','grains' - do h = 1_pInt,material_Nhomogenization - write(6,'(1x,a32,1x,a16,1x,i6)') homogenization_name(h),homogenization_type(h),homogenization_Ngrains(h) - enddo - write(6,'(/,a14,18x,1x,a11,1x,a12,1x,a13)') 'microstructure','crystallite','constituents','homogeneous' - do m = 1_pInt,material_Nmicrostructure - write(6,'(1x,a32,1x,i11,1x,i12,1x,l13)') microstructure_name(m), & - microstructure_crystallite(m), & - microstructure_Nconstituents(m), & - microstructure_elemhomo(m) - if (microstructure_Nconstituents(m) > 0_pInt) then - do c = 1_pInt,microstructure_Nconstituents(m) - write(6,'(a1,1x,a32,1x,a32,1x,f7.4)') '>',phase_name(microstructure_phase(c,m)),& - texture_name(microstructure_texture(c,m)),& - microstructure_fraction(c,m) - enddo - write(6,*) - endif - enddo - endif debugOut - - call material_populateGrains - - allocate(phaseAt ( homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems),source=0_pInt) - allocate(phasememberAt ( homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems),source=0_pInt) - allocate(mappingHomogenization (2, mesh_maxNips,mesh_NcpElems),source=0_pInt) - allocate(mappingCrystallite (2,homogenization_maxNgrains, mesh_NcpElems),source=0_pInt) - allocate(mappingHomogenizationConst( mesh_maxNips,mesh_NcpElems),source=1_pInt) - - allocate(ConstitutivePosition (material_Nphase), source=0_pInt) - allocate(HomogenizationPosition(material_Nhomogenization),source=0_pInt) - allocate(CrystallitePosition (material_Nphase), source=0_pInt) - - ElemLoop:do e = 1_pInt,mesh_NcpElems ! loop over elements - myHomog = mesh_element(3,e) - IPloop:do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) ! loop over IPs - HomogenizationPosition(myHomog) = HomogenizationPosition(myHomog) + 1_pInt - mappingHomogenization(1:2,i,e) = [HomogenizationPosition(myHomog),myHomog] - GrainLoop:do g = 1_pInt,homogenization_Ngrains(mesh_element(3,e)) ! loop over grains - phase = material_phase(g,i,e) - ConstitutivePosition(phase) = ConstitutivePosition(phase)+1_pInt ! not distinguishing between instances of same phase - phaseAt(g,i,e) = phase - phasememberAt(g,i,e) = ConstitutivePosition(phase) - enddo GrainLoop - enddo IPloop - enddo ElemLoop - -! hack needed to initialize field values used during constitutive and crystallite initializations - do myHomog = 1,material_Nhomogenization - thermalMapping (myHomog)%p => mappingHomogenizationConst - damageMapping (myHomog)%p => mappingHomogenizationConst - vacancyfluxMapping (myHomog)%p => mappingHomogenizationConst - porosityMapping (myHomog)%p => mappingHomogenizationConst - hydrogenfluxMapping(myHomog)%p => mappingHomogenizationConst - allocate(temperature (myHomog)%p(1), source=thermal_initialT(myHomog)) - allocate(damage (myHomog)%p(1), source=damage_initialPhi(myHomog)) - allocate(vacancyConc (myHomog)%p(1), source=vacancyflux_initialCv(myHomog)) - allocate(porosity (myHomog)%p(1), source=porosity_initialPhi(myHomog)) - allocate(hydrogenConc (myHomog)%p(1), source=hydrogenflux_initialCh(myHomog)) - allocate(temperatureRate (myHomog)%p(1), source=0.0_pReal) - allocate(vacancyConcRate (myHomog)%p(1), source=0.0_pReal) - allocate(hydrogenConcRate(myHomog)%p(1), source=0.0_pReal) - enddo - -end subroutine material_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief parses the homogenization part in the material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine material_parseHomogenization(fileUnit,myPart) - use IO, only: & - IO_read, & - IO_globalTagInPart, & - IO_countSections, & - IO_error, & - IO_countTagInPart, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringValue, & - IO_intValue, & - IO_floatValue, & - IO_stringPos, & - IO_EOF - use mesh, only: & - mesh_element - - implicit none - character(len=*), intent(in) :: myPart - integer(pInt), intent(in) :: fileUnit - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: Nsections, section, s, p - character(len=65536) :: & - tag, line - logical :: echo - - echo = IO_globalTagInPart(fileUnit,myPart,'/echo/') - Nsections = IO_countSections(fileUnit,myPart) - material_Nhomogenization = Nsections - if (Nsections < 1_pInt) call IO_error(160_pInt,ext_msg=myPart) - - allocate(homogenization_name(Nsections)); homogenization_name = '' - allocate(homogenization_type(Nsections), source=HOMOGENIZATION_undefined_ID) - allocate(thermal_type(Nsections), source=THERMAL_isothermal_ID) - allocate(damage_type (Nsections), source=DAMAGE_none_ID) - allocate(vacancyflux_type(Nsections), source=VACANCYFLUX_isoconc_ID) - allocate(porosity_type (Nsections), source=POROSITY_none_ID) - allocate(hydrogenflux_type(Nsections), source=HYDROGENFLUX_isoconc_ID) - allocate(homogenization_typeInstance(Nsections), source=0_pInt) - allocate(thermal_typeInstance(Nsections), source=0_pInt) - allocate(damage_typeInstance(Nsections), source=0_pInt) - allocate(vacancyflux_typeInstance(Nsections), source=0_pInt) - allocate(porosity_typeInstance(Nsections), source=0_pInt) - allocate(hydrogenflux_typeInstance(Nsections), source=0_pInt) - allocate(homogenization_Ngrains(Nsections), source=0_pInt) - allocate(homogenization_Noutput(Nsections), source=0_pInt) - allocate(homogenization_active(Nsections), source=.false.) !!!!!!!!!!!!!!! - allocate(thermal_initialT(Nsections), source=300.0_pReal) - allocate(damage_initialPhi(Nsections), source=1.0_pReal) - allocate(vacancyflux_initialCv(Nsections), source=0.0_pReal) - allocate(porosity_initialPhi(Nsections), source=1.0_pReal) - allocate(hydrogenflux_initialCh(Nsections), source=0.0_pReal) - - forall (s = 1_pInt:Nsections) homogenization_active(s) = any(mesh_element(3,:) == s) ! current homogenization used in model? Homogenization view, maximum operations depend on maximum number of homog schemes - homogenization_Noutput = IO_countTagInPart(fileUnit,myPart,'(output)',Nsections) - - rewind(fileUnit) - line = '' ! to have it initialized - section = 0_pInt ! - " - - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= myPart) ! wind forward to - line = IO_read(fileUnit) - enddo - if (echo) write(6,'(/,1x,a)') trim(line) ! echo part header - - do while (trim(line) /= IO_EOF) ! read through sections of material part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (echo) write(6,'(2x,a)') trim(line) ! echo back read lines - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - homogenization_name(section) = IO_getTag(line,'[',']') - endif - if (section > 0_pInt) then - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('type') - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case(HOMOGENIZATION_NONE_label) - homogenization_type(section) = HOMOGENIZATION_NONE_ID - homogenization_Ngrains(section) = 1_pInt - case(HOMOGENIZATION_ISOSTRAIN_label) - homogenization_type(section) = HOMOGENIZATION_ISOSTRAIN_ID - case(HOMOGENIZATION_RGC_label) - homogenization_type(section) = HOMOGENIZATION_RGC_ID - case default - call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) - end select - homogenization_typeInstance(section) = & - count(homogenization_type==homogenization_type(section)) ! count instances - case ('thermal') - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case(THERMAL_isothermal_label) - thermal_type(section) = THERMAL_isothermal_ID - case(THERMAL_adiabatic_label) - thermal_type(section) = THERMAL_adiabatic_ID - case(THERMAL_conduction_label) - thermal_type(section) = THERMAL_conduction_ID - case default - call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) - end select - - case ('damage') - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case(DAMAGE_NONE_label) - damage_type(section) = DAMAGE_none_ID - case(DAMAGE_LOCAL_label) - damage_type(section) = DAMAGE_local_ID - case(DAMAGE_NONLOCAL_label) - damage_type(section) = DAMAGE_nonlocal_ID - case default - call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) - end select - - case ('vacancyflux') - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case(VACANCYFLUX_isoconc_label) - vacancyflux_type(section) = VACANCYFLUX_isoconc_ID - case(VACANCYFLUX_isochempot_label) - vacancyflux_type(section) = VACANCYFLUX_isochempot_ID - case(VACANCYFLUX_cahnhilliard_label) - vacancyflux_type(section) = VACANCYFLUX_cahnhilliard_ID - case default - call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) - end select - - case ('porosity') - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case(POROSITY_NONE_label) - porosity_type(section) = POROSITY_none_ID - case(POROSITY_phasefield_label) - porosity_type(section) = POROSITY_phasefield_ID - case default - call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) - end select - - case ('hydrogenflux') - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case(HYDROGENFLUX_isoconc_label) - hydrogenflux_type(section) = HYDROGENFLUX_isoconc_ID - case(HYDROGENFLUX_cahnhilliard_label) - hydrogenflux_type(section) = HYDROGENFLUX_cahnhilliard_ID - case default - call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) - end select - - case ('nconstituents','ngrains') - homogenization_Ngrains(section) = IO_intValue(line,chunkPos,2_pInt) - - case ('initialtemperature','initialt') - thermal_initialT(section) = IO_floatValue(line,chunkPos,2_pInt) - - case ('initialdamage') - damage_initialPhi(section) = IO_floatValue(line,chunkPos,2_pInt) - - case ('initialvacancyconc','initialcv') - vacancyflux_initialCv(section) = IO_floatValue(line,chunkPos,2_pInt) - - case ('initialporosity') - porosity_initialPhi(section) = IO_floatValue(line,chunkPos,2_pInt) - - case ('initialhydrogenconc','initialch') - hydrogenflux_initialCh(section) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif - enddo - - do p=1_pInt, Nsections - homogenization_typeInstance(p) = count(homogenization_type(1:p) == homogenization_type(p)) - thermal_typeInstance(p) = count(thermal_type (1:p) == thermal_type (p)) - damage_typeInstance(p) = count(damage_type (1:p) == damage_type (p)) - vacancyflux_typeInstance(p) = count(vacancyflux_type (1:p) == vacancyflux_type (p)) - porosity_typeInstance(p) = count(porosity_type (1:p) == porosity_type (p)) - hydrogenflux_typeInstance(p) = count(hydrogenflux_type (1:p) == hydrogenflux_type (p)) - enddo - - homogenization_maxNgrains = maxval(homogenization_Ngrains,homogenization_active) - -end subroutine material_parseHomogenization - - -!-------------------------------------------------------------------------------------------------- -!> @brief parses the microstructure part in the material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine material_parseMicrostructure(fileUnit,myPart) - use IO - use mesh, only: & - mesh_element, & - mesh_NcpElems - - implicit none - character(len=*), intent(in) :: myPart - integer(pInt), intent(in) :: fileUnit - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: Nsections, section, constituent, e, i - character(len=65536) :: & - tag, line - logical :: echo - - echo = IO_globalTagInPart(fileUnit,myPart,'/echo/') - - Nsections = IO_countSections(fileUnit,myPart) - material_Nmicrostructure = Nsections - if (Nsections < 1_pInt) call IO_error(160_pInt,ext_msg=myPart) - - allocate(microstructure_name(Nsections)); microstructure_name = '' - allocate(microstructure_crystallite(Nsections), source=0_pInt) - allocate(microstructure_Nconstituents(Nsections), source=0_pInt) - allocate(microstructure_active(Nsections), source=.false.) - allocate(microstructure_elemhomo(Nsections), source=.false.) - - if(any(mesh_element(4,1:mesh_NcpElems) > Nsections)) & - call IO_error(155_pInt,ext_msg='Microstructure in geometry > Sections in material.config') - - forall (e = 1_pInt:mesh_NcpElems) microstructure_active(mesh_element(4,e)) = .true. ! current microstructure used in model? Elementwise view, maximum N operations for N elements - - microstructure_Nconstituents = IO_countTagInPart(fileUnit,myPart,'(constituent)',Nsections) - microstructure_maxNconstituents = maxval(microstructure_Nconstituents) - microstructure_elemhomo = IO_spotTagInPart(fileUnit,myPart,'/elementhomogeneous/',Nsections) - - allocate(microstructure_phase (microstructure_maxNconstituents,Nsections),source=0_pInt) - allocate(microstructure_texture (microstructure_maxNconstituents,Nsections),source=0_pInt) - allocate(microstructure_fraction(microstructure_maxNconstituents,Nsections),source=0.0_pReal) - - rewind(fileUnit) - line = '' ! to have it initialized - section = 0_pInt ! - " - - constituent = 0_pInt ! - " - - - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= myPart) ! wind forward to - line = IO_read(fileUnit) - enddo - if (echo) write(6,'(/,1x,a)') trim(line) ! echo part header - - do while (trim(line) /= IO_EOF) ! read through sections of material part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (echo) write(6,'(2x,a)') trim(line) ! echo back read lines - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - constituent = 0_pInt - microstructure_name(section) = IO_getTag(line,'[',']') - endif - if (section > 0_pInt) then - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('crystallite') - microstructure_crystallite(section) = IO_intValue(line,chunkPos,2_pInt) - case ('(constituent)') - constituent = constituent + 1_pInt - do i=2_pInt,6_pInt,2_pInt - tag = IO_lc(IO_stringValue(line,chunkPos,i)) - select case (tag) - case('phase') - microstructure_phase(constituent,section) = IO_intValue(line,chunkPos,i+1_pInt) - case('texture') - microstructure_texture(constituent,section) = IO_intValue(line,chunkPos,i+1_pInt) - case('fraction') - microstructure_fraction(constituent,section) = IO_floatValue(line,chunkPos,i+1_pInt) - end select - enddo - end select - endif - enddo - -end subroutine material_parseMicrostructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief parses the crystallite part in the material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine material_parseCrystallite(fileUnit,myPart) - use IO, only: & - IO_read, & - IO_countSections, & - IO_error, & - IO_countTagInPart, & - IO_globalTagInPart, & - IO_getTag, & - IO_lc, & - IO_isBlank, & - IO_EOF - - implicit none - character(len=*), intent(in) :: myPart - integer(pInt), intent(in) :: fileUnit - - integer(pInt) :: Nsections, & - section - character(len=65536) :: line - logical :: echo - - echo = IO_globalTagInPart(fileUnit,myPart,'/echo/') - - Nsections = IO_countSections(fileUnit,myPart) - material_Ncrystallite = Nsections - if (Nsections < 1_pInt) call IO_error(160_pInt,ext_msg=myPart) - - allocate(crystallite_name(Nsections)); crystallite_name = '' - allocate(crystallite_Noutput(Nsections), source=0_pInt) - - crystallite_Noutput = IO_countTagInPart(fileUnit,myPart,'(output)',Nsections) - - rewind(fileUnit) - line = '' ! to have it initialized - section = 0_pInt ! - " - - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= myPart) ! wind forward to - line = IO_read(fileUnit) - enddo - if (echo) write(6,'(/,1x,a)') trim(line) ! echo part header - - do while (trim(line) /= IO_EOF) ! read through sections of material part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (echo) write(6,'(2x,a)') trim(line) ! echo back read lines - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - crystallite_name(section) = IO_getTag(line,'[',']') - endif - enddo - -end subroutine material_parseCrystallite - - -!-------------------------------------------------------------------------------------------------- -!> @brief parses the phase part in the material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine material_parsePhase(fileUnit,myPart) - use IO, only: & - IO_read, & - IO_globalTagInPart, & - IO_countSections, & - IO_error, & - IO_countTagInPart, & - IO_getTag, & - IO_spotTagInPart, & - IO_lc, & - IO_isBlank, & - IO_stringValue, & - IO_stringPos, & - IO_EOF - - implicit none - character(len=*), intent(in) :: myPart - integer(pInt), intent(in) :: fileUnit - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: Nsections, section, sourceCtr, kinematicsCtr, stiffDegradationCtr, p - character(len=65536) :: & - tag,line - logical :: echo - - echo = IO_globalTagInPart(fileUnit,myPart,'/echo/') - - Nsections = IO_countSections(fileUnit,myPart) - material_Nphase = Nsections - if (Nsections < 1_pInt) call IO_error(160_pInt,ext_msg=myPart) - - allocate(phase_name(Nsections)); phase_name = '' - allocate(phase_elasticity(Nsections), source=ELASTICITY_undefined_ID) - allocate(phase_elasticityInstance(Nsections), source=0_pInt) - allocate(phase_plasticity(Nsections) , source=PLASTICITY_undefined_ID) - allocate(phase_plasticityInstance(Nsections), source=0_pInt) - allocate(phase_Nsources(Nsections), source=0_pInt) - allocate(phase_Nkinematics(Nsections), source=0_pInt) - allocate(phase_NstiffnessDegradations(Nsections),source=0_pInt) - allocate(phase_Noutput(Nsections), source=0_pInt) - allocate(phase_localPlasticity(Nsections), source=.false.) - - phase_Noutput = IO_countTagInPart(fileUnit,myPart,'(output)',Nsections) - phase_Nsources = IO_countTagInPart(fileUnit,myPart,'(source)',Nsections) - phase_Nkinematics = IO_countTagInPart(fileUnit,myPart,'(kinematics)',Nsections) - phase_NstiffnessDegradations = IO_countTagInPart(fileUnit,myPart,'(stiffness_degradation)',Nsections) - phase_localPlasticity = .not. IO_spotTagInPart(fileUnit,myPart,'/nonlocal/',Nsections) - - allocate(phase_source(maxval(phase_Nsources),Nsections), source=SOURCE_undefined_ID) - allocate(phase_kinematics(maxval(phase_Nkinematics),Nsections), source=KINEMATICS_undefined_ID) - allocate(phase_stiffnessDegradation(maxval(phase_NstiffnessDegradations),Nsections), & - source=STIFFNESS_DEGRADATION_undefined_ID) - - rewind(fileUnit) - line = '' ! to have it initialized - section = 0_pInt ! - " - - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= myPart) ! wind forward to - line = IO_read(fileUnit) - enddo - if (echo) write(6,'(/,1x,a)') trim(line) ! echo part header - - do while (trim(line) /= IO_EOF) ! read through sections of material part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (echo) write(6,'(2x,a)') trim(line) ! echo back read lines - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - sourceCtr = 0_pInt - kinematicsCtr = 0_pInt - stiffDegradationCtr = 0_pInt - phase_name(section) = IO_getTag(line,'[',']') - endif - if (section > 0_pInt) then - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('elasticity') - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case (ELASTICITY_HOOKE_label) - phase_elasticity(section) = ELASTICITY_HOOKE_ID - case default - call IO_error(200_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) - end select - case ('plasticity') - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case (PLASTICITY_NONE_label) - phase_plasticity(section) = PLASTICITY_NONE_ID - case (PLASTICITY_ISOTROPIC_label) - phase_plasticity(section) = PLASTICITY_ISOTROPIC_ID - case (PLASTICITY_J2_label) - phase_plasticity(section) = PLASTICITY_J2_ID - case (PLASTICITY_PHENOPOWERLAW_label) - phase_plasticity(section) = PLASTICITY_PHENOPOWERLAW_ID - case (PLASTICITY_PHENOPLUS_label) - phase_plasticity(section) = PLASTICITY_PHENOPLUS_ID - case (PLASTICITY_DISLOTWIN_label) - phase_plasticity(section) = PLASTICITY_DISLOTWIN_ID - case (PLASTICITY_DISLOUCLA_label) - phase_plasticity(section) = PLASTICITY_DISLOUCLA_ID - case (PLASTICITY_TITANMOD_label) - phase_plasticity(section) = PLASTICITY_TITANMOD_ID - case (PLASTICITY_NONLOCAL_label) - phase_plasticity(section) = PLASTICITY_NONLOCAL_ID - case default - call IO_error(201_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) - end select - case ('(source)') - sourceCtr = sourceCtr + 1_pInt - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case (SOURCE_thermal_dissipation_label) - phase_source(sourceCtr,section) = SOURCE_thermal_dissipation_ID - case (SOURCE_thermal_externalheat_label) - phase_source(sourceCtr,section) = SOURCE_thermal_externalheat_ID - case (SOURCE_damage_isoBrittle_label) - phase_source(sourceCtr,section) = SOURCE_damage_isoBrittle_ID - case (SOURCE_damage_isoDuctile_label) - phase_source(sourceCtr,section) = SOURCE_damage_isoDuctile_ID - case (SOURCE_damage_anisoBrittle_label) - phase_source(sourceCtr,section) = SOURCE_damage_anisoBrittle_ID - case (SOURCE_damage_anisoDuctile_label) - phase_source(sourceCtr,section) = SOURCE_damage_anisoDuctile_ID - case (SOURCE_vacancy_phenoplasticity_label) - phase_source(sourceCtr,section) = SOURCE_vacancy_phenoplasticity_ID - case (SOURCE_vacancy_irradiation_label) - phase_source(sourceCtr,section) = SOURCE_vacancy_irradiation_ID - case (SOURCE_vacancy_thermalfluc_label) - phase_source(sourceCtr,section) = SOURCE_vacancy_thermalfluc_ID - end select - case ('(kinematics)') - kinematicsCtr = kinematicsCtr + 1_pInt - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case (KINEMATICS_cleavage_opening_label) - phase_kinematics(kinematicsCtr,section) = KINEMATICS_cleavage_opening_ID - case (KINEMATICS_slipplane_opening_label) - phase_kinematics(kinematicsCtr,section) = KINEMATICS_slipplane_opening_ID - case (KINEMATICS_thermal_expansion_label) - phase_kinematics(kinematicsCtr,section) = KINEMATICS_thermal_expansion_ID - case (KINEMATICS_vacancy_strain_label) - phase_kinematics(kinematicsCtr,section) = KINEMATICS_vacancy_strain_ID - case (KINEMATICS_hydrogen_strain_label) - phase_kinematics(kinematicsCtr,section) = KINEMATICS_hydrogen_strain_ID - end select - case ('(stiffness_degradation)') - stiffDegradationCtr = stiffDegradationCtr + 1_pInt - select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case (STIFFNESS_DEGRADATION_damage_label) - phase_stiffnessDegradation(stiffDegradationCtr,section) = STIFFNESS_DEGRADATION_damage_ID - case (STIFFNESS_DEGRADATION_porosity_label) - phase_stiffnessDegradation(stiffDegradationCtr,section) = STIFFNESS_DEGRADATION_porosity_ID - end select - - end select - endif - enddo - - do p=1_pInt, Nsections - phase_elasticityInstance(p) = count(phase_elasticity(1:p) == phase_elasticity(p)) - phase_plasticityInstance(p) = count(phase_plasticity(1:p) == phase_plasticity(p)) - enddo - -end subroutine material_parsePhase - -!-------------------------------------------------------------------------------------------------- -!> @brief parses the texture part in the material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine material_parseTexture(fileUnit,myPart) - use IO, only: & - IO_read, & - IO_globalTagInPart, & - IO_countSections, & - IO_error, & - IO_countTagInPart, & - IO_getTag, & - IO_spotTagInPart, & - IO_lc, & - IO_isBlank, & - IO_floatValue, & - IO_stringValue, & - IO_stringPos, & - IO_EOF - use math, only: & - inRad, & - math_sampleRandomOri, & - math_I3, & - math_inv33 - - implicit none - character(len=*), intent(in) :: myPart - integer(pInt), intent(in) :: fileUnit - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: Nsections, section, gauss, fiber, j - character(len=65536) :: tag - character(len=65536) :: line - logical :: echo - - echo = IO_globalTagInPart(fileUnit,myPart,'/echo/') - - Nsections = IO_countSections(fileUnit,myPart) - material_Ntexture = Nsections - if (Nsections < 1_pInt) call IO_error(160_pInt,ext_msg=myPart) - - allocate(texture_name(Nsections)); texture_name='' - allocate(texture_ODFfile(Nsections)); texture_ODFfile='' - allocate(texture_symmetry(Nsections), source=1_pInt) - allocate(texture_Ngauss(Nsections), source=0_pInt) - allocate(texture_Nfiber(Nsections), source=0_pInt) - - texture_Ngauss = IO_countTagInPart(fileUnit,myPart,'(gauss)', Nsections) + & - IO_countTagInPart(fileUnit,myPart,'(random)',Nsections) - texture_Nfiber = IO_countTagInPart(fileUnit,myPart,'(fiber)', Nsections) - texture_maxNgauss = maxval(texture_Ngauss) - texture_maxNfiber = maxval(texture_Nfiber) - allocate(texture_Gauss (5,texture_maxNgauss,Nsections), source=0.0_pReal) - allocate(texture_Fiber (6,texture_maxNfiber,Nsections), source=0.0_pReal) - allocate(texture_transformation(3,3,Nsections), source=0.0_pReal) - texture_transformation = spread(math_I3,3,Nsections) - - rewind(fileUnit) - line = '' ! to have in initialized - section = 0_pInt ! - " - - gauss = 0_pInt ! - " - - fiber = 0_pInt ! - " - - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= myPart) ! wind forward to - line = IO_read(fileUnit) - enddo - if (echo) write(6,'(/,1x,a)') trim(line) ! echo part header - - do while (trim(line) /= IO_EOF) - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (echo) write(6,'(2x,a)') trim(line) ! echo back read lines - if (IO_getTag(line,'[',']') /= '') then ! next section - section = section + 1_pInt - gauss = 0_pInt - fiber = 0_pInt - texture_name(section) = IO_getTag(line,'[',']') - endif - if (section > 0_pInt) then - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - textureType: select case(tag) - - case ('axes', 'rotation') textureType - do j = 1_pInt, 3_pInt ! look for "x", "y", and "z" entries - tag = IO_lc(IO_stringValue(line,chunkPos,j+1_pInt)) - select case (tag) - case('x', '+x') - texture_transformation(j,1:3,section) = [ 1.0_pReal, 0.0_pReal, 0.0_pReal] ! original axis is now +x-axis - case('-x') - texture_transformation(j,1:3,section) = [-1.0_pReal, 0.0_pReal, 0.0_pReal] ! original axis is now -x-axis - case('y', '+y') - texture_transformation(j,1:3,section) = [ 0.0_pReal, 1.0_pReal, 0.0_pReal] ! original axis is now +y-axis - case('-y') - texture_transformation(j,1:3,section) = [ 0.0_pReal,-1.0_pReal, 0.0_pReal] ! original axis is now -y-axis - case('z', '+z') - texture_transformation(j,1:3,section) = [ 0.0_pReal, 0.0_pReal, 1.0_pReal] ! original axis is now +z-axis - case('-z') - texture_transformation(j,1:3,section) = [ 0.0_pReal, 0.0_pReal,-1.0_pReal] ! original axis is now -z-axis - case default - call IO_error(157_pInt,section) - end select - enddo - - case ('hybridia') textureType - texture_ODFfile(section) = IO_stringValue(line,chunkPos,2_pInt) - - case ('symmetry') textureType - tag = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - select case (tag) - case('orthotropic') - texture_symmetry(section) = 4_pInt - case('monoclinic') - texture_symmetry(section) = 2_pInt - case default - texture_symmetry(section) = 1_pInt - end select - - case ('(random)') textureType - gauss = gauss + 1_pInt - texture_Gauss(1:3,gauss,section) = math_sampleRandomOri() - do j = 2_pInt,4_pInt,2_pInt - tag = IO_lc(IO_stringValue(line,chunkPos,j)) - select case (tag) - case('scatter') - texture_Gauss(4,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad - case('fraction') - texture_Gauss(5,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt) - end select - enddo - - case ('(gauss)') textureType - gauss = gauss + 1_pInt - do j = 2_pInt,10_pInt,2_pInt - tag = IO_lc(IO_stringValue(line,chunkPos,j)) - select case (tag) - case('phi1') - texture_Gauss(1,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad - case('phi') - texture_Gauss(2,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad - case('phi2') - texture_Gauss(3,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad - case('scatter') - texture_Gauss(4,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad - case('fraction') - texture_Gauss(5,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt) - end select - enddo - - case ('(fiber)') textureType - fiber = fiber + 1_pInt - do j = 2_pInt,12_pInt,2_pInt - tag = IO_lc(IO_stringValue(line,chunkPos,j)) - select case (tag) - case('alpha1') - texture_Fiber(1,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad - case('alpha2') - texture_Fiber(2,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad - case('beta1') - texture_Fiber(3,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad - case('beta2') - texture_Fiber(4,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad - case('scatter') - texture_Fiber(5,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad - case('fraction') - texture_Fiber(6,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt) - end select - enddo - - end select textureType - endif - enddo - -end subroutine material_parseTexture - - -!-------------------------------------------------------------------------------------------------- -!> @brief populates the grains -!> @details populates the grains by identifying active microstructure/homogenization pairs, -!! calculates the volume of the grains and deals with texture components and hybridIA -!-------------------------------------------------------------------------------------------------- -subroutine material_populateGrains - use math, only: & - math_RtoEuler, & - math_EulerToR, & - math_mul33x33, & - math_range, & - math_sampleRandomOri, & - math_sampleGaussOri, & - math_sampleFiberOri, & - math_symmetricEulers - use mesh, only: & - mesh_element, & - mesh_maxNips, & - mesh_NcpElems, & - mesh_ipVolume, & - FE_Nips, & - FE_geomtype - use IO, only: & - IO_error, & - IO_hybridIA - use debug, only: & - debug_level, & - debug_material, & - debug_levelBasic - - implicit none - integer(pInt), dimension (:,:), allocatable :: Ngrains - integer(pInt), dimension (microstructure_maxNconstituents) :: & - NgrainsOfConstituent, & - currentGrainOfConstituent, & - randomOrder - real(pReal), dimension (microstructure_maxNconstituents) :: & - rndArray - real(pReal), dimension (:), allocatable :: volumeOfGrain - real(pReal), dimension (:,:), allocatable :: orientationOfGrain - real(pReal), dimension (3) :: orientation - real(pReal), dimension (3,3) :: symOrientation - integer(pInt), dimension (:), allocatable :: phaseOfGrain, textureOfGrain - integer(pInt) :: t,e,i,g,j,m,c,r,homog,micro,sgn,hme, myDebug, & - phaseID,textureID,dGrains,myNgrains,myNorientations,myNconstituents, & - grain,constituentGrain,ipGrain,symExtension, ip - real(pReal) :: extreme,rnd - integer(pInt), dimension (:,:), allocatable :: Nelems ! counts number of elements in homog, micro array - type(p_intvec), dimension (:,:), allocatable :: elemsOfHomogMicro ! lists element number in homog, micro array - - myDebug = debug_level(debug_material) - - allocate(material_volume(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(material_phase(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source=0_pInt) - allocate(material_homog(mesh_maxNips,mesh_NcpElems), source=0_pInt) - allocate(material_texture(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source=0_pInt) - allocate(material_EulerAngles(3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems),source=0.0_pReal) - - allocate(Ngrains(material_Nhomogenization,material_Nmicrostructure), source=0_pInt) - allocate(Nelems(material_Nhomogenization,material_Nmicrostructure), source=0_pInt) - -! populating homogenization schemes in each -!-------------------------------------------------------------------------------------------------- - do e = 1_pInt, mesh_NcpElems - material_homog(1_pInt:FE_Nips(FE_geomtype(mesh_element(2,e))),e) = mesh_element(3,e) - enddo - -!-------------------------------------------------------------------------------------------------- -! precounting of elements for each homog/micro pair - do e = 1_pInt, mesh_NcpElems - homog = mesh_element(3,e) - micro = mesh_element(4,e) - Nelems(homog,micro) = Nelems(homog,micro) + 1_pInt - enddo - allocate(elemsOfHomogMicro(material_Nhomogenization,material_Nmicrostructure)) - do homog = 1,material_Nhomogenization - do micro = 1,material_Nmicrostructure - if (Nelems(homog,micro) > 0_pInt) then - allocate(elemsOfHomogMicro(homog,micro)%p(Nelems(homog,micro))) - elemsOfHomogMicro(homog,micro)%p = 0_pInt - endif - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! identify maximum grain count per IP (from element) and find grains per homog/micro pair - Nelems = 0_pInt ! reuse as counter - elementLooping: do e = 1_pInt,mesh_NcpElems - t = FE_geomtype(mesh_element(2,e)) - homog = mesh_element(3,e) - micro = mesh_element(4,e) - if (homog < 1_pInt .or. homog > material_Nhomogenization) & ! out of bounds - call IO_error(154_pInt,e,0_pInt,0_pInt) - if (micro < 1_pInt .or. micro > material_Nmicrostructure) & ! out of bounds - call IO_error(155_pInt,e,0_pInt,0_pInt) - if (microstructure_elemhomo(micro)) then ! how many grains are needed at this element? - dGrains = homogenization_Ngrains(homog) ! only one set of Ngrains (other IPs are plain copies) - else - dGrains = homogenization_Ngrains(homog) * FE_Nips(t) ! each IP has Ngrains - endif - Ngrains(homog,micro) = Ngrains(homog,micro) + dGrains ! total grain count - Nelems(homog,micro) = Nelems(homog,micro) + 1_pInt ! total element count - elemsOfHomogMicro(homog,micro)%p(Nelems(homog,micro)) = e ! remember elements active in this homog/micro pair - enddo elementLooping - - allocate(volumeOfGrain(maxval(Ngrains)), source=0.0_pReal) ! reserve memory for maximum case - allocate(phaseOfGrain(maxval(Ngrains)), source=0_pInt) ! reserve memory for maximum case - allocate(textureOfGrain(maxval(Ngrains)), source=0_pInt) ! reserve memory for maximum case - allocate(orientationOfGrain(3,maxval(Ngrains)),source=0.0_pReal) ! reserve memory for maximum case - - if (iand(myDebug,debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(/,a/)') ' MATERIAL grain population' - write(6,'(a32,1x,a32,1x,a6)') 'homogenization_name','microstructure_name','grain#' - !$OMP END CRITICAL (write2out) - endif - do homog = 1_pInt,material_Nhomogenization ! loop over homogenizations - dGrains = homogenization_Ngrains(homog) ! grain number per material point - do micro = 1_pInt,material_Nmicrostructure ! all pairs of homog and micro - if (Ngrains(homog,micro) > 0_pInt) then ! an active pair of homog and micro - myNgrains = Ngrains(homog,micro) ! assign short name for total number of grains to populate - myNconstituents = microstructure_Nconstituents(micro) ! assign short name for number of constituents - if (iand(myDebug,debug_levelBasic) /= 0_pInt) then - !$OMP CRITICAL (write2out) - write(6,'(/,a32,1x,a32,1x,i6)') homogenization_name(homog),microstructure_name(micro),myNgrains - !$OMP END CRITICAL (write2out) - endif - - -!-------------------------------------------------------------------------------------------------- -! calculate volume of each grain - - volumeOfGrain = 0.0_pReal - grain = 0_pInt - - do hme = 1_pInt, Nelems(homog,micro) - e = elemsOfHomogMicro(homog,micro)%p(hme) ! my combination of homog and micro, only perform calculations for elements with homog, micro combinations which is indexed in cpElemsindex - t = FE_geomtype(mesh_element(2,e)) - if (microstructure_elemhomo(micro)) then ! homogeneous distribution of grains over each element's IPs - volumeOfGrain(grain+1_pInt:grain+dGrains) = sum(mesh_ipVolume(1:FE_Nips(t),e))/& - real(dGrains,pReal) ! each grain combines size of all IPs in that element - grain = grain + dGrains ! wind forward by Ngrains@IP - else - forall (i = 1_pInt:FE_Nips(t)) & ! loop over IPs - volumeOfGrain(grain+(i-1)*dGrains+1_pInt:grain+i*dGrains) = & - mesh_ipVolume(i,e)/dGrains ! assign IPvolume/Ngrains@IP to all grains of IP - grain = grain + FE_Nips(t) * dGrains ! wind forward by Nips*Ngrains@IP - endif - enddo - - if (grain /= myNgrains) & - call IO_error(0,el = homog,ip = micro,ext_msg = 'inconsistent grain count after volume calc') - -!-------------------------------------------------------------------------------------------------- -! divide myNgrains as best over constituents -! -! example: three constituents with fractions of 0.25, 0.25, and 0.5 distributed over 20 (microstructure) grains -! -! ***** ***** ********** -! NgrainsOfConstituent: 5, 5, 10 -! counters: -! |-----> grain (if constituent == 2) -! |--> constituentGrain (of constituent 2) -! - - NgrainsOfConstituent = 0_pInt ! reset counter of grains per constituent - forall (i = 1_pInt:myNconstituents) & - NgrainsOfConstituent(i) = nint(microstructure_fraction(i,micro) * myNgrains, pInt) ! do rounding integer conversion - do while (sum(NgrainsOfConstituent) /= myNgrains) ! total grain count over constituents wrong? - sgn = sign(1_pInt, myNgrains - sum(NgrainsOfConstituent)) ! direction of required change - extreme = 0.0_pReal - t = 0_pInt - do i = 1_pInt,myNconstituents ! find largest deviator - if (real(sgn,pReal)*log(NgrainsOfConstituent(i)/myNgrains/microstructure_fraction(i,micro)) > extreme) then - extreme = real(sgn,pReal)*log(NgrainsOfConstituent(i)/myNgrains/microstructure_fraction(i,micro)) - t = i - endif - enddo - NgrainsOfConstituent(t) = NgrainsOfConstituent(t) + sgn ! change that by one - enddo - -!-------------------------------------------------------------------------------------------------- -! assign phase and texture info - - phaseOfGrain = 0_pInt - textureOfGrain = 0_pInt - orientationOfGrain = 0.0_pReal - - texture: do i = 1_pInt,myNconstituents ! loop over constituents - grain = sum(NgrainsOfConstituent(1_pInt:i-1_pInt)) ! set microstructure grain index of current constituent - ! "grain" points to start of this constituent's grain population - constituentGrain = 0_pInt ! constituent grain index - - phaseID = microstructure_phase(i,micro) - textureID = microstructure_texture(i,micro) - phaseOfGrain (grain+1_pInt:grain+NgrainsOfConstituent(i)) = phaseID ! assign resp. phase - textureOfGrain(grain+1_pInt:grain+NgrainsOfConstituent(i)) = textureID ! assign resp. texture - - myNorientations = ceiling(real(NgrainsOfConstituent(i),pReal)/& - real(texture_symmetry(textureID),pReal),pInt) ! max number of unique orientations (excl. symmetry) - -!-------------------------------------------------------------------------------------------------- -! ...has texture components - if (texture_ODFfile(textureID) == '') then - gauss: do t = 1_pInt,texture_Ngauss(textureID) ! loop over Gauss components - do g = 1_pInt,int(myNorientations*texture_Gauss(5,t,textureID),pInt) ! loop over required grain count - orientationOfGrain(:,grain+constituentGrain+g) = & - math_sampleGaussOri(texture_Gauss(1:3,t,textureID),& - texture_Gauss( 4,t,textureID)) - enddo - constituentGrain = & - constituentGrain + int(myNorientations*texture_Gauss(5,t,textureID)) ! advance counter for grains of current constituent - enddo gauss - - fiber: do t = 1_pInt,texture_Nfiber(textureID) ! loop over fiber components - do g = 1_pInt,int(myNorientations*texture_Fiber(6,t,textureID),pInt) ! loop over required grain count - orientationOfGrain(:,grain+constituentGrain+g) = & - math_sampleFiberOri(texture_Fiber(1:2,t,textureID),& - texture_Fiber(3:4,t,textureID),& - texture_Fiber( 5,t,textureID)) - enddo - constituentGrain = & - constituentGrain + int(myNorientations*texture_fiber(6,t,textureID),pInt) ! advance counter for grains of current constituent - enddo fiber - - random: do constituentGrain = constituentGrain+1_pInt,myNorientations ! fill remainder with random - orientationOfGrain(:,grain+constituentGrain) = math_sampleRandomOri() - enddo random -!-------------------------------------------------------------------------------------------------- -! ...has hybrid IA - else - orientationOfGrain(1:3,grain+1_pInt:grain+myNorientations) = & - IO_hybridIA(myNorientations,texture_ODFfile(textureID)) - if (all(orientationOfGrain(1:3,grain+1_pInt) == -1.0_pReal)) call IO_error(156_pInt) - endif - -!-------------------------------------------------------------------------------------------------- -! ...texture transformation - - do j = 1_pInt,myNorientations ! loop over each "real" orientation - orientationOfGrain(1:3,grain+j) = math_RtoEuler( & ! translate back to Euler angles - math_mul33x33( & ! pre-multiply - math_EulertoR(orientationOfGrain(1:3,grain+j)), & ! face-value orientation - texture_transformation(1:3,1:3,textureID) & ! and transformation matrix - ) & - ) - enddo - -!-------------------------------------------------------------------------------------------------- -! ...sample symmetry - - symExtension = texture_symmetry(textureID) - 1_pInt - if (symExtension > 0_pInt) then ! sample symmetry (number of additional equivalent orientations) - constituentGrain = myNorientations ! start right after "real" orientations - do j = 1_pInt,myNorientations ! loop over each "real" orientation - symOrientation = math_symmetricEulers(texture_symmetry(textureID), & - orientationOfGrain(1:3,grain+j)) ! get symmetric equivalents - e = min(symExtension,NgrainsOfConstituent(i)-constituentGrain) ! do not overshoot end of constituent grain array - if (e > 0_pInt) then - orientationOfGrain(1:3,grain+constituentGrain+1: & - grain+constituentGrain+e) = & - symOrientation(1:3,1:e) - constituentGrain = constituentGrain + e ! remainder shrinks by e - endif - enddo - endif - -!-------------------------------------------------------------------------------------------------- -! shuffle grains within current constituent - - do j = 1_pInt,NgrainsOfConstituent(i)-1_pInt ! walk thru grains of current constituent - call random_number(rnd) - t = nint(rnd*(NgrainsOfConstituent(i)-j)+j+0.5_pReal,pInt) ! select a grain in remaining list - m = phaseOfGrain(grain+t) ! exchange current with random - phaseOfGrain(grain+t) = phaseOfGrain(grain+j) - phaseOfGrain(grain+j) = m - m = textureOfGrain(grain+t) ! exchange current with random - textureOfGrain(grain+t) = textureOfGrain(grain+j) - textureOfGrain(grain+j) = m - orientation = orientationOfGrain(1:3,grain+t) ! exchange current with random - orientationOfGrain(1:3,grain+t) = orientationOfGrain(1:3,grain+j) - orientationOfGrain(1:3,grain+j) = orientation - enddo - - enddo texture -!< @todo calc fraction after weighing with volumePerGrain, exchange in MC steps to improve result (humbug at the moment) - - - -!-------------------------------------------------------------------------------------------------- -! distribute grains of all constituents as accurately as possible to given constituent fractions - - ip = 0_pInt - currentGrainOfConstituent = 0_pInt - - do hme = 1_pInt, Nelems(homog,micro) - e = elemsOfHomogMicro(homog,micro)%p(hme) ! only perform calculations for elements with homog, micro combinations which is indexed in cpElemsindex - t = FE_geomtype(mesh_element(2,e)) - if (microstructure_elemhomo(micro)) then ! homogeneous distribution of grains over each element's IPs - m = 1_pInt ! process only first IP - else - m = FE_Nips(t) ! process all IPs - endif - - do i = 1_pInt, m ! loop over necessary IPs - ip = ip + 1_pInt ! keep track of total ip count - ipGrain = 0_pInt ! count number of grains assigned at this IP - randomOrder = math_range(microstructure_maxNconstituents) ! start out with ordered sequence of constituents - call random_number(rndArray) ! as many rnd numbers as (max) constituents - do j = 1_pInt, myNconstituents - 1_pInt ! loop over constituents ... - r = nint(rndArray(j)*(myNconstituents-j)+j+0.5_pReal,pInt) ! ... select one in remaining list - c = randomOrder(r) ! ... call it "c" - randomOrder(r) = randomOrder(j) ! ... and exchange with present position in constituent list - grain = sum(NgrainsOfConstituent(1:c-1_pInt)) ! figure out actual starting index in overall/consecutive grain population - do g = 1_pInt, min(dGrains-ipGrain, & ! leftover number of grains at this IP - max(0_pInt, & ! no negative values - nint(real(ip * dGrains * NgrainsOfConstituent(c)) / & ! fraction of grains scaled to this constituent... - real(myNgrains),pInt) - & ! ...minus those already distributed - currentGrainOfConstituent(c))) - ipGrain = ipGrain + 1_pInt ! advance IP grain counter - currentGrainOfConstituent(c) = currentGrainOfConstituent(c) + 1_pInt ! advance index of grain population for constituent c - material_volume(ipGrain,i,e) = volumeOfGrain(grain+currentGrainOfConstituent(c)) ! assign properties - material_phase(ipGrain,i,e) = phaseOfGrain(grain+currentGrainOfConstituent(c)) - material_texture(ipGrain,i,e) = textureOfGrain(grain+currentGrainOfConstituent(c)) - material_EulerAngles(1:3,ipGrain,i,e) = orientationOfGrain(1:3,grain+currentGrainOfConstituent(c)) - enddo; enddo - - c = randomOrder(microstructure_Nconstituents(micro)) ! look up constituent remaining after random shuffling - grain = sum(NgrainsOfConstituent(1:c-1_pInt)) ! figure out actual starting index in overall/consecutive grain population - do ipGrain = ipGrain + 1_pInt, dGrains ! ensure last constituent fills up to dGrains - currentGrainOfConstituent(c) = currentGrainOfConstituent(c) + 1_pInt - material_volume(ipGrain,i,e) = volumeOfGrain(grain+currentGrainOfConstituent(c)) - material_phase(ipGrain,i,e) = phaseOfGrain(grain+currentGrainOfConstituent(c)) - material_texture(ipGrain,i,e) = textureOfGrain(grain+currentGrainOfConstituent(c)) - material_EulerAngles(1:3,ipGrain,i,e) = orientationOfGrain(1:3,grain+currentGrainOfConstituent(c)) - enddo - - enddo - - do i = i, FE_Nips(t) ! loop over IPs to (possibly) distribute copies from first IP - material_volume (1_pInt:dGrains,i,e) = material_volume (1_pInt:dGrains,1,e) - material_phase (1_pInt:dGrains,i,e) = material_phase (1_pInt:dGrains,1,e) - material_texture(1_pInt:dGrains,i,e) = material_texture(1_pInt:dGrains,1,e) - material_EulerAngles(1:3,1_pInt:dGrains,i,e) = material_EulerAngles(1:3,1_pInt:dGrains,1,e) - enddo - - enddo - endif ! active homog,micro pair - enddo - enddo - - deallocate(volumeOfGrain) - deallocate(phaseOfGrain) - deallocate(textureOfGrain) - deallocate(orientationOfGrain) - deallocate(Nelems) - !> @todo - causing segmentation fault: needs looking into - !do homog = 1,material_Nhomogenization - ! do micro = 1,material_Nmicrostructure - ! if (Nelems(homog,micro) > 0_pInt) deallocate(elemsOfHomogMicro(homog,micro)%p) - ! enddo - !enddo - deallocate(elemsOfHomogMicro) - -end subroutine material_populateGrains - -#ifdef HDF -integer(pInt) pure function material_NconstituentsPhase(matID) - - implicit none - integer(pInt), intent(in) :: matID - - material_NconstituentsPhase = count(microstructure_phase == matID) -end function -#endif - -end module material diff --git a/code/math.f90 b/code/math.f90 deleted file mode 100644 index 8636ad6bc..000000000 --- a/code/math.f90 +++ /dev/null @@ -1,2678 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @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 Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Mathematical library, including random number generation and tensor represenations -!-------------------------------------------------------------------------------------------------- -module math - use, intrinsic :: iso_c_binding - use prec, only: & - pReal, & - pInt - - implicit none - private - real(pReal), parameter, public :: PI = 3.14159265358979323846264338327950288419716939937510_pReal !< ratio of a circle's circumference to its diameter - real(pReal), parameter, public :: INDEG = 180.0_pReal/PI !< conversion from radian into degree - real(pReal), parameter, public :: INRAD = PI/180.0_pReal !< conversion from degree into radian - complex(pReal), parameter, public :: TWOPIIMG = (0.0_pReal,2.0_pReal)* PI !< Re(0.0), Im(2xPi) - - real(pReal), dimension(3,3), parameter, public :: & - MATH_I3 = reshape([& - 1.0_pReal,0.0_pReal,0.0_pReal, & - 0.0_pReal,1.0_pReal,0.0_pReal, & - 0.0_pReal,0.0_pReal,1.0_pReal & - ],[3,3]) !< 3x3 Identity - - integer(pInt), dimension (2,6), parameter, private :: & - mapMandel = reshape([& - 1_pInt,1_pInt, & - 2_pInt,2_pInt, & - 3_pInt,3_pInt, & - 1_pInt,2_pInt, & - 2_pInt,3_pInt, & - 1_pInt,3_pInt & - ],[2,6]) !< arrangement in Mandel notation - - real(pReal), dimension(6), parameter, private :: & - nrmMandel = [& - 1.0_pReal, 1.0_pReal, 1.0_pReal,& - 1.414213562373095_pReal, 1.414213562373095_pReal, 1.414213562373095_pReal ] !< weighting for Mandel notation (forward) - - real(pReal), dimension(6), parameter , public :: & - invnrmMandel = [& - 1.0_pReal, 1.0_pReal, 1.0_pReal,& - 0.7071067811865476_pReal, 0.7071067811865476_pReal, 0.7071067811865476_pReal ] !< weighting for Mandel notation (backward) - - integer(pInt), dimension (2,6), parameter, private :: & - mapVoigt = reshape([& - 1_pInt,1_pInt, & - 2_pInt,2_pInt, & - 3_pInt,3_pInt, & - 2_pInt,3_pInt, & - 1_pInt,3_pInt, & - 1_pInt,2_pInt & - ],[2,6]) !< arrangement in Voigt notation - - real(pReal), dimension(6), parameter, private :: & - nrmVoigt = 1.0_pReal, & !< weighting for Voigt notation (forward) - invnrmVoigt = 1.0_pReal !< weighting for Voigt notation (backward) - - integer(pInt), dimension (2,9), parameter, private :: & - mapPlain = reshape([& - 1_pInt,1_pInt, & - 1_pInt,2_pInt, & - 1_pInt,3_pInt, & - 2_pInt,1_pInt, & - 2_pInt,2_pInt, & - 2_pInt,3_pInt, & - 3_pInt,1_pInt, & - 3_pInt,2_pInt, & - 3_pInt,3_pInt & - ],[2,9]) !< arrangement in Plain notation - -#ifdef Spectral - include 'fftw3.f03' -#endif - - public :: & - math_init, & - math_qsort, & - math_range, & - math_identity2nd, & - math_identity4th, & - math_civita, & - math_delta, & - math_crossproduct, & - math_tensorproduct33, & - math_mul3x3, & - math_mul6x6, & - math_mul33xx33, & - math_mul3333xx33, & - math_mul3333xx3333, & - math_mul33x33, & - math_mul66x66, & - math_mul99x99, & - math_mul33x3, & - math_mul33x3_complex, & - math_mul66x6 , & - math_exp33 , & - math_transpose33, & - math_inv33, & - math_invert33, & - math_invSym3333, & - math_invert, & - math_symmetric33, & - math_symmetric66, & - math_skew33, & - math_spherical33, & - math_deviatoric33, & - math_equivStrain33, & - math_equivStress33, & - math_trace33, & - math_det33, & - math_Plain33to9, & - math_Plain9to33, & - math_Mandel33to6, & - math_Mandel6to33, & - math_Plain3333to99, & - math_Plain99to3333, & - math_Mandel66toPlain66, & - math_Plain66toMandel66, & - math_Mandel3333to66, & - math_Mandel66to3333, & - math_Voigt66to3333, & - math_qRand, & - math_qMul, & - math_qDot, & - math_qConj, & - math_qInv, & - math_qRot, & - math_RtoEuler, & - math_RtoQ, & - math_EulerToR, & - math_EulerToQ, & - math_EulerAxisAngleToR, & - math_axisAngleToR, & - math_EulerAxisAngleToQ, & - math_axisAngleToQ, & - math_qToRodrig, & - math_qToEuler, & - math_qToEulerAxisAngle, & - math_qToAxisAngle, & - math_qToR, & - math_EulerMisorientation, & - math_sampleRandomOri, & - math_sampleGaussOri, & - math_sampleFiberOri, & - math_sampleGaussVar, & - math_symmetricEulers, & - math_spectralDecompositionSym33, & - math_spectralDecompositionSym, & - math_rotationalPart33, & - math_invariantsSym33, & - math_eigenvaluesSym33, & - math_factorial, & - math_binomial, & - math_multinomial, & - math_volTetrahedron, & - math_areaTriangle, & - math_rotate_forward33, & - math_rotate_backward33, & - math_rotate_forward3333 -#ifdef Spectral - public :: & - fftw_set_timelimit, & - fftw_plan_dft_3d, & - fftw_plan_many_dft_r2c, & - fftw_plan_many_dft_c2r, & - fftw_plan_with_nthreads, & - fftw_init_threads, & - fftw_alloc_complex, & - fftw_execute_dft, & - fftw_execute_dft_r2c, & - fftw_execute_dft_c2r, & - fftw_destroy_plan, & - math_tensorAvg -#endif - private :: & - math_partition, & - halton, & - halton_memory, & - halton_ndim_set, & - halton_seed_set, & - i_to_halton, & - prime - external :: & - dsyev, & - dgetrf, & - dgetri - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief initialization of random seed generator -!-------------------------------------------------------------------------------------------------- -subroutine math_init - - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: tol_math_check - use numerics, only: & - worldrank, & - fixedSeed - use IO, only: IO_error, IO_timeStamp - - implicit none - integer(pInt) :: i - real(pReal), dimension(3,3) :: R,R2 - real(pReal), dimension(3) :: Eulers,v - real(pReal), dimension(4) :: q,q2,axisangle,randTest -! the following variables are system dependend and shound NOT be pInt - integer :: randSize ! gfortran requires a variable length to compile - integer, dimension(:), allocatable :: randInit ! if recalculations of former randomness (with given seed) is necessary - ! comment the first random_seed call out, set randSize to 1, and use ifort - character(len=64) :: error_msg - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- math init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - call random_seed(size=randSize) - if (allocated(randInit)) deallocate(randInit) - allocate(randInit(randSize)) - if (fixedSeed > 0_pInt) then - randInit(1:randSize) = int(fixedSeed) ! fixedSeed is of type pInt, randInit not - call random_seed(put=randInit) - else - call random_seed() - call random_seed(get = randInit) - randInit(2:randSize) = randInit(1) - call random_seed(put = randInit) - endif - - do i = 1_pInt, 4_pInt - call random_number(randTest(i)) - enddo - - mainProcess2: if (worldrank == 0) then - write(6,*) 'size of random seed: ', randSize - do i =1, randSize - write(6,*) 'value of random seed: ', i, randInit(i) - enddo - write(6,'(a,4(/,26x,f17.14),/)') ' start of random sequence: ', randTest - endif mainProcess2 - - call random_seed(put = randInit) - - call halton_seed_set(int(randInit(1), pInt)) - call halton_ndim_set(3_pInt) - - ! --- check rotation dictionary --- - - q = math_qRand() ! random quaternion - - ! +++ q -> a -> q +++ - axisangle = math_qToAxisAngle(q) - q2 = math_axisAngleToQ(axisangle(1:3),axisangle(4)) - if ( any(abs( q-q2) > tol_math_check) .and. & - any(abs(-q-q2) > tol_math_check) ) then - write (error_msg, '(a,e14.6)' ) 'maximum deviation ',min(maxval(abs( q-q2)),maxval(abs(-q-q2))) - call IO_error(401_pInt,ext_msg=error_msg) - endif - - ! +++ q -> R -> q +++ - R = math_qToR(q) - q2 = math_RtoQ(R) - if ( any(abs( q-q2) > tol_math_check) .and. & - any(abs(-q-q2) > tol_math_check) ) then - write (error_msg, '(a,e14.6)' ) 'maximum deviation ',min(maxval(abs( q-q2)),maxval(abs(-q-q2))) - call IO_error(402_pInt,ext_msg=error_msg) - endif - - ! +++ q -> euler -> q +++ - Eulers = math_qToEuler(q) - q2 = math_EulerToQ(Eulers) - if ( any(abs( q-q2) > tol_math_check) .and. & - any(abs(-q-q2) > tol_math_check) ) then - write (error_msg, '(a,e14.6)' ) 'maximum deviation ',min(maxval(abs( q-q2)),maxval(abs(-q-q2))) - call IO_error(403_pInt,ext_msg=error_msg) - endif - - ! +++ R -> euler -> R +++ - Eulers = math_RtoEuler(R) - R2 = math_EulerToR(Eulers) - if ( any(abs( R-R2) > tol_math_check) ) then - write (error_msg, '(a,e14.6)' ) 'maximum deviation ',maxval(abs( R-R2)) - call IO_error(404_pInt,ext_msg=error_msg) - endif - - ! +++ check rotation sense of q and R +++ - q = math_qRand() ! random quaternion - call halton(3_pInt,v) ! random vector - R = math_qToR(q) - if (any(abs(math_mul33x3(R,v) - math_qRot(q,v)) > tol_math_check)) then - write(6,'(a,4(f8.3,1x))') 'q',q - call IO_error(409_pInt) - endif - -end subroutine math_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief Quicksort algorithm for two-dimensional integer arrays -! Sorting is done with respect to array(1,:) -! and keeps array(2:N,:) linked to it. -!-------------------------------------------------------------------------------------------------- -recursive subroutine math_qsort(a, istart, iend) - - implicit none - integer(pInt), dimension(:,:), intent(inout) :: a - integer(pInt), intent(in) :: istart,iend - integer(pInt) :: ipivot - - if (istart < iend) then - ipivot = math_partition(a,istart, iend) - call math_qsort(a, istart, ipivot-1_pInt) - call math_qsort(a, ipivot+1_pInt, iend) - endif - -end subroutine math_qsort - - -!-------------------------------------------------------------------------------------------------- -!> @brief Partitioning required for quicksort -!-------------------------------------------------------------------------------------------------- -integer(pInt) function math_partition(a, istart, iend) - - implicit none - integer(pInt), dimension(:,:), intent(inout) :: a - integer(pInt), intent(in) :: istart,iend - integer(pInt) :: d,i,j,k,x,tmp - - d = int(size(a,1_pInt), pInt) ! number of linked data -! set the starting and ending points, and the pivot point - - i = istart - - j = iend - x = a(1,istart) - do -! find the first element on the right side less than or equal to the pivot point - do j = j, istart, -1_pInt - if (a(1,j) <= x) exit - enddo -! find the first element on the left side greater than the pivot point - do i = i, iend - if (a(1,i) > x) exit - enddo - if (i < j) then ! if the indexes do not cross, exchange values - do k = 1_pInt,d - tmp = a(k,i) - a(k,i) = a(k,j) - a(k,j) = tmp - enddo - else ! if they do cross, exchange left value with pivot and return with the partition index - do k = 1_pInt,d - tmp = a(k,istart) - a(k,istart) = a(k,j) - a(k,j) = tmp - enddo - math_partition = j - return - endif - enddo - -end function math_partition - - -!-------------------------------------------------------------------------------------------------- -!> @brief range of integers starting at one -!-------------------------------------------------------------------------------------------------- -pure function math_range(N) - - implicit none - integer(pInt), intent(in) :: N !< length of range - integer(pInt) :: i - integer(pInt), dimension(N) :: math_range - - math_range = [(i,i=1_pInt,N)] - -end function math_range - - -!-------------------------------------------------------------------------------------------------- -!> @brief second rank identity tensor of specified dimension -!-------------------------------------------------------------------------------------------------- -pure function math_identity2nd(dimen) - - implicit none - integer(pInt), intent(in) :: dimen !< tensor dimension - integer(pInt) :: i - real(pReal), dimension(dimen,dimen) :: math_identity2nd - - math_identity2nd = 0.0_pReal - forall (i=1_pInt:dimen) math_identity2nd(i,i) = 1.0_pReal - -end function math_identity2nd - -!-------------------------------------------------------------------------------------------------- -!> @brief symmetric fourth rank identity tensor of specified dimension -! from http://en.wikipedia.org/wiki/Tensor_derivative_(continuum_mechanics)#Derivative_of_a_second-order_tensor_with_respect_to_itself -!-------------------------------------------------------------------------------------------------- -pure function math_identity4th(dimen) - - implicit none - integer(pInt), intent(in) :: dimen !< tensor dimension - integer(pInt) :: i,j,k,l - real(pReal), dimension(dimen,dimen,dimen,dimen) :: math_identity4th - - forall (i=1_pInt:dimen,j=1_pInt:dimen,k=1_pInt:dimen,l=1_pInt:dimen) math_identity4th(i,j,k,l) = & - 0.5_pReal*(math_I3(i,k)*math_I3(j,l)+math_I3(i,l)*math_I3(j,k)) - -end function math_identity4th - - -!-------------------------------------------------------------------------------------------------- -!> @brief permutation tensor e_ijk used for computing cross product of two tensors -! e_ijk = 1 if even permutation of ijk -! e_ijk = -1 if odd permutation of ijk -! e_ijk = 0 otherwise -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_civita(i,j,k) - - implicit none - integer(pInt), intent(in) :: i,j,k - - math_civita = 0.0_pReal - if (((i == 1_pInt).and.(j == 2_pInt).and.(k == 3_pInt)) .or. & - ((i == 2_pInt).and.(j == 3_pInt).and.(k == 1_pInt)) .or. & - ((i == 3_pInt).and.(j == 1_pInt).and.(k == 2_pInt))) math_civita = 1.0_pReal - if (((i == 1_pInt).and.(j == 3_pInt).and.(k == 2_pInt)) .or. & - ((i == 2_pInt).and.(j == 1_pInt).and.(k == 3_pInt)) .or. & - ((i == 3_pInt).and.(j == 2_pInt).and.(k == 1_pInt))) math_civita = -1.0_pReal - -end function math_civita - - -!-------------------------------------------------------------------------------------------------- -!> @brief kronecker delta function d_ij -! d_ij = 1 if i = j -! d_ij = 0 otherwise -! inspired by http://fortraninacworld.blogspot.de/2012/12/ternary-operator.html -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_delta(i,j) - - implicit none - integer(pInt), intent (in) :: i,j - - math_delta = merge(0.0_pReal, 1.0_pReal, i /= j) - -end function math_delta - - -!-------------------------------------------------------------------------------------------------- -!> @brief cross product a x b -!-------------------------------------------------------------------------------------------------- -pure function math_crossproduct(A,B) - - implicit none - real(pReal), dimension(3), intent(in) :: A,B - real(pReal), dimension(3) :: math_crossproduct - - math_crossproduct = [ A(2)*B(3) -A(3)*B(2), & - A(3)*B(1) -A(1)*B(3), & - A(1)*B(2) -A(2)*B(1) ] - -end function math_crossproduct - - -!-------------------------------------------------------------------------------------------------- -!> @brief tensor product a \otimes b -!-------------------------------------------------------------------------------------------------- -pure function math_tensorproduct33(A,B) - - implicit none - real(pReal), dimension(3,3) :: math_tensorproduct33 - real(pReal), dimension(3), intent(in) :: A,B - integer(pInt) :: i,j - - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) math_tensorproduct33(i,j) = A(i)*B(j) - -end function math_tensorproduct33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication 3x3 = 1 -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_mul3x3(A,B) - - implicit none - real(pReal), dimension(3), intent(in) :: A,B - - math_mul3x3 = sum(A*B) - -end function math_mul3x3 - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication 6x6 = 1 -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_mul6x6(A,B) - - implicit none - real(pReal), dimension(6), intent(in) :: A,B - - math_mul6x6 = sum(A*B) - -end function math_mul6x6 - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication 33xx33 = 1 (double contraction --> ij * ij) -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_mul33xx33(A,B) - - implicit none - real(pReal), dimension(3,3), intent(in) :: A,B - integer(pInt) :: i,j - real(pReal), dimension(3,3) :: C - - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) C(i,j) = A(i,j) * B(i,j) - math_mul33xx33 = sum(C) - -end function math_mul33xx33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication 3333x33 = 33 (double contraction --> ijkl *kl = ij) -!-------------------------------------------------------------------------------------------------- -pure function math_mul3333xx33(A,B) - - implicit none - real(pReal), dimension(3,3) :: math_mul3333xx33 - real(pReal), dimension(3,3,3,3), intent(in) :: A - real(pReal), dimension(3,3), intent(in) :: B - integer(pInt) :: i,j - - forall(i = 1_pInt:3_pInt,j = 1_pInt:3_pInt) & - math_mul3333xx33(i,j) = sum(A(i,j,1:3,1:3)*B(1:3,1:3)) - -end function math_mul3333xx33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication 3333x3333 = 3333 (ijkl *klmn = ijmn) -!-------------------------------------------------------------------------------------------------- -pure function math_mul3333xx3333(A,B) - - implicit none - integer(pInt) :: i,j,k,l - real(pReal), dimension(3,3,3,3), intent(in) :: A - real(pReal), dimension(3,3,3,3), intent(in) :: B - real(pReal), dimension(3,3,3,3) :: math_mul3333xx3333 - - forall(i = 1_pInt:3_pInt,j = 1_pInt:3_pInt, k = 1_pInt:3_pInt, l= 1_pInt:3_pInt) & - math_mul3333xx3333(i,j,k,l) = sum(A(i,j,1:3,1:3)*B(1:3,1:3,k,l)) - -end function math_mul3333xx3333 - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication 33x33 = 33 -!-------------------------------------------------------------------------------------------------- -pure function math_mul33x33(A,B) - - implicit none - real(pReal), dimension(3,3) :: math_mul33x33 - real(pReal), dimension(3,3), intent(in) :: A,B - integer(pInt) :: i,j - - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) & - math_mul33x33(i,j) = A(i,1)*B(1,j) + A(i,2)*B(2,j) + A(i,3)*B(3,j) - -end function math_mul33x33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication 66x66 = 66 -!-------------------------------------------------------------------------------------------------- -pure function math_mul66x66(A,B) - - implicit none - real(pReal), dimension(6,6) :: math_mul66x66 - real(pReal), dimension(6,6), intent(in) :: A,B - integer(pInt) :: i,j - - forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) math_mul66x66(i,j) = & - A(i,1)*B(1,j) + A(i,2)*B(2,j) + A(i,3)*B(3,j) + & - A(i,4)*B(4,j) + A(i,5)*B(5,j) + A(i,6)*B(6,j) - -end function math_mul66x66 - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication 99x99 = 99 -!-------------------------------------------------------------------------------------------------- -pure function math_mul99x99(A,B) - - implicit none - real(pReal), dimension(9,9) :: math_mul99x99 - real(pReal), dimension(9,9), intent(in) :: A,B - integer(pInt) i,j - - forall (i=1_pInt:9_pInt,j=1_pInt:9_pInt) math_mul99x99(i,j) = & - A(i,1)*B(1,j) + A(i,2)*B(2,j) + A(i,3)*B(3,j) + & - A(i,4)*B(4,j) + A(i,5)*B(5,j) + A(i,6)*B(6,j) + & - A(i,7)*B(7,j) + A(i,8)*B(8,j) + A(i,9)*B(9,j) - -end function math_mul99x99 - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication 33x3 = 3 -!-------------------------------------------------------------------------------------------------- -pure function math_mul33x3(A,B) - - implicit none - real(pReal), dimension(3) :: math_mul33x3 - real(pReal), dimension(3,3), intent(in) :: A - real(pReal), dimension(3), intent(in) :: B - integer(pInt) :: i - - forall (i=1_pInt:3_pInt) math_mul33x3(i) = sum(A(i,1:3)*B) - -end function math_mul33x3 - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication complex(33) x real(3) = complex(3) -!-------------------------------------------------------------------------------------------------- -pure function math_mul33x3_complex(A,B) - - implicit none - complex(pReal), dimension(3) :: math_mul33x3_complex - complex(pReal), dimension(3,3), intent(in) :: A - real(pReal), dimension(3), intent(in) :: B - integer(pInt) :: i - - forall (i=1_pInt:3_pInt) math_mul33x3_complex(i) = sum(A(i,1:3)*cmplx(B,0.0_pReal,pReal)) - -end function math_mul33x3_complex - - -!-------------------------------------------------------------------------------------------------- -!> @brief matrix multiplication 66x6 = 6 -!-------------------------------------------------------------------------------------------------- -pure function math_mul66x6(A,B) - - implicit none - real(pReal), dimension(6) :: math_mul66x6 - real(pReal), dimension(6,6), intent(in) :: A - real(pReal), dimension(6), intent(in) :: B - integer(pInt) :: i - - forall (i=1_pInt:6_pInt) math_mul66x6(i) = & - A(i,1)*B(1) + A(i,2)*B(2) + A(i,3)*B(3) + & - A(i,4)*B(4) + A(i,5)*B(5) + A(i,6)*B(6) - -end function math_mul66x6 - - -!-------------------------------------------------------------------------------------------------- -!> @brief 3x3 matrix exponential up to series approximation order n (default 5) -!-------------------------------------------------------------------------------------------------- -pure function math_exp33(A,n) - - implicit none - integer(pInt) :: i,order - integer(pInt), intent(in), optional :: n - real(pReal), dimension(3,3), intent(in) :: A - real(pReal), dimension(3,3) :: B,math_exp33 - real(pReal) :: invfac - - order = merge(n,5_pInt,present(n)) - - B = math_I3 ! init - invfac = 1.0_pReal ! 0! - math_exp33 = B ! A^0 = eye2 - - do i = 1_pInt,n - invfac = invfac/real(i) ! invfac = 1/i! - B = math_mul33x33(B,A) - math_exp33 = math_exp33 + invfac*B ! exp = SUM (A^i)/i! - enddo - -end function math_exp33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief transposition of a 33 matrix -!-------------------------------------------------------------------------------------------------- -pure function math_transpose33(A) - - implicit none - real(pReal),dimension(3,3) :: math_transpose33 - real(pReal),dimension(3,3),intent(in) :: A - integer(pInt) :: i,j - - forall(i=1_pInt:3_pInt, j=1_pInt:3_pInt) math_transpose33(i,j) = A(j,i) - -end function math_transpose33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief Cramer inversion of 33 matrix (function) -! direct Cramer inversion of matrix A. -! returns all zeroes if not possible, i.e. if det close to zero -!-------------------------------------------------------------------------------------------------- -pure function math_inv33(A) - - implicit none - real(pReal),dimension(3,3),intent(in) :: A - real(pReal) :: DetA - real(pReal),dimension(3,3) :: math_inv33 - - math_inv33(1,1) = A(2,2) * A(3,3) - A(2,3) * A(3,2) - math_inv33(2,1) = -A(2,1) * A(3,3) + A(2,3) * A(3,1) - math_inv33(3,1) = A(2,1) * A(3,2) - A(2,2) * A(3,1) - - DetA = A(1,1) * math_inv33(1,1) + A(1,2) * math_inv33(2,1) + A(1,3) * math_inv33(3,1) - - if (abs(DetA) > tiny(DetA)) then ! use a real threshold here - math_inv33(1,2) = -A(1,2) * A(3,3) + A(1,3) * A(3,2) - math_inv33(2,2) = A(1,1) * A(3,3) - A(1,3) * A(3,1) - math_inv33(3,2) = -A(1,1) * A(3,2) + A(1,2) * A(3,1) - - math_inv33(1,3) = A(1,2) * A(2,3) - A(1,3) * A(2,2) - math_inv33(2,3) = -A(1,1) * A(2,3) + A(1,3) * A(2,1) - math_inv33(3,3) = A(1,1) * A(2,2) - A(1,2) * A(2,1) - - math_inv33 = math_inv33/DetA - else - math_inv33 = 0.0_pReal - endif - -end function math_inv33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief Cramer inversion of 33 matrix (subroutine) -! direct Cramer inversion of matrix A. -! also returns determinant -! returns error if not possible, i.e. if det close to zero -!-------------------------------------------------------------------------------------------------- -pure subroutine math_invert33(A, InvA, DetA, error) - - implicit none - logical, intent(out) :: error - real(pReal),dimension(3,3),intent(in) :: A - real(pReal),dimension(3,3),intent(out) :: InvA - real(pReal), intent(out) :: DetA - - InvA(1,1) = A(2,2) * A(3,3) - A(2,3) * A(3,2) - InvA(2,1) = -A(2,1) * A(3,3) + A(2,3) * A(3,1) - InvA(3,1) = A(2,1) * A(3,2) - A(2,2) * A(3,1) - - DetA = A(1,1) * InvA(1,1) + A(1,2) * InvA(2,1) + A(1,3) * InvA(3,1) - - if (abs(DetA) <= tiny(DetA)) then - error = .true. - else - InvA(1,2) = -A(1,2) * A(3,3) + A(1,3) * A(3,2) - InvA(2,2) = A(1,1) * A(3,3) - A(1,3) * A(3,1) - InvA(3,2) = -A(1,1) * A(3,2) + A(1,2) * A(3,1) - - InvA(1,3) = A(1,2) * A(2,3) - A(1,3) * A(2,2) - InvA(2,3) = -A(1,1) * A(2,3) + A(1,3) * A(2,1) - InvA(3,3) = A(1,1) * A(2,2) - A(1,2) * A(2,1) - - InvA = InvA/DetA - error = .false. - endif - -end subroutine math_invert33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief Inversion of symmetriced 3x3x3x3 tensor. -!-------------------------------------------------------------------------------------------------- -function math_invSym3333(A) - use IO, only: & - IO_error - - implicit none - real(pReal),dimension(3,3,3,3) :: math_invSym3333 - - real(pReal),dimension(3,3,3,3),intent(in) :: A - - integer(pInt) :: ierr - integer(pInt), dimension(6) :: ipiv6 - real(pReal), dimension(6,6) :: temp66_Real - real(pReal), dimension(6) :: work6 - - temp66_real = math_Mandel3333to66(A) -#if(FLOAT==8) - call dgetrf(6,6,temp66_real,6,ipiv6,ierr) - call dgetri(6,temp66_real,6,ipiv6,work6,6,ierr) -#elif(FLOAT==4) - call sgetrf(6,6,temp66_real,6,ipiv6,ierr) - call sgetri(6,temp66_real,6,ipiv6,work6,6,ierr) -#endif - if (ierr == 0_pInt) then - math_invSym3333 = math_Mandel66to3333(temp66_real) - else - call IO_error(400_pInt, ext_msg = 'math_invSym3333') - endif - -end function math_invSym3333 - - -!-------------------------------------------------------------------------------------------------- -!> @brief invert matrix of arbitrary dimension -!-------------------------------------------------------------------------------------------------- -subroutine math_invert(myDim,A, InvA, error) - - implicit none - integer(pInt), intent(in) :: myDim - real(pReal), dimension(myDim,myDim), intent(in) :: A - - - integer(pInt) :: ierr - integer(pInt), dimension(myDim) :: ipiv - real(pReal), dimension(myDim) :: work - - real(pReal), dimension(myDim,myDim), intent(out) :: invA - logical, intent(out) :: error - - invA = A -#if(FLOAT==8) - call dgetrf(myDim,myDim,invA,myDim,ipiv,ierr) - call dgetri(myDim,InvA,myDim,ipiv,work,myDim,ierr) -#elif(FLOAT==4) - call sgetrf(myDim,myDim,invA,myDim,ipiv,ierr) - call sgetri(myDim,InvA,myDim,ipiv,work,myDim,ierr) -#endif - error = merge(.true.,.false., ierr /= 0_pInt) ! http://fortraninacworld.blogspot.de/2012/12/ternary-operator.html - -end subroutine math_invert - - -!-------------------------------------------------------------------------------------------------- -!> @brief symmetrize a 33 matrix -!-------------------------------------------------------------------------------------------------- -pure function math_symmetric33(m) - - implicit none - real(pReal), dimension(3,3) :: math_symmetric33 - real(pReal), dimension(3,3), intent(in) :: m - - math_symmetric33 = 0.5_pReal * (m + transpose(m)) - -end function math_symmetric33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief symmetrize a 66 matrix -!-------------------------------------------------------------------------------------------------- -pure function math_symmetric66(m) - - implicit none - real(pReal), dimension(6,6) :: math_symmetric66 - real(pReal), dimension(6,6), intent(in) :: m - - math_symmetric66 = 0.5_pReal * (m + transpose(m)) - -end function math_symmetric66 - - -!-------------------------------------------------------------------------------------------------- -!> @brief skew part of a 33 matrix -!-------------------------------------------------------------------------------------------------- -pure function math_skew33(m) - - implicit none - real(pReal), dimension(3,3) :: math_skew33 - real(pReal), dimension(3,3), intent(in) :: m - - math_skew33 = m - math_symmetric33(m) - -end function math_skew33 - -!-------------------------------------------------------------------------------------------------- -!> @brief hydrostatic part of a 33 matrix -!-------------------------------------------------------------------------------------------------- -pure function math_spherical33(m) - - implicit none - real(pReal), dimension(3,3) :: math_spherical33 - real(pReal), dimension(3,3), intent(in) :: m - - math_spherical33 = math_I3 * math_trace33(m)/3.0_pReal - -end function math_spherical33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief deviatoric part of a 33 matrix -!-------------------------------------------------------------------------------------------------- -pure function math_deviatoric33(m) - - implicit none - real(pReal), dimension(3,3) :: math_deviatoric33 - real(pReal), dimension(3,3), intent(in) :: m - - math_deviatoric33 = m - math_spherical33(m) - -end function math_deviatoric33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief equivalent scalar quantity of a full symmetric strain tensor -!-------------------------------------------------------------------------------------------------- -pure function math_equivStrain33(m) - - implicit none - real(pReal), dimension(3,3), intent(in) :: m - real(pReal), dimension(3) :: e,s - real(pReal) :: math_equivStrain33 - real(pReal), parameter :: TWOTHIRD = 2.0_pReal/3.0_pReal - - e = [2.0_pReal*m(1,1)-m(2,2)-m(3,3), & - 2.0_pReal*m(2,2)-m(3,3)-m(1,1), & - 2.0_pReal*m(3,3)-m(1,1)-m(2,2)]/3.0_pReal - s = [m(1,2),m(2,3),m(1,3)]*2.0_pReal - - math_equivStrain33 = TWOTHIRD*(1.50_pReal*(sum(e**2.0_pReal)) + & - 0.75_pReal*(sum(s**2.0_pReal)))**(0.5_pReal) - -end function math_equivStrain33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief von Mises equivalent of a full symmetric stress tensor -!-------------------------------------------------------------------------------------------------- -pure function math_equivStress33(m) - - implicit none - real(pReal), dimension(3,3), intent(in) :: m - real(pReal) :: math_equivStress33 - - math_equivStress33 =( ( (m(1,1)-m(2,2))**2.0_pReal + & - (m(2,2)-m(3,3))**2.0_pReal + & - (m(3,3)-m(1,1))**2.0_pReal + & - 6.0_pReal*( m(1,2)**2.0_pReal + & - m(2,3)**2.0_pReal + & - m(1,3)**2.0_pReal & - ) & - )**0.5_pReal & - )/sqrt(2.0_pReal) - -end function math_equivStress33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief trace of a 33 matrix -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_trace33(m) - - implicit none - real(pReal), dimension(3,3), intent(in) :: m - - math_trace33 = m(1,1) + m(2,2) + m(3,3) - -end function math_trace33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief determinant of a 33 matrix -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_det33(m) - - implicit none - real(pReal), dimension(3,3), intent(in) :: m - - math_det33 = m(1,1)* (m(2,2)*m(3,3)-m(2,3)*m(3,2)) & - - m(1,2)* (m(2,1)*m(3,3)-m(2,3)*m(3,1)) & - + m(1,3)* (m(2,1)*m(3,2)-m(2,2)*m(3,1)) - -end function math_det33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief determinant of a symmetric 33 matrix -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_detSym33(m) - - implicit none - real(pReal), dimension(3,3), intent(in) :: m - - math_detSym33 = -(m(1,1)*m(2,3)**2_pInt + m(2,2)*m(1,3)**2_pInt + m(3,3)*m(1,2)**2_pInt) & - + m(1,1)*m(2,2)*m(3,3) - 2.0_pReal * m(1,2)*m(1,3)*m(2,3) - -end function math_detSym33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief convert 33 matrix into vector 9 -!-------------------------------------------------------------------------------------------------- -pure function math_Plain33to9(m33) - - implicit none - real(pReal), dimension(9) :: math_Plain33to9 - real(pReal), dimension(3,3), intent(in) :: m33 - integer(pInt) :: i - - forall (i=1_pInt:9_pInt) math_Plain33to9(i) = m33(mapPlain(1,i),mapPlain(2,i)) - -end function math_Plain33to9 - - -!-------------------------------------------------------------------------------------------------- -!> @brief convert Plain 9 back to 33 matrix -!-------------------------------------------------------------------------------------------------- -pure function math_Plain9to33(v9) - - implicit none - real(pReal), dimension(3,3) :: math_Plain9to33 - real(pReal), dimension(9), intent(in) :: v9 - integer(pInt) :: i - - forall (i=1_pInt:9_pInt) math_Plain9to33(mapPlain(1,i),mapPlain(2,i)) = v9(i) - -end function math_Plain9to33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief convert symmetric 33 matrix into Mandel vector 6 -!-------------------------------------------------------------------------------------------------- -pure function math_Mandel33to6(m33) - - implicit none - real(pReal), dimension(6) :: math_Mandel33to6 - real(pReal), dimension(3,3), intent(in) :: m33 - - integer(pInt) :: i - - forall (i=1_pInt:6_pInt) math_Mandel33to6(i) = nrmMandel(i)*m33(mapMandel(1,i),mapMandel(2,i)) - -end function math_Mandel33to6 - - -!-------------------------------------------------------------------------------------------------- -!> @brief convert Mandel 6 back to symmetric 33 matrix -!-------------------------------------------------------------------------------------------------- -pure function math_Mandel6to33(v6) - - implicit none - real(pReal), dimension(6), intent(in) :: v6 - real(pReal), dimension(3,3) :: math_Mandel6to33 - integer(pInt) :: i - - forall (i=1_pInt:6_pInt) - math_Mandel6to33(mapMandel(1,i),mapMandel(2,i)) = invnrmMandel(i)*v6(i) - math_Mandel6to33(mapMandel(2,i),mapMandel(1,i)) = invnrmMandel(i)*v6(i) - end forall - -end function math_Mandel6to33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief convert 3333 tensor into plain matrix 99 -!-------------------------------------------------------------------------------------------------- -pure function math_Plain3333to99(m3333) - - implicit none - real(pReal), dimension(3,3,3,3), intent(in) :: m3333 - real(pReal), dimension(9,9) :: math_Plain3333to99 - integer(pInt) :: i,j - - forall (i=1_pInt:9_pInt,j=1_pInt:9_pInt) math_Plain3333to99(i,j) = & - m3333(mapPlain(1,i),mapPlain(2,i),mapPlain(1,j),mapPlain(2,j)) - -end function math_Plain3333to99 - -!-------------------------------------------------------------------------------------------------- -!> @brief plain matrix 99 into 3333 tensor -!-------------------------------------------------------------------------------------------------- -pure function math_Plain99to3333(m99) - - implicit none - real(pReal), dimension(9,9), intent(in) :: m99 - real(pReal), dimension(3,3,3,3) :: math_Plain99to3333 - integer(pInt) :: i,j - - forall (i=1_pInt:9_pInt,j=1_pInt:9_pInt) math_Plain99to3333(mapPlain(1,i),mapPlain(2,i),& - mapPlain(1,j),mapPlain(2,j)) = m99(i,j) - -end function math_Plain99to3333 - - -!-------------------------------------------------------------------------------------------------- -!> @brief convert Mandel matrix 66 into Plain matrix 66 -!-------------------------------------------------------------------------------------------------- -pure function math_Mandel66toPlain66(m66) - - implicit none - real(pReal), dimension(6,6), intent(in) :: m66 - real(pReal), dimension(6,6) :: math_Mandel66toPlain66 - integer(pInt) :: i,j - - forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) & - math_Mandel66toPlain66(i,j) = invnrmMandel(i) * invnrmMandel(j) * m66(i,j) - -end function math_Mandel66toPlain66 - - -!-------------------------------------------------------------------------------------------------- -!> @brief convert Plain matrix 66 into Mandel matrix 66 -!-------------------------------------------------------------------------------------------------- -pure function math_Plain66toMandel66(m66) - - implicit none - real(pReal), dimension(6,6), intent(in) :: m66 - real(pReal), dimension(6,6) :: math_Plain66toMandel66 - integer(pInt) :: i,j - - forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) & - math_Plain66toMandel66(i,j) = nrmMandel(i) * nrmMandel(j) * m66(i,j) - -end function math_Plain66toMandel66 - - -!-------------------------------------------------------------------------------------------------- -!> @brief convert symmetric 3333 tensor into Mandel matrix 66 -!-------------------------------------------------------------------------------------------------- -pure function math_Mandel3333to66(m3333) - - implicit none - - real(pReal), dimension(3,3,3,3), intent(in) :: m3333 - real(pReal), dimension(6,6) :: math_Mandel3333to66 - integer(pInt) :: i,j - - forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) math_Mandel3333to66(i,j) = & - nrmMandel(i)*nrmMandel(j)*m3333(mapMandel(1,i),mapMandel(2,i),mapMandel(1,j),mapMandel(2,j)) - -end function math_Mandel3333to66 - - -!-------------------------------------------------------------------------------------------------- -!> @brief convert Mandel matrix 66 back to symmetric 3333 tensor -!-------------------------------------------------------------------------------------------------- -pure function math_Mandel66to3333(m66) - - implicit none - real(pReal), dimension(3,3,3,3) :: math_Mandel66to3333 - real(pReal), dimension(6,6), intent(in) :: m66 - integer(pInt) :: i,j - - forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) - math_Mandel66to3333(mapMandel(1,i),mapMandel(2,i),mapMandel(1,j),mapMandel(2,j)) = & - invnrmMandel(i)*invnrmMandel(j)*m66(i,j) - math_Mandel66to3333(mapMandel(2,i),mapMandel(1,i),mapMandel(1,j),mapMandel(2,j)) = & - invnrmMandel(i)*invnrmMandel(j)*m66(i,j) - math_Mandel66to3333(mapMandel(1,i),mapMandel(2,i),mapMandel(2,j),mapMandel(1,j)) = & - invnrmMandel(i)*invnrmMandel(j)*m66(i,j) - math_Mandel66to3333(mapMandel(2,i),mapMandel(1,i),mapMandel(2,j),mapMandel(1,j)) = & - invnrmMandel(i)*invnrmMandel(j)*m66(i,j) - end forall - -end function math_Mandel66to3333 - - -!-------------------------------------------------------------------------------------------------- -!> @brief convert Voigt matrix 66 back to symmetric 3333 tensor -!-------------------------------------------------------------------------------------------------- -pure function math_Voigt66to3333(m66) - - implicit none - real(pReal), dimension(3,3,3,3) :: math_Voigt66to3333 - real(pReal), dimension(6,6), intent(in) :: m66 - integer(pInt) :: i,j - - forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) - math_Voigt66to3333(mapVoigt(1,i),mapVoigt(2,i),mapVoigt(1,j),mapVoigt(2,j)) = & - invnrmVoigt(i)*invnrmVoigt(j)*m66(i,j) - math_Voigt66to3333(mapVoigt(2,i),mapVoigt(1,i),mapVoigt(1,j),mapVoigt(2,j)) = & - invnrmVoigt(i)*invnrmVoigt(j)*m66(i,j) - math_Voigt66to3333(mapVoigt(1,i),mapVoigt(2,i),mapVoigt(2,j),mapVoigt(1,j)) = & - invnrmVoigt(i)*invnrmVoigt(j)*m66(i,j) - math_Voigt66to3333(mapVoigt(2,i),mapVoigt(1,i),mapVoigt(2,j),mapVoigt(1,j)) = & - invnrmVoigt(i)*invnrmVoigt(j)*m66(i,j) - end forall - -end function math_Voigt66to3333 - - -!-------------------------------------------------------------------------------------------------- -!> @brief random quaternion -!-------------------------------------------------------------------------------------------------- -function math_qRand() - - implicit none - real(pReal), dimension(4) :: math_qRand - real(pReal), dimension(3) :: rnd - - call halton(3_pInt,rnd) - math_qRand(1) = cos(2.0_pReal*PI*rnd(1))*sqrt(rnd(3)) - math_qRand(2) = sin(2.0_pReal*PI*rnd(2))*sqrt(1.0_pReal-rnd(3)) - math_qRand(3) = cos(2.0_pReal*PI*rnd(2))*sqrt(1.0_pReal-rnd(3)) - math_qRand(4) = sin(2.0_pReal*PI*rnd(1))*sqrt(rnd(3)) - -end function math_qRand - - -!-------------------------------------------------------------------------------------------------- -!> @brief quaternion multiplication q1xq2 = q12 -!-------------------------------------------------------------------------------------------------- -pure function math_qMul(A,B) - - implicit none - real(pReal), dimension(4) :: math_qMul - real(pReal), dimension(4), intent(in) :: A, B - - math_qMul = [ A(1)*B(1) - A(2)*B(2) - A(3)*B(3) - A(4)*B(4), & - A(1)*B(2) + A(2)*B(1) + A(3)*B(4) - A(4)*B(3), & - A(1)*B(3) - A(2)*B(4) + A(3)*B(1) + A(4)*B(2), & - A(1)*B(4) + A(2)*B(3) - A(3)*B(2) + A(4)*B(1) ] - -end function math_qMul - - -!-------------------------------------------------------------------------------------------------- -!> @brief quaternion dotproduct -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_qDot(A,B) - - implicit none - real(pReal), dimension(4), intent(in) :: A, B - - math_qDot = sum(A*B) - -end function math_qDot - - -!-------------------------------------------------------------------------------------------------- -!> @brief quaternion conjugation -!-------------------------------------------------------------------------------------------------- -pure function math_qConj(Q) - - implicit none - real(pReal), dimension(4) :: math_qConj - real(pReal), dimension(4), intent(in) :: Q - - math_qConj = [Q(1), -Q(2:4)] - -end function math_qConj - - -!-------------------------------------------------------------------------------------------------- -!> @brief quaternion norm -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_qNorm(Q) - - implicit none - real(pReal), dimension(4), intent(in) :: Q - - math_qNorm = norm2(Q) - -end function math_qNorm - - -!-------------------------------------------------------------------------------------------------- -!> @brief quaternion inversion -!-------------------------------------------------------------------------------------------------- -pure function math_qInv(Q) - - implicit none - real(pReal), dimension(4), intent(in) :: Q - real(pReal), dimension(4) :: math_qInv - real(pReal) :: squareNorm - - math_qInv = 0.0_pReal - - squareNorm = math_qDot(Q,Q) - if (abs(squareNorm) > tiny(squareNorm)) & - math_qInv = math_qConj(Q) / squareNorm - -end function math_qInv - - -!-------------------------------------------------------------------------------------------------- -!> @brief action of a quaternion on a vector (rotate vector v with Q) -!-------------------------------------------------------------------------------------------------- -pure function math_qRot(Q,v) - - implicit none - real(pReal), dimension(4), intent(in) :: Q - real(pReal), dimension(3), intent(in) :: v - real(pReal), dimension(3) :: math_qRot - real(pReal), dimension(4,4) :: T - integer(pInt) :: i, j - - do i = 1_pInt,4_pInt - do j = 1_pInt,i - T(i,j) = Q(i) * Q(j) - enddo - enddo - - math_qRot = [-v(1)*(T(3,3)+T(4,4)) + v(2)*(T(3,2)-T(4,1)) + v(3)*(T(4,2)+T(3,1)), & - v(1)*(T(3,2)+T(4,1)) - v(2)*(T(2,2)+T(4,4)) + v(3)*(T(4,3)-T(2,1)), & - v(1)*(T(4,2)-T(3,1)) + v(2)*(T(4,3)+T(2,1)) - v(3)*(T(2,2)+T(3,3))] - - math_qRot = 2.0_pReal * math_qRot + v - -end function math_qRot - - -!-------------------------------------------------------------------------------------------------- -!> @brief Euler angles (in radians) from rotation matrix -!> @details rotation matrix is meant to represent a PASSIVE rotation, -!> composed of INTRINSIC rotations around the axes of the -!> rotating reference frame -!> (see http://en.wikipedia.org/wiki/Euler_angles for definitions) -!-------------------------------------------------------------------------------------------------- -pure function math_RtoEuler(R) - - implicit none - real(pReal), dimension (3,3), intent(in) :: R - real(pReal), dimension(3) :: math_RtoEuler - real(pReal) :: sqhkl, squvw, sqhk - - sqhkl=sqrt(R(1,3)*R(1,3)+R(2,3)*R(2,3)+R(3,3)*R(3,3)) - squvw=sqrt(R(1,1)*R(1,1)+R(2,1)*R(2,1)+R(3,1)*R(3,1)) - sqhk =sqrt(R(1,3)*R(1,3)+R(2,3)*R(2,3)) - -! calculate PHI - math_RtoEuler(2) = acos(math_limit(R(3,3)/sqhkl,-1.0_pReal, 1.0_pReal)) - - if((math_RtoEuler(2) < 1.0e-8_pReal) .or. (pi-math_RtoEuler(2) < 1.0e-8_pReal)) then - math_RtoEuler(3) = 0.0_pReal - math_RtoEuler(1) = acos(math_limit(R(1,1)/squvw, -1.0_pReal, 1.0_pReal)) - if(R(2,1) > 0.0_pReal) math_RtoEuler(1) = 2.0_pReal*pi-math_RtoEuler(1) - else - math_RtoEuler(3) = acos(math_limit(R(2,3)/sqhk, -1.0_pReal, 1.0_pReal)) - if(R(1,3) < 0.0) math_RtoEuler(3) = 2.0_pReal*pi-math_RtoEuler(3) - math_RtoEuler(1) = acos(math_limit(-R(3,2)/sin(math_RtoEuler(2)), -1.0_pReal, 1.0_pReal)) - if(R(3,1) < 0.0) math_RtoEuler(1) = 2.0_pReal*pi-math_RtoEuler(1) - end if - -end function math_RtoEuler - - -!-------------------------------------------------------------------------------------------------- -!> @brief converts a rotation matrix into a quaternion (w+ix+jy+kz) -!> @details math adopted from http://arxiv.org/pdf/math/0701759v1.pdf -!-------------------------------------------------------------------------------------------------- -pure function math_RtoQ(R) - - implicit none - real(pReal), dimension(3,3), intent(in) :: R - real(pReal), dimension(4) :: absQ, math_RtoQ - real(pReal) :: max_absQ - integer, dimension(1) :: largest !no pInt, maxloc returns integer default - - math_RtoQ = 0.0_pReal - - absQ = [+ R(1,1) + R(2,2) + R(3,3), & - + R(1,1) - R(2,2) - R(3,3), & - - R(1,1) + R(2,2) - R(3,3), & - - R(1,1) - R(2,2) + R(3,3)] + 1.0_pReal - - largest = maxloc(absQ) - - largestComponent: select case(largest(1)) - case (1) largestComponent - !1---------------------------------- - math_RtoQ(2) = R(3,2) - R(2,3) - math_RtoQ(3) = R(1,3) - R(3,1) - math_RtoQ(4) = R(2,1) - R(1,2) - - case (2) largestComponent - math_RtoQ(1) = R(3,2) - R(2,3) - !2---------------------------------- - math_RtoQ(3) = R(2,1) + R(1,2) - math_RtoQ(4) = R(1,3) + R(3,1) - - case (3) largestComponent - math_RtoQ(1) = R(1,3) - R(3,1) - math_RtoQ(2) = R(2,1) + R(1,2) - !3---------------------------------- - math_RtoQ(4) = R(3,2) + R(2,3) - - case (4) largestComponent - math_RtoQ(1) = R(2,1) - R(1,2) - math_RtoQ(2) = R(1,3) + R(3,1) - math_RtoQ(3) = R(2,3) + R(3,2) - !4---------------------------------- - end select largestComponent - - max_absQ = 0.5_pReal * sqrt(absQ(largest(1))) - math_RtoQ = math_RtoQ * 0.25_pReal / max_absQ - math_RtoQ(largest(1)) = max_absQ - -end function math_RtoQ - - -!-------------------------------------------------------------------------------------------------- -!> @brief rotation matrix from Euler angles (in radians) -!> @details rotation matrix is meant to represent a PASSIVE rotation, -!> @details composed of INTRINSIC rotations around the axes of the -!> @details rotating reference frame -!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) -!-------------------------------------------------------------------------------------------------- -pure function math_EulerToR(Euler) - - implicit none - real(pReal), dimension(3), intent(in) :: Euler - real(pReal), dimension(3,3) :: math_EulerToR - real(pReal) c1, c, c2, s1, s, s2 - - C1 = cos(Euler(1)) - C = cos(Euler(2)) - C2 = cos(Euler(3)) - S1 = sin(Euler(1)) - S = sin(Euler(2)) - S2 = sin(Euler(3)) - - math_EulerToR(1,1)=C1*C2-S1*S2*C - math_EulerToR(1,2)=-C1*S2-S1*C2*C - math_EulerToR(1,3)=S1*S - math_EulerToR(2,1)=S1*C2+C1*S2*C - math_EulerToR(2,2)=-S1*S2+C1*C2*C - math_EulerToR(2,3)=-C1*S - math_EulerToR(3,1)=S2*S - math_EulerToR(3,2)=C2*S - math_EulerToR(3,3)=C - - math_EulerToR = transpose(math_EulerToR) ! convert to passive rotation - -end function math_EulerToR - - -!-------------------------------------------------------------------------------------------------- -!> @brief quaternion (w+ix+jy+kz) from 3-1-3 Euler angles (in radians) -!> @details quaternion is meant to represent a PASSIVE rotation, -!> @details composed of INTRINSIC rotations around the axes of the -!> @details rotating reference frame -!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) -!-------------------------------------------------------------------------------------------------- -pure function math_EulerToQ(eulerangles) - - implicit none - real(pReal), dimension(3), intent(in) :: eulerangles - real(pReal), dimension(4) :: math_EulerToQ - real(pReal), dimension(3) :: halfangles - real(pReal) :: c, s - - halfangles = 0.5_pReal * eulerangles - - c = cos(halfangles(2)) - s = sin(halfangles(2)) - - math_EulerToQ= [cos(halfangles(1)+halfangles(3)) * c, & - cos(halfangles(1)-halfangles(3)) * s, & - sin(halfangles(1)-halfangles(3)) * s, & - sin(halfangles(1)+halfangles(3)) * c ] - math_EulerToQ = math_qConj(math_EulerToQ) ! convert to passive rotation - -end function math_EulerToQ - - -!-------------------------------------------------------------------------------------------------- -!> @brief rotation matrix from axis and angle (in radians) -!> @details rotation matrix is meant to represent a ACTIVE rotation -!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) -!> @details formula for active rotation taken from http://mathworld.wolfram.com/RodriguesRotationFormula.html -!-------------------------------------------------------------------------------------------------- -pure function math_axisAngleToR(axis,omega) - - implicit none - real(pReal), dimension(3,3) :: math_axisAngleToR - real(pReal), dimension(3), intent(in) :: axis - real(pReal), intent(in) :: omega - real(pReal), dimension(3) :: axisNrm - real(pReal) :: norm,s,c,c1 - - norm = sqrt(math_mul3x3(axis,axis)) - if (norm > 1.0e-8_pReal) then ! non-zero rotation - axisNrm = axis/norm ! normalize axis to be sure - - s = sin(omega) - c = cos(omega) - c1 = 1.0_pReal - c - - math_axisAngleToR(1,1) = c + c1*axisNrm(1)**2.0_pReal - math_axisAngleToR(1,2) = -s*axisNrm(3) + c1*axisNrm(1)*axisNrm(2) - math_axisAngleToR(1,3) = s*axisNrm(2) + c1*axisNrm(1)*axisNrm(3) - - math_axisAngleToR(2,1) = s*axisNrm(3) + c1*axisNrm(2)*axisNrm(1) - math_axisAngleToR(2,2) = c + c1*axisNrm(2)**2.0_pReal - math_axisAngleToR(2,3) = -s*axisNrm(1) + c1*axisNrm(2)*axisNrm(3) - - math_axisAngleToR(3,1) = -s*axisNrm(2) + c1*axisNrm(3)*axisNrm(1) - math_axisAngleToR(3,2) = s*axisNrm(1) + c1*axisNrm(3)*axisNrm(2) - math_axisAngleToR(3,3) = c + c1*axisNrm(3)**2.0_pReal - else - math_axisAngleToR = math_I3 - endif - -end function math_axisAngleToR - - -!-------------------------------------------------------------------------------------------------- -!> @brief rotation matrix from axis and angle (in radians) -!> @details rotation matrix is meant to represent a PASSIVE rotation -!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) -!-------------------------------------------------------------------------------------------------- -pure function math_EulerAxisAngleToR(axis,omega) - - implicit none - real(pReal), dimension(3,3) :: math_EulerAxisAngleToR - real(pReal), dimension(3), intent(in) :: axis - real(pReal), intent(in) :: omega - - math_EulerAxisAngleToR = transpose(math_axisAngleToR(axis,omega)) ! convert to passive rotation - -end function math_EulerAxisAngleToR - - -!-------------------------------------------------------------------------------------------------- -!> @brief quaternion (w+ix+jy+kz) from Euler axis and angle (in radians) -!> @details quaternion is meant to represent a PASSIVE rotation -!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) -!> @details formula for active rotation taken from -!> @details http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29#Rodrigues_parameters -!-------------------------------------------------------------------------------------------------- -pure function math_EulerAxisAngleToQ(axis,omega) - - implicit none - real(pReal), dimension(4) :: math_EulerAxisAngleToQ - real(pReal), dimension(3), intent(in) :: axis - real(pReal), intent(in) :: omega - - math_EulerAxisAngleToQ = math_qConj(math_axisAngleToQ(axis,omega)) ! convert to passive rotation - -end function math_EulerAxisAngleToQ - - -!-------------------------------------------------------------------------------------------------- -!> @brief quaternion (w+ix+jy+kz) from axis and angle (in radians) -!> @details quaternion is meant to represent an ACTIVE rotation -!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) -!> @details formula for active rotation taken from -!> @details http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29#Rodrigues_parameters -!-------------------------------------------------------------------------------------------------- -pure function math_axisAngleToQ(axis,omega) - - implicit none - real(pReal), dimension(4) :: math_axisAngleToQ - real(pReal), dimension(3), intent(in) :: axis - real(pReal), intent(in) :: omega - real(pReal), dimension(3) :: axisNrm - real(pReal) :: norm - - norm = sqrt(math_mul3x3(axis,axis)) - rotation: if (norm > 1.0e-8_pReal) then - axisNrm = axis/norm ! normalize axis to be sure - math_axisAngleToQ = [cos(0.5_pReal*omega), sin(0.5_pReal*omega) * axisNrm(1:3)] - else rotation - math_axisAngleToQ = [1.0_pReal,0.0_pReal,0.0_pReal,0.0_pReal] - endif rotation - -end function math_axisAngleToQ - - -!-------------------------------------------------------------------------------------------------- -!> @brief orientation matrix from quaternion (w+ix+jy+kz) -!> @details taken from http://arxiv.org/pdf/math/0701759v1.pdf -!> @details see also http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions -!-------------------------------------------------------------------------------------------------- -pure function math_qToR(q) - - implicit none - real(pReal), dimension(4), intent(in) :: q - real(pReal), dimension(3,3) :: math_qToR, T,S - integer(pInt) :: i, j - - forall (i = 1_pInt:3_pInt, j = 1_pInt:3_pInt) & - T(i,j) = q(i+1_pInt) * q(j+1_pInt) - - S = reshape( [0.0_pReal, -q(4), q(3), & - q(4), 0.0_pReal, -q(2), & - -q(3), q(2), 0.0_pReal],[3,3]) ! notation is transposed - - math_qToR = (2.0_pReal * q(1)*q(1) - 1.0_pReal) * math_I3 & - + 2.0_pReal * T - 2.0_pReal * q(1) * S - -end function math_qToR - - -!-------------------------------------------------------------------------------------------------- -!> @brief 3-1-3 Euler angles (in radians) from quaternion (w+ix+jy+kz) -!> @details quaternion is meant to represent a PASSIVE rotation, -!> @details composed of INTRINSIC rotations around the axes of the -!> @details rotating reference frame -!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) -!-------------------------------------------------------------------------------------------------- -pure function math_qToEuler(qPassive) - - implicit none - real(pReal), dimension(4), intent(in) :: qPassive - real(pReal), dimension(4) :: q - real(pReal), dimension(3) :: math_qToEuler - - q = math_qConj(qPassive) ! convert to active rotation, since formulas are defined for active rotations - - math_qToEuler(2) = acos(1.0_pReal-2.0_pReal*(q(2)*q(2)+q(3)*q(3))) - - if (abs(math_qToEuler(2)) < 1.0e-6_pReal) then - math_qToEuler(1) = sign(2.0_pReal*acos(math_limit(q(1),-1.0_pReal, 1.0_pReal)),q(4)) - math_qToEuler(3) = 0.0_pReal - else - math_qToEuler(1) = atan2(q(1)*q(3)+q(2)*q(4), q(1)*q(2)-q(3)*q(4)) - math_qToEuler(3) = atan2(-q(1)*q(3)+q(2)*q(4), q(1)*q(2)+q(3)*q(4)) - endif - - math_qToEuler = merge(math_qToEuler + [2.0_pReal*PI, PI, 2.0_pReal*PI], & ! ensure correct range - math_qToEuler, math_qToEuler<0.0_pReal) - -end function math_qToEuler - - -!-------------------------------------------------------------------------------------------------- -!> @brief axis-angle (x, y, z, ang in radians) from quaternion (w+ix+jy+kz) -!> @details quaternion is meant to represent an ACTIVE rotation -!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) -!> @details formula for active rotation taken from -!> @details http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29#Rodrigues_parameters -!-------------------------------------------------------------------------------------------------- -pure function math_qToAxisAngle(Q) - - implicit none - real(pReal), dimension(4), intent(in) :: Q - real(pReal) :: halfAngle, sinHalfAngle - real(pReal), dimension(4) :: math_qToAxisAngle - - halfAngle = acos(max(-1.0_pReal, min(1.0_pReal, Q(1)))) ! limit to [-1,1] --> 0 to 180 deg - sinHalfAngle = sin(halfAngle) - - if (sinHalfAngle <= 1.0e-4_pReal) then ! very small rotation angle? - math_qToAxisAngle = 0.0_pReal - else - math_qToAxisAngle= [ Q(2:4)/sinHalfAngle, halfAngle*2.0_pReal] - endif - -end function math_qToAxisAngle - - -!-------------------------------------------------------------------------------------------------- -!> @brief Euler axis-angle (x, y, z, ang in radians) from quaternion (w+ix+jy+kz) -!> @details quaternion is meant to represent a PASSIVE rotation -!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) -!-------------------------------------------------------------------------------------------------- -pure function math_qToEulerAxisAngle(qPassive) - - implicit none - real(pReal), dimension(4), intent(in) :: qPassive - real(pReal), dimension(4) :: q - real(pReal), dimension(4) :: math_qToEulerAxisAngle - - q = math_qConj(qPassive) ! convert to active rotation - math_qToEulerAxisAngle = math_qToAxisAngle(q) - -end function math_qToEulerAxisAngle - - -!-------------------------------------------------------------------------------------------------- -!> @brief Rodrigues vector (x, y, z) from unit quaternion (w+ix+jy+kz) -!-------------------------------------------------------------------------------------------------- -pure function math_qToRodrig(Q) - use prec, only: & - DAMASK_NaN, & - tol_math_check - - implicit none - real(pReal), dimension(4), intent(in) :: Q - real(pReal), dimension(3) :: math_qToRodrig - - math_qToRodrig = merge(Q(2:4)/Q(1),DAMASK_NaN,abs(Q(1)) > tol_math_check) ! NaN for 180 deg since Rodrig is unbound - -end function math_qToRodrig - - -!-------------------------------------------------------------------------------------------------- -!> @brief misorientation angle between two sets of Euler angles -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_EulerMisorientation(EulerA,EulerB) - - implicit none - real(pReal), dimension(3), intent(in) :: EulerA,EulerB - real(pReal), dimension(3,3) :: r - real(pReal) :: tr - - r = math_mul33x33(math_EulerToR(EulerB),transpose(math_EulerToR(EulerA))) - - tr = (math_trace33(r)-1.0_pReal)*0.4999999_pReal - math_EulerMisorientation = abs(0.5_pReal*PI-asin(tr)) - -end function math_EulerMisorientation - - -!-------------------------------------------------------------------------------------------------- -!> @brief draw a random sample from Euler space -!-------------------------------------------------------------------------------------------------- -function math_sampleRandomOri() - - implicit none - real(pReal), dimension(3) :: math_sampleRandomOri, rnd - - call halton(3_pInt,rnd) - math_sampleRandomOri = [rnd(1)*2.0_pReal*PI, & - acos(2.0_pReal*rnd(2)-1.0_pReal), & - rnd(3)*2.0_pReal*PI] - -end function math_sampleRandomOri - - -!-------------------------------------------------------------------------------------------------- -!> @brief draw a random sample from Gauss component with noise (in radians) half-width -!-------------------------------------------------------------------------------------------------- -function math_sampleGaussOri(center,noise) - use prec, only: & - tol_math_check - - implicit none - real(pReal), intent(in) :: noise - real(pReal), dimension(3), intent(in) :: center - real(pReal) :: cosScatter,scatter - real(pReal), dimension(3) :: math_sampleGaussOri, disturb - real(pReal), dimension(3), parameter :: ORIGIN = [0.0_pReal,0.0_pReal,0.0_pReal] - real(pReal), dimension(5) :: rnd - integer(pInt) :: i - - if (abs(noise) < tol_math_check) then - math_sampleGaussOri = center - return - endif - -! Helming uses different distribution with Bessel functions -! therefore the gauss scatter width has to be scaled differently - scatter = 0.95_pReal * noise - cosScatter = cos(scatter) - - do - call halton(5_pInt,rnd) - forall (i=1_pInt:3_pInt) rnd(i) = 2.0_pReal*rnd(i)-1.0_pReal ! expand 1:3 to range [-1,+1] - disturb = [ scatter * rnd(1), & ! phi1 - sign(1.0_pReal,rnd(2))*acos(cosScatter+(1.0_pReal-cosScatter)*rnd(4)), & ! Phi - scatter * rnd(2)] ! phi2 - if (rnd(5) <= exp(-1.0_pReal*(math_EulerMisorientation(ORIGIN,disturb)/scatter)**2_pReal)) exit - enddo - - math_sampleGaussOri = math_RtoEuler(math_mul33x33(math_EulerToR(disturb),math_EulerToR(center))) - -end function math_sampleGaussOri - - -!-------------------------------------------------------------------------------------------------- -!> @brief draw a random sample from Fiber component with noise (in radians) -!-------------------------------------------------------------------------------------------------- -function math_sampleFiberOri(alpha,beta,noise) - use prec, only: & - tol_math_check - - implicit none - real(pReal), dimension(3) :: math_sampleFiberOri, fiberInC,fiberInS,axis - real(pReal), dimension(2), intent(in) :: alpha,beta - real(pReal), dimension(6) :: rnd - real(pReal), dimension(3,3) :: oRot,fRot,pRot - real(pReal) :: noise, scatter, cos2Scatter, angle - integer(pInt), dimension(2,3), parameter :: ROTMAP = reshape([2_pInt,3_pInt,& - 3_pInt,1_pInt,& - 1_pInt,2_pInt],[2,3]) - integer(pInt) :: i - -! Helming uses different distribution with Bessel functions -! therefore the gauss scatter width has to be scaled differently - scatter = 0.95_pReal * noise - cos2Scatter = cos(2.0_pReal*scatter) - -! fiber axis in crystal coordinate system - fiberInC = [ sin(alpha(1))*cos(alpha(2)) , & - sin(alpha(1))*sin(alpha(2)), & - cos(alpha(1))] -! fiber axis in sample coordinate system - fiberInS = [ sin(beta(1))*cos(beta(2)), & - sin(beta(1))*sin(beta(2)), & - cos(beta(1))] - -! ---# rotation matrix from sample to crystal system #--- - angle = -acos(dot_product(fiberInC,fiberInS)) - if(abs(angle) > tol_math_check) then -! rotation axis between sample and crystal system (cross product) - forall(i=1_pInt:3_pInt) axis(i) = fiberInC(ROTMAP(1,i))*fiberInS(ROTMAP(2,i))-fiberInC(ROTMAP(2,i))*fiberInS(ROTMAP(1,i)) - oRot = math_EulerAxisAngleToR(math_crossproduct(fiberInC,fiberInS),angle) - else - oRot = math_I3 - end if - -! ---# rotation matrix about fiber axis (random angle) #--- - do - call halton(6_pInt,rnd) - fRot = math_EulerAxisAngleToR(fiberInS,rnd(1)*2.0_pReal*pi) - -! ---# rotation about random axis perpend to fiber #--- -! random axis pependicular to fiber axis - axis(1:2) = rnd(2:3) - if (abs(fiberInS(3)) > tol_math_check) then - axis(3)=-(axis(1)*fiberInS(1)+axis(2)*fiberInS(2))/fiberInS(3) - else if(abs(fiberInS(2)) > tol_math_check) then - axis(3)=axis(2) - axis(2)=-(axis(1)*fiberInS(1)+axis(3)*fiberInS(3))/fiberInS(2) - else if(abs(fiberInS(1)) > tol_math_check) then - axis(3)=axis(1) - axis(1)=-(axis(2)*fiberInS(2)+axis(3)*fiberInS(3))/fiberInS(1) - end if - -! scattered rotation angle - if (noise > 0.0_pReal) then - angle = acos(cos2Scatter+(1.0_pReal-cos2Scatter)*rnd(4)) - if (rnd(5) <= exp(-1.0_pReal*(angle/scatter)**2.0_pReal)) exit - else - angle = 0.0_pReal - exit - end if - enddo - if (rnd(6) <= 0.5) angle = -angle - - pRot = math_EulerAxisAngleToR(axis,angle) - -! ---# apply the three rotations #--- - math_sampleFiberOri = math_RtoEuler(math_mul33x33(pRot,math_mul33x33(fRot,oRot))) - -end function math_sampleFiberOri - - -!-------------------------------------------------------------------------------------------------- -!> @brief draw a random sample from Gauss variable -!-------------------------------------------------------------------------------------------------- -real(pReal) function math_sampleGaussVar(meanvalue, stddev, width) - use prec, only: & - tol_math_check - - implicit none - real(pReal), intent(in) :: meanvalue, & ! meanvalue of gauss distribution - stddev ! standard deviation of gauss distribution - real(pReal), intent(in), optional :: width ! width of considered values as multiples of standard deviation - real(pReal), dimension(2) :: rnd ! random numbers - real(pReal) :: scatter, & ! normalized scatter around meanvalue - myWidth - - if (abs(stddev) < tol_math_check) then - math_sampleGaussVar = meanvalue - return - endif - - myWidth = merge(width,3.0_pReal,present(width)) ! use +-3*sigma as default value for scatter if not given - - do - call halton(2_pInt, rnd) - scatter = myWidth * (2.0_pReal * rnd(1) - 1.0_pReal) - if (rnd(2) <= exp(-0.5_pReal * scatter ** 2.0_pReal)) exit ! test if scattered value is drawn - enddo - - math_sampleGaussVar = scatter * stddev - -end function math_sampleGaussVar - - -!-------------------------------------------------------------------------------------------------- -!> @brief symmetrically equivalent Euler angles for given sample symmetry 1:triclinic, 2:monoclinic, 4:orthotropic -!-------------------------------------------------------------------------------------------------- -pure function math_symmetricEulers(sym,Euler) - - implicit none - integer(pInt), intent(in) :: sym - real(pReal), dimension(3), intent(in) :: Euler - real(pReal), dimension(3,3) :: math_symmetricEulers - integer(pInt) :: i,j - - math_symmetricEulers(1,1) = PI+Euler(1) - math_symmetricEulers(2,1) = Euler(2) - math_symmetricEulers(3,1) = Euler(3) - - math_symmetricEulers(1,2) = PI-Euler(1) - math_symmetricEulers(2,2) = PI-Euler(2) - math_symmetricEulers(3,2) = PI+Euler(3) - - math_symmetricEulers(1,3) = 2.0_pReal*PI-Euler(1) - math_symmetricEulers(2,3) = PI-Euler(2) - math_symmetricEulers(3,3) = PI+Euler(3) - - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) math_symmetricEulers(j,i) = modulo(math_symmetricEulers(j,i),2.0_pReal*pi) - - select case (sym) - case (4_pInt) ! all done - - case (2_pInt) ! return only first - math_symmetricEulers(1:3,2:3) = 0.0_pReal - - case default ! return blank - math_symmetricEulers = 0.0_pReal - end select - -end function math_symmetricEulers - - -!-------------------------------------------------------------------------------------------------- -!> @brief eigenvalues and eigenvectors of symmetric matrix m -!-------------------------------------------------------------------------------------------------- -subroutine math_spectralDecompositionSym(m,values,vectors,error) - - implicit none - real(pReal), dimension(:,:), intent(in) :: m - real(pReal), dimension(size(m,1)), intent(out) :: values - real(pReal), dimension(size(m,1),size(m,1)), intent(out) :: vectors - logical, intent(out) :: error - - integer(pInt) :: info - real(pReal), dimension((64+2)*size(m,1)) :: work ! block size of 64 taken from http://www.netlib.org/lapack/double/dsyev.f - - vectors = M ! copy matrix to input (doubles as output) array -#if(FLOAT==8) - call dsyev('V','U',size(m,1),vectors,size(m,1),values,work,(64+2)*size(m,1),info) -#elif(FLOAT==4) - call ssyev('V','U',size(m,1),vectors,size(m,1),values,work,(64+2)*size(m,1),info) -#endif - error = (info == 0_pInt) - -end subroutine math_spectralDecompositionSym - - -!-------------------------------------------------------------------------------------------------- -!> @brief eigenvalues and eigenvectors of symmetric 33 matrix m using an analytical expression -!> and the general LAPACK powered version for arbritrary sized matrices as fallback -!> @author Joachim Kopp, Max–Planck–Institut für Kernphysik, Heidelberg (Copyright (C) 2006) -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @details See http://arxiv.org/abs/physics/0610206 (DSYEVH3) -!-------------------------------------------------------------------------------------------------- -subroutine math_spectralDecompositionSym33(m,values,vectors) - - implicit none - real(pReal), dimension(3,3),intent(in) :: m - real(pReal), dimension(3), intent(out) :: values - real(pReal), dimension(3,3),intent(out) :: vectors - real(pReal) :: T, U, norm, threshold - logical :: error - - values = math_eigenvaluesSym33(m) - - vectors(1:3,2) = [ m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2), & - m(1, 3) * m(1, 2) - m(2, 3) * m(1, 1), & - m(1, 2)**2_pInt] - - T = maxval(abs(values)) - U = max(T, T**2_pInt) - threshold = sqrt(5.0e-14_pReal * U**2_pInt) - -! Calculate first eigenvector by the formula v[0] = (m - lambda[0]).e1 x (m - lambda[0]).e2 - vectors(1:3,1) = [ vectors(1,2) + m(1, 3) * values(1), & - vectors(2,2) + m(2, 3) * values(1), & - (m(1,1) - values(1)) * (m(2,2) - values(1)) - vectors(3,2)] - norm = norm2(vectors(1:3, 1)) - - fallback1: if(norm < threshold) then - call math_spectralDecompositionSym(m,values,vectors,error) - return - endif fallback1 - - vectors(1:3,1) = vectors(1:3, 1) / norm - -! Calculate second eigenvector by the formula v[1] = (m - lambda[1]).e1 x (m - lambda[1]).e2 - vectors(1:3,2) = [ vectors(1,2) + m(1, 3) * values(2), & - vectors(2,2) + m(2, 3) * values(2), & - (m(1,1) - values(2)) * (m(2,2) - values(2)) - vectors(3,2)] - norm = norm2(vectors(1:3, 2)) - - fallback2: if(norm < threshold) then - call math_spectralDecompositionSym(m,values,vectors,error) - return - endif fallback2 - vectors(1:3,2) = vectors(1:3, 2) / norm - -! Calculate third eigenvector according to v[2] = v[0] x v[1] - vectors(1:3,3) = math_crossproduct(vectors(1:3,1),vectors(1:3,2)) - -end subroutine math_spectralDecompositionSym33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief rotational part from polar decomposition of tensor m -!-------------------------------------------------------------------------------------------------- -function math_rotationalPart33(m) - use IO, only: & - IO_warning - - implicit none - real(pReal), intent(in), dimension(3,3) :: m - real(pReal), dimension(3,3) :: math_rotationalPart33 - real(pReal), dimension(3,3) :: U, mTm , Uinv, EB - real(pReal), dimension(3) :: EV - - mTm = math_mul33x33(math_transpose33(m),m) - call math_spectralDecompositionSym33(mTm,EV,EB) - - U = sqrt(EV(1)) * math_tensorproduct33(EB(1:3,1),EB(1:3,1)) & - + sqrt(EV(2)) * math_tensorproduct33(EB(1:3,2),EB(1:3,2)) & - + sqrt(EV(3)) * math_tensorproduct33(EB(1:3,3),EB(1:3,3)) - - Uinv = math_inv33(U) - if (all(abs(Uinv) <= tiny(Uinv))) then ! math_inv33 returns zero when failed, avoid floating point equality comparison - math_rotationalPart33 = math_I3 - call IO_warning(650_pInt) - else - math_rotationalPart33 = math_mul33x33(m,Uinv) - endif - -end function math_rotationalPart33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief Eigenvalues of symmetric matrix m -! will return NaN on error -!-------------------------------------------------------------------------------------------------- -function math_eigenvaluesSym(m) - use prec, only: & - DAMASK_NaN - - implicit none - real(pReal), dimension(:,:), intent(in) :: m - real(pReal), dimension(size(m,1)) :: math_eigenvaluesSym - real(pReal), dimension(size(m,1),size(m,1)) :: vectors - - integer(pInt) :: info - real(pReal), dimension((64+2)*size(m,1)) :: work ! block size of 64 taken from http://www.netlib.org/lapack/double/dsyev.f - - vectors = m ! copy matrix to input (doubles as output) array -#if(FLOAT==8) - call dsyev('N','U',size(m,1),vectors,size(m,1),math_eigenvaluesSym,work,(64+2)*size(m,1),info) -#elif(FLOAT==4) - call ssyev('N','U',size(m,1),vectors,size(m,1),math_eigenvaluesSym,work,(64+2)*size(m,1),info) -#endif - if (info /= 0_pInt) math_eigenvaluesSym = DAMASK_NaN - -end function math_eigenvaluesSym - - -!-------------------------------------------------------------------------------------------------- -!> @brief eigenvalues of symmetric 33 matrix m using an analytical expression -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @details similar to http://arxiv.org/abs/physics/0610206 (DSYEVC3) -!> but apparently more stable solution and has general LAPACK powered version for arbritrary sized -!> matrices as fallback -!-------------------------------------------------------------------------------------------------- -function math_eigenvaluesSym33(m) - - implicit none - real(pReal), intent(in), dimension(3,3) :: m - real(pReal), dimension(3) :: math_eigenvaluesSym33,invariants - real(pReal) :: P, Q, rho, phi - real(pReal), parameter :: TOL=1.e-14_pReal - - invariants = math_invariantsSym33(m) ! invariants are coefficients in characteristic polynomial apart for the sign of c0 and c2 in http://arxiv.org/abs/physics/0610206 - - P = invariants(2)-invariants(1)**2.0_pReal/3.0_pReal ! different from http://arxiv.org/abs/physics/0610206 (this formulation was in DAMASK) - Q = -2.0_pReal/27.0_pReal*invariants(1)**3.0_pReal+product(invariants(1:2))/3.0_pReal-invariants(3)! different from http://arxiv.org/abs/physics/0610206 (this formulation was in DAMASK) - - if(any(abs([p,q]) < TOL)) then - math_eigenvaluesSym33 = math_eigenvaluesSym(m) - else - rho=sqrt(-3.0_pReal*P**3.0_pReal)/9.0_pReal - phi=acos(math_limit(-Q/rho*0.5_pReal,-1.0_pReal,1.0_pReal)) - math_eigenvaluesSym33 = 2.0_pReal*rho**(1.0_pReal/3.0_pReal)* & - [cos(phi/3.0_pReal), & - cos((phi+2.0_pReal*PI)/3.0_pReal), & - cos((phi+4.0_pReal*PI)/3.0_pReal) & - ] + invariants(1)/3.0_pReal - endif -end function math_eigenvaluesSym33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief invariants of symmetrix 33 matrix m -!-------------------------------------------------------------------------------------------------- -pure function math_invariantsSym33(m) - - implicit none - real(pReal), dimension(3,3), intent(in) :: m - real(pReal), dimension(3) :: math_invariantsSym33 - - math_invariantsSym33(1) = math_trace33(m) - math_invariantsSym33(2) = m(1,1)*m(2,2) + m(1,1)*m(3,3) + m(2,2)*m(3,3) & - -(m(1,2)**2 + m(1,3)**2 + m(2,3)**2) - math_invariantsSym33(3) = math_detSym33(m) - -end function math_invariantsSym33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief computes the next element in the Halton sequence. -!> @author John Burkardt -!-------------------------------------------------------------------------------------------------- -subroutine halton(ndim, r) - - implicit none - integer(pInt), intent(in) :: ndim !< dimension of the element - real(pReal), intent(out), dimension(ndim) :: r !< next element of the current Halton sequence - integer(pInt), dimension(ndim) :: base - integer(pInt) :: seed - integer(pInt), dimension(1) :: value_halton - - call halton_memory ('GET', 'SEED', 1_pInt, value_halton) - seed = value_halton(1) - - call halton_memory ('GET', 'BASE', ndim, base) - - call i_to_halton (seed, base, ndim, r) - - value_halton(1) = 1_pInt - call halton_memory ('INC', 'SEED', 1_pInt, value_halton) - -end subroutine halton - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets or returns quantities associated with the Halton sequence. -!> @details If action_halton is 'SET' and action_halton is 'BASE', then NDIM is input, and -!> @details is the number of entries in value_halton to be put into BASE. -!> @details If action_halton is 'SET', then on input, value_halton contains values to be assigned -!> @details to the internal variable. -!> @details If action_halton is 'GET', then on output, value_halton contains the values of -!> @details the specified internal variable. -!> @details If action_halton is 'INC', then on input, value_halton contains the increment to -!> @details be added to the specified internal variable. -!> @author John Burkardt -!-------------------------------------------------------------------------------------------------- -subroutine halton_memory (action_halton, name_halton, ndim, value_halton) - - implicit none - character(len = *), intent(in) :: & - action_halton, & !< desired action: GET the value of a particular quantity, SET the value of a particular quantity, INC the value of a particular quantity (only for SEED) - name_halton !< name of the quantity: BASE: Halton base(s), NDIM: spatial dimension, SEED: current Halton seed - integer(pInt), dimension(*), intent(inout) :: value_halton - integer(pInt), allocatable, save, dimension(:) :: base - logical, save :: first_call = .true. - integer(pInt), intent(in) :: ndim !< dimension of the quantity - integer(pInt):: i - integer(pInt), save :: ndim_save = 0_pInt, seed = 1_pInt - - if (first_call) then - ndim_save = 1_pInt - allocate(base(ndim_save)) - base(1) = 2_pInt - first_call = .false. - endif - -!-------------------------------------------------------------------------------------------------- -! Set - if(action_halton(1:1) == 'S' .or. action_halton(1:1) == 's') then - - if(name_halton(1:1) == 'B' .or. name_halton(1:1) == 'b') then - - if(ndim_save /= ndim) then - deallocate(base) - ndim_save = ndim - allocate(base(ndim_save)) - endif - - base(1:ndim) = value_halton(1:ndim) - - elseif(name_halton(1:1) == 'N' .or. name_halton(1:1) == 'n') then - - if(ndim_save /= value_halton(1)) then - deallocate(base) - ndim_save = value_halton(1) - allocate(base(ndim_save)) - do i = 1_pInt, ndim_save - base(i) = prime (i) - enddo - else - ndim_save = value_halton(1) - endif - elseif(name_halton(1:1) == 'S' .or. name_halton(1:1) == 's') then - seed = value_halton(1) - endif - -!-------------------------------------------------------------------------------------------------- -! Get - elseif(action_halton(1:1) == 'G' .or. action_halton(1:1) == 'g') then - if(name_halton(1:1) == 'B' .or. name_halton(1:1) == 'b') then - if(ndim /= ndim_save) then - deallocate(base) - ndim_save = ndim - allocate(base(ndim_save)) - do i = 1_pInt, ndim_save - base(i) = prime(i) - enddo - endif - value_halton(1:ndim_save) = base(1:ndim_save) - elseif(name_halton(1:1) == 'N' .or. name_halton(1:1) == 'n') then - value_halton(1) = ndim_save - elseif(name_halton(1:1) == 'S' .or. name_halton(1:1) == 's') then - value_halton(1) = seed - endif - -!-------------------------------------------------------------------------------------------------- -! Increment - elseif(action_halton(1:1) == 'I' .or. action_halton(1:1) == 'i') then - if(name_halton(1:1) == 'S' .or. name_halton(1:1) == 's') then - seed = seed + value_halton(1) - end if - endif - -end subroutine halton_memory - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the dimension for a Halton sequence -!> @author John Burkardt -!-------------------------------------------------------------------------------------------------- -subroutine halton_ndim_set (ndim) - - implicit none - integer(pInt), intent(in) :: ndim !< dimension of the Halton vectors - integer(pInt) :: value_halton(1) - - value_halton(1) = ndim - call halton_memory ('SET', 'NDIM', 1_pInt, value_halton) - -end subroutine halton_ndim_set - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the seed for the Halton sequence. -!> @details Calling HALTON repeatedly returns the elements of the Halton sequence in order, -!> @details starting with element number 1. -!> @details An internal counter, called SEED, keeps track of the next element to return. Each time -!> @details is computed, and then SEED is incremented by 1. -!> @details To restart the Halton sequence, it is only necessary to reset SEED to 1. It might also -!> @details be desirable to reset SEED to some other value. This routine allows the user to specify -!> @details any value of SEED. -!> @details The default value of SEED is 1, which restarts the Halton sequence. -!> @author John Burkardt -!-------------------------------------------------------------------------------------------------- -subroutine halton_seed_set(seed) - implicit none - - integer(pInt), parameter :: NDIM = 1_pInt - integer(pInt), intent(in) :: seed !< seed for the Halton sequence. - integer(pInt) :: value_halton(ndim) - - value_halton(1) = seed - call halton_memory ('SET', 'SEED', NDIM, value_halton) - -end subroutine halton_seed_set - - -!-------------------------------------------------------------------------------------------------- -!> @brief computes an element of a Halton sequence. -!> @details Only the absolute value of SEED is considered. SEED = 0 is allowed, and returns R = 0. -!> @details Halton Bases should be distinct prime numbers. This routine only checks that each base -!> @details is greater than 1. -!> @details Reference: -!> @details J.H. Halton: On the efficiency of certain quasi-random sequences of points in evaluating -!> @details multi-dimensional integrals, Numerische Mathematik, Volume 2, pages 84-90, 1960. -!> @author John Burkardt -!-------------------------------------------------------------------------------------------------- -subroutine i_to_halton (seed, base, ndim, r) - use IO, only: & - IO_error - - implicit none - integer(pInt), intent(in) :: ndim !< dimension of the sequence - integer(pInt), intent(in), dimension(ndim) :: base !< Halton bases - real(pReal), dimension(ndim) :: base_inv - integer(pInt), dimension(ndim) :: digit - real(pReal), dimension(ndim), intent(out) ::r !< the SEED-th element of the Halton sequence for the given bases - integer(pInt) , intent(in):: seed !< index of the desired element - integer(pInt), dimension(ndim) :: seed2 - - seed2(1:ndim) = abs(seed) - - r(1:ndim) = 0.0_pReal - - if (any (base(1:ndim) <= 1_pInt)) call IO_error(error_ID=405_pInt) - - base_inv(1:ndim) = 1.0_pReal / real (base(1:ndim), pReal) - - do while ( any ( seed2(1:ndim) /= 0_pInt) ) - digit(1:ndim) = mod ( seed2(1:ndim), base(1:ndim)) - r(1:ndim) = r(1:ndim) + real ( digit(1:ndim), pReal) * base_inv(1:ndim) - base_inv(1:ndim) = base_inv(1:ndim) / real ( base(1:ndim), pReal) - seed2(1:ndim) = seed2(1:ndim) / base(1:ndim) - enddo - -end subroutine i_to_halton - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns any of the first 1500 prime numbers. -!> @details n <= 0 returns 1500, the index of the largest prime (12553) available. -!> @details n = 0 is legal, returning PRIME = 1. -!> @details Reference: -!> @details Milton Abramowitz and Irene Stegun: Handbook of Mathematical Functions, -!> @details US Department of Commerce, 1964, pages 870-873. -!> @details Daniel Zwillinger: CRC Standard Mathematical Tables and Formulae, -!> @details 30th Edition, CRC Press, 1996, pages 95-98. -!> @author John Burkardt -!-------------------------------------------------------------------------------------------------- -integer(pInt) function prime(n) - use IO, only: & - IO_error - - implicit none - integer(pInt), intent(in) :: n !< index of the desired prime number - integer(pInt), parameter :: PRIME_MAX = 1500_pInt - integer(pInt), save :: icall = 0_pInt - integer(pInt), save, dimension(PRIME_MAX) :: npvec - - if (icall == 0_pInt) then - icall = 1_pInt - - npvec = [& - 2_pInt, 3_pInt, 5_pInt, 7_pInt, 11_pInt, 13_pInt, 17_pInt, 19_pInt, 23_pInt, 29_pInt, & - 31_pInt, 37_pInt, 41_pInt, 43_pInt, 47_pInt, 53_pInt, 59_pInt, 61_pInt, 67_pInt, 71_pInt, & - 73_pInt, 79_pInt, 83_pInt, 89_pInt, 97_pInt, 101_pInt, 103_pInt, 107_pInt, 109_pInt, 113_pInt, & - 127_pInt, 131_pInt, 137_pInt, 139_pInt, 149_pInt, 151_pInt, 157_pInt, 163_pInt, 167_pInt, 173_pInt, & - 179_pInt, 181_pInt, 191_pInt, 193_pInt, 197_pInt, 199_pInt, 211_pInt, 223_pInt, 227_pInt, 229_pInt, & - 233_pInt, 239_pInt, 241_pInt, 251_pInt, 257_pInt, 263_pInt, 269_pInt, 271_pInt, 277_pInt, 281_pInt, & - 283_pInt, 293_pInt, 307_pInt, 311_pInt, 313_pInt, 317_pInt, 331_pInt, 337_pInt, 347_pInt, 349_pInt, & - 353_pInt, 359_pInt, 367_pInt, 373_pInt, 379_pInt, 383_pInt, 389_pInt, 397_pInt, 401_pInt, 409_pInt, & - 419_pInt, 421_pInt, 431_pInt, 433_pInt, 439_pInt, 443_pInt, 449_pInt, 457_pInt, 461_pInt, 463_pInt, & - 467_pInt, 479_pInt, 487_pInt, 491_pInt, 499_pInt, 503_pInt, 509_pInt, 521_pInt, 523_pInt, 541_pInt, & - ! 101:200 - 547_pInt, 557_pInt, 563_pInt, 569_pInt, 571_pInt, 577_pInt, 587_pInt, 593_pInt, 599_pInt, 601_pInt, & - 607_pInt, 613_pInt, 617_pInt, 619_pInt, 631_pInt, 641_pInt, 643_pInt, 647_pInt, 653_pInt, 659_pInt, & - 661_pInt, 673_pInt, 677_pInt, 683_pInt, 691_pInt, 701_pInt, 709_pInt, 719_pInt, 727_pInt, 733_pInt, & - 739_pInt, 743_pInt, 751_pInt, 757_pInt, 761_pInt, 769_pInt, 773_pInt, 787_pInt, 797_pInt, 809_pInt, & - 811_pInt, 821_pInt, 823_pInt, 827_pInt, 829_pInt, 839_pInt, 853_pInt, 857_pInt, 859_pInt, 863_pInt, & - 877_pInt, 881_pInt, 883_pInt, 887_pInt, 907_pInt, 911_pInt, 919_pInt, 929_pInt, 937_pInt, 941_pInt, & - 947_pInt, 953_pInt, 967_pInt, 971_pInt, 977_pInt, 983_pInt, 991_pInt, 997_pInt, 1009_pInt, 1013_pInt, & - 1019_pInt, 1021_pInt, 1031_pInt, 1033_pInt, 1039_pInt, 1049_pInt, 1051_pInt, 1061_pInt, 1063_pInt, 1069_pInt, & - 1087_pInt, 1091_pInt, 1093_pInt, 1097_pInt, 1103_pInt, 1109_pInt, 1117_pInt, 1123_pInt, 1129_pInt, 1151_pInt, & - 1153_pInt, 1163_pInt, 1171_pInt, 1181_pInt, 1187_pInt, 1193_pInt, 1201_pInt, 1213_pInt, 1217_pInt, 1223_pInt, & - ! 201:300 - 1229_pInt, 1231_pInt, 1237_pInt, 1249_pInt, 1259_pInt, 1277_pInt, 1279_pInt, 1283_pInt, 1289_pInt, 1291_pInt, & - 1297_pInt, 1301_pInt, 1303_pInt, 1307_pInt, 1319_pInt, 1321_pInt, 1327_pInt, 1361_pInt, 1367_pInt, 1373_pInt, & - 1381_pInt, 1399_pInt, 1409_pInt, 1423_pInt, 1427_pInt, 1429_pInt, 1433_pInt, 1439_pInt, 1447_pInt, 1451_pInt, & - 1453_pInt, 1459_pInt, 1471_pInt, 1481_pInt, 1483_pInt, 1487_pInt, 1489_pInt, 1493_pInt, 1499_pInt, 1511_pInt, & - 1523_pInt, 1531_pInt, 1543_pInt, 1549_pInt, 1553_pInt, 1559_pInt, 1567_pInt, 1571_pInt, 1579_pInt, 1583_pInt, & - 1597_pInt, 1601_pInt, 1607_pInt, 1609_pInt, 1613_pInt, 1619_pInt, 1621_pInt, 1627_pInt, 1637_pInt, 1657_pInt, & - 1663_pInt, 1667_pInt, 1669_pInt, 1693_pInt, 1697_pInt, 1699_pInt, 1709_pInt, 1721_pInt, 1723_pInt, 1733_pInt, & - 1741_pInt, 1747_pInt, 1753_pInt, 1759_pInt, 1777_pInt, 1783_pInt, 1787_pInt, 1789_pInt, 1801_pInt, 1811_pInt, & - 1823_pInt, 1831_pInt, 1847_pInt, 1861_pInt, 1867_pInt, 1871_pInt, 1873_pInt, 1877_pInt, 1879_pInt, 1889_pInt, & - 1901_pInt, 1907_pInt, 1913_pInt, 1931_pInt, 1933_pInt, 1949_pInt, 1951_pInt, 1973_pInt, 1979_pInt, 1987_pInt, & - ! 301:400 - 1993_pInt, 1997_pInt, 1999_pInt, 2003_pInt, 2011_pInt, 2017_pInt, 2027_pInt, 2029_pInt, 2039_pInt, 2053_pInt, & - 2063_pInt, 2069_pInt, 2081_pInt, 2083_pInt, 2087_pInt, 2089_pInt, 2099_pInt, 2111_pInt, 2113_pInt, 2129_pInt, & - 2131_pInt, 2137_pInt, 2141_pInt, 2143_pInt, 2153_pInt, 2161_pInt, 2179_pInt, 2203_pInt, 2207_pInt, 2213_pInt, & - 2221_pInt, 2237_pInt, 2239_pInt, 2243_pInt, 2251_pInt, 2267_pInt, 2269_pInt, 2273_pInt, 2281_pInt, 2287_pInt, & - 2293_pInt, 2297_pInt, 2309_pInt, 2311_pInt, 2333_pInt, 2339_pInt, 2341_pInt, 2347_pInt, 2351_pInt, 2357_pInt, & - 2371_pInt, 2377_pInt, 2381_pInt, 2383_pInt, 2389_pInt, 2393_pInt, 2399_pInt, 2411_pInt, 2417_pInt, 2423_pInt, & - 2437_pInt, 2441_pInt, 2447_pInt, 2459_pInt, 2467_pInt, 2473_pInt, 2477_pInt, 2503_pInt, 2521_pInt, 2531_pInt, & - 2539_pInt, 2543_pInt, 2549_pInt, 2551_pInt, 2557_pInt, 2579_pInt, 2591_pInt, 2593_pInt, 2609_pInt, 2617_pInt, & - 2621_pInt, 2633_pInt, 2647_pInt, 2657_pInt, 2659_pInt, 2663_pInt, 2671_pInt, 2677_pInt, 2683_pInt, 2687_pInt, & - 2689_pInt, 2693_pInt, 2699_pInt, 2707_pInt, 2711_pInt, 2713_pInt, 2719_pInt, 2729_pInt, 2731_pInt, 2741_pInt, & - ! 401:500 - 2749_pInt, 2753_pInt, 2767_pInt, 2777_pInt, 2789_pInt, 2791_pInt, 2797_pInt, 2801_pInt, 2803_pInt, 2819_pInt, & - 2833_pInt, 2837_pInt, 2843_pInt, 2851_pInt, 2857_pInt, 2861_pInt, 2879_pInt, 2887_pInt, 2897_pInt, 2903_pInt, & - 2909_pInt, 2917_pInt, 2927_pInt, 2939_pInt, 2953_pInt, 2957_pInt, 2963_pInt, 2969_pInt, 2971_pInt, 2999_pInt, & - 3001_pInt, 3011_pInt, 3019_pInt, 3023_pInt, 3037_pInt, 3041_pInt, 3049_pInt, 3061_pInt, 3067_pInt, 3079_pInt, & - 3083_pInt, 3089_pInt, 3109_pInt, 3119_pInt, 3121_pInt, 3137_pInt, 3163_pInt, 3167_pInt, 3169_pInt, 3181_pInt, & - 3187_pInt, 3191_pInt, 3203_pInt, 3209_pInt, 3217_pInt, 3221_pInt, 3229_pInt, 3251_pInt, 3253_pInt, 3257_pInt, & - 3259_pInt, 3271_pInt, 3299_pInt, 3301_pInt, 3307_pInt, 3313_pInt, 3319_pInt, 3323_pInt, 3329_pInt, 3331_pInt, & - 3343_pInt, 3347_pInt, 3359_pInt, 3361_pInt, 3371_pInt, 3373_pInt, 3389_pInt, 3391_pInt, 3407_pInt, 3413_pInt, & - 3433_pInt, 3449_pInt, 3457_pInt, 3461_pInt, 3463_pInt, 3467_pInt, 3469_pInt, 3491_pInt, 3499_pInt, 3511_pInt, & - 3517_pInt, 3527_pInt, 3529_pInt, 3533_pInt, 3539_pInt, 3541_pInt, 3547_pInt, 3557_pInt, 3559_pInt, 3571_pInt, & - ! 501:600 - 3581_pInt, 3583_pInt, 3593_pInt, 3607_pInt, 3613_pInt, 3617_pInt, 3623_pInt, 3631_pInt, 3637_pInt, 3643_pInt, & - 3659_pInt, 3671_pInt, 3673_pInt, 3677_pInt, 3691_pInt, 3697_pInt, 3701_pInt, 3709_pInt, 3719_pInt, 3727_pInt, & - 3733_pInt, 3739_pInt, 3761_pInt, 3767_pInt, 3769_pInt, 3779_pInt, 3793_pInt, 3797_pInt, 3803_pInt, 3821_pInt, & - 3823_pInt, 3833_pInt, 3847_pInt, 3851_pInt, 3853_pInt, 3863_pInt, 3877_pInt, 3881_pInt, 3889_pInt, 3907_pInt, & - 3911_pInt, 3917_pInt, 3919_pInt, 3923_pInt, 3929_pInt, 3931_pInt, 3943_pInt, 3947_pInt, 3967_pInt, 3989_pInt, & - 4001_pInt, 4003_pInt, 4007_pInt, 4013_pInt, 4019_pInt, 4021_pInt, 4027_pInt, 4049_pInt, 4051_pInt, 4057_pInt, & - 4073_pInt, 4079_pInt, 4091_pInt, 4093_pInt, 4099_pInt, 4111_pInt, 4127_pInt, 4129_pInt, 4133_pInt, 4139_pInt, & - 4153_pInt, 4157_pInt, 4159_pInt, 4177_pInt, 4201_pInt, 4211_pInt, 4217_pInt, 4219_pInt, 4229_pInt, 4231_pInt, & - 4241_pInt, 4243_pInt, 4253_pInt, 4259_pInt, 4261_pInt, 4271_pInt, 4273_pInt, 4283_pInt, 4289_pInt, 4297_pInt, & - 4327_pInt, 4337_pInt, 4339_pInt, 4349_pInt, 4357_pInt, 4363_pInt, 4373_pInt, 4391_pInt, 4397_pInt, 4409_pInt, & - ! 601:700 - 4421_pInt, 4423_pInt, 4441_pInt, 4447_pInt, 4451_pInt, 4457_pInt, 4463_pInt, 4481_pInt, 4483_pInt, 4493_pInt, & - 4507_pInt, 4513_pInt, 4517_pInt, 4519_pInt, 4523_pInt, 4547_pInt, 4549_pInt, 4561_pInt, 4567_pInt, 4583_pInt, & - 4591_pInt, 4597_pInt, 4603_pInt, 4621_pInt, 4637_pInt, 4639_pInt, 4643_pInt, 4649_pInt, 4651_pInt, 4657_pInt, & - 4663_pInt, 4673_pInt, 4679_pInt, 4691_pInt, 4703_pInt, 4721_pInt, 4723_pInt, 4729_pInt, 4733_pInt, 4751_pInt, & - 4759_pInt, 4783_pInt, 4787_pInt, 4789_pInt, 4793_pInt, 4799_pInt, 4801_pInt, 4813_pInt, 4817_pInt, 4831_pInt, & - 4861_pInt, 4871_pInt, 4877_pInt, 4889_pInt, 4903_pInt, 4909_pInt, 4919_pInt, 4931_pInt, 4933_pInt, 4937_pInt, & - 4943_pInt, 4951_pInt, 4957_pInt, 4967_pInt, 4969_pInt, 4973_pInt, 4987_pInt, 4993_pInt, 4999_pInt, 5003_pInt, & - 5009_pInt, 5011_pInt, 5021_pInt, 5023_pInt, 5039_pInt, 5051_pInt, 5059_pInt, 5077_pInt, 5081_pInt, 5087_pInt, & - 5099_pInt, 5101_pInt, 5107_pInt, 5113_pInt, 5119_pInt, 5147_pInt, 5153_pInt, 5167_pInt, 5171_pInt, 5179_pInt, & - 5189_pInt, 5197_pInt, 5209_pInt, 5227_pInt, 5231_pInt, 5233_pInt, 5237_pInt, 5261_pInt, 5273_pInt, 5279_pInt, & - ! 701:800 - 5281_pInt, 5297_pInt, 5303_pInt, 5309_pInt, 5323_pInt, 5333_pInt, 5347_pInt, 5351_pInt, 5381_pInt, 5387_pInt, & - 5393_pInt, 5399_pInt, 5407_pInt, 5413_pInt, 5417_pInt, 5419_pInt, 5431_pInt, 5437_pInt, 5441_pInt, 5443_pInt, & - 5449_pInt, 5471_pInt, 5477_pInt, 5479_pInt, 5483_pInt, 5501_pInt, 5503_pInt, 5507_pInt, 5519_pInt, 5521_pInt, & - 5527_pInt, 5531_pInt, 5557_pInt, 5563_pInt, 5569_pInt, 5573_pInt, 5581_pInt, 5591_pInt, 5623_pInt, 5639_pInt, & - 5641_pInt, 5647_pInt, 5651_pInt, 5653_pInt, 5657_pInt, 5659_pInt, 5669_pInt, 5683_pInt, 5689_pInt, 5693_pInt, & - 5701_pInt, 5711_pInt, 5717_pInt, 5737_pInt, 5741_pInt, 5743_pInt, 5749_pInt, 5779_pInt, 5783_pInt, 5791_pInt, & - 5801_pInt, 5807_pInt, 5813_pInt, 5821_pInt, 5827_pInt, 5839_pInt, 5843_pInt, 5849_pInt, 5851_pInt, 5857_pInt, & - 5861_pInt, 5867_pInt, 5869_pInt, 5879_pInt, 5881_pInt, 5897_pInt, 5903_pInt, 5923_pInt, 5927_pInt, 5939_pInt, & - 5953_pInt, 5981_pInt, 5987_pInt, 6007_pInt, 6011_pInt, 6029_pInt, 6037_pInt, 6043_pInt, 6047_pInt, 6053_pInt, & - 6067_pInt, 6073_pInt, 6079_pInt, 6089_pInt, 6091_pInt, 6101_pInt, 6113_pInt, 6121_pInt, 6131_pInt, 6133_pInt, & - ! 801:900 - 6143_pInt, 6151_pInt, 6163_pInt, 6173_pInt, 6197_pInt, 6199_pInt, 6203_pInt, 6211_pInt, 6217_pInt, 6221_pInt, & - 6229_pInt, 6247_pInt, 6257_pInt, 6263_pInt, 6269_pInt, 6271_pInt, 6277_pInt, 6287_pInt, 6299_pInt, 6301_pInt, & - 6311_pInt, 6317_pInt, 6323_pInt, 6329_pInt, 6337_pInt, 6343_pInt, 6353_pInt, 6359_pInt, 6361_pInt, 6367_pInt, & - 6373_pInt, 6379_pInt, 6389_pInt, 6397_pInt, 6421_pInt, 6427_pInt, 6449_pInt, 6451_pInt, 6469_pInt, 6473_pInt, & - 6481_pInt, 6491_pInt, 6521_pInt, 6529_pInt, 6547_pInt, 6551_pInt, 6553_pInt, 6563_pInt, 6569_pInt, 6571_pInt, & - 6577_pInt, 6581_pInt, 6599_pInt, 6607_pInt, 6619_pInt, 6637_pInt, 6653_pInt, 6659_pInt, 6661_pInt, 6673_pInt, & - 6679_pInt, 6689_pInt, 6691_pInt, 6701_pInt, 6703_pInt, 6709_pInt, 6719_pInt, 6733_pInt, 6737_pInt, 6761_pInt, & - 6763_pInt, 6779_pInt, 6781_pInt, 6791_pInt, 6793_pInt, 6803_pInt, 6823_pInt, 6827_pInt, 6829_pInt, 6833_pInt, & - 6841_pInt, 6857_pInt, 6863_pInt, 6869_pInt, 6871_pInt, 6883_pInt, 6899_pInt, 6907_pInt, 6911_pInt, 6917_pInt, & - 6947_pInt, 6949_pInt, 6959_pInt, 6961_pInt, 6967_pInt, 6971_pInt, 6977_pInt, 6983_pInt, 6991_pInt, 6997_pInt, & - ! 901:1000 - 7001_pInt, 7013_pInt, 7019_pInt, 7027_pInt, 7039_pInt, 7043_pInt, 7057_pInt, 7069_pInt, 7079_pInt, 7103_pInt, & - 7109_pInt, 7121_pInt, 7127_pInt, 7129_pInt, 7151_pInt, 7159_pInt, 7177_pInt, 7187_pInt, 7193_pInt, 7207_pInt, & - 7211_pInt, 7213_pInt, 7219_pInt, 7229_pInt, 7237_pInt, 7243_pInt, 7247_pInt, 7253_pInt, 7283_pInt, 7297_pInt, & - 7307_pInt, 7309_pInt, 7321_pInt, 7331_pInt, 7333_pInt, 7349_pInt, 7351_pInt, 7369_pInt, 7393_pInt, 7411_pInt, & - 7417_pInt, 7433_pInt, 7451_pInt, 7457_pInt, 7459_pInt, 7477_pInt, 7481_pInt, 7487_pInt, 7489_pInt, 7499_pInt, & - 7507_pInt, 7517_pInt, 7523_pInt, 7529_pInt, 7537_pInt, 7541_pInt, 7547_pInt, 7549_pInt, 7559_pInt, 7561_pInt, & - 7573_pInt, 7577_pInt, 7583_pInt, 7589_pInt, 7591_pInt, 7603_pInt, 7607_pInt, 7621_pInt, 7639_pInt, 7643_pInt, & - 7649_pInt, 7669_pInt, 7673_pInt, 7681_pInt, 7687_pInt, 7691_pInt, 7699_pInt, 7703_pInt, 7717_pInt, 7723_pInt, & - 7727_pInt, 7741_pInt, 7753_pInt, 7757_pInt, 7759_pInt, 7789_pInt, 7793_pInt, 7817_pInt, 7823_pInt, 7829_pInt, & - 7841_pInt, 7853_pInt, 7867_pInt, 7873_pInt, 7877_pInt, 7879_pInt, 7883_pInt, 7901_pInt, 7907_pInt, 7919_pInt, & - ! 1001:1100 - 7927_pInt, 7933_pInt, 7937_pInt, 7949_pInt, 7951_pInt, 7963_pInt, 7993_pInt, 8009_pInt, 8011_pInt, 8017_pInt, & - 8039_pInt, 8053_pInt, 8059_pInt, 8069_pInt, 8081_pInt, 8087_pInt, 8089_pInt, 8093_pInt, 8101_pInt, 8111_pInt, & - 8117_pInt, 8123_pInt, 8147_pInt, 8161_pInt, 8167_pInt, 8171_pInt, 8179_pInt, 8191_pInt, 8209_pInt, 8219_pInt, & - 8221_pInt, 8231_pInt, 8233_pInt, 8237_pInt, 8243_pInt, 8263_pInt, 8269_pInt, 8273_pInt, 8287_pInt, 8291_pInt, & - 8293_pInt, 8297_pInt, 8311_pInt, 8317_pInt, 8329_pInt, 8353_pInt, 8363_pInt, 8369_pInt, 8377_pInt, 8387_pInt, & - 8389_pInt, 8419_pInt, 8423_pInt, 8429_pInt, 8431_pInt, 8443_pInt, 8447_pInt, 8461_pInt, 8467_pInt, 8501_pInt, & - 8513_pInt, 8521_pInt, 8527_pInt, 8537_pInt, 8539_pInt, 8543_pInt, 8563_pInt, 8573_pInt, 8581_pInt, 8597_pInt, & - 8599_pInt, 8609_pInt, 8623_pInt, 8627_pInt, 8629_pInt, 8641_pInt, 8647_pInt, 8663_pInt, 8669_pInt, 8677_pInt, & - 8681_pInt, 8689_pInt, 8693_pInt, 8699_pInt, 8707_pInt, 8713_pInt, 8719_pInt, 8731_pInt, 8737_pInt, 8741_pInt, & - 8747_pInt, 8753_pInt, 8761_pInt, 8779_pInt, 8783_pInt, 8803_pInt, 8807_pInt, 8819_pInt, 8821_pInt, 8831_pInt, & - ! 1101:1200 - 8837_pInt, 8839_pInt, 8849_pInt, 8861_pInt, 8863_pInt, 8867_pInt, 8887_pInt, 8893_pInt, 8923_pInt, 8929_pInt, & - 8933_pInt, 8941_pInt, 8951_pInt, 8963_pInt, 8969_pInt, 8971_pInt, 8999_pInt, 9001_pInt, 9007_pInt, 9011_pInt, & - 9013_pInt, 9029_pInt, 9041_pInt, 9043_pInt, 9049_pInt, 9059_pInt, 9067_pInt, 9091_pInt, 9103_pInt, 9109_pInt, & - 9127_pInt, 9133_pInt, 9137_pInt, 9151_pInt, 9157_pInt, 9161_pInt, 9173_pInt, 9181_pInt, 9187_pInt, 9199_pInt, & - 9203_pInt, 9209_pInt, 9221_pInt, 9227_pInt, 9239_pInt, 9241_pInt, 9257_pInt, 9277_pInt, 9281_pInt, 9283_pInt, & - 9293_pInt, 9311_pInt, 9319_pInt, 9323_pInt, 9337_pInt, 9341_pInt, 9343_pInt, 9349_pInt, 9371_pInt, 9377_pInt, & - 9391_pInt, 9397_pInt, 9403_pInt, 9413_pInt, 9419_pInt, 9421_pInt, 9431_pInt, 9433_pInt, 9437_pInt, 9439_pInt, & - 9461_pInt, 9463_pInt, 9467_pInt, 9473_pInt, 9479_pInt, 9491_pInt, 9497_pInt, 9511_pInt, 9521_pInt, 9533_pInt, & - 9539_pInt, 9547_pInt, 9551_pInt, 9587_pInt, 9601_pInt, 9613_pInt, 9619_pInt, 9623_pInt, 9629_pInt, 9631_pInt, & - 9643_pInt, 9649_pInt, 9661_pInt, 9677_pInt, 9679_pInt, 9689_pInt, 9697_pInt, 9719_pInt, 9721_pInt, 9733_pInt, & - ! 1201:1300 - 9739_pInt, 9743_pInt, 9749_pInt, 9767_pInt, 9769_pInt, 9781_pInt, 9787_pInt, 9791_pInt, 9803_pInt, 9811_pInt, & - 9817_pInt, 9829_pInt, 9833_pInt, 9839_pInt, 9851_pInt, 9857_pInt, 9859_pInt, 9871_pInt, 9883_pInt, 9887_pInt, & - 9901_pInt, 9907_pInt, 9923_pInt, 9929_pInt, 9931_pInt, 9941_pInt, 9949_pInt, 9967_pInt, 9973_pInt,10007_pInt, & - 10009_pInt,10037_pInt,10039_pInt,10061_pInt,10067_pInt,10069_pInt,10079_pInt,10091_pInt,10093_pInt,10099_pInt, & - 10103_pInt,10111_pInt,10133_pInt,10139_pInt,10141_pInt,10151_pInt,10159_pInt,10163_pInt,10169_pInt,10177_pInt, & - 10181_pInt,10193_pInt,10211_pInt,10223_pInt,10243_pInt,10247_pInt,10253_pInt,10259_pInt,10267_pInt,10271_pInt, & - 10273_pInt,10289_pInt,10301_pInt,10303_pInt,10313_pInt,10321_pInt,10331_pInt,10333_pInt,10337_pInt,10343_pInt, & - 10357_pInt,10369_pInt,10391_pInt,10399_pInt,10427_pInt,10429_pInt,10433_pInt,10453_pInt,10457_pInt,10459_pInt, & - 10463_pInt,10477_pInt,10487_pInt,10499_pInt,10501_pInt,10513_pInt,10529_pInt,10531_pInt,10559_pInt,10567_pInt, & - 10589_pInt,10597_pInt,10601_pInt,10607_pInt,10613_pInt,10627_pInt,10631_pInt,10639_pInt,10651_pInt,10657_pInt, & - ! 1301:1400 - 10663_pInt,10667_pInt,10687_pInt,10691_pInt,10709_pInt,10711_pInt,10723_pInt,10729_pInt,10733_pInt,10739_pInt, & - 10753_pInt,10771_pInt,10781_pInt,10789_pInt,10799_pInt,10831_pInt,10837_pInt,10847_pInt,10853_pInt,10859_pInt, & - 10861_pInt,10867_pInt,10883_pInt,10889_pInt,10891_pInt,10903_pInt,10909_pInt,19037_pInt,10939_pInt,10949_pInt, & - 10957_pInt,10973_pInt,10979_pInt,10987_pInt,10993_pInt,11003_pInt,11027_pInt,11047_pInt,11057_pInt,11059_pInt, & - 11069_pInt,11071_pInt,11083_pInt,11087_pInt,11093_pInt,11113_pInt,11117_pInt,11119_pInt,11131_pInt,11149_pInt, & - 11159_pInt,11161_pInt,11171_pInt,11173_pInt,11177_pInt,11197_pInt,11213_pInt,11239_pInt,11243_pInt,11251_pInt, & - 11257_pInt,11261_pInt,11273_pInt,11279_pInt,11287_pInt,11299_pInt,11311_pInt,11317_pInt,11321_pInt,11329_pInt, & - 11351_pInt,11353_pInt,11369_pInt,11383_pInt,11393_pInt,11399_pInt,11411_pInt,11423_pInt,11437_pInt,11443_pInt, & - 11447_pInt,11467_pInt,11471_pInt,11483_pInt,11489_pInt,11491_pInt,11497_pInt,11503_pInt,11519_pInt,11527_pInt, & - 11549_pInt,11551_pInt,11579_pInt,11587_pInt,11593_pInt,11597_pInt,11617_pInt,11621_pInt,11633_pInt,11657_pInt, & - ! 1401:1500 - 11677_pInt,11681_pInt,11689_pInt,11699_pInt,11701_pInt,11717_pInt,11719_pInt,11731_pInt,11743_pInt,11777_pInt, & - 11779_pInt,11783_pInt,11789_pInt,11801_pInt,11807_pInt,11813_pInt,11821_pInt,11827_pInt,11831_pInt,11833_pInt, & - 11839_pInt,11863_pInt,11867_pInt,11887_pInt,11897_pInt,11903_pInt,11909_pInt,11923_pInt,11927_pInt,11933_pInt, & - 11939_pInt,11941_pInt,11953_pInt,11959_pInt,11969_pInt,11971_pInt,11981_pInt,11987_pInt,12007_pInt,12011_pInt, & - 12037_pInt,12041_pInt,12043_pInt,12049_pInt,12071_pInt,12073_pInt,12097_pInt,12101_pInt,12107_pInt,12109_pInt, & - 12113_pInt,12119_pInt,12143_pInt,12149_pInt,12157_pInt,12161_pInt,12163_pInt,12197_pInt,12203_pInt,12211_pInt, & - 12227_pInt,12239_pInt,12241_pInt,12251_pInt,12253_pInt,12263_pInt,12269_pInt,12277_pInt,12281_pInt,12289_pInt, & - 12301_pInt,12323_pInt,12329_pInt,12343_pInt,12347_pInt,12373_pInt,12377_pInt,12379_pInt,12391_pInt,12401_pInt, & - 12409_pInt,12413_pInt,12421_pInt,12433_pInt,12437_pInt,12451_pInt,12457_pInt,12473_pInt,12479_pInt,12487_pInt, & - 12491_pInt,12497_pInt,12503_pInt,12511_pInt,12517_pInt,12527_pInt,12539_pInt,12541_pInt,12547_pInt,12553_pInt] - endif - - if(n < 0_pInt) then - prime = PRIME_MAX - else if (n == 0_pInt) then - prime = 1_pInt - else if (n <= PRIME_MAX) then - prime = npvec(n) - else - prime = -1_pInt - call IO_error(error_ID=406_pInt) - end if - -end function prime - - -!-------------------------------------------------------------------------------------------------- -!> @brief factorial -!-------------------------------------------------------------------------------------------------- -integer(pInt) pure function math_factorial(n) - - implicit none - integer(pInt), intent(in) :: n - integer(pInt) :: i - - math_factorial = product([(i, i=1,n)]) - -end function math_factorial - - -!-------------------------------------------------------------------------------------------------- -!> @brief binomial coefficient -!-------------------------------------------------------------------------------------------------- -integer(pInt) pure function math_binomial(n,k) - - implicit none - integer(pInt), intent(in) :: n, k - integer(pInt) :: i, j - - j = min(k,n-k) - math_binomial = product([(i, i=n, n-j+1, -1)])/math_factorial(j) - -end function math_binomial - - -!-------------------------------------------------------------------------------------------------- -!> @brief multinomial coefficient -!-------------------------------------------------------------------------------------------------- -integer(pInt) pure function math_multinomial(alpha) - - implicit none - integer(pInt), intent(in), dimension(:) :: alpha - integer(pInt) :: i - - math_multinomial = 1_pInt - do i = 1, size(alpha) - math_multinomial = math_multinomial*math_binomial(sum(alpha(1:i)),alpha(i)) - enddo - -end function math_multinomial - - -!-------------------------------------------------------------------------------------------------- -!> @brief volume of tetrahedron given by four vertices -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_volTetrahedron(v1,v2,v3,v4) - - implicit none - real(pReal), dimension (3), intent(in) :: v1,v2,v3,v4 - real(pReal), dimension (3,3) :: m - - m(1:3,1) = v1-v2 - m(1:3,2) = v2-v3 - m(1:3,3) = v3-v4 - - math_volTetrahedron = math_det33(m)/6.0_pReal - -end function math_volTetrahedron - - -!-------------------------------------------------------------------------------------------------- -!> @brief area of triangle given by three vertices -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_areaTriangle(v1,v2,v3) - - implicit none - real(pReal), dimension (3), intent(in) :: v1,v2,v3 - - math_areaTriangle = 0.5_pReal * norm2(math_crossproduct(v1-v2,v1-v3)) - -end function math_areaTriangle - - -!-------------------------------------------------------------------------------------------------- -!> @brief rotate 33 tensor forward -!-------------------------------------------------------------------------------------------------- -pure function math_rotate_forward33(tensor,rot_tensor) - - implicit none - - real(pReal), dimension(3,3) :: math_rotate_forward33 - real(pReal), dimension(3,3), intent(in) :: tensor, rot_tensor - - math_rotate_forward33 = math_mul33x33(rot_tensor,& - math_mul33x33(tensor,math_transpose33(rot_tensor))) - -end function math_rotate_forward33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief rotate 33 tensor backward -!-------------------------------------------------------------------------------------------------- -pure function math_rotate_backward33(tensor,rot_tensor) - - implicit none - real(pReal), dimension(3,3) :: math_rotate_backward33 - real(pReal), dimension(3,3), intent(in) :: tensor, rot_tensor - - math_rotate_backward33 = math_mul33x33(math_transpose33(rot_tensor),& - math_mul33x33(tensor,rot_tensor)) - -end function math_rotate_backward33 - - -!-------------------------------------------------------------------------------------------------- -!> @brief rotate 3333 tensor C'_ijkl=g_im*g_jn*g_ko*g_lp*C_mnop -!-------------------------------------------------------------------------------------------------- -pure function math_rotate_forward3333(tensor,rot_tensor) - - implicit none - real(pReal), dimension(3,3,3,3) :: math_rotate_forward3333 - real(pReal), dimension(3,3), intent(in) :: rot_tensor - real(pReal), dimension(3,3,3,3), intent(in) :: tensor - integer(pInt) :: i,j,k,l,m,n,o,p - - math_rotate_forward3333= 0.0_pReal - - do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt; do k = 1_pInt,3_pInt; do l = 1_pInt,3_pInt - do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt; do p = 1_pInt,3_pInt - math_rotate_forward3333(i,j,k,l) = math_rotate_forward3333(i,j,k,l) & - + rot_tensor(m,i) * rot_tensor(n,j) & - * rot_tensor(o,k) * rot_tensor(p,l) * tensor(m,n,o,p) - enddo; enddo; enddo; enddo; enddo; enddo; enddo; enddo - -end function math_rotate_forward3333 - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate average of tensor field -!-------------------------------------------------------------------------------------------------- -function math_tensorAvg(field) - - implicit none - real(pReal), dimension(3,3) :: math_tensorAvg - real(pReal), intent(in), dimension(:,:,:,:,:) :: field - real(pReal) :: wgt - - wgt = 1.0_pReal/real(size(field,3)*size(field,4)*size(field,5), pReal) - math_tensorAvg = sum(sum(sum(field,dim=5),dim=4),dim=3)*wgt - -end function math_tensorAvg - - -!-------------------------------------------------------------------------------------------------- -!> @brief limits a scalar value to a certain range (either one or two sided) -! Will return NaN if left > right -!-------------------------------------------------------------------------------------------------- -real(pReal) pure function math_limit(a, left, right) - use prec, only: & - DAMASK_NaN - - implicit none - real(pReal), intent(in) :: a - real(pReal), intent(in), optional :: left, right - - - math_limit = min ( & - max (merge(left, -huge(a), present(left)), a), & - merge(right, huge(a), present(right)) & - ) - - if (present(left) .and. present(right)) math_limit = merge (DAMASK_NaN,math_limit, left>right) - -end function math_limit - -end module math diff --git a/code/mesh.f90 b/code/mesh.f90 deleted file mode 100644 index 1cd80a625..000000000 --- a/code/mesh.f90 +++ /dev/null @@ -1,4784 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Christoph Koords, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Krishna Komerla, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Sets up the mesh for the solvers MSC.Marc, Abaqus and the spectral solver -!-------------------------------------------------------------------------------------------------- -module mesh - use, intrinsic :: iso_c_binding - use prec, only: pReal, pInt - - implicit none - private - integer(pInt), public, protected :: & - mesh_NcpElems, & !< total number of CP elements in local mesh - mesh_NelemSets, & - mesh_maxNelemInSet, & - mesh_Nmaterials, & - mesh_Nnodes, & !< total number of nodes in mesh - mesh_Ncellnodes, & !< total number of cell nodes in mesh (including duplicates) - mesh_Ncells, & !< total number of cells in mesh - mesh_maxNnodes, & !< max number of nodes in any CP element - mesh_maxNips, & !< max number of IPs in any CP element - mesh_maxNipNeighbors, & !< max number of IP neighbors in any CP element - mesh_maxNsharedElems, & !< max number of CP elements sharing a node - mesh_maxNcellnodes, & !< max number of cell nodes in any CP element - mesh_Nelems !< total number of elements in mesh - -#ifdef Spectral - integer(pInt), dimension(3), public, protected :: & - grid !< (global) grid - integer(pInt), public, protected :: & - mesh_NcpElemsGlobal, & !< total number of CP elements in global mesh - grid3, & !< (local) grid in 3rd direction - grid3Offset !< (local) grid offset in 3rd direction - real(pReal), dimension(3), public, protected :: & - geomSize - real(pReal), public, protected :: & - size3, & !< (local) size in 3rd direction - size3offset !< (local) size offset in 3rd direction -#endif - - integer(pInt), dimension(:,:), allocatable, public, protected :: & - mesh_element, & !< FEid, type(internal representation), material, texture, node indices as CP IDs - mesh_sharedElem, & !< entryCount and list of elements containing node - mesh_nodeTwins !< node twins are surface nodes that lie exactly on opposite sides of the mesh (surfaces nodes with equal coordinate values in two dimensions) - - integer(pInt), dimension(:,:,:,:), allocatable, public, protected :: & - mesh_ipNeighborhood !< 6 or less neighboring IPs as [element_num, IP_index, neighbor_index that points to me] - - real(pReal), public, protected :: & - mesh_unitlength !< physical length of one unit in mesh - - real(pReal), dimension(:,:), allocatable, public :: & - mesh_node, & !< node x,y,z coordinates (after deformation! ONLY FOR MARC!!!) - mesh_cellnode !< cell node x,y,z coordinates (after deformation! ONLY FOR MARC!!!) - - real(pReal), dimension(:,:), allocatable, public, protected :: & - mesh_ipVolume, & !< volume associated with IP (initially!) - mesh_node0 !< node x,y,z coordinates (initially!) - - real(pReal), dimension(:,:,:), allocatable, public, protected :: & - mesh_ipArea !< area of interface to neighboring IP (initially!) - - real(pReal), dimension(:,:,:), allocatable, public :: & - mesh_ipCoordinates !< IP x,y,z coordinates (after deformation!) - - real(pReal),dimension(:,:,:,:), allocatable, public, protected :: & - mesh_ipAreaNormal !< area normal of interface to neighboring IP (initially!) - - logical, dimension(3), public, protected :: mesh_periodicSurface !< flag indicating periodic outer surfaces (used for fluxes) - -#ifdef Marc4DAMASK - integer(pInt), private :: & - hypoelasticTableStyle, & !< Table style (Marc only) - initialcondTableStyle !< Table style (Marc only) -#endif - - integer(pInt), dimension(2), private :: & - mesh_maxValStateVar = 0_pInt - -#ifndef Spectral - character(len=64), dimension(:), allocatable, private :: & - mesh_nameElemSet, & !< names of elementSet - mesh_nameMaterial, & !< names of material in solid section - mesh_mapMaterial !< name of elementSet for material - - integer(pInt), dimension(:,:), allocatable, private :: & - mesh_mapElemSet !< list of elements in elementSet -#endif - integer(pInt), dimension(:,:), allocatable, private :: & - mesh_cellnodeParent !< cellnode's parent element ID, cellnode's intra-element ID - - integer(pInt), dimension(:,:), allocatable, target, private :: & - mesh_mapFEtoCPelem, & !< [sorted FEid, corresponding CPid] - mesh_mapFEtoCPnode !< [sorted FEid, corresponding CPid] - - integer(pInt),dimension(:,:,:), allocatable, private :: & - mesh_cell !< cell connectivity for each element,ip/cell - - integer(pInt), dimension(:,:,:), allocatable, private :: & - FE_nodesAtIP, & !< map IP index to node indices in a specific type of element - FE_ipNeighbor, & !< +x,-x,+y,-y,+z,-z list of intra-element IPs and(negative) neighbor faces per own IP in a specific type of element - FE_cell, & !< list of intra-element cell node IDs that constitute the cells in a specific type of element geometry - FE_cellface !< list of intra-cell cell node IDs that constitute the cell faces of a specific type of cell - - real(pReal), dimension(:,:,:), allocatable, private :: & - FE_cellnodeParentnodeWeights !< list of node weights for the generation of cell nodes - - integer(pInt), dimension(:,:,:,:), allocatable, private :: & - FE_subNodeOnIPFace - -#ifdef Abaqus - logical, private :: noPart !< for cases where the ABAQUS input file does not use part/assembly information -#endif - -#ifdef Spectral -#ifdef PETSc -#include - include 'fftw3-mpi.f03' -#else - include 'fftw3.f03' -#endif -#endif - -! These definitions should actually reside in the FE-solver specific part (different for MARC/ABAQUS) -! Hence, I suggest to prefix with "FE_" - - integer(pInt), parameter, public :: & - FE_Nelemtypes = 13_pInt, & - FE_Ngeomtypes = 10_pInt, & - FE_Ncelltypes = 4_pInt, & - FE_maxNnodes = 20_pInt, & - FE_maxNips = 27_pInt, & - FE_maxNipNeighbors = 6_pInt, & - FE_maxmaxNnodesAtIP = 8_pInt, & !< max number of (equivalent) nodes attached to an IP - FE_maxNmatchingNodesPerFace = 4_pInt, & - FE_maxNfaces = 6_pInt, & - FE_maxNcellnodes = 64_pInt, & - FE_maxNcellnodesPerCell = 8_pInt, & - FE_maxNcellfaces = 6_pInt, & - FE_maxNcellnodesPerCellface = 4_pInt - - integer(pInt), dimension(FE_Nelemtypes), parameter, public :: FE_geomtype = & !< geometry type of particular element type - int([ & - 1, & ! element 6 (2D 3node 1ip) - 2, & ! element 125 (2D 6node 3ip) - 3, & ! element 11 (2D 4node 4ip) - 4, & ! element 27 (2D 8node 9ip) - 3, & ! element 54 (2D 8node 4ip) - 5, & ! element 134 (3D 4node 1ip) - 6, & ! element 157 (3D 5node 4ip) - 6, & ! element 127 (3D 10node 4ip) - 7, & ! element 136 (3D 6node 6ip) - 8, & ! element 117 (3D 8node 1ip) - 9, & ! element 7 (3D 8node 8ip) - 9, & ! element 57 (3D 20node 8ip) - 10 & ! element 21 (3D 20node 27ip) - ],pInt) - - integer(pInt), dimension(FE_Ngeomtypes), parameter, public :: FE_celltype = & !< cell type that is used by each geometry type - int([ & - 1, & ! element 6 (2D 3node 1ip) - 2, & ! element 125 (2D 6node 3ip) - 2, & ! element 11 (2D 4node 4ip) - 2, & ! element 27 (2D 8node 9ip) - 3, & ! element 134 (3D 4node 1ip) - 4, & ! element 127 (3D 10node 4ip) - 4, & ! element 136 (3D 6node 6ip) - 4, & ! element 117 (3D 8node 1ip) - 4, & ! element 7 (3D 8node 8ip) - 4 & ! element 21 (3D 20node 27ip) - ],pInt) - - integer(pInt), dimension(FE_Ngeomtypes), parameter, public :: FE_dimension = & !< dimension of geometry type - int([ & - 2, & ! element 6 (2D 3node 1ip) - 2, & ! element 125 (2D 6node 3ip) - 2, & ! element 11 (2D 4node 4ip) - 2, & ! element 27 (2D 8node 9ip) - 3, & ! element 134 (3D 4node 1ip) - 3, & ! element 127 (3D 10node 4ip) - 3, & ! element 136 (3D 6node 6ip) - 3, & ! element 117 (3D 8node 1ip) - 3, & ! element 7 (3D 8node 8ip) - 3 & ! element 21 (3D 20node 27ip) - ],pInt) - - integer(pInt), dimension(FE_Nelemtypes), parameter, public :: FE_Nnodes = & !< number of nodes that constitute a specific type of element - int([ & - 3, & ! element 6 (2D 3node 1ip) - 6, & ! element 125 (2D 6node 3ip) - 4, & ! element 11 (2D 4node 4ip) - 8, & ! element 27 (2D 8node 9ip) - 8, & ! element 54 (2D 8node 4ip) - 4, & ! element 134 (3D 4node 1ip) - 5, & ! element 157 (3D 5node 4ip) - 10, & ! element 127 (3D 10node 4ip) - 6, & ! element 136 (3D 6node 6ip) - 8, & ! element 117 (3D 8node 1ip) - 8, & ! element 7 (3D 8node 8ip) - 20, & ! element 57 (3D 20node 8ip) - 20 & ! element 21 (3D 20node 27ip) - ],pInt) - - integer(pInt), dimension(FE_Ngeomtypes), parameter, public :: FE_Nfaces = & !< number of faces of a specific type of element geometry - int([ & - 3, & ! element 6 (2D 3node 1ip) - 3, & ! element 125 (2D 6node 3ip) - 4, & ! element 11 (2D 4node 4ip) - 4, & ! element 27 (2D 8node 9ip) - 4, & ! element 134 (3D 4node 1ip) - 4, & ! element 127 (3D 10node 4ip) - 5, & ! element 136 (3D 6node 6ip) - 6, & ! element 117 (3D 8node 1ip) - 6, & ! element 7 (3D 8node 8ip) - 6 & ! element 21 (3D 20node 27ip) - ],pInt) - - integer(pInt), dimension(FE_Ngeomtypes), parameter, private :: FE_NmatchingNodes = & !< number of nodes that are needed for face matching in a specific type of element geometry - int([ & - 3, & ! element 6 (2D 3node 1ip) - 3, & ! element 125 (2D 6node 3ip) - 4, & ! element 11 (2D 4node 4ip) - 4, & ! element 27 (2D 8node 9ip) - 4, & ! element 134 (3D 4node 1ip) - 4, & ! element 127 (3D 10node 4ip) - 6, & ! element 136 (3D 6node 6ip) - 8, & ! element 117 (3D 8node 1ip) - 8, & ! element 7 (3D 8node 8ip) - 8 & ! element 21 (3D 20node 27ip) - ],pInt) - - integer(pInt), dimension(FE_maxNfaces,FE_Ngeomtypes), parameter, private :: & - FE_NmatchingNodesPerFace = & !< number of matching nodes per face in a specific type of element geometry - reshape(int([ & - 2,2,2,0,0,0, & ! element 6 (2D 3node 1ip) - 2,2,2,0,0,0, & ! element 125 (2D 6node 3ip) - 2,2,2,2,0,0, & ! element 11 (2D 4node 4ip) - 2,2,2,2,0,0, & ! element 27 (2D 8node 9ip) - 3,3,3,3,0,0, & ! element 134 (3D 4node 1ip) - 3,3,3,3,0,0, & ! element 127 (3D 10node 4ip) - 3,4,4,4,3,0, & ! element 136 (3D 6node 6ip) - 4,4,4,4,4,4, & ! element 117 (3D 8node 1ip) - 4,4,4,4,4,4, & ! element 7 (3D 8node 8ip) - 4,4,4,4,4,4 & ! element 21 (3D 20node 27ip) - ],pInt),[FE_maxNipNeighbors,FE_Ngeomtypes]) - - integer(pInt), dimension(FE_maxNmatchingNodesPerFace,FE_maxNfaces,FE_Ngeomtypes), & - parameter, private :: FE_face = & !< List of node indices on each face of a specific type of element geometry - reshape(int([& - 1,2,0,0 , & ! element 6 (2D 3node 1ip) - 2,3,0,0 , & - 3,1,0,0 , & - 0,0,0,0 , & - 0,0,0,0 , & - 0,0,0,0 , & - 1,2,0,0 , & ! element 125 (2D 6node 3ip) - 2,3,0,0 , & - 3,1,0,0 , & - 0,0,0,0 , & - 0,0,0,0 , & - 0,0,0,0 , & - 1,2,0,0 , & ! element 11 (2D 4node 4ip) - 2,3,0,0 , & - 3,4,0,0 , & - 4,1,0,0 , & - 0,0,0,0 , & - 0,0,0,0 , & - 1,2,0,0 , & ! element 27 (2D 8node 9ip) - 2,3,0,0 , & - 3,4,0,0 , & - 4,1,0,0 , & - 0,0,0,0 , & - 0,0,0,0 , & - 1,2,3,0 , & ! element 134 (3D 4node 1ip) - 1,4,2,0 , & - 2,3,4,0 , & - 1,3,4,0 , & - 0,0,0,0 , & - 0,0,0,0 , & - 1,2,3,0 , & ! element 127 (3D 10node 4ip) - 1,4,2,0 , & - 2,4,3,0 , & - 1,3,4,0 , & - 0,0,0,0 , & - 0,0,0,0 , & - 1,2,3,0 , & ! element 136 (3D 6node 6ip) - 1,4,5,2 , & - 2,5,6,3 , & - 1,3,6,4 , & - 4,6,5,0 , & - 0,0,0,0 , & - 1,2,3,4 , & ! element 117 (3D 8node 1ip) - 2,1,5,6 , & - 3,2,6,7 , & - 4,3,7,8 , & - 4,1,5,8 , & - 8,7,6,5 , & - 1,2,3,4 , & ! element 7 (3D 8node 8ip) - 2,1,5,6 , & - 3,2,6,7 , & - 4,3,7,8 , & - 4,1,5,8 , & - 8,7,6,5 , & - 1,2,3,4 , & ! element 21 (3D 20node 27ip) - 2,1,5,6 , & - 3,2,6,7 , & - 4,3,7,8 , & - 4,1,5,8 , & - 8,7,6,5 & - ],pInt),[FE_maxNmatchingNodesPerFace,FE_maxNfaces,FE_Ngeomtypes]) - - integer(pInt), dimension(FE_Ngeomtypes), parameter, private :: FE_Ncellnodes = & !< number of cell nodes in a specific geometry type - int([ & - 3, & ! element 6 (2D 3node 1ip) - 7, & ! element 125 (2D 6node 3ip) - 9, & ! element 11 (2D 4node 4ip) - 16, & ! element 27 (2D 8node 9ip) - 4, & ! element 134 (3D 4node 1ip) - 15, & ! element 127 (3D 10node 4ip) - 21, & ! element 136 (3D 6node 6ip) - 8, & ! element 117 (3D 8node 1ip) - 27, & ! element 7 (3D 8node 8ip) - 64 & ! element 21 (3D 20node 27ip) - ],pInt) - - integer(pInt), dimension(FE_Ncelltypes), parameter, private :: FE_NcellnodesPerCell = & !< number of cell nodes in a specific cell type - int([ & - 3, & ! (2D 3node) - 4, & ! (2D 4node) - 4, & ! (3D 4node) - 8 & ! (3D 8node) - ],pInt) - - integer(pInt), dimension(FE_Ncelltypes), parameter, private :: FE_NcellnodesPerCellface = & !< number of cell nodes per cell face in a specific cell type - int([& - 2, & ! (2D 3node) - 2, & ! (2D 4node) - 3, & ! (3D 4node) - 4 & ! (3D 8node) - ],pInt) - - integer(pInt), dimension(FE_Ngeomtypes), parameter, public :: FE_Nips = & !< number of IPs in a specific type of element - int([ & - 1, & ! element 6 (2D 3node 1ip) - 3, & ! element 125 (2D 6node 3ip) - 4, & ! element 11 (2D 4node 4ip) - 9, & ! element 27 (2D 8node 9ip) - 1, & ! element 134 (3D 4node 1ip) - 4, & ! element 127 (3D 10node 4ip) - 6, & ! element 136 (3D 6node 6ip) - 1, & ! element 117 (3D 8node 1ip) - 8, & ! element 7 (3D 8node 8ip) - 27 & ! element 21 (3D 20node 27ip) - ],pInt) - - integer(pInt), dimension(FE_Ncelltypes), parameter, public :: FE_NipNeighbors = & !< number of ip neighbors / cell faces in a specific cell type - int([& - 3, & ! (2D 3node) - 4, & ! (2D 4node) - 4, & ! (3D 4node) - 6 & ! (3D 8node) - ],pInt) - - - integer(pInt), dimension(FE_Ngeomtypes), parameter, private :: FE_maxNnodesAtIP = & !< maximum number of parent nodes that belong to an IP for a specific type of element - int([ & - 3, & ! element 6 (2D 3node 1ip) - 1, & ! element 125 (2D 6node 3ip) - 1, & ! element 11 (2D 4node 4ip) - 2, & ! element 27 (2D 8node 9ip) - 4, & ! element 134 (3D 4node 1ip) - 1, & ! element 127 (3D 10node 4ip) - 1, & ! element 136 (3D 6node 6ip) - 8, & ! element 117 (3D 8node 1ip) - 1, & ! element 7 (3D 8node 8ip) - 4 & ! element 21 (3D 20node 27ip) - ],pInt) - - - integer(pInt), dimension(FE_Nelemtypes), parameter, private :: MESH_VTKELEMTYPE = & - int([ & - 5, & ! element 6 (2D 3node 1ip) - 22, & ! element 125 (2D 6node 3ip) - 9, & ! element 11 (2D 4node 4ip) - 23, & ! element 27 (2D 8node 9ip) - 23, & ! element 54 (2D 8node 4ip) - 10, & ! element 134 (3D 4node 1ip) - 10, & ! element 157 (3D 5node 4ip) - 24, & ! element 127 (3D 10node 4ip) - 13, & ! element 136 (3D 6node 6ip) - 12, & ! element 117 (3D 8node 1ip) - 12, & ! element 7 (3D 8node 8ip) - 25, & ! element 57 (3D 20node 8ip) - 25 & ! element 21 (3D 20node 27ip) - ],pInt) - - integer(pInt), dimension(FE_Ncelltypes), parameter, private :: MESH_VTKCELLTYPE = & - int([ & - 5, & ! (2D 3node) - 9, & ! (2D 4node) - 10, & ! (3D 4node) - 12 & ! (3D 8node) - ],pInt) - - - public :: & - mesh_init, & - mesh_FEasCP, & - mesh_build_cellnodes, & - mesh_build_ipVolumes, & - mesh_build_ipCoordinates, & - mesh_cellCenterCoordinates, & - mesh_init_postprocessing, & - mesh_get_Ncellnodes, & - mesh_get_unitlength, & - mesh_get_nodeAtIP -#ifdef Spectral - public :: & - mesh_spectral_getGrid, & - mesh_spectral_getSize, & - mesh_nodesAroundCentres, & - mesh_deformedCoordsFFT, & - mesh_volumeMismatch, & - mesh_shapeMismatch -#endif - - private :: & -#ifdef Spectral - mesh_spectral_getHomogenization, & - mesh_spectral_count, & - mesh_spectral_mapNodesAndElems, & - mesh_spectral_count_cpSizes, & - mesh_spectral_build_nodes, & - mesh_spectral_build_elements, & - mesh_spectral_build_ipNeighborhood, & -#endif -#ifdef Marc4DAMASK - mesh_marc_get_tableStyles, & - mesh_marc_count_nodesAndElements, & - mesh_marc_count_elementSets, & - mesh_marc_map_elementSets, & - mesh_marc_count_cpElements, & - mesh_marc_map_Elements, & - mesh_marc_map_nodes, & - mesh_marc_build_nodes, & - mesh_marc_count_cpSizes, & - mesh_marc_build_elements, & -#endif -#ifdef Abaqus - mesh_abaqus_count_nodesAndElements, & - mesh_abaqus_count_elementSets, & - mesh_abaqus_count_materials, & - mesh_abaqus_map_elementSets, & - mesh_abaqus_map_materials, & - mesh_abaqus_count_cpElements, & - mesh_abaqus_map_elements, & - mesh_abaqus_map_nodes, & - mesh_abaqus_build_nodes, & - mesh_abaqus_count_cpSizes, & - mesh_abaqus_build_elements, & -#endif -#ifndef Spectral - mesh_build_nodeTwins, & - mesh_build_sharedElems, & - mesh_build_ipNeighborhood, & -#endif - mesh_get_damaskOptions, & - mesh_build_cellconnectivity, & - mesh_build_ipAreas, & - mesh_tell_statistics, & - FE_mapElemtype, & - mesh_faceMatch, & - mesh_build_FEdata, & - mesh_write_cellGeom, & - mesh_write_elemGeom, & - mesh_write_meshfile, & - mesh_read_meshfile - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief initializes the mesh by calling all necessary private routines the mesh module -!! Order and routines strongly depend on type of solver -!-------------------------------------------------------------------------------------------------- -subroutine mesh_init(ip,el) -#ifdef Spectral - use, intrinsic :: iso_c_binding -#endif - use DAMASK_interface - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & -#ifdef Abaqus - IO_abaqus_hasNoPart, & -#endif -#ifdef Spectral - IO_open_file, & -#else - IO_open_InputFile, & -#endif - IO_timeStamp, & - IO_error, & - IO_write_jobFile - use debug, only: & - debug_e, & - debug_i, & - debug_level, & - debug_mesh, & - debug_levelBasic - use numerics, only: & - usePingPong, & - numerics_unitlength, & - worldrank - use FEsolving, only: & - FEsolving_execElem, & -#ifndef Spectral - modelName, & -#endif - FEsolving_execIP, & - calcMode - - implicit none -#ifdef Spectral - integer(C_INTPTR_T) :: gridMPI(3), alloc_local, local_K, local_K_offset -#endif - integer(pInt), parameter :: FILEUNIT = 222_pInt - integer(pInt), intent(in) :: el, ip - integer(pInt) :: j - logical :: myDebug - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- mesh init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - if (allocated(mesh_mapFEtoCPelem)) deallocate(mesh_mapFEtoCPelem) - if (allocated(mesh_mapFEtoCPnode)) deallocate(mesh_mapFEtoCPnode) - if (allocated(mesh_node0)) deallocate(mesh_node0) - if (allocated(mesh_node)) deallocate(mesh_node) - if (allocated(mesh_element)) deallocate(mesh_element) - if (allocated(mesh_cell)) deallocate(mesh_cell) - if (allocated(mesh_cellnode)) deallocate(mesh_cellnode) - if (allocated(mesh_cellnodeParent)) deallocate(mesh_cellnodeParent) - if (allocated(mesh_ipCoordinates)) deallocate(mesh_ipCoordinates) - if (allocated(mesh_ipArea)) deallocate(mesh_ipArea) - if (allocated(mesh_ipAreaNormal)) deallocate(mesh_ipAreaNormal) - if (allocated(mesh_sharedElem)) deallocate(mesh_sharedElem) - if (allocated(mesh_ipNeighborhood)) deallocate(mesh_ipNeighborhood) - if (allocated(mesh_ipVolume)) deallocate(mesh_ipVolume) - if (allocated(mesh_nodeTwins)) deallocate(mesh_nodeTwins) - if (allocated(FE_nodesAtIP)) deallocate(FE_nodesAtIP) - if (allocated(FE_ipNeighbor)) deallocate(FE_ipNeighbor) - if (allocated(FE_cellnodeParentnodeWeights)) deallocate(FE_cellnodeParentnodeWeights) - if (allocated(FE_subNodeOnIPFace)) deallocate(FE_subNodeOnIPFace) - call mesh_build_FEdata ! get properties of the different types of elements - mesh_unitlength = numerics_unitlength ! set physical extent of a length unit in mesh - - myDebug = (iand(debug_level(debug_mesh),debug_levelBasic) /= 0_pInt) - -#ifdef Spectral -#ifdef PETSc - call fftw_mpi_init() -#endif - call IO_open_file(FILEUNIT,geometryFile) ! parse info from geometry file... - if (myDebug) write(6,'(a)') ' Opened geometry file'; flush(6) - grid = mesh_spectral_getGrid(fileUnit) - geomSize = mesh_spectral_getSize(fileUnit) - -#ifdef PETSc - gridMPI = int(grid,C_INTPTR_T) - alloc_local = fftw_mpi_local_size_3d(gridMPI(3), gridMPI(2), gridMPI(1)/2 +1, & - MPI_COMM_WORLD, local_K, local_K_offset) - grid3 = int(local_K,pInt) - grid3Offset = int(local_K_offset,pInt) - - size3 = geomSize(3)*real(grid3,pReal) /real(grid(3),pReal) - size3Offset = geomSize(3)*real(grid3Offset,pReal)/real(grid(3),pReal) -#endif - - if (myDebug) write(6,'(a)') ' Grid partitioned'; flush(6) - call mesh_spectral_count() - if (myDebug) write(6,'(a)') ' Counted nodes/elements'; flush(6) - call mesh_spectral_mapNodesAndElems - if (myDebug) write(6,'(a)') ' Mapped nodes and elements'; flush(6) - call mesh_spectral_count_cpSizes - if (myDebug) write(6,'(a)') ' Built CP statistics'; flush(6) - call mesh_spectral_build_nodes() - if (myDebug) write(6,'(a)') ' Built nodes'; flush(6) - call mesh_spectral_build_elements(FILEUNIT) - if (myDebug) write(6,'(a)') ' Built elements'; flush(6) -#endif -#ifdef Marc4DAMASK - call IO_open_inputFile(FILEUNIT,modelName) ! parse info from input file... - if (myDebug) write(6,'(a)') ' Opened input file'; flush(6) - call mesh_marc_get_tableStyles(FILEUNIT) - if (myDebug) write(6,'(a)') ' Got table styles'; flush(6) - call mesh_marc_count_nodesAndElements(FILEUNIT) - if (myDebug) write(6,'(a)') ' Counted nodes/elements'; flush(6) - call mesh_marc_count_elementSets(FILEUNIT) - if (myDebug) write(6,'(a)') ' Counted element sets'; flush(6) - call mesh_marc_map_elementSets(FILEUNIT) - if (myDebug) write(6,'(a)') ' Mapped element sets'; flush(6) - call mesh_marc_count_cpElements(FILEUNIT) - if (myDebug) write(6,'(a)') ' Counted CP elements'; flush(6) - call mesh_marc_map_elements(FILEUNIT) - if (myDebug) write(6,'(a)') ' Mapped elements'; flush(6) - call mesh_marc_map_nodes(FILEUNIT) - if (myDebug) write(6,'(a)') ' Mapped nodes'; flush(6) - call mesh_marc_build_nodes(FILEUNIT) - if (myDebug) write(6,'(a)') ' Built nodes'; flush(6) - call mesh_marc_count_cpSizes(FILEUNIT) - if (myDebug) write(6,'(a)') ' Counted CP sizes'; flush(6) - call mesh_marc_build_elements(FILEUNIT) - if (myDebug) write(6,'(a)') ' Built elements'; flush(6) -#endif -#ifdef Abaqus - call IO_open_inputFile(FILEUNIT,modelName) ! parse info from input file... - if (myDebug) write(6,'(a)') ' Opened input file'; flush(6) - noPart = IO_abaqus_hasNoPart(FILEUNIT) - call mesh_abaqus_count_nodesAndElements(FILEUNIT) - if (myDebug) write(6,'(a)') ' Counted nodes/elements'; flush(6) - call mesh_abaqus_count_elementSets(FILEUNIT) - if (myDebug) write(6,'(a)') ' Counted element sets'; flush(6) - call mesh_abaqus_count_materials(FILEUNIT) - if (myDebug) write(6,'(a)') ' Counted materials'; flush(6) - call mesh_abaqus_map_elementSets(FILEUNIT) - if (myDebug) write(6,'(a)') ' Mapped element sets'; flush(6) - call mesh_abaqus_map_materials(FILEUNIT) - if (myDebug) write(6,'(a)') ' Mapped materials'; flush(6) - call mesh_abaqus_count_cpElements(FILEUNIT) - if (myDebug) write(6,'(a)') ' Counted CP elements'; flush(6) - call mesh_abaqus_map_elements(FILEUNIT) - if (myDebug) write(6,'(a)') ' Mapped elements'; flush(6) - call mesh_abaqus_map_nodes(FILEUNIT) - if (myDebug) write(6,'(a)') ' Mapped nodes'; flush(6) - call mesh_abaqus_build_nodes(FILEUNIT) - if (myDebug) write(6,'(a)') ' Built nodes'; flush(6) - call mesh_abaqus_count_cpSizes(FILEUNIT) - if (myDebug) write(6,'(a)') ' Counted CP sizes'; flush(6) - call mesh_abaqus_build_elements(FILEUNIT) - if (myDebug) write(6,'(a)') ' Built elements'; flush(6) -#endif - - call mesh_get_damaskOptions(FILEUNIT) - if (myDebug) write(6,'(a)') ' Got DAMASK options'; flush(6) - call mesh_build_cellconnectivity - if (myDebug) write(6,'(a)') ' Built cell connectivity'; flush(6) - mesh_cellnode = mesh_build_cellnodes(mesh_node,mesh_Ncellnodes) - if (myDebug) write(6,'(a)') ' Built cell nodes'; flush(6) - call mesh_build_ipCoordinates - if (myDebug) write(6,'(a)') ' Built IP coordinates'; flush(6) - call mesh_build_ipVolumes - if (myDebug) write(6,'(a)') ' Built IP volumes'; flush(6) - call mesh_build_ipAreas - if (myDebug) write(6,'(a)') ' Built IP areas'; flush(6) - close (FILEUNIT) - -#if defined(Marc4DAMASK) || defined(Abaqus) - call mesh_build_nodeTwins - if (myDebug) write(6,'(a)') ' Built node twins'; flush(6) - call mesh_build_sharedElems - if (myDebug) write(6,'(a)') ' Built shared elements'; flush(6) - call mesh_build_ipNeighborhood -#else - call mesh_spectral_build_ipNeighborhood(FILEUNIT) -#endif - if (myDebug) write(6,'(a)') ' Built IP neighborhood'; flush(6) - - if (worldrank == 0_pInt) then - call mesh_tell_statistics - call mesh_write_meshfile - call mesh_write_cellGeom - call mesh_write_elemGeom - endif - - if (usePingPong .and. (mesh_Nelems /= mesh_NcpElems)) & - call IO_error(600_pInt) ! ping-pong must be disabled when having non-DAMASK elements - if (debug_e < 1 .or. debug_e > mesh_NcpElems) & - call IO_error(602_pInt,ext_msg='element') ! selected element does not exist - if (debug_i < 1 .or. debug_i > FE_Nips(FE_geomtype(mesh_element(2_pInt,debug_e)))) & - call IO_error(602_pInt,ext_msg='IP') ! selected element does not have requested IP - - FEsolving_execElem = [ 1_pInt,mesh_NcpElems ] ! parallel loop bounds set to comprise all DAMASK elements - if (allocated(FEsolving_execIP)) deallocate(FEsolving_execIP) - allocate(FEsolving_execIP(2_pInt,mesh_NcpElems)); FEsolving_execIP = 1_pInt ! parallel loop bounds set to comprise from first IP... - forall (j = 1_pInt:mesh_NcpElems) FEsolving_execIP(2,j) = FE_Nips(FE_geomtype(mesh_element(2,j))) ! ...up to own IP count for each element - - if (allocated(calcMode)) deallocate(calcMode) - allocate(calcMode(mesh_maxNips,mesh_NcpElems)) - calcMode = .false. ! pretend to have collected what first call is asking (F = I) - calcMode(ip,mesh_FEasCP('elem',el)) = .true. ! first ip,el needs to be already pingponged to "calc" - - -end subroutine mesh_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief Gives the FE to CP ID mapping by binary search through lookup array -!! valid questions (what) are 'elem', 'node' -!-------------------------------------------------------------------------------------------------- -integer(pInt) function mesh_FEasCP(what,myID) - use IO, only: & - IO_lc - - implicit none - character(len=*), intent(in) :: what - integer(pInt), intent(in) :: myID - - integer(pInt), dimension(:,:), pointer :: lookupMap - integer(pInt) :: lower,upper,center - - mesh_FEasCP = 0_pInt - select case(IO_lc(what(1:4))) - case('elem') - lookupMap => mesh_mapFEtoCPelem - case('node') - lookupMap => mesh_mapFEtoCPnode - case default - return - endselect - - lower = 1_pInt - upper = int(size(lookupMap,2_pInt),pInt) - - if (lookupMap(1_pInt,lower) == myID) then ! check at bounds QUESTION is it valid to extend bounds by 1 and just do binary search w/o init check at bounds? - mesh_FEasCP = lookupMap(2_pInt,lower) - return - elseif (lookupMap(1_pInt,upper) == myID) then - mesh_FEasCP = lookupMap(2_pInt,upper) - return - endif - ! this might be the reason for the heap problems - binarySearch: do while (upper-lower > 1_pInt) - center = (lower+upper)/2_pInt - if (lookupMap(1_pInt,center) < myID) then - lower = center - elseif (lookupMap(1_pInt,center) > myID) then - upper = center - else - mesh_FEasCP = lookupMap(2_pInt,center) - exit - endif - enddo binarySearch - -end function mesh_FEasCP - - -!-------------------------------------------------------------------------------------------------- -!> @brief Split CP elements into cells. -!> @details Build a mapping between cells and the corresponding cell nodes ('mesh_cell'). -!> Cell nodes that are also matching nodes are unique in the list of cell nodes, -!> all others (currently) might be stored more than once. -!> Also allocates the 'mesh_node' array. -!-------------------------------------------------------------------------------------------------- -subroutine mesh_build_cellconnectivity - - implicit none - integer(pInt), dimension(:), allocatable :: & - matchingNode2cellnode - integer(pInt), dimension(:,:), allocatable :: & - cellnodeParent - integer(pInt), dimension(mesh_maxNcellnodes) :: & - localCellnode2globalCellnode - integer(pInt) :: & - e,t,g,c,n,i, & - matchingNodeID, & - localCellnodeID - - allocate(mesh_cell(FE_maxNcellnodesPerCell,mesh_maxNips,mesh_NcpElems), source=0_pInt) - allocate(matchingNode2cellnode(mesh_Nnodes), source=0_pInt) - allocate(cellnodeParent(2_pInt,mesh_maxNcellnodes*mesh_NcpElems), source=0_pInt) - -!-------------------------------------------------------------------------------------------------- -! Count cell nodes (including duplicates) and generate cell connectivity list - mesh_Ncellnodes = 0_pInt - mesh_Ncells = 0_pInt - do e = 1_pInt,mesh_NcpElems ! loop over cpElems - t = mesh_element(2_pInt,e) ! get element type - g = FE_geomtype(t) ! get geometry type - c = FE_celltype(g) ! get cell type - localCellnode2globalCellnode = 0_pInt - mesh_Ncells = mesh_Ncells + FE_Nips(g) - do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element - do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in this cell - localCellnodeID = FE_cell(n,i,g) - if (localCellnodeID <= FE_NmatchingNodes(g)) then ! this cell node is a matching node - matchingNodeID = mesh_element(4_pInt+localCellnodeID,e) - if (matchingNode2cellnode(matchingNodeID) == 0_pInt) then ! if this matching node does not yet exist in the glbal cell node list ... - mesh_Ncellnodes = mesh_Ncellnodes + 1_pInt ! ... count it as cell node ... - matchingNode2cellnode(matchingNodeID) = mesh_Ncellnodes ! ... and remember its global ID - cellnodeParent(1_pInt,mesh_Ncellnodes) = e ! ... and where it belongs to - cellnodeParent(2_pInt,mesh_Ncellnodes) = localCellnodeID - endif - mesh_cell(n,i,e) = matchingNode2cellnode(matchingNodeID) - else ! this cell node is no matching node - if (localCellnode2globalCellnode(localCellnodeID) == 0_pInt) then ! if this local cell node does not yet exist in the global cell node list ... - mesh_Ncellnodes = mesh_Ncellnodes + 1_pInt ! ... count it as cell node ... - localCellnode2globalCellnode(localCellnodeID) = mesh_Ncellnodes ! ... and remember its global ID ... - cellnodeParent(1_pInt,mesh_Ncellnodes) = e ! ... and it belongs to - cellnodeParent(2_pInt,mesh_Ncellnodes) = localCellnodeID - endif - mesh_cell(n,i,e) = localCellnode2globalCellnode(localCellnodeID) - endif - enddo - enddo - enddo - - allocate(mesh_cellnodeParent(2_pInt,mesh_Ncellnodes)) - allocate(mesh_cellnode(3_pInt,mesh_Ncellnodes)) - forall(n = 1_pInt:mesh_Ncellnodes) - mesh_cellnodeParent(1,n) = cellnodeParent(1,n) - mesh_cellnodeParent(2,n) = cellnodeParent(2,n) - endforall - - deallocate(matchingNode2cellnode) - deallocate(cellnodeParent) - -end subroutine mesh_build_cellconnectivity - - -!-------------------------------------------------------------------------------------------------- -!> @brief Calculate position of cellnodes from the given position of nodes -!> Build list of cellnodes' coordinates. -!> Cellnode coordinates are calculated from a weighted sum of node coordinates. -!-------------------------------------------------------------------------------------------------- -function mesh_build_cellnodes(nodes,Ncellnodes) - - implicit none - integer(pInt), intent(in) :: Ncellnodes !< requested number of cellnodes - real(pReal), dimension(3,mesh_Nnodes), intent(in) :: nodes - real(pReal), dimension(3,Ncellnodes) :: mesh_build_cellnodes - - integer(pInt) :: & - e,t,n,m, & - localCellnodeID - real(pReal), dimension(3) :: & - myCoords - - mesh_build_cellnodes = 0.0_pReal -!$OMP PARALLEL DO PRIVATE(e,localCellnodeID,t,myCoords) - do n = 1_pInt,Ncellnodes ! loop over cell nodes - e = mesh_cellnodeParent(1,n) - localCellnodeID = mesh_cellnodeParent(2,n) - t = mesh_element(2,e) ! get element type - myCoords = 0.0_pReal - do m = 1_pInt,FE_Nnodes(t) - myCoords = myCoords + nodes(1:3,mesh_element(4_pInt+m,e)) & - * FE_cellnodeParentnodeWeights(m,localCellnodeID,t) - enddo - mesh_build_cellnodes(1:3,n) = myCoords / sum(FE_cellnodeParentnodeWeights(:,localCellnodeID,t)) - enddo -!$OMP END PARALLEL DO - -end function mesh_build_cellnodes - - -!-------------------------------------------------------------------------------------------------- -!> @brief Calculates IP volume. Allocates global array 'mesh_ipVolume' -!> @details The IP volume is calculated differently depending on the cell type. -!> 2D cells assume an element depth of one in order to calculate the volume. -!> For the hexahedral cell we subdivide the cell into subvolumes of pyramidal -!> shape with a cell face as basis and the central ip at the tip. This subvolume is -!> calculated as an average of four tetrahedals with three corners on the cell face -!> and one corner at the central ip. -!-------------------------------------------------------------------------------------------------- -subroutine mesh_build_ipVolumes - use math, only: & - math_volTetrahedron, & - math_areaTriangle - - implicit none - integer(pInt) :: e,t,g,c,i,m,f,n - real(pReal), dimension(FE_maxNcellnodesPerCellface,FE_maxNcellfaces) :: subvolume - - if (.not. allocated(mesh_ipVolume)) then - allocate(mesh_ipVolume(mesh_maxNips,mesh_NcpElems)) - mesh_ipVolume = 0.0_pReal - endif - - !$OMP PARALLEL DO PRIVATE(t,g,c,m,subvolume) - do e = 1_pInt,mesh_NcpElems ! loop over cpElems - t = mesh_element(2_pInt,e) ! get element type - g = FE_geomtype(t) ! get geometry type - c = FE_celltype(g) ! get cell type - select case (c) - - case (1_pInt) ! 2D 3node - forall (i = 1_pInt:FE_Nips(g)) & ! loop over ips=cells in this element - mesh_ipVolume(i,e) = math_areaTriangle(mesh_cellnode(1:3,mesh_cell(1,i,e)), & - mesh_cellnode(1:3,mesh_cell(2,i,e)), & - mesh_cellnode(1:3,mesh_cell(3,i,e))) - - case (2_pInt) ! 2D 4node - forall (i = 1_pInt:FE_Nips(g)) & ! loop over ips=cells in this element - mesh_ipVolume(i,e) = math_areaTriangle(mesh_cellnode(1:3,mesh_cell(1,i,e)), & ! here we assume a planar shape, so division in two triangles suffices - mesh_cellnode(1:3,mesh_cell(2,i,e)), & - mesh_cellnode(1:3,mesh_cell(3,i,e))) & - + math_areaTriangle(mesh_cellnode(1:3,mesh_cell(3,i,e)), & - mesh_cellnode(1:3,mesh_cell(4,i,e)), & - mesh_cellnode(1:3,mesh_cell(1,i,e))) - - case (3_pInt) ! 3D 4node - forall (i = 1_pInt:FE_Nips(g)) & ! loop over ips=cells in this element - mesh_ipVolume(i,e) = math_volTetrahedron(mesh_cellnode(1:3,mesh_cell(1,i,e)), & - mesh_cellnode(1:3,mesh_cell(2,i,e)), & - mesh_cellnode(1:3,mesh_cell(3,i,e)), & - mesh_cellnode(1:3,mesh_cell(4,i,e))) - - case (4_pInt) ! 3D 8node - m = FE_NcellnodesPerCellface(c) - do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element - subvolume = 0.0_pReal - forall(f = 1_pInt:FE_NipNeighbors(c), n = 1_pInt:FE_NcellnodesPerCellface(c)) & - subvolume(n,f) = math_volTetrahedron(& - mesh_cellnode(1:3,mesh_cell(FE_cellface( n ,f,c),i,e)), & - mesh_cellnode(1:3,mesh_cell(FE_cellface(1+mod(n ,m),f,c),i,e)), & - mesh_cellnode(1:3,mesh_cell(FE_cellface(1+mod(n+1,m),f,c),i,e)), & - mesh_ipCoordinates(1:3,i,e)) - mesh_ipVolume(i,e) = 0.5_pReal * sum(subvolume) ! each subvolume is based on four tetrahedrons, altough the face consists of only two triangles -> averaging factor two - enddo - - end select - enddo - !$OMP END PARALLEL DO - -end subroutine mesh_build_ipVolumes - - -!-------------------------------------------------------------------------------------------------- -!> @brief Calculates IP Coordinates. Allocates global array 'mesh_ipCoordinates' -! Called by all solvers in mesh_init in order to initialize the ip coordinates. -! Later on the current ip coordinates are directly prvided by the spectral solver and by Abaqus, -! so no need to use this subroutine anymore; Marc however only provides nodal displacements, -! so in this case the ip coordinates are always calculated on the basis of this subroutine. -! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! FOR THE MOMENT THIS SUBROUTINE ACTUALLY CALCULATES THE CELL CENTER AND NOT THE IP COORDINATES, -! AS THE IP IS NOT (ALWAYS) LOCATED IN THE CENTER OF THE IP VOLUME. -! HAS TO BE CHANGED IN A LATER VERSION. -! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!-------------------------------------------------------------------------------------------------- -subroutine mesh_build_ipCoordinates - - implicit none - integer(pInt) :: e,t,g,c,i,n - real(pReal), dimension(3) :: myCoords - - if (.not. allocated(mesh_ipCoordinates)) then - allocate(mesh_ipCoordinates(3,mesh_maxNips,mesh_NcpElems)) - mesh_ipCoordinates = 0.0_pReal - endif - - !$OMP PARALLEL DO PRIVATE(t,g,c,myCoords) - do e = 1_pInt,mesh_NcpElems ! loop over cpElems - t = mesh_element(2_pInt,e) ! get element type - g = FE_geomtype(t) ! get geometry type - c = FE_celltype(g) ! get cell type - do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element - myCoords = 0.0_pReal - do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in this cell - myCoords = myCoords + mesh_cellnode(1:3,mesh_cell(n,i,e)) - enddo - mesh_ipCoordinates(1:3,i,e) = myCoords / FE_NcellnodesPerCell(c) - enddo - enddo - !$OMP END PARALLEL DO - -end subroutine mesh_build_ipCoordinates - - -!-------------------------------------------------------------------------------------------------- -!> @brief Calculates cell center coordinates. -!-------------------------------------------------------------------------------------------------- -pure function mesh_cellCenterCoordinates(ip,el) - - implicit none - integer(pInt), intent(in) :: el, & !< element number - ip !< integration point number - real(pReal), dimension(3) :: mesh_cellCenterCoordinates !< x,y,z coordinates of the cell center of the requested IP cell - integer(pInt) :: t,g,c,n - - - t = mesh_element(2_pInt,el) ! get element type - g = FE_geomtype(t) ! get geometry type - c = FE_celltype(g) ! get cell type - mesh_cellCenterCoordinates = 0.0_pReal - do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in this cell - mesh_cellCenterCoordinates = mesh_cellCenterCoordinates + mesh_cellnode(1:3,mesh_cell(n,ip,el)) - enddo - mesh_cellCenterCoordinates = mesh_cellCenterCoordinates / FE_NcellnodesPerCell(c) - - end function mesh_cellCenterCoordinates - - -#ifdef Spectral -!-------------------------------------------------------------------------------------------------- -!> @brief Reads grid information from geometry file. If fileUnit is given, -!! assumes an opened file, otherwise tries to open the one specified in geometryFile -!-------------------------------------------------------------------------------------------------- -function mesh_spectral_getGrid(fileUnit) - use IO, only: & - IO_checkAndRewind, & - IO_open_file, & - IO_stringPos, & - IO_lc, & - IO_stringValue, & - IO_intValue, & - IO_floatValue, & - IO_error - use DAMASK_interface, only: & - geometryFile - - implicit none - integer(pInt), dimension(3) :: mesh_spectral_getGrid - integer(pInt), intent(in), optional :: fileUnit - integer(pInt), allocatable, dimension(:) :: chunkPos - - integer(pInt) :: headerLength = 0_pInt - character(len=1024) :: line, & - keyword - integer(pInt) :: i, j, myFileUnit - logical :: gotGrid = .false. - - mesh_spectral_getGrid = -1_pInt - if(.not. present(fileUnit)) then - myFileUnit = 289_pInt - call IO_open_file(myFileUnit,trim(geometryFile)) - else - myFileUnit = fileUnit - endif - - call IO_checkAndRewind(myFileUnit) - - read(myFileUnit,'(a1024)') line - chunkPos = IO_stringPos(line) - keyword = IO_lc(IO_StringValue(line,chunkPos,2_pInt,.true.)) - if (keyword(1:4) == 'head') then - headerLength = IO_intValue(line,chunkPos,1_pInt) + 1_pInt - else - call IO_error(error_ID=841_pInt, ext_msg='mesh_spectral_getGrid') - endif - rewind(myFileUnit) - do i = 1_pInt, headerLength - read(myFileUnit,'(a1024)') line - chunkPos = IO_stringPos(line) - select case ( IO_lc(IO_StringValue(line,chunkPos,1_pInt,.true.)) ) - case ('grid') - gotGrid = .true. - do j = 2_pInt,6_pInt,2_pInt - select case (IO_lc(IO_stringValue(line,chunkPos,j))) - case('a') - mesh_spectral_getGrid(1) = IO_intValue(line,chunkPos,j+1_pInt) - case('b') - mesh_spectral_getGrid(2) = IO_intValue(line,chunkPos,j+1_pInt) - case('c') - mesh_spectral_getGrid(3) = IO_intValue(line,chunkPos,j+1_pInt) - end select - enddo - end select - enddo - - if(.not. present(fileUnit)) close(myFileUnit) - - if (.not. gotGrid) & - call IO_error(error_ID = 845_pInt, ext_msg='grid') - if(any(mesh_spectral_getGrid < 1_pInt)) & - call IO_error(error_ID = 843_pInt, ext_msg='mesh_spectral_getGrid') - -end function mesh_spectral_getGrid - - -!-------------------------------------------------------------------------------------------------- -!> @brief Reads size information from geometry file. If fileUnit is given, -!! assumes an opened file, otherwise tries to open the one specified in geometryFile -!-------------------------------------------------------------------------------------------------- -function mesh_spectral_getSize(fileUnit) - use IO, only: & - IO_checkAndRewind, & - IO_open_file, & - IO_stringPos, & - IO_lc, & - IO_stringValue, & - IO_intValue, & - IO_floatValue, & - IO_error - use DAMASK_interface, only: & - geometryFile - - implicit none - real(pReal), dimension(3) :: mesh_spectral_getSize - integer(pInt), intent(in), optional :: fileUnit - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: headerLength = 0_pInt - character(len=1024) :: line, & - keyword - integer(pInt) :: i, j, myFileUnit - logical :: gotSize = .false. - - mesh_spectral_getSize = -1.0_pReal - if(.not. present(fileUnit)) then - myFileUnit = 289_pInt - call IO_open_file(myFileUnit,trim(geometryFile)) - else - myFileUnit = fileUnit - endif - - call IO_checkAndRewind(myFileUnit) - - read(myFileUnit,'(a1024)') line - chunkPos = IO_stringPos(line) - keyword = IO_lc(IO_StringValue(line,chunkPos,2_pInt,.true.)) - if (keyword(1:4) == 'head') then - headerLength = IO_intValue(line,chunkPos,1_pInt) + 1_pInt - else - call IO_error(error_ID=841_pInt, ext_msg='mesh_spectral_getSize') - endif - rewind(myFileUnit) - do i = 1_pInt, headerLength - read(myFileUnit,'(a1024)') line - chunkPos = IO_stringPos(line) - select case ( IO_lc(IO_StringValue(line,chunkPos,1,.true.)) ) - case ('size') - gotSize = .true. - do j = 2_pInt,6_pInt,2_pInt - select case (IO_lc(IO_stringValue(line,chunkPos,j))) - case('x') - mesh_spectral_getSize(1) = IO_floatValue(line,chunkPos,j+1_pInt) - case('y') - mesh_spectral_getSize(2) = IO_floatValue(line,chunkPos,j+1_pInt) - case('z') - mesh_spectral_getSize(3) = IO_floatValue(line,chunkPos,j+1_pInt) - end select - enddo - end select - enddo - - if(.not. present(fileUnit)) close(myFileUnit) - - if (.not. gotSize) & - call IO_error(error_ID = 845_pInt, ext_msg='size') - if (any(mesh_spectral_getSize<=0.0_pReal)) & - call IO_error(error_ID = 844_pInt, ext_msg='mesh_spectral_getSize') - -end function mesh_spectral_getSize - - -!-------------------------------------------------------------------------------------------------- -!> @brief Reads homogenization information from geometry file. If fileUnit is given, -!! assumes an opened file, otherwise tries to open the one specified in geometryFile -!-------------------------------------------------------------------------------------------------- -integer(pInt) function mesh_spectral_getHomogenization(fileUnit) - use IO, only: & - IO_checkAndRewind, & - IO_open_file, & - IO_stringPos, & - IO_lc, & - IO_stringValue, & - IO_intValue, & - IO_error - use DAMASK_interface, only: & - geometryFile - - implicit none - integer(pInt), intent(in), optional :: fileUnit - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: headerLength = 0_pInt - character(len=1024) :: line, & - keyword - integer(pInt) :: i, myFileUnit - logical :: gotHomogenization = .false. - - mesh_spectral_getHomogenization = -1_pInt - if(.not. present(fileUnit)) then - myFileUnit = 289_pInt - call IO_open_file(myFileUnit,trim(geometryFile)) - else - myFileUnit = fileUnit - endif - - call IO_checkAndRewind(myFileUnit) - - read(myFileUnit,'(a1024)') line - chunkPos = IO_stringPos(line) - keyword = IO_lc(IO_StringValue(line,chunkPos,2_pInt,.true.)) - if (keyword(1:4) == 'head') then - headerLength = IO_intValue(line,chunkPos,1_pInt) + 1_pInt - else - call IO_error(error_ID=841_pInt, ext_msg='mesh_spectral_getHomogenization') - endif - rewind(myFileUnit) - do i = 1_pInt, headerLength - read(myFileUnit,'(a1024)') line - chunkPos = IO_stringPos(line) - select case ( IO_lc(IO_StringValue(line,chunkPos,1,.true.)) ) - case ('homogenization') - gotHomogenization = .true. - mesh_spectral_getHomogenization = IO_intValue(line,chunkPos,2_pInt) - end select - enddo - - if(.not. present(fileUnit)) close(myFileUnit) - - if (.not. gotHomogenization ) & - call IO_error(error_ID = 845_pInt, ext_msg='homogenization') - if (mesh_spectral_getHomogenization<1_pInt) & - call IO_error(error_ID = 842_pInt, ext_msg='mesh_spectral_getHomogenization') - -end function mesh_spectral_getHomogenization - - -!-------------------------------------------------------------------------------------------------- -!> @brief Count overall number of nodes and elements in mesh and stores them in -!! 'mesh_Nelems', 'mesh_Nnodes' and 'mesh_NcpElems' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_spectral_count() - - implicit none - - mesh_Nelems = product(grid(1:2))*grid3 - mesh_NcpElems= mesh_Nelems - mesh_Nnodes = product(grid(1:2) + 1_pInt)*(grid3 + 1_pInt) - - mesh_NcpElemsGlobal = product(grid) - -end subroutine mesh_spectral_count - - -!-------------------------------------------------------------------------------------------------- -!> @brief fake map node from FE ID to internal (consecutive) representation for node and element -!! Allocates global array 'mesh_mapFEtoCPnode' and 'mesh_mapFEtoCPelem' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_spectral_mapNodesAndElems - use math, only: & - math_range - - implicit none - allocate (mesh_mapFEtoCPnode(2_pInt,mesh_Nnodes), source = 0_pInt) - allocate (mesh_mapFEtoCPelem(2_pInt,mesh_NcpElems), source = 0_pInt) - - mesh_mapFEtoCPnode = spread(math_range(mesh_Nnodes),1,2) - mesh_mapFEtoCPelem = spread(math_range(mesh_NcpElems),1,2) - -end subroutine mesh_spectral_mapNodesAndElems - - -!-------------------------------------------------------------------------------------------------- -!> @brief Gets maximum count of nodes, IPs, IP neighbors, and subNodes among cpElements. -!! Sets global values 'mesh_maxNnodes', 'mesh_maxNips', 'mesh_maxNipNeighbors', -!! and 'mesh_maxNcellnodes' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_spectral_count_cpSizes - - implicit none - integer(pInt) :: t,g,c - - t = FE_mapElemtype('C3D8R') ! fake 3D hexahedral 8 node 1 IP element - g = FE_geomtype(t) - c = FE_celltype(g) - - mesh_maxNnodes = FE_Nnodes(t) - mesh_maxNips = FE_Nips(g) - mesh_maxNipNeighbors = FE_NipNeighbors(c) - mesh_maxNcellnodes = FE_Ncellnodes(g) - -end subroutine mesh_spectral_count_cpSizes - - -!-------------------------------------------------------------------------------------------------- -!> @brief Store x,y,z coordinates of all nodes in mesh. -!! Allocates global arrays 'mesh_node0' and 'mesh_node' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_spectral_build_nodes() - - implicit none - integer(pInt) :: n - - allocate (mesh_node0 (3,mesh_Nnodes), source = 0.0_pReal) - allocate (mesh_node (3,mesh_Nnodes), source = 0.0_pReal) - - forall (n = 0_pInt:mesh_Nnodes-1_pInt) - mesh_node0(1,n+1_pInt) = mesh_unitlength * & - geomSize(1)*real(mod(n,(grid(1)+1_pInt) ),pReal) & - / real(grid(1),pReal) - mesh_node0(2,n+1_pInt) = mesh_unitlength * & - geomSize(2)*real(mod(n/(grid(1)+1_pInt),(grid(2)+1_pInt)),pReal) & - / real(grid(2),pReal) - mesh_node0(3,n+1_pInt) = mesh_unitlength * & - size3*real(mod(n/(grid(1)+1_pInt)/(grid(2)+1_pInt),(grid3+1_pInt)),pReal) & - / real(grid3,pReal) + & - size3offset - end forall - - mesh_node = mesh_node0 - -end subroutine mesh_spectral_build_nodes - - -!-------------------------------------------------------------------------------------------------- -!> @brief Store FEid, type, material, texture, and node list per element. -!! Allocates global array 'mesh_element' -!> @todo does the IO_error makes sense? -!-------------------------------------------------------------------------------------------------- -subroutine mesh_spectral_build_elements(fileUnit) - use IO, only: & - IO_checkAndRewind, & - IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_error, & - IO_continuousIntValues, & - IO_intValue, & - IO_countContinuousIntValues - - implicit none - integer(pInt), intent(in) :: & - fileUnit - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - e, i, & - headerLength = 0_pInt, & - maxIntCount, & - homog, & - elemType, & - elemOffset - integer(pInt), dimension(:), allocatable :: & - microstructures, & - mesh_microGlobal - integer(pInt), dimension(1,1) :: & - dummySet = 0_pInt - character(len=65536) :: & - line, & - keyword - character(len=64), dimension(1) :: & - dummyName = '' - - homog = mesh_spectral_getHomogenization(fileUnit) - -!-------------------------------------------------------------------------------------------------- -! get header length - call IO_checkAndRewind(fileUnit) - read(fileUnit,'(a65536)') line - chunkPos = IO_stringPos(line) - keyword = IO_lc(IO_StringValue(line,chunkPos,2_pInt,.true.)) - if (keyword(1:4) == 'head') then - headerLength = IO_intValue(line,chunkPos,1_pInt) + 1_pInt - else - call IO_error(error_ID=841_pInt, ext_msg='mesh_spectral_build_elements') - endif - -!-------------------------------------------------------------------------------------------------- -! get maximum microstructure index - call IO_checkAndRewind(fileUnit) - do i = 1_pInt, headerLength - read(fileUnit,'(a65536)') line - enddo - - maxIntCount = 0_pInt - i = 1_pInt - - do while (i > 0_pInt) - i = IO_countContinuousIntValues(fileUnit) - maxIntCount = max(maxIntCount, i) - enddo - allocate (mesh_element (4_pInt+mesh_maxNnodes,mesh_NcpElems), source = 0_pInt) - allocate (microstructures (1_pInt+maxIntCount), source = 1_pInt) - allocate (mesh_microGlobal(mesh_NcpElemsGlobal), source = 1_pInt) - -!-------------------------------------------------------------------------------------------------- -! read in microstructures - call IO_checkAndRewind(fileUnit) - do i=1_pInt,headerLength - read(fileUnit,'(a65536)') line - enddo - - e = 0_pInt - do while (e < mesh_NcpElemsGlobal .and. microstructures(1) > 0_pInt) ! fill expected number of elements, stop at end of data (or blank line!) - microstructures = IO_continuousIntValues(fileUnit,maxIntCount,dummyName,dummySet,0_pInt) ! get affected elements - do i = 1_pInt,microstructures(1_pInt) - e = e+1_pInt ! valid element entry - mesh_microGlobal(e) = microstructures(1_pInt+i) - enddo - enddo - - elemType = FE_mapElemtype('C3D8R') - elemOffset = product(grid(1:2))*grid3Offset - e = 0_pInt - do while (e < mesh_NcpElems) ! fill expected number of elements, stop at end of data (or blank line!) - e = e+1_pInt ! valid element entry - mesh_element( 1,e) = e ! FE id - mesh_element( 2,e) = elemType ! elem type - mesh_element( 3,e) = homog ! homogenization - mesh_element( 4,e) = mesh_microGlobal(e+elemOffset) ! microstructure - mesh_element( 5,e) = e + (e-1_pInt)/grid(1) + & - ((e-1_pInt)/(grid(1)*grid(2)))*(grid(1)+1_pInt) ! base node - mesh_element( 6,e) = mesh_element(5,e) + 1_pInt - mesh_element( 7,e) = mesh_element(5,e) + grid(1) + 2_pInt - mesh_element( 8,e) = mesh_element(5,e) + grid(1) + 1_pInt - mesh_element( 9,e) = mesh_element(5,e) +(grid(1) + 1_pInt) * (grid(2) + 1_pInt) ! second floor base node - mesh_element(10,e) = mesh_element(9,e) + 1_pInt - mesh_element(11,e) = mesh_element(9,e) + grid(1) + 2_pInt - mesh_element(12,e) = mesh_element(9,e) + grid(1) + 1_pInt - mesh_maxValStateVar(1) = max(mesh_maxValStateVar(1),mesh_element(3,e)) ! needed for statistics - mesh_maxValStateVar(2) = max(mesh_maxValStateVar(2),mesh_element(4,e)) - enddo - - deallocate(microstructures) - deallocate(mesh_microGlobal) - if (e /= mesh_NcpElems) call IO_error(880_pInt,e) - -end subroutine mesh_spectral_build_elements - - -!-------------------------------------------------------------------------------------------------- -!> @brief build neighborhood relations for spectral -!> @details assign globals: mesh_ipNeighborhood -!-------------------------------------------------------------------------------------------------- -subroutine mesh_spectral_build_ipNeighborhood(fileUnit) - - implicit none - integer(pInt), intent(in) :: & - fileUnit - integer(pInt) :: & - x,y,z, & - e - allocate(mesh_ipNeighborhood(3,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems),source=0_pInt) - - e = 0_pInt - do z = 0_pInt,grid3-1_pInt - do y = 0_pInt,grid(2)-1_pInt - do x = 0_pInt,grid(1)-1_pInt - e = e + 1_pInt - mesh_ipNeighborhood(1,1,1,e) = z * grid(1) * grid(2) & - + y * grid(1) & - + modulo(x+1_pInt,grid(1)) & - + 1_pInt - mesh_ipNeighborhood(1,2,1,e) = z * grid(1) * grid(2) & - + y * grid(1) & - + modulo(x-1_pInt,grid(1)) & - + 1_pInt - mesh_ipNeighborhood(1,3,1,e) = z * grid(1) * grid(2) & - + modulo(y+1_pInt,grid(2)) * grid(1) & - + x & - + 1_pInt - mesh_ipNeighborhood(1,4,1,e) = z * grid(1) * grid(2) & - + modulo(y-1_pInt,grid(2)) * grid(1) & - + x & - + 1_pInt - mesh_ipNeighborhood(1,5,1,e) = modulo(z+1_pInt,grid3) * grid(1) * grid(2) & - + y * grid(1) & - + x & - + 1_pInt - mesh_ipNeighborhood(1,6,1,e) = modulo(z-1_pInt,grid3) * grid(1) * grid(2) & - + y * grid(1) & - + x & - + 1_pInt - mesh_ipNeighborhood(2,1:6,1,e) = 1_pInt - mesh_ipNeighborhood(3,1,1,e) = 2_pInt - mesh_ipNeighborhood(3,2,1,e) = 1_pInt - mesh_ipNeighborhood(3,3,1,e) = 4_pInt - mesh_ipNeighborhood(3,4,1,e) = 3_pInt - mesh_ipNeighborhood(3,5,1,e) = 6_pInt - mesh_ipNeighborhood(3,6,1,e) = 5_pInt - enddo - enddo - enddo - -end subroutine mesh_spectral_build_ipNeighborhood - - -!-------------------------------------------------------------------------------------------------- -!> @brief builds mesh of (distorted) cubes for given coordinates (= center of the cubes) -!-------------------------------------------------------------------------------------------------- -function mesh_nodesAroundCentres(gDim,Favg,centres) result(nodes) - use debug, only: & - debug_mesh, & - debug_level, & - debug_levelBasic - use math, only: & - math_mul33x3 - - implicit none - real(pReal), intent(in), dimension(:,:,:,:) :: & - centres - real(pReal), dimension(3,size(centres,2)+1,size(centres,3)+1,size(centres,4)+1) :: & - nodes - real(pReal), intent(in), dimension(3) :: & - gDim - real(pReal), intent(in), dimension(3,3) :: & - Favg - real(pReal), dimension(3,size(centres,2)+2,size(centres,3)+2,size(centres,4)+2) :: & - wrappedCentres - - integer(pInt) :: & - i,j,k,n - integer(pInt), dimension(3), parameter :: & - diag = 1_pInt - integer(pInt), dimension(3) :: & - shift = 0_pInt, & - lookup = 0_pInt, & - me = 0_pInt, & - iRes = 0_pInt - integer(pInt), dimension(3,8) :: & - neighbor = reshape([ & - 0_pInt, 0_pInt, 0_pInt, & - 1_pInt, 0_pInt, 0_pInt, & - 1_pInt, 1_pInt, 0_pInt, & - 0_pInt, 1_pInt, 0_pInt, & - 0_pInt, 0_pInt, 1_pInt, & - 1_pInt, 0_pInt, 1_pInt, & - 1_pInt, 1_pInt, 1_pInt, & - 0_pInt, 1_pInt, 1_pInt ], [3,8]) - -!-------------------------------------------------------------------------------------------------- -! initializing variables - iRes = [size(centres,2),size(centres,3),size(centres,4)] - nodes = 0.0_pReal - wrappedCentres = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! report - if (iand(debug_level(debug_mesh),debug_levelBasic) /= 0_pInt) then - write(6,'(a)') ' Meshing cubes around centroids' - write(6,'(a,3(e12.5))') ' Dimension: ', gDim - write(6,'(a,3(i5))') ' Resolution:', iRes - endif - -!-------------------------------------------------------------------------------------------------- -! building wrappedCentres = centroids + ghosts - wrappedCentres(1:3,2_pInt:iRes(1)+1_pInt,2_pInt:iRes(2)+1_pInt,2_pInt:iRes(3)+1_pInt) = centres - do k = 0_pInt,iRes(3)+1_pInt - do j = 0_pInt,iRes(2)+1_pInt - do i = 0_pInt,iRes(1)+1_pInt - if (k==0_pInt .or. k==iRes(3)+1_pInt .or. & ! z skin - j==0_pInt .or. j==iRes(2)+1_pInt .or. & ! y skin - i==0_pInt .or. i==iRes(1)+1_pInt ) then ! x skin - me = [i,j,k] ! me on skin - shift = sign(abs(iRes+diag-2_pInt*me)/(iRes+diag),iRes+diag-2_pInt*me) - lookup = me-diag+shift*iRes - wrappedCentres(1:3,i+1_pInt, j+1_pInt, k+1_pInt) = & - centres(1:3,lookup(1)+1_pInt,lookup(2)+1_pInt,lookup(3)+1_pInt) - & - math_mul33x3(Favg, shift*gDim) - endif - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! averaging - do k = 0_pInt,iRes(3); do j = 0_pInt,iRes(2); do i = 0_pInt,iRes(1) - do n = 1_pInt,8_pInt - nodes(1:3,i+1_pInt,j+1_pInt,k+1_pInt) = & - nodes(1:3,i+1_pInt,j+1_pInt,k+1_pInt) + wrappedCentres(1:3,i+1_pInt+neighbor(1,n), & - j+1_pInt+neighbor(2,n), & - k+1_pInt+neighbor(3,n) ) - enddo - enddo; enddo; enddo - nodes = nodes/8.0_pReal - -end function mesh_nodesAroundCentres - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate coordinates in current configuration for given defgrad -! using integration in Fourier space -!-------------------------------------------------------------------------------------------------- -function mesh_deformedCoordsFFT(gDim,F,FavgIn,scalingIn) result(coords) - use IO, only: & - IO_error - use numerics, only: & - fftw_timelimit, & - fftw_planner_flag - use debug, only: & - debug_mesh, & - debug_level, & - debug_levelBasic - use math, only: & - PI, & - math_mul33x3 - - implicit none - real(pReal), intent(in), dimension(:,:,:,:,:) :: F - real(pReal), dimension(3,size(F,3),size(F,4),size(F,5)) :: coords - real(pReal), intent(in), dimension(3) :: gDim - real(pReal), intent(in), dimension(3,3), optional :: FavgIn - real(pReal), intent(in), dimension(3), optional :: scalingIn - -! allocatable arrays for fftw c routines - type(C_PTR) :: planForth, planBack - type(C_PTR) :: coords_fftw, defgrad_fftw - real(pReal), dimension(:,:,:,:,:), pointer :: F_real - complex(pReal), dimension(:,:,:,:,:), pointer :: F_fourier - real(pReal), dimension(:,:,:,:), pointer :: coords_real - complex(pReal), dimension(:,:,:,:), pointer :: coords_fourier - ! other variables - integer(pInt) :: i, j, k, m, res1Red - integer(pInt), dimension(3) :: k_s, iRes - real(pReal), dimension(3) :: scaling, step, offset_coords, integrator - real(pReal), dimension(3,3) :: Favg - integer(pInt), dimension(2:3,2) :: Nyquist ! highest frequencies to be removed (1 if even, 2 if odd) - - if (present(scalingIn)) then - where (scalingIn < 0.0_pReal) ! invalid values. in case of f2py -1 if not present - scaling = [1.0_pReal,1.0_pReal,1.0_pReal] - elsewhere - scaling = scalingIn - end where - else - scaling = 1.0_pReal - endif - - iRes = [size(F,3),size(F,4),size(F,5)] - integrator = gDim / 2.0_pReal / PI ! see notes where it is used - res1Red = iRes(1)/2_pInt + 1_pInt ! size of complex array in first dimension (c2r, r2c) - step = gDim/real(iRes, pReal) - Nyquist(2,1:2) = [iRes(2)/2_pInt + 1_pInt, iRes(2)/2_pInt + 1_pInt + mod(iRes(2),2_pInt)] - Nyquist(3,1:2) = [iRes(3)/2_pInt + 1_pInt, iRes(3)/2_pInt + 1_pInt + mod(iRes(3),2_pInt)] - -!-------------------------------------------------------------------------------------------------- -! report - if (iand(debug_level(debug_mesh),debug_levelBasic) /= 0_pInt) then - write(6,'(a)') ' Restore geometry using FFT-based integration' - write(6,'(a,3(i12 ))') ' grid a b c: ', iRes - write(6,'(a,3(es12.5))') ' size x y z: ', gDim - endif - -!-------------------------------------------------------------------------------------------------- -! sanity check - if (pReal /= C_DOUBLE .or. pInt /= C_INT) & - call IO_error(0_pInt,ext_msg='Fortran to C in mesh_deformedCoordsFFT') - -!-------------------------------------------------------------------------------------------------- -! allocation and FFTW initialization - defgrad_fftw = fftw_alloc_complex(int(res1Red *iRes(2)*iRes(3)*9_pInt,C_SIZE_T)) ! C_SIZE_T is of type integer(8) - coords_fftw = fftw_alloc_complex(int(res1Red *iRes(2)*iRes(3)*3_pInt,C_SIZE_T)) ! C_SIZE_T is of type integer(8) - call c_f_pointer(defgrad_fftw, F_real, & - [iRes(1)+2_pInt-mod(iRes(1),2_pInt),iRes(2),iRes(3),3_pInt,3_pInt]) - call c_f_pointer(defgrad_fftw, F_fourier, & - [res1Red, iRes(2),iRes(3),3_pInt,3_pInt]) - call c_f_pointer(coords_fftw, coords_real, & - [iRes(1)+2_pInt-mod(iRes(1),2_pInt),iRes(2),iRes(3),3_pInt]) - call c_f_pointer(coords_fftw, coords_fourier, & - [res1Red, iRes(2),iRes(3),3_pInt]) - - call fftw_set_timelimit(fftw_timelimit) - planForth = fftw_plan_many_dft_r2c(3_pInt,[iRes(3),iRes(2) ,iRes(1)],9_pInt,& ! dimensions , length in each dimension in reversed order - F_real,[iRes(3),iRes(2) ,iRes(1)+2_pInt-mod(iRes(1),2_pInt)],& ! input data , physical length in each dimension in reversed order - 1_pInt, iRes(3)*iRes(2)*(iRes(1)+2_pInt-mod(iRes(1),2_pInt)),& ! striding , product of physical lenght in the 3 dimensions - F_fourier,[iRes(3),iRes(2) ,res1Red],& - 1_pInt, iRes(3)*iRes(2)* res1Red,fftw_planner_flag) - - planBack = fftw_plan_many_dft_c2r(3_pInt,[iRes(3),iRes(2) ,iRes(1)],3_pInt,& - coords_fourier,[iRes(3),iRes(2) ,res1Red],& - 1_pInt, iRes(3)*iRes(2)* res1Red,& - coords_real,[iRes(3),iRes(2) ,iRes(1)+2_pInt-mod(iRes(1),2_pInt)],& - 1_pInt, iRes(3)*iRes(2)*(iRes(1)+2_pInt-mod(iRes(1),2_pInt)),& - fftw_planner_flag) - F_real(1:iRes(1),1:iRes(2),1:iRes(3),1:3,1:3) = & - reshape(F,[iRes(1),iRes(2),iRes(3),3,3], order = [4,5,1,2,3]) ! F_real is overwritten during plan creatio, is larger (padding) and has different order - -!-------------------------------------------------------------------------------------------------- -! FFT - call fftw_execute_dft_r2c(planForth, F_real, F_fourier) - -!-------------------------------------------------------------------------------------------------- -! if no average F is given, compute it in Fourier space - if (present(FavgIn)) then - if (all(FavgIn < 0.0_pReal)) then - Favg = real(F_fourier(1,1,1,1:3,1:3),pReal)/real(product(iRes),pReal) !the f2py way to tell it is not present - else - Favg = FavgIn - endif - else - Favg = real(F_fourier(1,1,1,1:3,1:3),pReal)/real(product(iRes),pReal) - endif - -!-------------------------------------------------------------------------------------------------- -! remove highest frequency in each direction, in third direction only if not 2D - - if(iRes(1)/=1_pInt) & ! do not delete the whole slice in case of 2D calculation - F_fourier (res1Red, 1:iRes(2), 1:iRes(3), 1:3,1:3) & - = cmplx(0.0_pReal,0.0_pReal,pReal) - if(iRes(2)/=1_pInt) & ! do not delete the whole slice in case of 2D calculation - F_fourier (1:res1Red,Nyquist(2,1):Nyquist(2,2),1:iRes(3), 1:3,1:3) & - = cmplx(0.0_pReal,0.0_pReal,pReal) - if(iRes(3)/=1_pInt) & ! do not delete the whole slice in case of 2D calculation - F_fourier (1:res1Red,1:iRes(2), Nyquist(3,1):Nyquist(3,2),1:3,1:3) & - = cmplx(0.0_pReal,0.0_pReal,pReal) - -!-------------------------------------------------------------------------------------------------- -! integration in Fourier space - coords_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) - do k = 1_pInt, iRes(3) - k_s(3) = k-1_pInt - if(k > iRes(3)/2_pInt+1_pInt) k_s(3) = k_s(3)-iRes(3) - do j = 1_pInt, iRes(2) - k_s(2) = j-1_pInt - if(j > iRes(2)/2_pInt+1_pInt) k_s(2) = k_s(2)-iRes(2) - do i = 1_pInt, res1Red - k_s(1) = i-1_pInt - do m = 1_pInt,3_pInt - coords_fourier(i,j,k,m) = sum(F_fourier(i,j,k,m,1:3)*& - cmplx(0.0_pReal,real(k_s,pReal)*integrator,pReal)) - enddo - if (any(k_s /= 0_pInt)) coords_fourier(i,j,k,1:3) = & - coords_fourier(i,j,k,1:3) / cmplx(-sum(k_s*k_s),0.0_pReal,pReal) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! iFFT and freeing memory - call fftw_execute_dft_c2r(planBack,coords_fourier,coords_real) - coords = reshape(coords_real(1:iRes(1),1:iRes(2),1:iRes(3),1:3), [3,iRes(1),iRes(2),iRes(3)], & - order = [2,3,4,1])/real(product(iRes),pReal) ! weight and change order - call fftw_destroy_plan(planForth) - call fftw_destroy_plan(planBack) - call fftw_free(defgrad_fftw) - call fftw_free(coords_fftw) - -!-------------------------------------------------------------------------------------------------- -! add average to scaled fluctuation and put (0,0,0) on (0,0,0) - offset_coords = math_mul33x3(F(1:3,1:3,1,1,1),step/2.0_pReal) - scaling*coords(1:3,1,1,1) - forall(k = 1_pInt:iRes(3), j = 1_pInt:iRes(2), i = 1_pInt:iRes(1)) & - coords(1:3,i,j,k) = scaling(1:3)*coords(1:3,i,j,k) & - + offset_coords & - + math_mul33x3(Favg,step*real([i,j,k]-1_pInt,pReal)) - -end function mesh_deformedCoordsFFT - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the mismatch between volume of reconstructed (compatible) cube and -! determinant of defgrad at the FP -!-------------------------------------------------------------------------------------------------- -function mesh_volumeMismatch(gDim,F,nodes) result(vMismatch) - use IO, only: & - IO_error - use debug, only: & - debug_mesh, & - debug_level, & - debug_levelBasic - use math, only: & - math_det33, & - math_volTetrahedron - - implicit none - real(pReal), intent(in), dimension(:,:,:,:,:) :: & - F - real(pReal), dimension(size(F,3),size(F,4),size(F,5)) :: & - vMismatch - real(pReal), intent(in), dimension(:,:,:,:) :: & - nodes - real(pReal), dimension(3) :: & - gDim - integer(pInt), dimension(3) :: & - iRes - real(pReal), dimension(3,8) :: coords - integer(pInt) :: i,j,k - real(pReal) :: volInitial - - iRes = [size(F,3),size(F,4),size(F,5)] - volInitial = product(gDim)/real(product(iRes), pReal) - -!-------------------------------------------------------------------------------------------------- -! report and check - if (iand(debug_level(debug_mesh),debug_levelBasic) /= 0_pInt) then - write(6,'(a)') ' Calculating volume mismatch' - write(6,'(a,3(i12 ))') ' grid a b c: ', iRes - write(6,'(a,3(es12.5))') ' size x y z: ', gDim - endif - - if (any([iRes/=size(nodes,2)-1_pInt,iRes/=size(nodes,3)-1_pInt,iRes/=size(nodes,4)-1_pInt]))& - call IO_error(0_pInt,ext_msg='Arrays F and nodes in mesh_volumeMismatch') - -!-------------------------------------------------------------------------------------------------- -! calculate actual volume and volume resulting from deformation gradient - do k = 1_pInt,iRes(3) - do j = 1_pInt,iRes(2) - do i = 1_pInt,iRes(1) - coords(1:3,1) = nodes(1:3,i, j, k ) - coords(1:3,2) = nodes(1:3,i+1_pInt,j, k ) - coords(1:3,3) = nodes(1:3,i+1_pInt,j+1_pInt,k ) - coords(1:3,4) = nodes(1:3,i, j+1_pInt,k ) - coords(1:3,5) = nodes(1:3,i, j, k+1_pInt) - coords(1:3,6) = nodes(1:3,i+1_pInt,j, k+1_pInt) - coords(1:3,7) = nodes(1:3,i+1_pInt,j+1_pInt,k+1_pInt) - coords(1:3,8) = nodes(1:3,i, j+1_pInt,k+1_pInt) - vMismatch(i,j,k) = & - abs(math_volTetrahedron(coords(1:3,7),coords(1:3,1),coords(1:3,8),coords(1:3,4))) & - + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,1),coords(1:3,8),coords(1:3,5))) & - + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,1),coords(1:3,3),coords(1:3,4))) & - + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,1),coords(1:3,3),coords(1:3,2))) & - + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,5),coords(1:3,2),coords(1:3,6))) & - + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,5),coords(1:3,2),coords(1:3,1))) - vMismatch(i,j,k) = vMismatch(i,j,k)/math_det33(F(1:3,1:3,i,j,k)) - enddo; enddo; enddo - vMismatch = vMismatch/volInitial - -end function mesh_volumeMismatch - - -!-------------------------------------------------------------------------------------------------- -!> @brief Routine to calculate the mismatch between the vectors from the central point to -! the corners of reconstructed (combatible) volume element and the vectors calculated by deforming -! the initial volume element with the current deformation gradient -!-------------------------------------------------------------------------------------------------- -function mesh_shapeMismatch(gDim,F,nodes,centres) result(sMismatch) - use IO, only: & - IO_error - use debug, only: & - debug_mesh, & - debug_level, & - debug_levelBasic - use math, only: & - math_mul33x3 - - implicit none - real(pReal), intent(in), dimension(:,:,:,:,:) :: & - F - real(pReal), dimension(size(F,3),size(F,4),size(F,5)) :: & - sMismatch - real(pReal), intent(in), dimension(:,:,:,:) :: & - nodes, & - centres - real(pReal), dimension(3) :: & - gDim, & - fRes - integer(pInt), dimension(3) :: & - iRes - real(pReal), dimension(3,8) :: coordsInitial - integer(pInt) i,j,k - - iRes = [size(F,3),size(F,4),size(F,5)] - fRes = real(iRes,pReal) - -!-------------------------------------------------------------------------------------------------- -! report and check - if (iand(debug_level(debug_mesh),debug_levelBasic) /= 0_pInt) then - write(6,'(a)') ' Calculating shape mismatch' - write(6,'(a,3(i12 ))') ' grid a b c: ', iRes - write(6,'(a,3(es12.5))') ' size x y z: ', gDim - endif - - if(any([iRes/=size(nodes,2)-1_pInt,iRes/=size(nodes,3)-1_pInt,iRes/=size(nodes,4)-1_pInt]) .or.& - any([iRes/=size(centres,2), iRes/=size(centres,3), iRes/=size(centres,4)]))& - call IO_error(0_pInt,ext_msg='Arrays F and nodes/centres in mesh_shapeMismatch') - -!-------------------------------------------------------------------------------------------------- -! initial positions - coordsInitial(1:3,1) = [-gDim(1)/fRes(1),-gDim(2)/fRes(2),-gDim(3)/fRes(3)] - coordsInitial(1:3,2) = [+gDim(1)/fRes(1),-gDim(2)/fRes(2),-gDim(3)/fRes(3)] - coordsInitial(1:3,3) = [+gDim(1)/fRes(1),+gDim(2)/fRes(2),-gDim(3)/fRes(3)] - coordsInitial(1:3,4) = [-gDim(1)/fRes(1),+gDim(2)/fRes(2),-gDim(3)/fRes(3)] - coordsInitial(1:3,5) = [-gDim(1)/fRes(1),-gDim(2)/fRes(2),+gDim(3)/fRes(3)] - coordsInitial(1:3,6) = [+gDim(1)/fRes(1),-gDim(2)/fRes(2),+gDim(3)/fRes(3)] - coordsInitial(1:3,7) = [+gDim(1)/fRes(1),+gDim(2)/fRes(2),+gDim(3)/fRes(3)] - coordsInitial(1:3,8) = [-gDim(1)/fRes(1),+gDim(2)/fRes(2),+gDim(3)/fRes(3)] - coordsInitial = coordsInitial/2.0_pReal - -!-------------------------------------------------------------------------------------------------- -! compare deformed original and deformed positions to actual positions - do k = 1_pInt,iRes(3) - do j = 1_pInt,iRes(2) - do i = 1_pInt,iRes(1) - sMismatch(i,j,k) = & - sqrt(sum((nodes(1:3,i, j, k ) - centres(1:3,i,j,k)& - - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,1)))**2.0_pReal))& - + sqrt(sum((nodes(1:3,i+1_pInt,j, k ) - centres(1:3,i,j,k)& - - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,2)))**2.0_pReal))& - + sqrt(sum((nodes(1:3,i+1_pInt,j+1_pInt,k ) - centres(1:3,i,j,k)& - - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,3)))**2.0_pReal))& - + sqrt(sum((nodes(1:3,i, j+1_pInt,k ) - centres(1:3,i,j,k)& - - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,4)))**2.0_pReal))& - + sqrt(sum((nodes(1:3,i, j, k+1_pInt) - centres(1:3,i,j,k)& - - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,5)))**2.0_pReal))& - + sqrt(sum((nodes(1:3,i+1_pInt,j, k+1_pInt) - centres(1:3,i,j,k)& - - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,6)))**2.0_pReal))& - + sqrt(sum((nodes(1:3,i+1_pInt,j+1_pInt,k+1_pInt) - centres(1:3,i,j,k)& - - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,7)))**2.0_pReal))& - + sqrt(sum((nodes(1:3,i, j+1_pInt,k+1_pInt) - centres(1:3,i,j,k)& - - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,8)))**2.0_pReal)) - enddo; enddo; enddo - -end function mesh_shapeMismatch -#endif - - -#ifdef Marc4DAMASK -!-------------------------------------------------------------------------------------------------- -!> @brief Figures out table styles (Marc only) and stores to 'initialcondTableStyle' and -!! 'hypoelasticTableStyle' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_marc_get_tableStyles(fileUnit) - use IO, only: & - IO_lc, & - IO_intValue, & - IO_stringValue, & - IO_stringPos - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) line - - initialcondTableStyle = 0_pInt - hypoelasticTableStyle = 0_pInt - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'table' .and. chunkPos(1_pInt) > 5) then - initialcondTableStyle = IO_intValue(line,chunkPos,4_pInt) - hypoelasticTableStyle = IO_intValue(line,chunkPos,5_pInt) - exit - endif - enddo - -620 end subroutine mesh_marc_get_tableStyles - - -!-------------------------------------------------------------------------------------------------- -!> @brief Count overall number of nodes and elements in mesh and stores the numbers in -!! 'mesh_Nelems' and 'mesh_Nnodes' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_marc_count_nodesAndElements(fileUnit) - use IO, only: & - IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_IntValue - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) line - - mesh_Nnodes = 0_pInt - mesh_Nelems = 0_pInt - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - - if ( IO_lc(IO_StringValue(line,chunkPos,1_pInt)) == 'sizing') & - mesh_Nelems = IO_IntValue (line,chunkPos,3_pInt) - if ( IO_lc(IO_StringValue(line,chunkPos,1_pInt)) == 'coordinates') then - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - mesh_Nnodes = IO_IntValue (line,chunkPos,2_pInt) - exit ! assumes that "coordinates" comes later in file - endif - enddo - -620 end subroutine mesh_marc_count_nodesAndElements - - -!-------------------------------------------------------------------------------------------------- -!> @brief Count overall number of element sets in mesh. Stores to 'mesh_NelemSets', and -!! 'mesh_maxNelemInSet' -!-------------------------------------------------------------------------------------------------- - subroutine mesh_marc_count_elementSets(fileUnit) - use IO, only: & - IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_countContinuousIntValues - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) line - - mesh_NelemSets = 0_pInt - mesh_maxNelemInSet = 0_pInt - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - - if ( IO_lc(IO_StringValue(line,chunkPos,1_pInt)) == 'define' .and. & - IO_lc(IO_StringValue(line,chunkPos,2_pInt)) == 'element' ) then - mesh_NelemSets = mesh_NelemSets + 1_pInt - mesh_maxNelemInSet = max(mesh_maxNelemInSet, & - IO_countContinuousIntValues(fileUnit)) - endif - enddo - -620 end subroutine mesh_marc_count_elementSets - - -!******************************************************************** -! map element sets -! -! allocate globals: mesh_nameElemSet, mesh_mapElemSet -!******************************************************************** -subroutine mesh_marc_map_elementSets(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_continuousIntValues - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - integer(pInt) :: elemSet = 0_pInt - - allocate (mesh_nameElemSet(mesh_NelemSets)) ; mesh_nameElemSet = '' - allocate (mesh_mapElemSet(1_pInt+mesh_maxNelemInSet,mesh_NelemSets)) ; mesh_mapElemSet = 0_pInt - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=640) line - chunkPos = IO_stringPos(line) - if( (IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'define' ) .and. & - (IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'element' ) ) then - elemSet = elemSet+1_pInt - mesh_nameElemSet(elemSet) = trim(IO_stringValue(line,chunkPos,4_pInt)) - mesh_mapElemSet(:,elemSet) = & - IO_continuousIntValues(fileUnit,mesh_maxNelemInSet,mesh_nameElemSet,mesh_mapElemSet,mesh_NelemSets) - endif - enddo - -640 end subroutine mesh_marc_map_elementSets - - -!-------------------------------------------------------------------------------------------------- -!> @brief Count overall number of CP elements in mesh and stores them in 'mesh_NcpElems' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_marc_count_cpElements(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_countContinuousIntValues - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: i - character(len=300):: line - - mesh_NcpElems = 0_pInt - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'hypoelastic') then - do i=1_pInt,3_pInt+hypoelasticTableStyle ! Skip 3 or 4 lines - read (fileUnit,610,END=620) line - enddo - mesh_NcpElems = mesh_NcpElems + IO_countContinuousIntValues(fileUnit) ! why not simply mesh_NcpElems = IO_countContinuousIntValues(fileUnit)? - exit - endif - enddo - -620 end subroutine mesh_marc_count_cpElements - - -!-------------------------------------------------------------------------------------------------- -!> @brief Maps elements from FE ID to internal (consecutive) representation. -!! Allocates global array 'mesh_mapFEtoCPelem' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_marc_map_elements(fileUnit) - - use math, only: math_qsort - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_continuousIntValues - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - - integer(pInt), dimension (1_pInt+mesh_NcpElems) :: contInts - integer(pInt) :: i,cpElem = 0_pInt - - allocate (mesh_mapFEtoCPelem(2,mesh_NcpElems)) ; mesh_mapFEtoCPelem = 0_pInt - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=660) line - chunkPos = IO_stringPos(line) - if( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'hypoelastic' ) then - do i=1_pInt,3_pInt+hypoelasticTableStyle ! skip three (or four if new table style!) lines - read (fileUnit,610,END=660) line - enddo - contInts = IO_continuousIntValues(fileUnit,mesh_NcpElems,mesh_nameElemSet,& - mesh_mapElemSet,mesh_NelemSets) - do i = 1_pInt,contInts(1) - cpElem = cpElem+1_pInt - mesh_mapFEtoCPelem(1,cpElem) = contInts(1_pInt+i) - mesh_mapFEtoCPelem(2,cpElem) = cpElem - enddo - endif - enddo - -660 call math_qsort(mesh_mapFEtoCPelem,1_pInt,int(size(mesh_mapFEtoCPelem,2_pInt),pInt)) ! should be mesh_NcpElems - -end subroutine mesh_marc_map_elements - - -!-------------------------------------------------------------------------------------------------- -!> @brief Maps node from FE ID to internal (consecutive) representation. -!! Allocates global array 'mesh_mapFEtoCPnode' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_marc_map_nodes(fileUnit) - - use math, only: math_qsort - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_fixedIntValue - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) line - - integer(pInt), dimension (mesh_Nnodes) :: node_count - integer(pInt) :: i - - allocate (mesh_mapFEtoCPnode(2_pInt,mesh_Nnodes)) ; mesh_mapFEtoCPnode = 0_pInt - -610 FORMAT(A300) - - node_count = 0_pInt - - rewind(fileUnit) - do - read (fileUnit,610,END=650) line - chunkPos = IO_stringPos(line) - if( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'coordinates' ) then - read (fileUnit,610,END=650) line ! skip crap line - do i = 1_pInt,mesh_Nnodes - read (fileUnit,610,END=650) line - mesh_mapFEtoCPnode(1_pInt,i) = IO_fixedIntValue (line,[ 0_pInt,10_pInt],1_pInt) - mesh_mapFEtoCPnode(2_pInt,i) = i - enddo - exit - endif - enddo - -650 call math_qsort(mesh_mapFEtoCPnode,1_pInt,int(size(mesh_mapFEtoCPnode,2_pInt),pInt)) - -end subroutine mesh_marc_map_nodes - - -!-------------------------------------------------------------------------------------------------- -!> @brief store x,y,z coordinates of all nodes in mesh. -!! Allocates global arrays 'mesh_node0' and 'mesh_node' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_marc_build_nodes(fileUnit) - - use IO, only: & - IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_fixedIntValue, & - IO_fixedNoEFloatValue - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), dimension(5), parameter :: node_ends = int([0,10,30,50,70],pInt) - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - integer(pInt) :: i,j,m - - allocate ( mesh_node0 (3,mesh_Nnodes) ); mesh_node0 = 0.0_pReal - allocate ( mesh_node (3,mesh_Nnodes) ); mesh_node = 0.0_pReal - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=670) line - chunkPos = IO_stringPos(line) - if( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'coordinates' ) then - read (fileUnit,610,END=670) line ! skip crap line - do i=1_pInt,mesh_Nnodes - read (fileUnit,610,END=670) line - m = mesh_FEasCP('node',IO_fixedIntValue(line,node_ends,1_pInt)) - do j = 1_pInt,3_pInt - mesh_node0(j,m) = mesh_unitlength * IO_fixedNoEFloatValue(line,node_ends,j+1_pInt) - enddo - enddo - exit - endif - enddo - -670 mesh_node = mesh_node0 - -end subroutine mesh_marc_build_nodes - - -!-------------------------------------------------------------------------------------------------- -!> @brief Gets maximum count of nodes, IPs, IP neighbors, and cellnodes among cpElements. -!! Sets global values 'mesh_maxNnodes', 'mesh_maxNips', 'mesh_maxNipNeighbors', -!! and 'mesh_maxNcellnodes' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_marc_count_cpSizes(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_intValue, & - IO_skipChunks - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - integer(pInt) :: i,t,g,e,c - - mesh_maxNnodes = 0_pInt - mesh_maxNips = 0_pInt - mesh_maxNipNeighbors = 0_pInt - mesh_maxNcellnodes = 0_pInt - -610 FORMAT(A300) - rewind(fileUnit) - do - read (fileUnit,610,END=630) line - chunkPos = IO_stringPos(line) - if( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'connectivity' ) then - read (fileUnit,610,END=630) line ! Garbage line - do i=1_pInt,mesh_Nelems ! read all elements - read (fileUnit,610,END=630) line - chunkPos = IO_stringPos(line) ! limit to id and type - e = mesh_FEasCP('elem',IO_intValue(line,chunkPos,1_pInt)) - if (e /= 0_pInt) then - t = FE_mapElemtype(IO_stringValue(line,chunkPos,2_pInt)) - g = FE_geomtype(t) - c = FE_celltype(g) - mesh_maxNnodes = max(mesh_maxNnodes,FE_Nnodes(t)) - mesh_maxNips = max(mesh_maxNips,FE_Nips(g)) - mesh_maxNipNeighbors = max(mesh_maxNipNeighbors,FE_NipNeighbors(c)) - mesh_maxNcellnodes = max(mesh_maxNcellnodes,FE_Ncellnodes(g)) - call IO_skipChunks(fileUnit,FE_Nnodes(t)-(chunkPos(1_pInt)-2_pInt)) ! read on if FE_Nnodes exceeds node count present on current line - endif - enddo - exit - endif - enddo - -630 end subroutine mesh_marc_count_cpSizes - - -!-------------------------------------------------------------------------------------------------- -!> @brief Store FEid, type, mat, tex, and node list per element. -!! Allocates global array 'mesh_element' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_marc_build_elements(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_fixedNoEFloatValue, & - IO_skipChunks, & - IO_stringPos, & - IO_intValue, & - IO_continuousIntValues - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) line - - integer(pInt), dimension(1_pInt+mesh_NcpElems) :: contInts - integer(pInt) :: i,j,t,sv,myVal,e,nNodesAlreadyRead - - allocate (mesh_element(4_pInt+mesh_maxNnodes,mesh_NcpElems)) ; mesh_element = 0_pInt - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - if( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'connectivity' ) then - read (fileUnit,610,END=620) line ! garbage line - do i = 1_pInt,mesh_Nelems - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - e = mesh_FEasCP('elem',IO_intValue(line,chunkPos,1_pInt)) - if (e /= 0_pInt) then ! disregard non CP elems - mesh_element(1,e) = IO_IntValue (line,chunkPos,1_pInt) ! FE id - t = FE_mapElemtype(IO_StringValue(line,chunkPos,2_pInt)) ! elem type - mesh_element(2,e) = t - nNodesAlreadyRead = 0_pInt - do j = 1_pInt,chunkPos(1)-2_pInt - mesh_element(4_pInt+j,e) = mesh_FEasCP('node',IO_IntValue(line,chunkPos,j+2_pInt)) ! CP ids of nodes - enddo - nNodesAlreadyRead = chunkPos(1) - 2_pInt - do while(nNodesAlreadyRead < FE_Nnodes(t)) ! read on if not all nodes in one line - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - do j = 1_pInt,chunkPos(1) - mesh_element(4_pInt+nNodesAlreadyRead+j,e) & - = mesh_FEasCP('node',IO_IntValue(line,chunkPos,j)) ! CP ids of nodes - enddo - nNodesAlreadyRead = nNodesAlreadyRead + chunkPos(1) - enddo - endif - enddo - exit - endif - enddo - -620 rewind(fileUnit) ! just in case "initial state" appears before "connectivity" - read (fileUnit,610,END=620) line - do - chunkPos = IO_stringPos(line) - if( (IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'initial') .and. & - (IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'state') ) then - if (initialcondTableStyle == 2_pInt) read (fileUnit,610,END=620) line ! read extra line for new style - read (fileUnit,610,END=630) line ! read line with index of state var - chunkPos = IO_stringPos(line) - sv = IO_IntValue(line,chunkPos,1_pInt) ! figure state variable index - if( (sv == 2_pInt).or.(sv == 3_pInt) ) then ! only state vars 2 and 3 of interest - read (fileUnit,610,END=620) line ! read line with value of state var - chunkPos = IO_stringPos(line) - do while (scan(IO_stringValue(line,chunkPos,1_pInt),'+-',back=.true.)>1) ! is noEfloat value? - myVal = nint(IO_fixedNoEFloatValue(line,[0_pInt,20_pInt],1_pInt),pInt) ! state var's value - mesh_maxValStateVar(sv-1_pInt) = max(myVal,mesh_maxValStateVar(sv-1_pInt)) ! remember max val of homogenization and microstructure index - if (initialcondTableStyle == 2_pInt) then - read (fileUnit,610,END=630) line ! read extra line - read (fileUnit,610,END=630) line ! read extra line - endif - contInts = IO_continuousIntValues& ! get affected elements - (fileUnit,mesh_NcpElems,mesh_nameElemSet,mesh_mapElemSet,mesh_NelemSets) - do i = 1_pInt,contInts(1) - e = mesh_FEasCP('elem',contInts(1_pInt+i)) - mesh_element(1_pInt+sv,e) = myVal - enddo - if (initialcondTableStyle == 0_pInt) read (fileUnit,610,END=620) line ! ignore IP range for old table style - read (fileUnit,610,END=630) line - chunkPos = IO_stringPos(line) - enddo - endif - else - read (fileUnit,610,END=630) line - endif - enddo - -630 end subroutine mesh_marc_build_elements -#endif - -#ifdef Abaqus -!-------------------------------------------------------------------------------------------------- -!> @brief Count overall number of nodes and elements in mesh and stores them in -!! 'mesh_Nelems' and 'mesh_Nnodes' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_count_nodesAndElements(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_countDataLines, & - IO_error - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - logical :: inPart - - mesh_Nnodes = 0_pInt - mesh_Nelems = 0_pInt - -610 FORMAT(A300) - - inPart = .false. - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. - - if (inPart .or. noPart) then - select case ( IO_lc(IO_stringValue(line,chunkPos,1_pInt))) - case('*node') - if( & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'print' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'file' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' & - ) & - mesh_Nnodes = mesh_Nnodes + IO_countDataLines(fileUnit) - case('*element') - if( & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'matrix' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' & - ) then - mesh_Nelems = mesh_Nelems + IO_countDataLines(fileUnit) - endif - endselect - endif - enddo - -620 if (mesh_Nnodes < 2_pInt) call IO_error(error_ID=900_pInt) - if (mesh_Nelems == 0_pInt) call IO_error(error_ID=901_pInt) - -end subroutine mesh_abaqus_count_nodesAndElements - - -!-------------------------------------------------------------------------------------------------- -!> @brief count overall number of element sets in mesh and write 'mesh_NelemSets' and -!! 'mesh_maxNelemInSet' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_count_elementSets(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_error - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - logical :: inPart - - mesh_NelemSets = 0_pInt - mesh_maxNelemInSet = mesh_Nelems ! have to be conservative, since Abaqus allows for recursive definitons - -610 FORMAT(A300) - - inPart = .false. - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. - - if ( (inPart .or. noPart) .and. IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*elset' ) & - mesh_NelemSets = mesh_NelemSets + 1_pInt - enddo - -620 continue - if (mesh_NelemSets == 0) call IO_error(error_ID=902_pInt) - -end subroutine mesh_abaqus_count_elementSets - - -!-------------------------------------------------------------------------------------------------- -! count overall number of solid sections sets in mesh (Abaqus only) -! -! mesh_Nmaterials -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_count_materials(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_error - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - logical inPart - - mesh_Nmaterials = 0_pInt - -610 FORMAT(A300) - - inPart = .false. - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. - - if ( (inPart .or. noPart) .and. & - IO_lc(IO_StringValue(line,chunkPos,1_pInt)) == '*solid' .and. & - IO_lc(IO_StringValue(line,chunkPos,2_pInt)) == 'section' ) & - mesh_Nmaterials = mesh_Nmaterials + 1_pInt - enddo - -620 if (mesh_Nmaterials == 0_pInt) call IO_error(error_ID=903_pInt) - -end subroutine mesh_abaqus_count_materials - - -!-------------------------------------------------------------------------------------------------- -! Build element set mapping -! -! allocate globals: mesh_nameElemSet, mesh_mapElemSet -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_map_elementSets(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_extractValue, & - IO_continuousIntValues, & - IO_error - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - integer(pInt) :: elemSet = 0_pInt,i - logical :: inPart = .false. - - allocate (mesh_nameElemSet(mesh_NelemSets)) ; mesh_nameElemSet = '' - allocate (mesh_mapElemSet(1_pInt+mesh_maxNelemInSet,mesh_NelemSets)) ; mesh_mapElemSet = 0_pInt - -610 FORMAT(A300) - - - rewind(fileUnit) - do - read (fileUnit,610,END=640) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. - - if ( (inPart .or. noPart) .and. IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*elset' ) then - elemSet = elemSet + 1_pInt - mesh_nameElemSet(elemSet) = trim(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,2_pInt)),'elset')) - mesh_mapElemSet(:,elemSet) = IO_continuousIntValues(fileUnit,mesh_Nelems,mesh_nameElemSet,& - mesh_mapElemSet,elemSet-1_pInt) - endif - enddo - -640 do i = 1_pInt,elemSet - if (mesh_mapElemSet(1,i) == 0_pInt) call IO_error(error_ID=904_pInt,ext_msg=mesh_nameElemSet(i)) - enddo - -end subroutine mesh_abaqus_map_elementSets - - -!-------------------------------------------------------------------------------------------------- -! map solid section (Abaqus only) -! -! allocate globals: mesh_nameMaterial, mesh_mapMaterial -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_map_materials(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_extractValue, & - IO_error - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) line - - integer(pInt) :: i,c = 0_pInt - logical :: inPart = .false. - character(len=64) :: elemSetName,materialName - - allocate (mesh_nameMaterial(mesh_Nmaterials)) ; mesh_nameMaterial = '' - allocate (mesh_mapMaterial(mesh_Nmaterials)) ; mesh_mapMaterial = '' - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. - - if ( (inPart .or. noPart) .and. & - IO_lc(IO_StringValue(line,chunkPos,1_pInt)) == '*solid' .and. & - IO_lc(IO_StringValue(line,chunkPos,2_pInt)) == 'section' ) then - - elemSetName = '' - materialName = '' - - do i = 3_pInt,chunkPos(1_pInt) - if (IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,i)),'elset') /= '') & - elemSetName = trim(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,i)),'elset')) - if (IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,i)),'material') /= '') & - materialName = trim(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,i)),'material')) - enddo - - if (elemSetName /= '' .and. materialName /= '') then - c = c + 1_pInt - mesh_nameMaterial(c) = materialName ! name of material used for this section - mesh_mapMaterial(c) = elemSetName ! mapped to respective element set - endif - endif - enddo - -620 if (c==0_pInt) call IO_error(error_ID=905_pInt) - do i=1_pInt,c - if (mesh_nameMaterial(i)=='' .or. mesh_mapMaterial(i)=='') call IO_error(error_ID=905_pInt) - enddo - - end subroutine mesh_abaqus_map_materials - - -!-------------------------------------------------------------------------------------------------- -!> @brief Count overall number of CP elements in mesh and stores them in 'mesh_NcpElems' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_count_cpElements(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_error, & - IO_extractValue - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) line - integer(pInt) :: i,k - logical :: materialFound = .false. - character(len=64) ::materialName,elemSetName - - mesh_NcpElems = 0_pInt - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - select case ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ) - case('*material') - materialName = trim(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,2_pInt)),'name')) ! extract name=value - materialFound = materialName /= '' ! valid name? - case('*user') - if (IO_lc(IO_StringValue(line,chunkPos,2_pInt)) == 'material' .and. materialFound) then - do i = 1_pInt,mesh_Nmaterials ! look thru material names - if (materialName == mesh_nameMaterial(i)) then ! found one - elemSetName = mesh_mapMaterial(i) ! take corresponding elemSet - do k = 1_pInt,mesh_NelemSets ! look thru all elemSet definitions - if (elemSetName == mesh_nameElemSet(k)) & ! matched? - mesh_NcpElems = mesh_NcpElems + mesh_mapElemSet(1,k) ! add those elem count - enddo - endif - enddo - materialFound = .false. - endif - endselect - enddo - -620 if (mesh_NcpElems == 0_pInt) call IO_error(error_ID=906_pInt) - -end subroutine mesh_abaqus_count_cpElements - - -!-------------------------------------------------------------------------------------------------- -!> @brief Maps elements from FE ID to internal (consecutive) representation. -!! Allocates global array 'mesh_mapFEtoCPelem' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_map_elements(fileUnit) - - use math, only: math_qsort - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_extractValue, & - IO_error - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - integer(pInt) ::i,j,k,cpElem = 0_pInt - logical :: materialFound = .false. - character (len=64) materialName,elemSetName ! why limited to 64? ABAQUS? - - allocate (mesh_mapFEtoCPelem(2,mesh_NcpElems)) ; mesh_mapFEtoCPelem = 0_pInt - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=660) line - chunkPos = IO_stringPos(line) - select case ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ) - case('*material') - materialName = trim(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,2_pInt)),'name')) ! extract name=value - materialFound = materialName /= '' ! valid name? - case('*user') - if (IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'material' .and. materialFound) then - do i = 1_pInt,mesh_Nmaterials ! look thru material names - if (materialName == mesh_nameMaterial(i)) then ! found one - elemSetName = mesh_mapMaterial(i) ! take corresponding elemSet - do k = 1_pInt,mesh_NelemSets ! look thru all elemSet definitions - if (elemSetName == mesh_nameElemSet(k)) then ! matched? - do j = 1_pInt,mesh_mapElemSet(1,k) - cpElem = cpElem + 1_pInt - mesh_mapFEtoCPelem(1,cpElem) = mesh_mapElemSet(1_pInt+j,k) ! store FE id - mesh_mapFEtoCPelem(2,cpElem) = cpElem ! store our id - enddo - endif - enddo - endif - enddo - materialFound = .false. - endif - endselect - enddo - -660 call math_qsort(mesh_mapFEtoCPelem,1_pInt,int(size(mesh_mapFEtoCPelem,2_pInt),pInt)) ! should be mesh_NcpElems - - if (int(size(mesh_mapFEtoCPelem),pInt) < 2_pInt) call IO_error(error_ID=907_pInt) - -end subroutine mesh_abaqus_map_elements - - -!-------------------------------------------------------------------------------------------------- -!> @brief Maps node from FE ID to internal (consecutive) representation. -!! Allocates global array 'mesh_mapFEtoCPnode' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_map_nodes(fileUnit) - - use math, only: math_qsort - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_countDataLines, & - IO_intValue, & - IO_error - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) line - - integer(pInt) :: i,c,cpNode = 0_pInt - logical :: inPart = .false. - - allocate (mesh_mapFEtoCPnode(2_pInt,mesh_Nnodes)) ; mesh_mapFEtoCPnode = 0_pInt - -610 FORMAT(A300) - - rewind(fileUnit) - do - read (fileUnit,610,END=650) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. - - if( (inPart .or. noPart) .and. & - IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*node' .and. & - ( IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'print' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'file' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' ) & - ) then - c = IO_countDataLines(fileUnit) - do i = 1_pInt,c - backspace(fileUnit) - enddo - do i = 1_pInt,c - read (fileUnit,610,END=650) line - chunkPos = IO_stringPos(line) - cpNode = cpNode + 1_pInt - mesh_mapFEtoCPnode(1_pInt,cpNode) = IO_intValue(line,chunkPos,1_pInt) - mesh_mapFEtoCPnode(2_pInt,cpNode) = cpNode - enddo - endif - enddo - -650 call math_qsort(mesh_mapFEtoCPnode,1_pInt,int(size(mesh_mapFEtoCPnode,2_pInt),pInt)) - - if (int(size(mesh_mapFEtoCPnode),pInt) == 0_pInt) call IO_error(error_ID=908_pInt) - -end subroutine mesh_abaqus_map_nodes - - -!-------------------------------------------------------------------------------------------------- -!> @brief store x,y,z coordinates of all nodes in mesh. -!! Allocates global arrays 'mesh_node0' and 'mesh_node' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_build_nodes(fileUnit) - use IO, only: & - IO_lc, & - IO_stringValue, & - IO_floatValue, & - IO_stringPos, & - IO_error, & - IO_countDataLines, & - IO_intValue - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - integer(pInt) :: i,j,m,c - logical :: inPart - - allocate ( mesh_node0 (3,mesh_Nnodes) ); mesh_node0 = 0.0_pReal - allocate ( mesh_node (3,mesh_Nnodes) ); mesh_node = 0.0_pReal - -610 FORMAT(A300) - - inPart = .false. - rewind(fileUnit) - do - read (fileUnit,610,END=670) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. - - if( (inPart .or. noPart) .and. & - IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*node' .and. & - ( IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'print' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'file' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' ) & - ) then - c = IO_countDataLines(fileUnit) ! how many nodes are defined here? - do i = 1_pInt,c - backspace(fileUnit) ! rewind to first entry - enddo - do i = 1_pInt,c - read (fileUnit,610,END=670) line - chunkPos = IO_stringPos(line) - m = mesh_FEasCP('node',IO_intValue(line,chunkPos,1_pInt)) - do j=1_pInt, 3_pInt - mesh_node0(j,m) = mesh_unitlength * IO_floatValue(line,chunkPos,j+1_pInt) - enddo - enddo - endif - enddo - -670 if (int(size(mesh_node0,2_pInt),pInt) /= mesh_Nnodes) call IO_error(error_ID=909_pInt) - mesh_node = mesh_node0 - -end subroutine mesh_abaqus_build_nodes - - -!-------------------------------------------------------------------------------------------------- -!> @brief Gets maximum count of nodes, IPs, IP neighbors, and subNodes among cpElements. -!! Sets global values 'mesh_maxNnodes', 'mesh_maxNips', 'mesh_maxNipNeighbors', -!! and 'mesh_maxNcellnodes' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_count_cpSizes(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_stringPos, & - IO_extractValue ,& - IO_error, & - IO_countDataLines, & - IO_intValue - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=300) :: line - integer(pInt) :: i,c,t,g - logical :: inPart - - mesh_maxNnodes = 0_pInt - mesh_maxNips = 0_pInt - mesh_maxNipNeighbors = 0_pInt - mesh_maxNcellnodes = 0_pInt - -610 FORMAT(A300) - - inPart = .false. - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. - - if( (inPart .or. noPart) .and. & - IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*element' .and. & - ( IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'matrix' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' ) & - ) then - t = FE_mapElemtype(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,2_pInt)),'type')) ! remember elem type - g = FE_geomtype(t) - c = FE_celltype(g) - mesh_maxNnodes = max(mesh_maxNnodes,FE_Nnodes(t)) - mesh_maxNips = max(mesh_maxNips,FE_Nips(g)) - mesh_maxNipNeighbors = max(mesh_maxNipNeighbors,FE_NipNeighbors(c)) - mesh_maxNcellnodes = max(mesh_maxNcellnodes,FE_Ncellnodes(g)) - endif - enddo - -620 end subroutine mesh_abaqus_count_cpSizes - - -!-------------------------------------------------------------------------------------------------- -!> @brief Store FEid, type, mat, tex, and node list per elemen. -!! Allocates global array 'mesh_element' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_abaqus_build_elements(fileUnit) - - use IO, only: IO_lc, & - IO_stringValue, & - IO_skipChunks, & - IO_stringPos, & - IO_intValue, & - IO_extractValue, & - IO_floatValue, & - IO_error, & - IO_countDataLines - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - - integer(pInt) :: i,j,k,c,e,t,homog,micro, nNodesAlreadyRead - logical inPart,materialFound - character (len=64) :: materialName,elemSetName - character(len=300) :: line - - allocate (mesh_element (4_pInt+mesh_maxNnodes,mesh_NcpElems)) ; mesh_element = 0_pInt - -610 FORMAT(A300) - - inPart = .false. - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. - if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. - - if( (inPart .or. noPart) .and. & - IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*element' .and. & - ( IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'matrix' .and. & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' ) & - ) then - t = FE_mapElemtype(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,2_pInt)),'type')) ! remember elem type - c = IO_countDataLines(fileUnit) - do i = 1_pInt,c - backspace(fileUnit) - enddo - do i = 1_pInt,c - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) ! limit to 64 nodes max - e = mesh_FEasCP('elem',IO_intValue(line,chunkPos,1_pInt)) - if (e /= 0_pInt) then ! disregard non CP elems - mesh_element(1,e) = IO_intValue(line,chunkPos,1_pInt) ! FE id - mesh_element(2,e) = t ! elem type - nNodesAlreadyRead = 0_pInt - do j = 1_pInt,chunkPos(1)-1_pInt - mesh_element(4_pInt+j,e) = mesh_FEasCP('node',IO_intValue(line,chunkPos,1_pInt+j)) ! put CP ids of nodes to position 5: - enddo - nNodesAlreadyRead = chunkPos(1) - 1_pInt - do while(nNodesAlreadyRead < FE_Nnodes(t)) ! read on if not all nodes in one line - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - do j = 1_pInt,chunkPos(1) - mesh_element(4_pInt+nNodesAlreadyRead+j,e) & - = mesh_FEasCP('node',IO_IntValue(line,chunkPos,j)) ! CP ids of nodes - enddo - nNodesAlreadyRead = nNodesAlreadyRead + chunkPos(1) - enddo - endif - enddo - endif - enddo - - -620 rewind(fileUnit) ! just in case "*material" definitions apear before "*element" - - materialFound = .false. - do - read (fileUnit,610,END=630) line - chunkPos = IO_stringPos(line) - select case ( IO_lc(IO_StringValue(line,chunkPos,1_pInt))) - case('*material') - materialName = trim(IO_extractValue(IO_lc(IO_StringValue(line,chunkPos,2_pInt)),'name')) ! extract name=value - materialFound = materialName /= '' ! valid name? - case('*user') - if ( IO_lc(IO_StringValue(line,chunkPos,2_pInt)) == 'material' .and. & - materialFound ) then - read (fileUnit,610,END=630) line ! read homogenization and microstructure - chunkPos = IO_stringPos(line) - homog = nint(IO_floatValue(line,chunkPos,1_pInt),pInt) - micro = nint(IO_floatValue(line,chunkPos,2_pInt),pInt) - do i = 1_pInt,mesh_Nmaterials ! look thru material names - if (materialName == mesh_nameMaterial(i)) then ! found one - elemSetName = mesh_mapMaterial(i) ! take corresponding elemSet - do k = 1_pInt,mesh_NelemSets ! look thru all elemSet definitions - if (elemSetName == mesh_nameElemSet(k)) then ! matched? - do j = 1_pInt,mesh_mapElemSet(1,k) - e = mesh_FEasCP('elem',mesh_mapElemSet(1+j,k)) - mesh_element(3,e) = homog ! store homogenization - mesh_element(4,e) = micro ! store microstructure - mesh_maxValStateVar(1) = max(mesh_maxValStateVar(1),homog) - mesh_maxValStateVar(2) = max(mesh_maxValStateVar(2),micro) - enddo - endif - enddo - endif - enddo - materialFound = .false. - endif - endselect - enddo - -630 end subroutine mesh_abaqus_build_elements -#endif - - -!-------------------------------------------------------------------------------------------------- -!> @brief get any additional damask options from input file, sets mesh_periodicSurface -!-------------------------------------------------------------------------------------------------- -subroutine mesh_get_damaskOptions(fileUnit) - -use IO, only: & - IO_lc, & - IO_stringValue, & - IO_stringPos - - implicit none - integer(pInt), intent(in) :: fileUnit - -#ifndef Spectral - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) chunk, Nchunks - character(len=300) :: line, damaskOption, v - character(len=300) :: keyword -#endif - -#ifdef Spectral - mesh_periodicSurface = .true. -#else - mesh_periodicSurface = .false. -#ifdef Marc4DAMASK - keyword = '$damask' -#endif -#ifdef Abaqus - keyword = '**damask' -#endif - - rewind(fileUnit) - do - read (fileUnit,610,END=620) line - chunkPos = IO_stringPos(line) - Nchunks = chunkPos(1) - if (IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == keyword .and. Nchunks > 1_pInt) then ! found keyword for damask option and there is at least one more chunk to read - damaskOption = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - select case(damaskOption) - case('periodic') ! damask Option that allows to specify periodic fluxes - do chunk = 3_pInt,Nchunks ! loop through chunks (skipping the keyword) - v = IO_lc(IO_stringValue(line,chunkPos,chunk)) ! chunk matches keyvalues x,y, or z? - mesh_periodicSurface(1) = mesh_periodicSurface(1) .or. v == 'x' - mesh_periodicSurface(2) = mesh_periodicSurface(2) .or. v == 'y' - mesh_periodicSurface(3) = mesh_periodicSurface(3) .or. v == 'z' - enddo - endselect - endif - enddo - -610 FORMAT(A300) -#endif - -620 end subroutine mesh_get_damaskOptions - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculation of IP interface areas, allocate globals '_ipArea', and '_ipAreaNormal' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_build_ipAreas - use math, only: & - math_crossproduct - - implicit none - integer(pInt) :: e,t,g,c,i,f,n,m - real(pReal), dimension (3,FE_maxNcellnodesPerCellface) :: nodePos, normals - real(pReal), dimension(3) :: normal - - allocate(mesh_ipArea(mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - allocate(mesh_ipAreaNormal(3_pInt,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) - - !$OMP PARALLEL DO PRIVATE(t,g,c,nodePos,normal,normals) - do e = 1_pInt,mesh_NcpElems ! loop over cpElems - t = mesh_element(2_pInt,e) ! get element type - g = FE_geomtype(t) ! get geometry type - c = FE_celltype(g) ! get cell type - select case (c) - - case (1_pInt,2_pInt) ! 2D 3 or 4 node - do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element - do f = 1_pInt,FE_NipNeighbors(c) ! loop over cell faces - forall(n = 1_pInt:FE_NcellnodesPerCellface(c)) & - nodePos(1:3,n) = mesh_cellnode(1:3,mesh_cell(FE_cellface(n,f,c),i,e)) - normal(1) = nodePos(2,2) - nodePos(2,1) ! x_normal = y_connectingVector - normal(2) = -(nodePos(1,2) - nodePos(1,1)) ! y_normal = -x_connectingVector - normal(3) = 0.0_pReal - mesh_ipArea(f,i,e) = norm2(normal) - mesh_ipAreaNormal(1:3,f,i,e) = normal / norm2(normal) ! ensure unit length of area normal - enddo - enddo - - case (3_pInt) ! 3D 4node - do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element - do f = 1_pInt,FE_NipNeighbors(c) ! loop over cell faces - forall(n = 1_pInt:FE_NcellnodesPerCellface(c)) & - nodePos(1:3,n) = mesh_cellnode(1:3,mesh_cell(FE_cellface(n,f,c),i,e)) - normal = math_crossproduct(nodePos(1:3,2) - nodePos(1:3,1), & - nodePos(1:3,3) - nodePos(1:3,1)) - mesh_ipArea(f,i,e) = norm2(normal) - mesh_ipAreaNormal(1:3,f,i,e) = normal / norm2(normal) ! ensure unit length of area normal - enddo - enddo - - case (4_pInt) ! 3D 8node - ! for this cell type we get the normal of the quadrilateral face as an average of - ! four normals of triangular subfaces; since the face consists only of two triangles, - ! the sum has to be divided by two; this whole prcedure tries to compensate for - ! probable non-planar cell surfaces - m = FE_NcellnodesPerCellface(c) - do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element - do f = 1_pInt,FE_NipNeighbors(c) ! loop over cell faces - forall(n = 1_pInt:FE_NcellnodesPerCellface(c)) & - nodePos(1:3,n) = mesh_cellnode(1:3,mesh_cell(FE_cellface(n,f,c),i,e)) - forall(n = 1_pInt:FE_NcellnodesPerCellface(c)) & - normals(1:3,n) = 0.5_pReal & - * math_crossproduct(nodePos(1:3,1+mod(n ,m)) - nodePos(1:3,n), & - nodePos(1:3,1+mod(n+1,m)) - nodePos(1:3,n)) - normal = 0.5_pReal * sum(normals,2) - mesh_ipArea(f,i,e) = norm2(normal) - mesh_ipAreaNormal(1:3,f,i,e) = normal / norm2(normal) - enddo - enddo - - end select - enddo - !$OMP END PARALLEL DO - -end subroutine mesh_build_ipAreas - -#ifndef Spectral -!-------------------------------------------------------------------------------------------------- -!> @brief assignment of twin nodes for each cp node, allocate globals '_nodeTwins' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_build_nodeTwins - - implicit none - integer(pInt) dir, & ! direction of periodicity - node, & - minimumNode, & - maximumNode, & - n1, & - n2 - integer(pInt), dimension(mesh_Nnodes+1) :: minimumNodes, maximumNodes ! list of surface nodes (minimum and maximum coordinate value) with first entry giving the number of nodes - real(pReal) minCoord, maxCoord, & ! extreme positions in one dimension - tolerance ! tolerance below which positions are assumed identical - real(pReal), dimension(3) :: distance ! distance between two nodes in all three coordinates - logical, dimension(mesh_Nnodes) :: unpaired - - allocate(mesh_nodeTwins(3,mesh_Nnodes)) - mesh_nodeTwins = 0_pInt - - tolerance = 0.001_pReal * minval(mesh_ipVolume) ** 0.333_pReal - - do dir = 1_pInt,3_pInt ! check periodicity in directions of x,y,z - if (mesh_periodicSurface(dir)) then ! only if periodicity is requested - - - !*** find out which nodes sit on the surface - !*** and have a minimum or maximum position in this dimension - - minimumNodes = 0_pInt - maximumNodes = 0_pInt - minCoord = minval(mesh_node0(dir,:)) - maxCoord = maxval(mesh_node0(dir,:)) - do node = 1_pInt,mesh_Nnodes ! loop through all nodes and find surface nodes - if (abs(mesh_node0(dir,node) - minCoord) <= tolerance) then - minimumNodes(1) = minimumNodes(1) + 1_pInt - minimumNodes(minimumNodes(1)+1_pInt) = node - elseif (abs(mesh_node0(dir,node) - maxCoord) <= tolerance) then - maximumNodes(1) = maximumNodes(1) + 1_pInt - maximumNodes(maximumNodes(1)+1_pInt) = node - endif - enddo - - - !*** find the corresponding node on the other side with the same position in this dimension - - unpaired = .true. - do n1 = 1_pInt,minimumNodes(1) - minimumNode = minimumNodes(n1+1_pInt) - if (unpaired(minimumNode)) then - do n2 = 1_pInt,maximumNodes(1) - maximumNode = maximumNodes(n2+1_pInt) - distance = abs(mesh_node0(:,minimumNode) - mesh_node0(:,maximumNode)) - if (sum(distance) - distance(dir) <= tolerance) then ! minimum possible distance (within tolerance) - mesh_nodeTwins(dir,minimumNode) = maximumNode - mesh_nodeTwins(dir,maximumNode) = minimumNode - unpaired(maximumNode) = .false. ! remember this node, we don't have to look for his partner again - exit - endif - enddo - endif - enddo - - endif - enddo - -end subroutine mesh_build_nodeTwins - - -!-------------------------------------------------------------------------------------------------- -!> @brief get maximum count of shared elements among cpElements and build list of elements shared -!! by each node in mesh. Allocate globals '_maxNsharedElems' and '_sharedElem' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_build_sharedElems - - implicit none - integer(pint) e, & ! element index - g, & ! element type - node, & ! CP node index - n, & ! node index per element - myDim, & ! dimension index - nodeTwin ! node twin in the specified dimension - integer(pInt), dimension (mesh_Nnodes) :: node_count - integer(pInt), dimension (:), allocatable :: node_seen - - allocate(node_seen(maxval(FE_NmatchingNodes))) - - - node_count = 0_pInt - - do e = 1_pInt,mesh_NcpElems - g = FE_geomtype(mesh_element(2,e)) ! get elemGeomType - node_seen = 0_pInt ! reset node duplicates - do n = 1_pInt,FE_NmatchingNodes(g) ! check each node of element - node = mesh_element(4+n,e) - if (all(node_seen /= node)) then - node_count(node) = node_count(node) + 1_pInt ! if FE node not yet encountered -> count it - do myDim = 1_pInt,3_pInt ! check in each dimension... - nodeTwin = mesh_nodeTwins(myDim,node) - if (nodeTwin > 0_pInt) & ! if I am a twin of some node... - node_count(nodeTwin) = node_count(nodeTwin) + 1_pInt ! -> count me again for the twin node - enddo - endif - node_seen(n) = node ! remember this node to be counted already - enddo - enddo - - mesh_maxNsharedElems = int(maxval(node_count),pInt) ! most shared node - - allocate(mesh_sharedElem(1+mesh_maxNsharedElems,mesh_Nnodes)) - mesh_sharedElem = 0_pInt - - do e = 1_pInt,mesh_NcpElems - g = FE_geomtype(mesh_element(2,e)) ! get elemGeomType - node_seen = 0_pInt - do n = 1_pInt,FE_NmatchingNodes(g) - node = mesh_element(4_pInt+n,e) - if (all(node_seen /= node)) then - mesh_sharedElem(1,node) = mesh_sharedElem(1,node) + 1_pInt ! count for each node the connected elements - mesh_sharedElem(mesh_sharedElem(1,node)+1_pInt,node) = e ! store the respective element id - do myDim = 1_pInt,3_pInt ! check in each dimension... - nodeTwin = mesh_nodeTwins(myDim,node) - if (nodeTwin > 0_pInt) then ! if i am a twin of some node... - mesh_sharedElem(1,nodeTwin) = mesh_sharedElem(1,nodeTwin) + 1_pInt ! ...count me again for the twin - mesh_sharedElem(mesh_sharedElem(1,nodeTwin)+1,nodeTwin) = e ! store the respective element id - endif - enddo - endif - node_seen(n) = node - enddo - enddo - - deallocate(node_seen) - -end subroutine mesh_build_sharedElems - - -!-------------------------------------------------------------------------------------------------- -!> @brief build up of IP neighborhood, allocate globals '_ipNeighborhood' -!-------------------------------------------------------------------------------------------------- -subroutine mesh_build_ipNeighborhood - use math, only: & - math_mul3x3 - - implicit none - integer(pInt) :: myElem, & ! my CP element index - myIP, & - myType, & ! my element type - myFace, & - neighbor, & ! neighor index - neighboringIPkey, & ! positive integer indicating the neighboring IP (for intra-element) and negative integer indicating the face towards neighbor (for neighboring element) - candidateIP, & - neighboringType, & ! element type of neighbor - NlinkedNodes, & ! number of linked nodes - twin_of_linkedNode, & ! node twin of a specific linkedNode - NmatchingNodes, & ! number of matching nodes - dir, & ! direction of periodicity - matchingElem, & ! CP elem number of matching element - matchingFace, & ! face ID of matching element - a, anchor, & - neighboringIP, & - neighboringElem, & - pointingToMe - integer(pInt), dimension(FE_maxmaxNnodesAtIP) :: & - linkedNodes = 0_pInt, & - matchingNodes - logical checkTwins - - allocate(mesh_ipNeighborhood(3,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems)) - mesh_ipNeighborhood = 0_pInt - - - do myElem = 1_pInt,mesh_NcpElems ! loop over cpElems - myType = FE_geomtype(mesh_element(2,myElem)) ! get elemGeomType - do myIP = 1_pInt,FE_Nips(myType) ! loop over IPs of elem - - do neighbor = 1_pInt,FE_NipNeighbors(FE_celltype(myType)) ! loop over neighbors of IP - neighboringIPkey = FE_ipNeighbor(neighbor,myIP,myType) - - !*** if the key is positive, the neighbor is inside the element - !*** that means, we have already found our neighboring IP - - if (neighboringIPkey > 0_pInt) then - mesh_ipNeighborhood(1,neighbor,myIP,myElem) = myElem - mesh_ipNeighborhood(2,neighbor,myIP,myElem) = neighboringIPkey - - - !*** if the key is negative, the neighbor resides in a neighboring element - !*** that means, we have to look through the face indicated by the key and see which element is behind that face - - elseif (neighboringIPkey < 0_pInt) then ! neighboring element's IP - myFace = -neighboringIPkey - call mesh_faceMatch(myElem, myFace, matchingElem, matchingFace) ! get face and CP elem id of face match - if (matchingElem > 0_pInt) then ! found match? - neighboringType = FE_geomtype(mesh_element(2,matchingElem)) - - !*** trivial solution if neighbor has only one IP - - if (FE_Nips(neighboringType) == 1_pInt) then - mesh_ipNeighborhood(1,neighbor,myIP,myElem) = matchingElem - mesh_ipNeighborhood(2,neighbor,myIP,myElem) = 1_pInt - cycle - endif - - !*** find those nodes which build the link to the neighbor - - NlinkedNodes = 0_pInt - linkedNodes = 0_pInt - do a = 1_pInt,FE_maxNnodesAtIP(myType) ! figure my anchor nodes on connecting face - anchor = FE_nodesAtIP(a,myIP,myType) - if (anchor /= 0_pInt) then ! valid anchor node - if (any(FE_face(:,myFace,myType) == anchor)) then ! ip anchor sits on face? - NlinkedNodes = NlinkedNodes + 1_pInt - linkedNodes(NlinkedNodes) = mesh_element(4_pInt+anchor,myElem) ! CP id of anchor node - else ! something went wrong with the linkage, since not all anchors sit on my face - NlinkedNodes = 0_pInt - linkedNodes = 0_pInt - exit - endif - endif - enddo - - !*** loop through the ips of my neighbor - !*** and try to find an ip with matching nodes - !*** also try to match with node twins - - checkCandidateIP: do candidateIP = 1_pInt,FE_Nips(neighboringType) - NmatchingNodes = 0_pInt - matchingNodes = 0_pInt - do a = 1_pInt,FE_maxNnodesAtIP(neighboringType) ! check each anchor node of that ip - anchor = FE_nodesAtIP(a,candidateIP,neighboringType) - if (anchor /= 0_pInt) then ! valid anchor node - if (any(FE_face(:,matchingFace,neighboringType) == anchor)) then ! sits on matching face? - NmatchingNodes = NmatchingNodes + 1_pInt - matchingNodes(NmatchingNodes) = mesh_element(4+anchor,matchingElem) ! CP id of neighbor's anchor node - else ! no matching, because not all nodes sit on the matching face - NmatchingNodes = 0_pInt - matchingNodes = 0_pInt - exit - endif - endif - enddo - - if (NmatchingNodes /= NlinkedNodes) & ! this ip has wrong count of anchors on face - cycle checkCandidateIP - - !*** check "normal" nodes whether they match or not - - checkTwins = .false. - do a = 1_pInt,NlinkedNodes - if (all(matchingNodes /= linkedNodes(a))) then ! this linkedNode does not match any matchingNode - checkTwins = .true. - exit ! no need to search further - endif - enddo - - !*** if no match found, then also check node twins - - if(checkTwins) then - dir = int(maxloc(abs(mesh_ipAreaNormal(1:3,neighbor,myIP,myElem)),1),pInt) ! check for twins only in direction of the surface normal - do a = 1_pInt,NlinkedNodes - twin_of_linkedNode = mesh_nodeTwins(dir,linkedNodes(a)) - if (twin_of_linkedNode == 0_pInt .or. & ! twin of linkedNode does not exist... - all(matchingNodes /= twin_of_linkedNode)) then ! ... or it does not match any matchingNode - cycle checkCandidateIP ! ... then check next candidateIP - endif - enddo - endif - - !*** we found a match !!! - - mesh_ipNeighborhood(1,neighbor,myIP,myElem) = matchingElem - mesh_ipNeighborhood(2,neighbor,myIP,myElem) = candidateIP - exit checkCandidateIP - enddo checkCandidateIP - endif ! end of valid external matching - endif ! end of internal/external matching - enddo - enddo - enddo - do myElem = 1_pInt,mesh_NcpElems ! loop over cpElems - myType = FE_geomtype(mesh_element(2,myElem)) ! get elemGeomType - do myIP = 1_pInt,FE_Nips(myType) ! loop over IPs of elem - do neighbor = 1_pInt,FE_NipNeighbors(FE_celltype(myType)) ! loop over neighbors of IP - neighboringElem = mesh_ipNeighborhood(1,neighbor,myIP,myElem) - neighboringIP = mesh_ipNeighborhood(2,neighbor,myIP,myElem) - if (neighboringElem > 0_pInt .and. neighboringIP > 0_pInt) then ! if neighbor exists ... - neighboringType = FE_geomtype(mesh_element(2,neighboringElem)) - do pointingToMe = 1_pInt,FE_NipNeighbors(FE_celltype(neighboringType)) ! find neighboring index that points from my neighbor to myself - if ( myElem == mesh_ipNeighborhood(1,pointingToMe,neighboringIP,neighboringElem) & - .and. myIP == mesh_ipNeighborhood(2,pointingToMe,neighboringIP,neighboringElem)) then ! possible candidate - if (math_mul3x3(mesh_ipAreaNormal(1:3,neighbor,myIP,myElem),& - mesh_ipAreaNormal(1:3,pointingToMe,neighboringIP,neighboringElem)) < 0.0_pReal) then ! area normals have opposite orientation (we have to check that because of special case for single element with two ips and periodicity. In this case the neighbor is identical in two different directions.) - mesh_ipNeighborhood(3,neighbor,myIP,myElem) = pointingToMe ! found match - exit ! so no need to search further - endif - endif - enddo - endif - enddo - enddo - enddo - -end subroutine mesh_build_ipNeighborhood -#endif - - -!-------------------------------------------------------------------------------------------------- -!> @brief write statistics regarding input file parsing to the output file -!-------------------------------------------------------------------------------------------------- -subroutine mesh_tell_statistics - use math, only: & - math_range - use IO, only: & - IO_error - use debug, only: & - debug_level, & - debug_MESH, & - debug_LEVELBASIC, & - debug_LEVELEXTENSIVE, & - debug_LEVELSELECTIVE, & - debug_e, & - debug_i - - implicit none - integer(pInt), dimension (:,:), allocatable :: mesh_HomogMicro - character(len=64) :: myFmt - integer(pInt) :: i,e,n,f,t,g,c, myDebug - - myDebug = debug_level(debug_mesh) - - if (mesh_maxValStateVar(1) < 1_pInt) call IO_error(error_ID=170_pInt) ! no homogenization specified - if (mesh_maxValStateVar(2) < 1_pInt) call IO_error(error_ID=180_pInt) ! no microstructure specified - - allocate (mesh_HomogMicro(mesh_maxValStateVar(1),mesh_maxValStateVar(2))); mesh_HomogMicro = 0_pInt -do e = 1_pInt,mesh_NcpElems - if (mesh_element(3,e) < 1_pInt) call IO_error(error_ID=170_pInt,el=e) ! no homogenization specified - if (mesh_element(4,e) < 1_pInt) call IO_error(error_ID=180_pInt,el=e) ! no microstructure specified - mesh_HomogMicro(mesh_element(3,e),mesh_element(4,e)) = & - mesh_HomogMicro(mesh_element(3,e),mesh_element(4,e)) + 1_pInt ! count combinations of homogenization and microstructure -enddo -!$OMP CRITICAL (write2out) - if (iand(myDebug,debug_levelBasic) /= 0_pInt) then - write(6,'(/,a,/)') ' Input Parser: STATISTICS' - write(6,*) mesh_Nelems, ' : total number of elements in mesh' - write(6,*) mesh_NcpElems, ' : total number of CP elements in mesh' - write(6,*) mesh_Nnodes, ' : total number of nodes in mesh' - write(6,*) mesh_maxNnodes, ' : max number of nodes in any CP element' - write(6,*) mesh_maxNips, ' : max number of IPs in any CP element' - write(6,*) mesh_maxNipNeighbors, ' : max number of IP neighbors in any CP element' - write(6,*) mesh_maxNsharedElems, ' : max number of CP elements sharing a node' - write(6,'(/,a,/)') ' Input Parser: HOMOGENIZATION/MICROSTRUCTURE' - write(6,*) mesh_maxValStateVar(1), ' : maximum homogenization index' - write(6,*) mesh_maxValStateVar(2), ' : maximum microstructure index' - write(6,*) - write (myFmt,'(a,i32.32,a)') '(9x,a2,1x,',mesh_maxValStateVar(2),'(i8))' - write(6,myFmt) '+-',math_range(mesh_maxValStateVar(2)) - write (myFmt,'(a,i32.32,a)') '(i8,1x,a2,1x,',mesh_maxValStateVar(2),'(i8))' - do i=1_pInt,mesh_maxValStateVar(1) ! loop over all (possibly assigned) homogenizations - write(6,myFmt) i,'| ',mesh_HomogMicro(i,:) ! loop over all (possibly assigned) microstructures - enddo - write(6,'(/,a,/)') ' Input Parser: ADDITIONAL MPIE OPTIONS' - write(6,*) 'periodic surface : ', mesh_periodicSurface - write(6,*) - flush(6) - endif - - if (iand(myDebug,debug_levelExtensive) /= 0_pInt) then - write(6,'(/,a,/)') 'Input Parser: ELEMENT TYPE' - write(6,'(a8,3(1x,a8))') 'elem','elemtype','geomtype','celltype' - do e = 1_pInt,mesh_NcpElems - if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_e /= e) cycle - t = mesh_element(2,e) ! get elemType - g = FE_geomtype(t) ! get elemGeomType - c = FE_celltype(g) ! get cellType - write(6,'(i8,3(1x,i8))') e,t,g,c - enddo - write(6,'(/,a)') 'Input Parser: ELEMENT VOLUME' - write(6,'(/,a13,1x,e15.8)') 'total volume', sum(mesh_ipVolume) - write(6,'(/,a8,1x,a5,1x,a15,1x,a5,1x,a15,1x,a16)') 'elem','IP','volume','face','area','-- normal --' - do e = 1_pInt,mesh_NcpElems - if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_e /= e) cycle - t = mesh_element(2,e) ! get element type - g = FE_geomtype(t) ! get geometry type - c = FE_celltype(g) ! get cell type - do i = 1_pInt,FE_Nips(g) - if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_i /= i) cycle - write(6,'(i8,1x,i5,1x,e15.8)') e,i,mesh_IPvolume(i,e) - do f = 1_pInt,FE_NipNeighbors(c) - write(6,'(i33,1x,e15.8,1x,3(f6.3,1x))') f,mesh_ipArea(f,i,e),mesh_ipAreaNormal(:,f,i,e) - enddo - enddo - enddo - write(6,'(/,a,/)') 'Input Parser: CELLNODE COORDINATES' - write(6,'(a8,1x,a2,1x,a8,3(1x,a12))') 'elem','IP','cellnode','x','y','z' - do e = 1_pInt,mesh_NcpElems ! loop over cpElems - if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_e /= e) cycle - t = mesh_element(2,e) ! get element type - g = FE_geomtype(t) ! get geometry type - c = FE_celltype(g) ! get cell type - do i = 1_pInt,FE_Nips(g) ! loop over IPs of elem - if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_i /= i) cycle - write(6,'(i8,1x,i2)') e,i - do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in the cell - write(6,'(12x,i8,3(1x,f12.8))') mesh_cell(n,i,e), & - mesh_cellnode(1:3,mesh_cell(n,i,e)) - enddo - enddo - enddo - write(6,'(/,a)') 'Input Parser: IP COORDINATES' - write(6,'(a8,1x,a5,3(1x,a12))') 'elem','IP','x','y','z' - do e = 1_pInt,mesh_NcpElems - if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_e /= e) cycle - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_i /= i) cycle - write(6,'(i8,1x,i5,3(1x,f12.8))') e, i, mesh_ipCoordinates(:,i,e) - enddo - enddo -#ifndef Spectral - write(6,'(/,a,/)') 'Input Parser: NODE TWINS' - write(6,'(a6,3(3x,a6))') ' node','twin_x','twin_y','twin_z' - do n = 1_pInt,mesh_Nnodes ! loop over cpNodes - if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. .not. any(mesh_element(5:,debug_e) == n)) cycle - write(6,'(i6,3(3x,i6))') n, mesh_nodeTwins(1:3,n) - enddo -#endif - write(6,'(/,a,/)') 'Input Parser: IP NEIGHBORHOOD' - write(6,'(a8,1x,a10,1x,a10,1x,a3,1x,a13,1x,a13)') 'elem','IP','neighbor','','elemNeighbor','ipNeighbor' - do e = 1_pInt,mesh_NcpElems ! loop over cpElems - if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_e /= e) cycle - t = mesh_element(2,e) ! get element type - g = FE_geomtype(t) ! get geometry type - c = FE_celltype(g) ! get cell type - do i = 1_pInt,FE_Nips(g) ! loop over IPs of elem - if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_i /= i) cycle - do n = 1_pInt,FE_NipNeighbors(c) ! loop over neighbors of IP - write(6,'(i8,1x,i10,1x,i10,1x,a3,1x,i13,1x,i13)') e,i,n,'-->',mesh_ipNeighborhood(1,n,i,e),mesh_ipNeighborhood(2,n,i,e) - enddo - enddo - enddo - endif -!$OMP END CRITICAL (write2out) - - deallocate(mesh_HomogMicro) - -end subroutine mesh_tell_statistics - - -!-------------------------------------------------------------------------------------------------- -!> @brief mapping of FE element types to internal representation -!-------------------------------------------------------------------------------------------------- -integer(pInt) function FE_mapElemtype(what) - use IO, only: IO_lc, IO_error - - implicit none - character(len=*), intent(in) :: what - - select case (IO_lc(what)) - case ( '6') - FE_mapElemtype = 1_pInt ! Two-dimensional Plane Strain Triangle - case ( '155', & - '125', & - '128') - FE_mapElemtype = 2_pInt ! Two-dimensional Plane Strain triangle (155: cubic shape function, 125/128: second order isoparametric) - case ( '11', & - 'cpe4', & - 'cpe4t') - FE_mapElemtype = 3_pInt ! Arbitrary Quadrilateral Plane-strain - case ( '27', & - 'cpe8', & - 'cpe8t') - FE_mapElemtype = 4_pInt ! Plane Strain, Eight-node Distorted Quadrilateral - case ( '54') - FE_mapElemtype = 5_pInt ! Plane Strain, Eight-node Distorted Quadrilateral with reduced integration - case ( '134', & - 'c3d4', & - 'c3d4t') - FE_mapElemtype = 6_pInt ! Three-dimensional Four-node Tetrahedron - case ( '157') - FE_mapElemtype = 7_pInt ! Three-dimensional, Low-order, Tetrahedron, Herrmann Formulations - case ( '127') - FE_mapElemtype = 8_pInt ! Three-dimensional Ten-node Tetrahedron - case ( '136', & - 'c3d6', & - 'c3d6t') - FE_mapElemtype = 9_pInt ! Three-dimensional Arbitrarily Distorted Pentahedral - case ( '117', & - '123', & - 'c3d8r', & - 'c3d8rt') - FE_mapElemtype = 10_pInt ! Three-dimensional Arbitrarily Distorted linear hexahedral with reduced integration - case ( '7', & - 'c3d8', & - 'c3d8t') - FE_mapElemtype = 11_pInt ! Three-dimensional Arbitrarily Distorted Brick - case ( '57', & - 'c3d20r', & - 'c3d20rt') - FE_mapElemtype = 12_pInt ! Three-dimensional Arbitrarily Distorted quad hexahedral with reduced integration - case ( '21', & - 'c3d20', & - 'c3d20t') - FE_mapElemtype = 13_pInt ! Three-dimensional Arbitrarily Distorted quadratic hexahedral - case default - call IO_error(error_ID=190_pInt,ext_msg=IO_lc(what)) - end select - -end function FE_mapElemtype - - -!-------------------------------------------------------------------------------------------------- -!> @brief find face-matching element of same type -!-------------------------------------------------------------------------------------------------- -subroutine mesh_faceMatch(elem, face ,matchingElem, matchingFace) - -implicit none -!*** output variables -integer(pInt), intent(out) :: matchingElem, & ! matching CP element ID - matchingFace ! matching face ID - -!*** input variables -integer(pInt), intent(in) :: face, & ! face ID - elem ! CP elem ID - -!*** local variables -integer(pInt), dimension(FE_NmatchingNodesPerFace(face,FE_geomtype(mesh_element(2,elem)))) :: & - myFaceNodes ! global node ids on my face -integer(pInt) :: myType, & - candidateType, & - candidateElem, & - candidateFace, & - candidateFaceNode, & - minNsharedElems, & - NsharedElems, & - lonelyNode = 0_pInt, & - i, & - n, & - dir ! periodicity direction -integer(pInt), dimension(:), allocatable :: element_seen -logical checkTwins - -matchingElem = 0_pInt -matchingFace = 0_pInt -minNsharedElems = mesh_maxNsharedElems + 1_pInt ! init to worst case -myType = FE_geomtype(mesh_element(2_pInt,elem)) ! figure elemGeomType - -do n = 1_pInt,FE_NmatchingNodesPerFace(face,myType) ! loop over nodes on face - myFaceNodes(n) = mesh_element(4_pInt+FE_face(n,face,myType),elem) ! CP id of face node - NsharedElems = mesh_sharedElem(1_pInt,myFaceNodes(n)) ! figure # shared elements for this node - if (NsharedElems < minNsharedElems) then - minNsharedElems = NsharedElems ! remember min # shared elems - lonelyNode = n ! remember most lonely node - endif -enddo - -allocate(element_seen(minNsharedElems)) -element_seen = 0_pInt - -checkCandidate: do i = 1_pInt,minNsharedElems ! iterate over lonelyNode's shared elements - candidateElem = mesh_sharedElem(1_pInt+i,myFaceNodes(lonelyNode)) ! present candidate elem - if (all(element_seen /= candidateElem)) then ! element seen for the first time? - element_seen(i) = candidateElem - candidateType = FE_geomtype(mesh_element(2_pInt,candidateElem)) ! figure elemGeomType of candidate -checkCandidateFace: do candidateFace = 1_pInt,FE_maxNipNeighbors ! check each face of candidate - if (FE_NmatchingNodesPerFace(candidateFace,candidateType) & - /= FE_NmatchingNodesPerFace(face,myType) & ! incompatible face - .or. (candidateElem == elem .and. candidateFace == face)) then ! this is my face - cycle checkCandidateFace - endif - checkTwins = .false. - do n = 1_pInt,FE_NmatchingNodesPerFace(candidateFace,candidateType) ! loop through nodes on face - candidateFaceNode = mesh_element(4_pInt+FE_face(n,candidateFace,candidateType),candidateElem) - if (all(myFaceNodes /= candidateFaceNode)) then ! candidate node does not match any of my face nodes - checkTwins = .true. ! perhaps the twin nodes do match - exit - endif - enddo - if(checkTwins) then -checkCandidateFaceTwins: do dir = 1_pInt,3_pInt - do n = 1_pInt,FE_NmatchingNodesPerFace(candidateFace,candidateType) ! loop through nodes on face - candidateFaceNode = mesh_element(4+FE_face(n,candidateFace,candidateType),candidateElem) - if (all(myFaceNodes /= mesh_nodeTwins(dir,candidateFaceNode))) then ! node twin does not match either - if (dir == 3_pInt) then - cycle checkCandidateFace - else - cycle checkCandidateFaceTwins ! try twins in next dimension - endif - endif - enddo - exit checkCandidateFaceTwins - enddo checkCandidateFaceTwins - endif - matchingFace = candidateFace - matchingElem = candidateElem - exit checkCandidate ! found my matching candidate - enddo checkCandidateFace - endif -enddo checkCandidate - -deallocate(element_seen) - -end subroutine mesh_faceMatch - - -!-------------------------------------------------------------------------------------------------- -!> @brief get properties of different types of finite elements -!> @details assign globals: FE_nodesAtIP, FE_ipNeighbor, FE_cellnodeParentnodeWeights, FE_subNodeOnIPFace -!-------------------------------------------------------------------------------------------------- -subroutine mesh_build_FEdata - - implicit none - integer(pInt) :: me - allocate(FE_nodesAtIP(FE_maxmaxNnodesAtIP,FE_maxNips,FE_Ngeomtypes)); FE_nodesAtIP = 0_pInt - allocate(FE_ipNeighbor(FE_maxNipNeighbors,FE_maxNips,FE_Ngeomtypes)); FE_ipNeighbor = 0_pInt - allocate(FE_cell(FE_maxNcellnodesPerCell,FE_maxNips,FE_Ngeomtypes)); FE_cell = 0_pInt - allocate(FE_cellnodeParentnodeWeights(FE_maxNnodes,FE_maxNcellnodes,FE_Nelemtypes)); FE_cellnodeParentnodeWeights = 0.0_pReal - allocate(FE_cellface(FE_maxNcellnodesPerCellface,FE_maxNcellfaces,FE_Ncelltypes)); FE_cellface = 0_pInt - - - !*** fill FE_nodesAtIP with data *** - - me = 0_pInt - - me = me + 1_pInt - FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 6 (2D 3node 1ip) - reshape(int([& - 1,2,3 & - ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) - - me = me + 1_pInt - FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 125 (2D 6node 3ip) - reshape(int([& - 1, & - 2, & - 3 & - ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) - - me = me + 1_pInt - FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 11 (2D 4node 4ip) - reshape(int([& - 1, & - 2, & - 4, & - 3 & - ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) - - me = me + 1_pInt - FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 27 (2D 8node 9ip) - reshape(int([& - 1,0, & - 1,2, & - 2,0, & - 1,4, & - 0,0, & - 2,3, & - 4,0, & - 3,4, & - 3,0 & - ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) - - me = me + 1_pInt - FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 134 (3D 4node 1ip) - reshape(int([& - 1,2,3,4 & - ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) - - me = me + 1_pInt - FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 127 (3D 10node 4ip) - reshape(int([& - 1, & - 2, & - 3, & - 4 & - ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) - - me = me + 1_pInt - FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 136 (3D 6node 6ip) - reshape(int([& - 1, & - 2, & - 3, & - 4, & - 5, & - 6 & - ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) - - me = me + 1_pInt - FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 117 (3D 8node 1ip) - reshape(int([& - 1,2,3,4,5,6,7,8 & - ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) - - me = me + 1_pInt - FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 7 (3D 8node 8ip) - reshape(int([& - 1, & - 2, & - 4, & - 3, & - 5, & - 6, & - 8, & - 7 & - ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) - - me = me + 1_pInt - FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 21 (3D 20node 27ip) - reshape(int([& - 1,0, 0,0, & - 1,2, 0,0, & - 2,0, 0,0, & - 1,4, 0,0, & - 1,3, 2,4, & - 2,3, 0,0, & - 4,0, 0,0, & - 3,4, 0,0, & - 3,0, 0,0, & - 1,5, 0,0, & - 1,6, 2,5, & - 2,6, 0,0, & - 1,8, 4,5, & - 0,0, 0,0, & - 2,7, 3,6, & - 4,8, 0,0, & - 3,8, 4,7, & - 3,7, 0,0, & - 5,0, 0,0, & - 5,6, 0,0, & - 6,0, 0,0, & - 5,8, 0,0, & - 5,7, 6,8, & - 6,7, 0,0, & - 8,0, 0,0, & - 7,8, 0,0, & - 7,0, 0,0 & - ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) - - - ! *** FE_ipNeighbor *** - ! is a list of the neighborhood of each IP. - ! It is sorted in (local) +x,-x, +y,-y, +z,-z direction. - ! Positive integers denote an intra-FE IP identifier. - ! Negative integers denote the interface behind which the neighboring (extra-FE) IP will be located. - me = 0_pInt - - me = me + 1_pInt - FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 6 (2D 3node 1ip) - reshape(int([& - -2,-3,-1 & - ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 125 (2D 6node 3ip) - reshape(int([& - 2,-3, 3,-1, & - -2, 1, 3,-1, & - 2,-3,-2, 1 & - ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 11 (2D 4node 4ip) - reshape(int([& - 2,-4, 3,-1, & - -2, 1, 4,-1, & - 4,-4,-3, 1, & - -2, 3,-3, 2 & - ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 27 (2D 8node 9ip) - reshape(int([& - 2,-4, 4,-1, & - 3, 1, 5,-1, & - -2, 2, 6,-1, & - 5,-4, 7, 1, & - 6, 4, 8, 2, & - -2, 5, 9, 3, & - 8,-4,-3, 4, & - 9, 7,-3, 5, & - -2, 8,-3, 6 & - ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 134 (3D 4node 1ip) - reshape(int([& - -1,-2,-3,-4 & - ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 127 (3D 10node 4ip) - reshape(int([& - 2,-4, 3,-2, 4,-1, & - -2, 1, 3,-2, 4,-1, & - 2,-4,-3, 1, 4,-1, & - 2,-4, 3,-2,-3, 1 & - ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 136 (3D 6node 6ip) - reshape(int([& - 2,-4, 3,-2, 4,-1, & - -3, 1, 3,-2, 5,-1, & - 2,-4,-3, 1, 6,-1, & - 5,-4, 6,-2,-5, 1, & - -3, 4, 6,-2,-5, 2, & - 5,-4,-3, 4,-5, 3 & - ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 117 (3D 8node 1ip) - reshape(int([& - -3,-5,-4,-2,-6,-1 & - ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 7 (3D 8node 8ip) - reshape(int([& - 2,-5, 3,-2, 5,-1, & - -3, 1, 4,-2, 6,-1, & - 4,-5,-4, 1, 7,-1, & - -3, 3,-4, 2, 8,-1, & - 6,-5, 7,-2,-6, 1, & - -3, 5, 8,-2,-6, 2, & - 8,-5,-4, 5,-6, 3, & - -3, 7,-4, 6,-6, 4 & - ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 21 (3D 20node 27ip) - reshape(int([& - 2,-5, 4,-2,10,-1, & - 3, 1, 5,-2,11,-1, & - -3, 2, 6,-2,12,-1, & - 5,-5, 7, 1,13,-1, & - 6, 4, 8, 2,14,-1, & - -3, 5, 9, 3,15,-1, & - 8,-5,-4, 4,16,-1, & - 9, 7,-4, 5,17,-1, & - -3, 8,-4, 6,18,-1, & - 11,-5,13,-2,19, 1, & - 12,10,14,-2,20, 2, & - -3,11,15,-2,21, 3, & - 14,-5,16,10,22, 4, & - 15,13,17,11,23, 5, & - -3,14,18,12,24, 6, & - 17,-5,-4,13,25, 7, & - 18,16,-4,14,26, 8, & - -3,17,-4,15,27, 9, & - 20,-5,22,-2,-6,10, & - 21,19,23,-2,-6,11, & - -3,20,24,-2,-6,12, & - 23,-5,25,19,-6,13, & - 24,22,26,20,-6,14, & - -3,23,27,21,-6,15, & - 26,-5,-4,22,-6,16, & - 27,25,-4,23,-6,17, & - -3,26,-4,24,-6,18 & - ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) - - - ! *** FE_cell *** - me = 0_pInt - - me = me + 1_pInt - FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 6 (2D 3node 1ip) - reshape(int([& - 1,2,3 & - ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 125 (2D 6node 3ip) - reshape(int([& - 1, 4, 7, 6, & - 2, 5, 7, 4, & - 3, 6, 7, 5 & - ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 11 (2D 4node 4ip) - reshape(int([& - 1, 5, 9, 8, & - 5, 2, 6, 9, & - 8, 9, 7, 4, & - 9, 6, 3, 7 & - ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 27 (2D 8node 9ip) - reshape(int([& - 1, 5,13,12, & - 5, 6,14,13, & - 6, 2, 7,14, & - 12,13,16,11, & - 13,14,15,16, & - 14, 7, 8,15, & - 11,16,10, 4, & - 16,15, 9,10, & - 15, 8, 3, 9 & - ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 134 (3D 4node 1ip) - reshape(int([& - 1, 2, 3, 4 & - ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 127 (3D 10node 4ip) - reshape(int([& - 1, 5,11, 7, 8,12,15,14, & - 5, 2, 6,11,12, 9,13,15, & - 7,11, 6, 3,14,15,13,10, & - 8,12,15, 4, 4, 9,13,10 & - ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 136 (3D 6node 6ip) - reshape(int([& - 1, 7,16, 9,10,17,21,19, & - 7, 2, 8,16,17,11,18,21, & - 9,16, 8, 3,19,21,18,12, & - 10,17,21,19, 4,13,20,15, & - 17,11,18,21,13, 5,14,20, & - 19,21,18,12,15,20,14, 6 & - ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 117 (3D 8node 1ip) - reshape(int([& - 1, 2, 3, 4, 5, 6, 7, 8 & - ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 7 (3D 8node 8ip) - reshape(int([& - 1, 9,21,12,13,22,27,25, & - 9, 2,10,21,22,14,23,27, & - 12,21,11, 4,25,27,24,16, & - 21,10, 3,11,27,23,15,24, & - 13,22,27,25, 5,17,26,20, & - 22,14,23,27,17, 6,18,26, & - 25,27,24,16,20,26,19, 8, & - 27,23,15,24,26,18, 7,19 & - ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) - - me = me + 1_pInt - FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 21 (3D 20node 27ip) - reshape(int([& - 1, 9,33,16,17,37,57,44, & - 9,10,34,33,37,38,58,57, & - 10, 2,11,34,38,18,39,58, & - 16,33,36,15,44,57,60,43, & - 33,34,35,36,57,58,59,60, & - 34,11,12,35,58,39,40,59, & - 15,36,14, 4,43,60,42,20, & - 36,35,13,14,60,59,41,42, & - 35,12, 3,13,59,40,19,41, & - 17,37,57,44,21,45,61,52, & - 37,38,58,57,45,46,62,61, & - 38,18,39,58,46,22,47,62, & - 44,57,60,43,52,61,64,51, & - 57,58,59,60,61,62,63,64, & - 58,39,40,59,62,47,48,63, & - 43,60,42,20,51,64,50,24, & - 60,59,41,42,64,63,49,50, & - 59,40,19,41,63,48,23,49, & - 21,45,61,52, 5,25,53,32, & - 45,46,62,61,25,26,54,53, & - 46,22,47,62,26, 6,27,54, & - 52,61,64,51,32,53,56,31, & - 61,62,63,64,53,54,55,56, & - 62,47,48,63,54,27,28,55, & - 51,64,50,24,31,56,30, 8, & - 64,63,49,50,56,55,29,30, & - 63,48,23,49,55,28, 7,29 & - ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) - - - ! *** FE_cellnodeParentnodeWeights *** - ! center of gravity of the weighted nodes gives the position of the cell node. - ! fill with 0. - ! example: face-centered cell node with face nodes 1,2,5,6 to be used in, - ! e.g., an 8 node element, would be encoded: - ! 1, 1, 0, 0, 1, 1, 0, 0 - me = 0_pInt - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 6 (2D 3node 1ip) - reshape(real([& - 1, 0, 0, & - 0, 1, 0, & - 0, 0, 1 & - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 125 (2D 6node 3ip) - reshape(real([& - 1, 0, 0, 0, 0, 0, & - 0, 1, 0, 0, 0, 0, & - 0, 0, 1, 0, 0, 0, & - 0, 0, 0, 1, 0, 0, & - 0, 0, 0, 0, 1, 0, & - 0, 0, 0, 0, 0, 1, & - 1, 1, 1, 2, 2, 2 & - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 11 (2D 4node 4ip) - reshape(real([& - 1, 0, 0, 0, & - 0, 1, 0, 0, & - 0, 0, 1, 0, & - 0, 0, 0, 1, & - 1, 1, 0, 0, & - 0, 1, 1, 0, & - 0, 0, 1, 1, & - 1, 0, 0, 1, & - 1, 1, 1, 1 & - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 27 (2D 8node 9ip) - reshape(real([& - 1, 0, 0, 0, 0, 0, 0, 0, & - 0, 1, 0, 0, 0, 0, 0, 0, & - 0, 0, 1, 0, 0, 0, 0, 0, & - 0, 0, 0, 1, 0, 0, 0, 0, & - 1, 0, 0, 0, 2, 0, 0, 0, & - 0, 1, 0, 0, 2, 0, 0, 0, & - 0, 1, 0, 0, 0, 2, 0, 0, & - 0, 0, 1, 0, 0, 2, 0, 0, & - 0, 0, 1, 0, 0, 0, 2, 0, & - 0, 0, 0, 1, 0, 0, 2, 0, & - 0, 0, 0, 1, 0, 0, 0, 2, & - 1, 0, 0, 0, 0, 0, 0, 2, & - 4, 1, 1, 1, 8, 2, 2, 8, & - 1, 4, 1, 1, 8, 8, 2, 2, & - 1, 1, 4, 1, 2, 8, 8, 2, & - 1, 1, 1, 4, 2, 2, 8, 8 & - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 54 (2D 8node 4ip) - reshape(real([& - 1, 0, 0, 0, 0, 0, 0, 0, & - 0, 1, 0, 0, 0, 0, 0, 0, & - 0, 0, 1, 0, 0, 0, 0, 0, & - 0, 0, 0, 1, 0, 0, 0, 0, & - 0, 0, 0, 0, 1, 0, 0, 0, & - 0, 0, 0, 0, 0, 1, 0, 0, & - 0, 0, 0, 0, 0, 0, 1, 0, & - 0, 0, 0, 0, 0, 0, 0, 1, & - 1, 1, 1, 1, 2, 2, 2, 2 & - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 134 (3D 4node 1ip) - reshape(real([& - 1, 0, 0, 0, & - 0, 1, 0, 0, & - 0, 0, 1, 0, & - 0, 0, 0, 1 & - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 157 (3D 5node 4ip) - reshape(real([& - 1, 0, 0, 0, 0, & - 0, 1, 0, 0, 0, & - 0, 0, 1, 0, 0, & - 0, 0, 0, 1, 0, & - 1, 1, 0, 0, 0, & - 0, 1, 1, 0, 0, & - 1, 0, 1, 0, 0, & - 1, 0, 0, 1, 0, & - 0, 1, 0, 1, 0, & - 0, 0, 1, 1, 0, & - 1, 1, 1, 0, 0, & - 1, 1, 0, 1, 0, & - 0, 1, 1, 1, 0, & - 1, 0, 1, 1, 0, & - 0, 0, 0, 0, 1 & - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 127 (3D 10node 4ip) - reshape(real([& - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, & - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, & - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, & - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, & - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, & - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, & - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, & - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, & - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, & - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, & - 1, 1, 1, 0, 2, 2, 2, 0, 0, 0, & - 1, 1, 0, 1, 2, 0, 0, 2, 2, 0, & - 0, 1, 1, 1, 0, 2, 0, 0, 2, 2, & - 1, 0, 1, 1, 0, 0, 2, 2, 0, 2, & - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 & - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 136 (3D 6node 6ip) - reshape(real([& - 1, 0, 0, 0, 0, 0, & - 0, 1, 0, 0, 0, 0, & - 0, 0, 1, 0, 0, 0, & - 0, 0, 0, 1, 0, 0, & - 0, 0, 0, 0, 1, 0, & - 0, 0, 0, 0, 0, 1, & - 1, 1, 0, 0, 0, 0, & - 0, 1, 1, 0, 0, 0, & - 1, 0, 1, 0, 0, 0, & - 1, 0, 0, 1, 0, 0, & - 0, 1, 0, 0, 1, 0, & - 0, 0, 1, 0, 0, 1, & - 0, 0, 0, 1, 1, 0, & - 0, 0, 0, 0, 1, 1, & - 0, 0, 0, 1, 0, 1, & - 1, 1, 1, 0, 0, 0, & - 1, 1, 0, 1, 1, 0, & - 0, 1, 1, 0, 1, 1, & - 1, 0, 1, 1, 0, 1, & - 0, 0, 0, 1, 1, 1, & - 1, 1, 1, 1, 1, 1 & - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 117 (3D 8node 1ip) - reshape(real([& - 1, 0, 0, 0, 0, 0, 0, 0, & - 0, 1, 0, 0, 0, 0, 0, 0, & - 0, 0, 1, 0, 0, 0, 0, 0, & - 0, 0, 0, 1, 0, 0, 0, 0, & - 0, 0, 0, 0, 1, 0, 0, 0, & - 0, 0, 0, 0, 0, 1, 0, 0, & - 0, 0, 0, 0, 0, 0, 1, 0, & - 0, 0, 0, 0, 0, 0, 0, 1 & - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 7 (3D 8node 8ip) - reshape(real([& - 1, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 1, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 1, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 1, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 1, 0, 0, 0, & ! 5 - 0, 0, 0, 0, 0, 1, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 1, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 1, & ! - 1, 1, 0, 0, 0, 0, 0, 0, & ! - 0, 1, 1, 0, 0, 0, 0, 0, & ! 10 - 0, 0, 1, 1, 0, 0, 0, 0, & ! - 1, 0, 0, 1, 0, 0, 0, 0, & ! - 1, 0, 0, 0, 1, 0, 0, 0, & ! - 0, 1, 0, 0, 0, 1, 0, 0, & ! - 0, 0, 1, 0, 0, 0, 1, 0, & ! 15 - 0, 0, 0, 1, 0, 0, 0, 1, & ! - 0, 0, 0, 0, 1, 1, 0, 0, & ! - 0, 0, 0, 0, 0, 1, 1, 0, & ! - 0, 0, 0, 0, 0, 0, 1, 1, & ! - 0, 0, 0, 0, 1, 0, 0, 1, & ! 20 - 1, 1, 1, 1, 0, 0, 0, 0, & ! - 1, 1, 0, 0, 1, 1, 0, 0, & ! - 0, 1, 1, 0, 0, 1, 1, 0, & ! - 0, 0, 1, 1, 0, 0, 1, 1, & ! - 1, 0, 0, 1, 1, 0, 0, 1, & ! 25 - 0, 0, 0, 0, 1, 1, 1, 1, & ! - 1, 1, 1, 1, 1, 1, 1, 1 & ! - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 57 (3D 20node 8ip) - reshape(real([& - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! 5 - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! 10 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, & ! 15 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, & ! - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, & ! 20 - 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 1, 1, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 0, 0, & ! - 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 0, & ! - 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, & ! - 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 2, 2, 0, 0, 2, & ! 25 - 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, & ! - 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 & ! - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - me = me + 1_pInt - FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 21 (3D 20node 27ip) - reshape(real([& - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! 5 - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! 10 - 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, & ! 15 - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, & ! - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, & ! - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, & ! - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, & ! 20 - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, & ! - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, & ! 25 - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, & ! 30 - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, & ! - 4, 1, 1, 1, 0, 0, 0, 0, 8, 2, 2, 8, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 1, 4, 1, 1, 0, 0, 0, 0, 8, 8, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 1, 1, 4, 1, 0, 0, 0, 0, 2, 8, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, & ! 35 - 1, 1, 1, 4, 0, 0, 0, 0, 2, 2, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, & ! - 4, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 8, 2, 0, 0, & ! - 1, 4, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 2, 8, 0, 0, & ! - 0, 4, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 8, 2, 0, & ! - 0, 1, 4, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 2, 8, 0, & ! 40 - 0, 0, 4, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 8, 2, & ! - 0, 0, 1, 4, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 2, 8, & ! - 1, 0, 0, 4, 1, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 2, 2, 0, 0, 8, & ! - 4, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 2, 8, 0, 0, 2, & ! - 1, 1, 0, 0, 4, 1, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 8, 2, 0, 0, & ! 45 - 1, 1, 0, 0, 1, 4, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 2, 8, 0, 0, & ! - 0, 1, 1, 0, 0, 4, 1, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 8, 2, 0, & ! - 0, 1, 1, 0, 0, 1, 4, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 2, 8, 0, & ! - 0, 0, 1, 1, 0, 0, 4, 1, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 8, 2, & ! - 0, 0, 1, 1, 0, 0, 1, 4, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 2, 8, & ! 50 - 1, 0, 0, 1, 1, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 8, 2, 0, 0, 8, & ! - 1, 0, 0, 1, 4, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 8, 8, 0, 0, 2, & ! - 0, 0, 0, 0, 4, 1, 1, 1, 0, 0, 0, 0, 8, 2, 2, 8, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 1, 4, 1, 1, 0, 0, 0, 0, 8, 8, 2, 2, 0, 0, 0, 0, & ! - 0, 0, 0, 0, 1, 1, 4, 1, 0, 0, 0, 0, 2, 8, 8, 2, 0, 0, 0, 0, & ! 55 - 0, 0, 0, 0, 1, 1, 1, 4, 0, 0, 0, 0, 2, 2, 8, 8, 0, 0, 0, 0, & ! - 24, 8, 4, 8, 8, 4, 3, 4, 32,12,12,32, 12, 4, 4,12, 32,12, 4,12, & ! - 8,24, 8, 4, 4, 8, 4, 3, 32,32,12,12, 12,12, 4, 4, 12,32,12, 4, & ! - 4, 8,24, 8, 3, 4, 8, 4, 12,32,32,12, 4,12,12, 4, 4,12,32,12, & ! - 8, 4, 8,24, 4, 3, 4, 8, 12,12,32,32, 4, 4,12,12, 12, 4,12,32, & ! 60 - 8, 4, 3, 4, 24, 8, 4, 8, 12, 4, 4,12, 32,12,12,32, 32,12, 4,12, & ! - 4, 8, 4, 3, 8,24, 8, 4, 12,12, 4, 4, 32,32,12,12, 12,32,12, 4, & ! - 3, 4, 8, 4, 4, 8,24, 8, 4,12,12, 4, 12,32,32,12, 4,12,32,12, & ! - 4, 3, 4, 8, 8, 4, 8,24, 4, 4,12,12, 12,12,32,32, 12, 4,12,32 & ! - ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) - - - - ! *** FE_cellface *** - me = 0_pInt - - me = me + 1_pInt - FE_cellface(1:FE_NcellnodesPerCellface(me),1:FE_NipNeighbors(me),me) = & ! 2D 3node, VTK_TRIANGLE (5) - reshape(int([& - 2,3, & - 3,1, & - 1,2 & - ],pInt),[FE_NcellnodesPerCellface(me),FE_NipNeighbors(me)]) - - me = me + 1_pInt - FE_cellface(1:FE_NcellnodesPerCellface(me),1:FE_NipNeighbors(me),me) = & ! 2D 4node, VTK_QUAD (9) - reshape(int([& - 2,3, & - 4,1, & - 3,4, & - 1,2 & - ],pInt),[FE_NcellnodesPerCellface(me),FE_NipNeighbors(me)]) - - me = me + 1_pInt - FE_cellface(1:FE_NcellnodesPerCellface(me),1:FE_NipNeighbors(me),me) = & ! 3D 4node, VTK_TETRA (10) - reshape(int([& - 1,3,2, & - 1,2,4, & - 2,3,4, & - 1,4,3 & - ],pInt),[FE_NcellnodesPerCellface(me),FE_NipNeighbors(me)]) - - me = me + 1_pInt - FE_cellface(1:FE_NcellnodesPerCellface(me),1:FE_NipNeighbors(me),me) = & ! 3D 8node, VTK_HEXAHEDRON (12) - reshape(int([& - 2,3,7,6, & - 4,1,5,8, & - 3,4,8,7, & - 1,2,6,5, & - 5,6,7,8, & - 1,4,3,2 & - ],pInt),[FE_NcellnodesPerCellface(me),FE_NipNeighbors(me)]) - - -end subroutine mesh_build_FEdata - - -!-------------------------------------------------------------------------------------------------- -!> @brief writes out initial cell geometry -!-------------------------------------------------------------------------------------------------- -subroutine mesh_write_cellGeom - use DAMASK_interface, only: & - getSolverJobName, & - getSolverWorkingDirectoryName - use IR_Precision, only: & - I4P - use Lib_VTK_IO, only: & - VTK_ini, & - VTK_geo, & - VTK_con, & - VTK_end -#ifdef HDF - use IO, only: & - HDF5_mappingCells -#endif - implicit none - integer(I4P), dimension(1:mesh_Ncells) :: celltype - integer(I4P), dimension(mesh_Ncells*(1_pInt+FE_maxNcellnodesPerCell)) :: cellconnection -#ifdef HDF - integer(pInt), dimension(mesh_Ncells*FE_maxNcellnodesPerCell) :: cellconnectionHDF5 - integer(pInt) :: j2=0_pInt -#endif - integer(I4P):: error - integer(I4P):: g, c, e, CellID, i, j - - cellID = 0_pInt - j = 0_pInt - do e = 1_pInt, mesh_NcpElems ! loop over cpElems - g = FE_geomtype(mesh_element(2_pInt,e)) ! get geometry type - c = FE_celltype(g) ! get cell type - do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element - cellID = cellID + 1_pInt - celltype(cellID) = MESH_VTKCELLTYPE(c) - cellconnection(j+1_pInt:j+FE_NcellnodesPerCell(c)+1_pInt) & - = [FE_NcellnodesPerCell(c),mesh_cell(1:FE_NcellnodesPerCell(c),i,e)-1_pInt] ! number of cellnodes per cell & list of global cellnode IDs belnging to this cell (cellnode counting starts at 0) - j = j + FE_NcellnodesPerCell(c) + 1_pInt -#ifdef HDF - cellconnectionHDF5(j2+1_pInt:j2+FE_NcellnodesPerCell(c)) & - = mesh_cell(1:FE_NcellnodesPerCell(c),i,e)-1_pInt - j2=j2 + FE_ncellnodesPerCell(c) -#endif - enddo - enddo -#ifdef HDF - call HDF5_mappingCells(cellconnectionHDF5(1:j2)) -#endif - - error=VTK_ini(output_format = 'ASCII', & - title=trim(getSolverJobName())//' cell mesh', & - filename = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'_ipbased.vtk', & - mesh_topology = 'UNSTRUCTURED_GRID') - !ToDo: check error here - error=VTK_geo(NN = int(mesh_Ncellnodes,I4P), & - X = mesh_cellnode(1,1:mesh_Ncellnodes), & - Y = mesh_cellnode(2,1:mesh_Ncellnodes), & - Z = mesh_cellnode(3,1:mesh_Ncellnodes)) - !ToDo: check error here - error=VTK_con(NC = int(mesh_Ncells,I4P), & - connect = cellconnection(1:j), & - !ToDo: check error here - cell_type = celltype) - error=VTK_end() - !ToDo: check error here - -end subroutine mesh_write_cellGeom - - -!-------------------------------------------------------------------------------------------------- -!> @brief writes out initial element geometry -!-------------------------------------------------------------------------------------------------- -subroutine mesh_write_elemGeom - use DAMASK_interface, only: & - getSolverJobName, & - getSolverWorkingDirectoryName - use IR_Precision, only: & - I4P - use Lib_VTK_IO, only: & - VTK_ini, & - VTK_geo, & - VTK_con, & - VTK_end - - implicit none - integer(I4P), dimension(1:mesh_NcpElems) :: elemtype - integer(I4P), dimension(mesh_NcpElems*(1_pInt+FE_maxNnodes)) :: elementconnection - integer(I4P):: error - integer(pInt):: e, t, n, i - - i = 0_pInt - do e = 1_pInt, mesh_NcpElems ! loop over cpElems - t = mesh_element(2,e) ! get element type - elemtype(e) = MESH_VTKELEMTYPE(t) - elementconnection(i+1_pInt) = FE_Nnodes(t) ! number of nodes per element - do n = 1_pInt,FE_Nnodes(t) - elementconnection(i+1_pInt+n) = mesh_element(4_pInt+n,e) - 1_pInt ! global node ID of node that belongs to this element (node counting starts at 0) - enddo - i = i + 1_pInt + FE_Nnodes(t) - enddo - - error=VTK_ini(output_format = 'ASCII', & - title=trim(getSolverJobName())//' element mesh', & - filename = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'_nodebased.vtk', & - mesh_topology = 'UNSTRUCTURED_GRID') - !ToDo: check error here - error=VTK_geo(NN = int(mesh_Nnodes,I4P), & - X = mesh_node0(1,1:mesh_Nnodes), & - Y = mesh_node0(2,1:mesh_Nnodes), & - Z = mesh_node0(3,1:mesh_Nnodes)) - !ToDo: check error here - error=VTK_con(NC = int(mesh_Nelems,I4P), & - connect = elementconnection(1:i), & - cell_type = elemtype) - !ToDo: check error here - error =VTK_end() - !ToDo: check error here - -end subroutine mesh_write_elemGeom - - -!-------------------------------------------------------------------------------------------------- -!> @brief writes description file for mesh -!-------------------------------------------------------------------------------------------------- -subroutine mesh_write_meshfile - use IO, only: & - IO_write_jobFile - - implicit none - integer(pInt), parameter :: fileUnit = 223_pInt - integer(pInt) :: e,i,t,g,c,n - - call IO_write_jobFile(fileUnit,'mesh') - write(fileUnit,'(A16,E10.3)') 'unitlength', mesh_unitlength - write(fileUnit,'(A16,I10)') 'maxNcellnodes', mesh_maxNcellnodes - write(fileUnit,'(A16,I10)') 'maxNips', mesh_maxNips - write(fileUnit,'(A16,I10)') 'maxNnodes', mesh_maxNnodes - write(fileUnit,'(A16,I10)') 'Nnodes', mesh_Nnodes - write(fileUnit,'(A16,I10)') 'NcpElems', mesh_NcpElems - do e = 1_pInt,mesh_NcpElems - t = mesh_element(2,e) - write(fileUnit,'(20(I10))') mesh_element(1_pInt:4_pInt+FE_Nnodes(t),e) - enddo - write(fileUnit,'(A16,I10)') 'Ncellnodes', mesh_Ncellnodes - do n = 1_pInt,mesh_Ncellnodes - write(fileUnit,'(2(I10))') mesh_cellnodeParent(1:2,n) - enddo - write(fileUnit,'(A16,I10)') 'Ncells', mesh_Ncells - do e = 1_pInt,mesh_NcpElems - t = mesh_element(2,e) - g = FE_geomtype(t) - c = FE_celltype(g) - do i = 1_pInt,FE_Nips(g) - write(fileUnit,'(8(I10))') & - mesh_cell(1_pInt:FE_NcellnodesPerCell(c),i,e) - enddo - enddo - close(fileUnit) - -end subroutine mesh_write_meshfile - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads mesh description file -!-------------------------------------------------------------------------------------------------- -integer function mesh_read_meshfile(filepath) - - implicit none - character(len=*), intent(in) :: filepath - integer(pInt), parameter :: fileUnit = 223_pInt - integer(pInt) :: e,i,t,g,n - - open(fileUnit,status='old',err=100,iostat=mesh_read_meshfile,action='read',file=filepath) - read(fileUnit,'(TR16,E10.3)',err=100,iostat=mesh_read_meshfile) mesh_unitlength - read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_maxNcellnodes - read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_maxNips - read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_maxNnodes - read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_Nnodes - read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_NcpElems - if (.not. allocated(mesh_element)) allocate(mesh_element(4_pInt+mesh_maxNnodes,mesh_NcpElems)) - mesh_element = 0_pInt - do e = 1_pInt,mesh_NcpElems - read(fileUnit,'(20(I10))',err=100,iostat=mesh_read_meshfile) & - mesh_element(:,e) - enddo - read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_Ncellnodes - if (.not. allocated(mesh_cellnodeParent)) allocate(mesh_cellnodeParent(2_pInt,mesh_Ncellnodes)) - do n = 1_pInt,mesh_Ncellnodes - read(fileUnit,'(2(I10))',err=100,iostat=mesh_read_meshfile) mesh_cellnodeParent(1:2,n) - enddo - read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_Ncells - if (.not. allocated(mesh_cell)) allocate(mesh_cell(FE_maxNcellnodesPerCell,mesh_maxNips,mesh_NcpElems)) - do e = 1_pInt,mesh_NcpElems - t = mesh_element(2,e) - g = FE_geomtype(t) - do i = 1_pInt,FE_Nips(g) - read(fileUnit,'(8(I10))',err=100,iostat=mesh_read_meshfile) mesh_cell(:,i,e) - enddo - enddo - close(fileUnit) - - mesh_read_meshfile = 0 ! successfully read data - -100 continue -end function mesh_read_meshfile - - -!-------------------------------------------------------------------------------------------------- -!> @brief initializes mesh data for use in post processing -!-------------------------------------------------------------------------------------------------- -integer function mesh_init_postprocessing(filepath) - - implicit none - character(len=*), intent(in) :: filepath - - call mesh_build_FEdata - mesh_init_postprocessing = mesh_read_meshfile(filepath) - -end function mesh_init_postprocessing - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns global variable mesh_Ncellnodes -!-------------------------------------------------------------------------------------------------- -integer(pInt) function mesh_get_Ncellnodes() - - implicit none - - mesh_get_Ncellnodes = mesh_Ncellnodes - -end function mesh_get_Ncellnodes - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns global variable mesh_unitlength -!-------------------------------------------------------------------------------------------------- -real(pReal) function mesh_get_unitlength() - - implicit none - - mesh_get_unitlength = mesh_unitlength - -end function mesh_get_unitlength - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns node that is located at an ip -!> @details return zero if requested ip does not exist or not available (more ips than nodes) -!-------------------------------------------------------------------------------------------------- -integer(pInt) function mesh_get_nodeAtIP(elemtypeFE,ip) - - implicit none - character(len=*), intent(in) :: elemtypeFE - integer(pInt), intent(in) :: ip - integer(pInt) :: elemtype - integer(pInt) :: geomtype - - mesh_get_nodeAtIP = 0_pInt - - elemtype = FE_mapElemtype(elemtypeFE) - geomtype = FE_geomtype(elemtype) - if (FE_Nips(geomtype) >= ip .and. FE_Nips(geomtype) <= FE_Nnodes(elemtype)) & - mesh_get_nodeAtIP = FE_nodesAtIP(1,ip,geomtype) - -end function mesh_get_nodeAtIP - - -end module mesh diff --git a/code/numerics.f90 b/code/numerics.f90 deleted file mode 100644 index 61f326c02..000000000 --- a/code/numerics.f90 +++ /dev/null @@ -1,726 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Managing of parameters related to numerics -!-------------------------------------------------------------------------------------------------- -module numerics - use prec, only: & - pInt, & - pReal - - implicit none - private -#ifdef PETSc -#include -#endif - character(len=64), parameter, private :: & - numerics_CONFIGFILE = 'numerics.config' !< name of configuration file - - integer(pInt), protected, public :: & - iJacoStiffness = 1_pInt, & !< frequency of stiffness update - iJacoLpresiduum = 1_pInt, & !< frequency of Jacobian update of residuum in Lp - nHomog = 20_pInt, & !< homogenization loop limit (only for debugging info, loop limit is determined by "subStepMinHomog") - nMPstate = 10_pInt, & !< materialpoint state loop limit - nCryst = 20_pInt, & !< crystallite loop limit (only for debugging info, loop limit is determined by "subStepMinCryst") - nState = 10_pInt, & !< state loop limit - nStress = 40_pInt, & !< stress loop limit - pert_method = 1_pInt, & !< method used in perturbation technique for tangent - fixedSeed = 0_pInt, & !< fixed seeding for pseudo-random number generator, Default 0: use random seed - worldrank = 0_pInt, & !< MPI worldrank (/=0 for MPI simulations only) - worldsize = 0_pInt !< MPI worldsize (/=0 for MPI simulations only) - integer, protected, public :: & - DAMASK_NumThreadsInt = 0 !< value stored in environment variable DAMASK_NUM_THREADS, set to zero if no OpenMP directive - integer(pInt), public :: & - numerics_integrationMode = 0_pInt !< integrationMode 1 = central solution; integrationMode 2 = perturbation, Default 0: undefined, is not read from file - integer(pInt), dimension(2) , protected, public :: & - numerics_integrator = 1_pInt !< method used for state integration (central & perturbed state), Default 1: fix-point iteration for both states - real(pReal), protected, public :: & - relevantStrain = 1.0e-7_pReal, & !< strain increment considered significant (used by crystallite to determine whether strain inc is considered significant) - defgradTolerance = 1.0e-7_pReal, & !< deviation of deformation gradient that is still allowed (used by CPFEM to determine outdated ffn1) - pert_Fg = 1.0e-7_pReal, & !< strain perturbation for FEM Jacobi - subStepMinCryst = 1.0e-3_pReal, & !< minimum (relative) size of sub-step allowed during cutback in crystallite - subStepMinHomog = 1.0e-3_pReal, & !< minimum (relative) size of sub-step allowed during cutback in homogenization - subStepSizeCryst = 0.25_pReal, & !< size of first substep when cutback in crystallite - subStepSizeHomog = 0.25_pReal, & !< size of first substep when cutback in homogenization - stepIncreaseCryst = 1.5_pReal, & !< increase of next substep size when previous substep converged in crystallite - stepIncreaseHomog = 1.5_pReal, & !< increase of next substep size when previous substep converged in homogenization - rTol_crystalliteState = 1.0e-6_pReal, & !< relative tolerance in crystallite state loop - rTol_crystalliteStress = 1.0e-6_pReal, & !< relative tolerance in crystallite stress loop - aTol_crystalliteStress = 1.0e-8_pReal, & !< absolute tolerance in crystallite stress loop, Default 1.0e-8: residuum is in Lp and hence strain is on this order - numerics_unitlength = 1.0_pReal, & !< determines the physical length of one computational length unit - absTol_RGC = 1.0e+4_pReal, & !< absolute tolerance of RGC residuum - relTol_RGC = 1.0e-3_pReal, & !< relative tolerance of RGC residuum - absMax_RGC = 1.0e+10_pReal, & !< absolute maximum of RGC residuum - relMax_RGC = 1.0e+2_pReal, & !< relative maximum of RGC residuum - pPert_RGC = 1.0e-7_pReal, & !< perturbation for computing RGC penalty tangent - xSmoo_RGC = 1.0e-5_pReal, & !< RGC penalty smoothing parameter (hyperbolic tangent) - viscPower_RGC = 1.0e+0_pReal, & !< power (sensitivity rate) of numerical viscosity in RGC scheme, Default 1.0e0: Newton viscosity (linear model) - viscModus_RGC = 0.0e+0_pReal, & !< stress modulus of RGC numerical viscosity, Default 0.0e0: No viscosity is applied - refRelaxRate_RGC = 1.0e-3_pReal, & !< reference relaxation rate in RGC viscosity - maxdRelax_RGC = 1.0e+0_pReal, & !< threshold of maximum relaxation vector increment (if exceed this then cutback) - maxVolDiscr_RGC = 1.0e-5_pReal, & !< threshold of maximum volume discrepancy allowed - volDiscrMod_RGC = 1.0e+12_pReal, & !< stiffness of RGC volume discrepancy (zero = without volume discrepancy constraint) - volDiscrPow_RGC = 5.0_pReal, & !< powerlaw penalty for volume discrepancy - charLength = 1.0_pReal, & !< characteristic length scale for gradient problems - residualStiffness = 1.0e-6_pReal !< non-zero residual damage - logical, protected, public :: & - analyticJaco = .true., & !< use analytic Jacobian or perturbation, Default for Spectral solver .true.: - usePingPong = .true., & - numerics_timeSyncing = .false. !< flag indicating if time synchronization in crystallite is used for nonlocal plasticity - -!-------------------------------------------------------------------------------------------------- -! field parameters: - real(pReal), protected, public :: & - err_struct_tolAbs = 1.0e-10_pReal, & !< absolute tolerance for mechanical equilibrium - err_struct_tolRel = 1.0e-4_pReal, & !< relative tolerance for mechanical equilibrium - err_thermal_tolAbs = 1.0e-2_pReal, & !< absolute tolerance for thermal equilibrium - err_thermal_tolRel = 1.0e-6_pReal, & !< relative tolerance for thermal equilibrium - err_damage_tolAbs = 1.0e-2_pReal, & !< absolute tolerance for damage evolution - err_damage_tolRel = 1.0e-6_pReal, & !< relative tolerance for damage evolution - err_vacancyflux_tolAbs = 1.0e-8_pReal, & !< absolute tolerance for vacancy transport - err_vacancyflux_tolRel = 1.0e-6_pReal, & !< relative tolerance for vacancy transport - err_porosity_tolAbs = 1.0e-2_pReal, & !< absolute tolerance for porosity evolution - err_porosity_tolRel = 1.0e-6_pReal, & !< relative tolerance for porosity evolution - err_hydrogenflux_tolAbs = 1.0e-8_pReal, & !< absolute tolerance for hydrogen transport - err_hydrogenflux_tolRel = 1.0e-6_pReal, & !< relative tolerance for hydrogen transport - vacancyBoundPenalty = 1.0e+4_pReal, & !< penalty to enforce 0 < Cv < 1 - hydrogenBoundPenalty = 1.0e+4_pReal !< penalty to enforce 0 < Ch < 1 - integer(pInt), protected, public :: & - itmax = 250_pInt, & !< maximum number of iterations - itmin = 1_pInt, & !< minimum number of iterations - stagItMax = 10_pInt, & !< max number of field level staggered iterations - maxCutBack = 3_pInt, & !< max number of cut backs - vacancyPolyOrder = 10_pInt, & !< order of polynomial approximation of entropic contribution to vacancy chemical potential - hydrogenPolyOrder = 10_pInt !< order of polynomial approximation of entropic contribution to hydrogen chemical potential - -!-------------------------------------------------------------------------------------------------- -! spectral parameters: -#ifdef Spectral - real(pReal), protected, public :: & - err_div_tolAbs = 1.0e-10_pReal, & !< absolute tolerance for equilibrium - err_div_tolRel = 5.0e-4_pReal, & !< relative tolerance for equilibrium - err_curl_tolAbs = 1.0e-10_pReal, & !< absolute tolerance for compatibility - err_curl_tolRel = 5.0e-4_pReal, & !< relative tolerance for compatibility - err_stress_tolAbs = 1.0e3_pReal, & !< absolute tolerance for fullfillment of stress BC - err_stress_tolRel = 0.01_pReal, & !< relative tolerance for fullfillment of stress BC - fftw_timelimit = -1.0_pReal, & !< sets the timelimit of plan creation for FFTW, see manual on www.fftw.org, Default -1.0: disable timelimit - rotation_tol = 1.0e-12_pReal, & !< tolerance of rotation specified in loadcase, Default 1.0e-12: first guess - polarAlpha = 1.0_pReal, & !< polarization scheme parameter 0.0 < alpha < 2.0. alpha = 1.0 ==> AL scheme, alpha = 2.0 ==> accelerated scheme - polarBeta = 1.0_pReal !< polarization scheme parameter 0.0 < beta < 2.0. beta = 1.0 ==> AL scheme, beta = 2.0 ==> accelerated scheme - character(len=64), private :: & - fftw_plan_mode = 'FFTW_PATIENT' !< reads the planing-rigor flag, see manual on www.fftw.org, Default FFTW_PATIENT: use patient planner flag - character(len=64), protected, public :: & - spectral_solver = 'basicpetsc' , & !< spectral solution method - spectral_derivative = 'continuous' !< spectral filtering method - character(len=1024), protected, public :: & - petsc_defaultOptions = '-mech_snes_type ngmres & - &-damage_snes_type ngmres & - &-thermal_snes_type ngmres ', & - petsc_options = '' - integer(pInt), protected, public :: & - fftw_planner_flag = 32_pInt, & !< conversion of fftw_plan_mode to integer, basically what is usually done in the include file of fftw - continueCalculation = 0_pInt, & !< 0: exit if BVP solver does not converge, 1: continue calculation if BVP solver does not converge - divergence_correction = 2_pInt !< correct divergence calculation in fourier space 0: no correction, 1: size scaled to 1, 2: size scaled to Npoints - logical, protected, public :: & - memory_efficient = .true., & !< for fast execution (pre calculation of gamma_hat), Default .true.: do not precalculate - update_gamma = .false. !< update gamma operator with current stiffness, Default .false.: use initial stiffness -#endif - -!-------------------------------------------------------------------------------------------------- -! FEM parameters: -#ifdef FEM - integer(pInt), protected, public :: & - integrationOrder = 2_pInt, & !< order of quadrature rule required - structOrder = 2_pInt, & !< order of displacement shape functions - thermalOrder = 2_pInt, & !< order of temperature field shape functions - damageOrder = 2_pInt, & !< order of damage field shape functions - vacancyfluxOrder = 2_pInt, & !< order of vacancy concentration and chemical potential field shape functions - porosityOrder = 2_pInt, & !< order of porosity field shape functions - hydrogenfluxOrder = 2_pInt !< order of hydrogen concentration and chemical potential field shape functions - logical, protected, public :: & - BBarStabilisation = .false. - character(len=4096), protected, public :: & - petsc_defaultOptions = '-mech_snes_type newtonls & - &-mech_snes_linesearch_type cp & - &-mech_snes_ksp_ew & - &-mech_snes_ksp_ew_rtol0 0.01 & - &-mech_snes_ksp_ew_rtolmax 0.01 & - &-mech_ksp_type fgmres & - &-mech_ksp_max_it 25 & - &-mech_pc_type ml & - &-mech_mg_levels_ksp_type chebyshev & - &-mech_mg_levels_pc_type sor & - &-mech_pc_ml_nullspace user & - &-damage_snes_type vinewtonrsls & - &-damage_snes_atol 1e-8 & - &-damage_ksp_type preonly & - &-damage_ksp_max_it 25 & - &-damage_pc_type cholesky & - &-damage_pc_factor_mat_solver_package mumps & - &-thermal_snes_type newtonls & - &-thermal_snes_linesearch_type cp & - &-thermal_ksp_type fgmres & - &-thermal_ksp_max_it 25 & - &-thermal_snes_atol 1e-3 & - &-thermal_pc_type hypre & - &-vacancy_snes_type newtonls & - &-vacancy_snes_linesearch_type cp & - &-vacancy_snes_atol 1e-9 & - &-vacancy_ksp_type fgmres & - &-vacancy_ksp_max_it 25 & - &-vacancy_pc_type ml & - &-vacancy_mg_levels_ksp_type chebyshev & - &-vacancy_mg_levels_pc_type sor & - &-porosity_snes_type newtonls & - &-porosity_snes_atol 1e-8 & - &-porosity_ksp_type fgmres & - &-porosity_ksp_max_it 25 & - &-porosity_pc_type hypre & - &-hydrogen_snes_type newtonls & - &-hydrogen_snes_linesearch_type cp & - &-hydrogen_snes_atol 1e-9 & - &-hydrogen_ksp_type fgmres & - &-hydrogen_ksp_max_it 25 & - &-hydrogen_pc_type ml & - &-hydrogen_mg_levels_ksp_type chebyshev & - &-hydrogen_mg_levels_pc_type sor ', & - petsc_options = '' -#endif - - public :: numerics_init - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief reads in parameters from numerics.config and sets openMP related parameters. Also does -! a sanity check -!-------------------------------------------------------------------------------------------------- -subroutine numerics_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_error, & - IO_open_file_stat, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_lc, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_timeStamp, & - IO_EOF - -#if defined(Spectral) || defined(FEM) -!$ use OMP_LIB, only: omp_set_num_threads ! Use the standard conforming module file for omp if using the spectral solver - implicit none -#else - implicit none -!$ include "omp_lib.h" ! use the not F90 standard conforming include file to prevent crashes with some versions of MSC.Marc -#endif - integer(pInt), parameter :: FILEUNIT = 300_pInt -!$ integer :: gotDAMASK_NUM_THREADS = 1 - integer :: i, ierr ! no pInt - integer(pInt), allocatable, dimension(:) :: chunkPos - character(len=65536) :: & - tag ,& - line -!$ character(len=6) DAMASK_NumThreadsString ! environment variable DAMASK_NUM_THREADS - external :: & - MPI_Comm_rank, & - MPI_Comm_size, & - MPI_Abort - -#ifdef PETSc - call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) - call MPI_Comm_size(PETSC_COMM_WORLD,worldsize,ierr);CHKERRQ(ierr) -#endif - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- numerics init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!$ call GET_ENVIRONMENT_VARIABLE(NAME='DAMASK_NUM_THREADS',VALUE=DAMASK_NumThreadsString,STATUS=gotDAMASK_NUM_THREADS) ! get environment variable DAMASK_NUM_THREADS... -!$ if(gotDAMASK_NUM_THREADS /= 0) then ! could not get number of threads, set it to 1 -!$ call IO_warning(35_pInt,ext_msg='BEGIN:'//DAMASK_NumThreadsString//':END') -!$ DAMASK_NumThreadsInt = 1 -!$ else -!$ read(DAMASK_NumThreadsString,'(i6)') DAMASK_NumThreadsInt ! read as integer -!$ if (DAMASK_NumThreadsInt < 1) DAMASK_NumThreadsInt = 1 ! in case of string conversion fails, set it to one -!$ endif -!$ call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution - -!-------------------------------------------------------------------------------------------------- -! try to open the config file - fileExists: if(IO_open_file_stat(FILEUNIT,numerics_configFile)) then - mainProcess2: if (worldrank == 0) then - write(6,'(a,/)') ' using values from config file' - flush(6) - endif mainProcess2 - -!-------------------------------------------------------------------------------------------------- -! read variables from config file and overwrite default parameters if keyword is present - line = '' - do while (trim(line) /= IO_EOF) ! read thru sections of phase part - line = IO_read(FILEUNIT) - do i=1,len(line) - if(line(i:i) == '=') line(i:i) = ' ' ! also allow keyword = value version - enddo - if (IO_isBlank(line)) cycle ! skip empty lines - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - - select case(tag) - case ('relevantstrain') - relevantStrain = IO_floatValue(line,chunkPos,2_pInt) - case ('defgradtolerance') - defgradTolerance = IO_floatValue(line,chunkPos,2_pInt) - case ('ijacostiffness') - iJacoStiffness = IO_intValue(line,chunkPos,2_pInt) - case ('ijacolpresiduum') - iJacoLpresiduum = IO_intValue(line,chunkPos,2_pInt) - case ('pert_fg') - pert_Fg = IO_floatValue(line,chunkPos,2_pInt) - case ('pert_method') - pert_method = IO_intValue(line,chunkPos,2_pInt) - case ('nhomog') - nHomog = IO_intValue(line,chunkPos,2_pInt) - case ('nmpstate') - nMPstate = IO_intValue(line,chunkPos,2_pInt) - case ('ncryst') - nCryst = IO_intValue(line,chunkPos,2_pInt) - case ('nstate') - nState = IO_intValue(line,chunkPos,2_pInt) - case ('nstress') - nStress = IO_intValue(line,chunkPos,2_pInt) - case ('substepmincryst') - subStepMinCryst = IO_floatValue(line,chunkPos,2_pInt) - case ('substepsizecryst') - subStepSizeCryst = IO_floatValue(line,chunkPos,2_pInt) - case ('stepincreasecryst') - stepIncreaseCryst = IO_floatValue(line,chunkPos,2_pInt) - case ('substepminhomog') - subStepMinHomog = IO_floatValue(line,chunkPos,2_pInt) - case ('substepsizehomog') - subStepSizeHomog = IO_floatValue(line,chunkPos,2_pInt) - case ('stepincreasehomog') - stepIncreaseHomog = IO_floatValue(line,chunkPos,2_pInt) - case ('rtol_crystallitestate') - rTol_crystalliteState = IO_floatValue(line,chunkPos,2_pInt) - case ('rtol_crystallitestress') - rTol_crystalliteStress = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_crystallitestress') - aTol_crystalliteStress = IO_floatValue(line,chunkPos,2_pInt) - case ('integrator') - numerics_integrator(1) = IO_intValue(line,chunkPos,2_pInt) - case ('integratorstiffness') - numerics_integrator(2) = IO_intValue(line,chunkPos,2_pInt) - case ('analyticjaco') - analyticJaco = IO_intValue(line,chunkPos,2_pInt) > 0_pInt - case ('usepingpong') - usepingpong = IO_intValue(line,chunkPos,2_pInt) > 0_pInt - case ('timesyncing') - numerics_timeSyncing = IO_intValue(line,chunkPos,2_pInt) > 0_pInt - case ('unitlength') - numerics_unitlength = IO_floatValue(line,chunkPos,2_pInt) - -!-------------------------------------------------------------------------------------------------- -! RGC parameters - case ('atol_rgc') - absTol_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('rtol_rgc') - relTol_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('amax_rgc') - absMax_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('rmax_rgc') - relMax_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('perturbpenalty_rgc') - pPert_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('relevantmismatch_rgc') - xSmoo_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('viscositypower_rgc') - viscPower_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('viscositymodulus_rgc') - viscModus_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('refrelaxationrate_rgc') - refRelaxRate_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('maxrelaxation_rgc') - maxdRelax_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('maxvoldiscrepancy_rgc') - maxVolDiscr_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('voldiscrepancymod_rgc') - volDiscrMod_RGC = IO_floatValue(line,chunkPos,2_pInt) - case ('discrepancypower_rgc') - volDiscrPow_RGC = IO_floatValue(line,chunkPos,2_pInt) - -!-------------------------------------------------------------------------------------------------- -! random seeding parameter - case ('fixed_seed') - fixedSeed = IO_intValue(line,chunkPos,2_pInt) - -!-------------------------------------------------------------------------------------------------- -! gradient parameter - case ('charlength') - charLength = IO_floatValue(line,chunkPos,2_pInt) - case ('residualstiffness') - residualStiffness = IO_floatValue(line,chunkPos,2_pInt) - -!-------------------------------------------------------------------------------------------------- -! field parameters - case ('err_struct_tolabs') - err_struct_tolAbs = IO_floatValue(line,chunkPos,2_pInt) - case ('err_struct_tolrel') - err_struct_tolRel = IO_floatValue(line,chunkPos,2_pInt) - case ('err_thermal_tolabs') - err_thermal_tolabs = IO_floatValue(line,chunkPos,2_pInt) - case ('err_thermal_tolrel') - err_thermal_tolrel = IO_floatValue(line,chunkPos,2_pInt) - case ('err_damage_tolabs') - err_damage_tolabs = IO_floatValue(line,chunkPos,2_pInt) - case ('err_damage_tolrel') - err_damage_tolrel = IO_floatValue(line,chunkPos,2_pInt) - case ('err_vacancyflux_tolabs') - err_vacancyflux_tolabs = IO_floatValue(line,chunkPos,2_pInt) - case ('err_vacancyflux_tolrel') - err_vacancyflux_tolrel = IO_floatValue(line,chunkPos,2_pInt) - case ('err_porosity_tolabs') - err_porosity_tolabs = IO_floatValue(line,chunkPos,2_pInt) - case ('err_porosity_tolrel') - err_porosity_tolrel = IO_floatValue(line,chunkPos,2_pInt) - case ('err_hydrogenflux_tolabs') - err_hydrogenflux_tolabs = IO_floatValue(line,chunkPos,2_pInt) - case ('err_hydrogenflux_tolrel') - err_hydrogenflux_tolrel = IO_floatValue(line,chunkPos,2_pInt) - case ('vacancyboundpenalty') - vacancyBoundPenalty = IO_floatValue(line,chunkPos,2_pInt) - case ('hydrogenboundpenalty') - hydrogenBoundPenalty = IO_floatValue(line,chunkPos,2_pInt) - case ('itmax') - itmax = IO_intValue(line,chunkPos,2_pInt) - case ('itmin') - itmin = IO_intValue(line,chunkPos,2_pInt) - case ('maxcutback') - maxCutBack = IO_intValue(line,chunkPos,2_pInt) - case ('maxstaggerediter') - stagItMax = IO_intValue(line,chunkPos,2_pInt) - case ('vacancypolyorder') - vacancyPolyOrder = IO_intValue(line,chunkPos,2_pInt) - case ('hydrogenpolyorder') - hydrogenPolyOrder = IO_intValue(line,chunkPos,2_pInt) - -!-------------------------------------------------------------------------------------------------- -! spectral parameters -#ifdef Spectral - case ('err_div_tolabs') - err_div_tolAbs = IO_floatValue(line,chunkPos,2_pInt) - case ('err_div_tolrel') - err_div_tolRel = IO_floatValue(line,chunkPos,2_pInt) - case ('err_stress_tolrel') - err_stress_tolrel = IO_floatValue(line,chunkPos,2_pInt) - case ('err_stress_tolabs') - err_stress_tolabs = IO_floatValue(line,chunkPos,2_pInt) - case ('continuecalculation') - continueCalculation = IO_intValue(line,chunkPos,2_pInt) - case ('memory_efficient') - memory_efficient = IO_intValue(line,chunkPos,2_pInt) > 0_pInt - case ('fftw_timelimit') - fftw_timelimit = IO_floatValue(line,chunkPos,2_pInt) - case ('fftw_plan_mode') - fftw_plan_mode = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('spectralderivative') - spectral_derivative = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('divergence_correction') - divergence_correction = IO_intValue(line,chunkPos,2_pInt) - case ('update_gamma') - update_gamma = IO_intValue(line,chunkPos,2_pInt) > 0_pInt - case ('petsc_options') - petsc_options = trim(line(chunkPos(4):)) - case ('spectralsolver','myspectralsolver') - spectral_solver = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('err_curl_tolabs') - err_curl_tolAbs = IO_floatValue(line,chunkPos,2_pInt) - case ('err_curl_tolrel') - err_curl_tolRel = IO_floatValue(line,chunkPos,2_pInt) - case ('polaralpha') - polarAlpha = IO_floatValue(line,chunkPos,2_pInt) - case ('polarbeta') - polarBeta = IO_floatValue(line,chunkPos,2_pInt) -#else - case ('err_div_tolabs','err_div_tolrel','err_stress_tolrel','err_stress_tolabs',& ! found spectral parameter for FEM build - 'memory_efficient','fftw_timelimit','fftw_plan_mode', & - 'divergence_correction','update_gamma','spectralfilter','myfilter', & - 'err_curl_tolabs','err_curl_tolrel', & - 'polaralpha','polarbeta') - call IO_warning(40_pInt,ext_msg=tag) -#endif - -!-------------------------------------------------------------------------------------------------- -! FEM parameters -#ifdef FEM - case ('integrationorder') - integrationorder = IO_intValue(line,chunkPos,2_pInt) - case ('structorder') - structorder = IO_intValue(line,chunkPos,2_pInt) - case ('thermalorder') - thermalorder = IO_intValue(line,chunkPos,2_pInt) - case ('damageorder') - damageorder = IO_intValue(line,chunkPos,2_pInt) - case ('vacancyfluxorder') - vacancyfluxOrder = IO_intValue(line,chunkPos,2_pInt) - case ('porosityorder') - porosityOrder = IO_intValue(line,chunkPos,2_pInt) - case ('hydrogenfluxorder') - hydrogenfluxOrder = IO_intValue(line,chunkPos,2_pInt) - case ('petsc_options') - petsc_options = trim(line(chunkPos(4):)) - case ('bbarstabilisation') - BBarStabilisation = IO_intValue(line,chunkPos,2_pInt) > 0_pInt -#else - case ('integrationorder','structorder','thermalorder', 'damageorder','vacancyfluxorder', & - 'porosityorder','hydrogenfluxorder','bbarstabilisation') - call IO_warning(40_pInt,ext_msg=tag) -#endif - case default ! found unknown keyword - call IO_error(300_pInt,ext_msg=tag) - endselect - enddo - close(FILEUNIT) - - else fileExists -#ifdef FEM - if (worldrank == 0) then -#endif - write(6,'(a,/)') ' using standard values' - flush(6) -#ifdef FEM - endif -#endif - endif fileExists - -#ifdef Spectral - select case(IO_lc(fftw_plan_mode)) ! setting parameters for the plan creation of FFTW. Basically a translation from fftw3.f - case('estimate','fftw_estimate') ! ordered from slow execution (but fast plan creation) to fast execution - fftw_planner_flag = 64_pInt - case('measure','fftw_measure') - fftw_planner_flag = 0_pInt - case('patient','fftw_patient') - fftw_planner_flag= 32_pInt - case('exhaustive','fftw_exhaustive') - fftw_planner_flag = 8_pInt - case default - call IO_warning(warning_ID=47_pInt,ext_msg=trim(IO_lc(fftw_plan_mode))) - fftw_planner_flag = 32_pInt - end select -#endif - - numerics_timeSyncing = numerics_timeSyncing .and. all(numerics_integrator==2_pInt) ! timeSyncing only allowed for explicit Euler integrator - -!-------------------------------------------------------------------------------------------------- -! writing parameters to output - mainProcess3: if (worldrank == 0) then - write(6,'(a24,1x,es8.1)') ' relevantStrain: ',relevantStrain - write(6,'(a24,1x,es8.1)') ' defgradTolerance: ',defgradTolerance - write(6,'(a24,1x,i8)') ' iJacoStiffness: ',iJacoStiffness - write(6,'(a24,1x,i8)') ' iJacoLpresiduum: ',iJacoLpresiduum - write(6,'(a24,1x,es8.1)') ' pert_Fg: ',pert_Fg - write(6,'(a24,1x,i8)') ' pert_method: ',pert_method - write(6,'(a24,1x,i8)') ' nCryst: ',nCryst - write(6,'(a24,1x,es8.1)') ' subStepMinCryst: ',subStepMinCryst - write(6,'(a24,1x,es8.1)') ' subStepSizeCryst: ',subStepSizeCryst - write(6,'(a24,1x,es8.1)') ' stepIncreaseCryst: ',stepIncreaseCryst - write(6,'(a24,1x,i8)') ' nState: ',nState - write(6,'(a24,1x,i8)') ' nStress: ',nStress - write(6,'(a24,1x,es8.1)') ' rTol_crystalliteState: ',rTol_crystalliteState - write(6,'(a24,1x,es8.1)') ' rTol_crystalliteStress: ',rTol_crystalliteStress - write(6,'(a24,1x,es8.1)') ' aTol_crystalliteStress: ',aTol_crystalliteStress - write(6,'(a24,2(1x,i8))') ' integrator: ',numerics_integrator - write(6,'(a24,1x,L8)') ' timeSyncing: ',numerics_timeSyncing - write(6,'(a24,1x,L8)') ' analytic Jacobian: ',analyticJaco - write(6,'(a24,1x,L8)') ' use ping pong scheme: ',usepingpong - write(6,'(a24,1x,es8.1,/)')' unitlength: ',numerics_unitlength - - write(6,'(a24,1x,i8)') ' nHomog: ',nHomog - write(6,'(a24,1x,es8.1)') ' subStepMinHomog: ',subStepMinHomog - write(6,'(a24,1x,es8.1)') ' subStepSizeHomog: ',subStepSizeHomog - write(6,'(a24,1x,es8.1)') ' stepIncreaseHomog: ',stepIncreaseHomog - write(6,'(a24,1x,i8,/)') ' nMPstate: ',nMPstate - -!-------------------------------------------------------------------------------------------------- -! RGC parameters - write(6,'(a24,1x,es8.1)') ' aTol_RGC: ',absTol_RGC - write(6,'(a24,1x,es8.1)') ' rTol_RGC: ',relTol_RGC - write(6,'(a24,1x,es8.1)') ' aMax_RGC: ',absMax_RGC - write(6,'(a24,1x,es8.1)') ' rMax_RGC: ',relMax_RGC - write(6,'(a24,1x,es8.1)') ' perturbPenalty_RGC: ',pPert_RGC - write(6,'(a24,1x,es8.1)') ' relevantMismatch_RGC: ',xSmoo_RGC - write(6,'(a24,1x,es8.1)') ' viscosityrate_RGC: ',viscPower_RGC - write(6,'(a24,1x,es8.1)') ' viscositymodulus_RGC: ',viscModus_RGC - write(6,'(a24,1x,es8.1)') ' maxrelaxation_RGC: ',maxdRelax_RGC - write(6,'(a24,1x,es8.1)') ' maxVolDiscrepancy_RGC: ',maxVolDiscr_RGC - write(6,'(a24,1x,es8.1)') ' volDiscrepancyMod_RGC: ',volDiscrMod_RGC - write(6,'(a24,1x,es8.1,/)') ' discrepancyPower_RGC: ',volDiscrPow_RGC - -!-------------------------------------------------------------------------------------------------- -! Random seeding parameter - write(6,'(a24,1x,i16,/)') ' fixed_seed: ',fixedSeed - if (fixedSeed <= 0_pInt) & - write(6,'(a,/)') ' No fixed Seed: Random is random!' - -!-------------------------------------------------------------------------------------------------- -! gradient parameter - write(6,'(a24,1x,es8.1)') ' charLength: ',charLength - write(6,'(a24,1x,es8.1)') ' residualStiffness: ',residualStiffness - -!-------------------------------------------------------------------------------------------------- -! openMP parameter - !$ write(6,'(a24,1x,i8,/)') ' number of threads: ',DAMASK_NumThreadsInt - -!-------------------------------------------------------------------------------------------------- -! field parameters - write(6,'(a24,1x,i8)') ' itmax: ',itmax - write(6,'(a24,1x,i8)') ' itmin: ',itmin - write(6,'(a24,1x,i8)') ' maxCutBack: ',maxCutBack - write(6,'(a24,1x,i8)') ' maxStaggeredIter: ',stagItMax - write(6,'(a24,1x,i8)') ' vacancyPolyOrder: ',vacancyPolyOrder - write(6,'(a24,1x,i8)') ' hydrogenPolyOrder: ',hydrogenPolyOrder - write(6,'(a24,1x,es8.1)') ' err_struct_tolAbs: ',err_struct_tolAbs - write(6,'(a24,1x,es8.1)') ' err_struct_tolRel: ',err_struct_tolRel - write(6,'(a24,1x,es8.1)') ' err_thermal_tolabs: ',err_thermal_tolabs - write(6,'(a24,1x,es8.1)') ' err_thermal_tolrel: ',err_thermal_tolrel - write(6,'(a24,1x,es8.1)') ' err_damage_tolabs: ',err_damage_tolabs - write(6,'(a24,1x,es8.1)') ' err_damage_tolrel: ',err_damage_tolrel - write(6,'(a24,1x,es8.1)') ' err_vacancyflux_tolabs: ',err_vacancyflux_tolabs - write(6,'(a24,1x,es8.1)') ' err_vacancyflux_tolrel: ',err_vacancyflux_tolrel - write(6,'(a24,1x,es8.1)') ' err_porosity_tolabs: ',err_porosity_tolabs - write(6,'(a24,1x,es8.1)') ' err_porosity_tolrel: ',err_porosity_tolrel - write(6,'(a24,1x,es8.1)') ' err_hydrogenflux_tolabs:',err_hydrogenflux_tolabs - write(6,'(a24,1x,es8.1)') ' err_hydrogenflux_tolrel:',err_hydrogenflux_tolrel - write(6,'(a24,1x,es8.1)') ' vacancyBoundPenalty: ',vacancyBoundPenalty - write(6,'(a24,1x,es8.1)') ' hydrogenBoundPenalty: ',hydrogenBoundPenalty - -!-------------------------------------------------------------------------------------------------- -! spectral parameters -#ifdef Spectral - write(6,'(a24,1x,i8)') ' continueCalculation: ',continueCalculation - write(6,'(a24,1x,L8)') ' memory_efficient: ',memory_efficient - write(6,'(a24,1x,i8)') ' divergence_correction: ',divergence_correction - write(6,'(a24,1x,a)') ' spectral_derivative: ',trim(spectral_derivative) - if(fftw_timelimit<0.0_pReal) then - write(6,'(a24,1x,L8)') ' fftw_timelimit: ',.false. - else - write(6,'(a24,1x,es8.1)') ' fftw_timelimit: ',fftw_timelimit - endif - write(6,'(a24,1x,a)') ' fftw_plan_mode: ',trim(fftw_plan_mode) - write(6,'(a24,1x,i8)') ' fftw_planner_flag: ',fftw_planner_flag - write(6,'(a24,1x,L8,/)') ' update_gamma: ',update_gamma - write(6,'(a24,1x,es8.1)') ' err_stress_tolAbs: ',err_stress_tolAbs - write(6,'(a24,1x,es8.1)') ' err_stress_tolRel: ',err_stress_tolRel - write(6,'(a24,1x,es8.1)') ' err_div_tolAbs: ',err_div_tolAbs - write(6,'(a24,1x,es8.1)') ' err_div_tolRel: ',err_div_tolRel - write(6,'(a24,1x,es8.1)') ' err_curl_tolAbs: ',err_curl_tolAbs - write(6,'(a24,1x,es8.1)') ' err_curl_tolRel: ',err_curl_tolRel - write(6,'(a24,1x,es8.1)') ' polarAlpha: ',polarAlpha - write(6,'(a24,1x,es8.1)') ' polarBeta: ',polarBeta - write(6,'(a24,1x,a)') ' spectral solver: ',trim(spectral_solver) - write(6,'(a24,1x,a)') ' PETSc_options: ',trim(petsc_defaultOptions)//' '//trim(petsc_options) -#endif - -!-------------------------------------------------------------------------------------------------- -! spectral parameters -#ifdef FEM - write(6,'(a24,1x,i8)') ' integrationOrder: ',integrationOrder - write(6,'(a24,1x,i8)') ' structOrder: ',structOrder - write(6,'(a24,1x,i8)') ' thermalOrder: ',thermalOrder - write(6,'(a24,1x,i8)') ' damageOrder: ',damageOrder - write(6,'(a24,1x,i8)') ' vacancyfluxOrder: ',vacancyfluxOrder - write(6,'(a24,1x,i8)') ' porosityOrder: ',porosityOrder - write(6,'(a24,1x,i8)') ' hydrogenfluxOrder: ',hydrogenfluxOrder - write(6,'(a24,1x,a)') ' PETSc_options: ',trim(petsc_defaultOptions)//' '//trim(petsc_options) - write(6,'(a24,1x,L8)') ' B-Bar stabilisation: ',BBarStabilisation -#endif - endif mainProcess3 - - -!-------------------------------------------------------------------------------------------------- -! sanity checks - if (relevantStrain <= 0.0_pReal) call IO_error(301_pInt,ext_msg='relevantStrain') - if (defgradTolerance <= 0.0_pReal) call IO_error(301_pInt,ext_msg='defgradTolerance') - if (iJacoStiffness < 1_pInt) call IO_error(301_pInt,ext_msg='iJacoStiffness') - if (iJacoLpresiduum < 1_pInt) call IO_error(301_pInt,ext_msg='iJacoLpresiduum') - if (pert_Fg <= 0.0_pReal) call IO_error(301_pInt,ext_msg='pert_Fg') - if (pert_method <= 0_pInt .or. pert_method >= 4_pInt) & - call IO_error(301_pInt,ext_msg='pert_method') - if (nHomog < 1_pInt) call IO_error(301_pInt,ext_msg='nHomog') - if (nMPstate < 1_pInt) call IO_error(301_pInt,ext_msg='nMPstate') - if (nCryst < 1_pInt) call IO_error(301_pInt,ext_msg='nCryst') - if (nState < 1_pInt) call IO_error(301_pInt,ext_msg='nState') - if (nStress < 1_pInt) call IO_error(301_pInt,ext_msg='nStress') - if (subStepMinCryst <= 0.0_pReal) call IO_error(301_pInt,ext_msg='subStepMinCryst') - if (subStepSizeCryst <= 0.0_pReal) call IO_error(301_pInt,ext_msg='subStepSizeCryst') - if (stepIncreaseCryst <= 0.0_pReal) call IO_error(301_pInt,ext_msg='stepIncreaseCryst') - if (subStepMinHomog <= 0.0_pReal) call IO_error(301_pInt,ext_msg='subStepMinHomog') - if (subStepSizeHomog <= 0.0_pReal) call IO_error(301_pInt,ext_msg='subStepSizeHomog') - if (stepIncreaseHomog <= 0.0_pReal) call IO_error(301_pInt,ext_msg='stepIncreaseHomog') - if (rTol_crystalliteState <= 0.0_pReal) call IO_error(301_pInt,ext_msg='rTol_crystalliteState') - if (rTol_crystalliteStress <= 0.0_pReal) call IO_error(301_pInt,ext_msg='rTol_crystalliteStress') - if (aTol_crystalliteStress <= 0.0_pReal) call IO_error(301_pInt,ext_msg='aTol_crystalliteStress') - if (any(numerics_integrator <= 0_pInt) .or. any(numerics_integrator >= 6_pInt)) & - call IO_error(301_pInt,ext_msg='integrator') - if (numerics_unitlength <= 0.0_pReal) call IO_error(301_pInt,ext_msg='unitlength') - if (absTol_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='absTol_RGC') - if (relTol_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='relTol_RGC') - if (absMax_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='absMax_RGC') - if (relMax_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='relMax_RGC') - if (pPert_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='pPert_RGC') - if (xSmoo_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='xSmoo_RGC') - if (viscPower_RGC < 0.0_pReal) call IO_error(301_pInt,ext_msg='viscPower_RGC') - if (viscModus_RGC < 0.0_pReal) call IO_error(301_pInt,ext_msg='viscModus_RGC') - if (refRelaxRate_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='refRelaxRate_RGC') - if (maxdRelax_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='maxdRelax_RGC') - if (maxVolDiscr_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='maxVolDiscr_RGC') - if (volDiscrMod_RGC < 0.0_pReal) call IO_error(301_pInt,ext_msg='volDiscrMod_RGC') - if (volDiscrPow_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='volDiscrPw_RGC') - if (residualStiffness < 0.0_pReal) call IO_error(301_pInt,ext_msg='residualStiffness') - if (itmax <= 1_pInt) call IO_error(301_pInt,ext_msg='itmax') - if (itmin > itmax .or. itmin < 1_pInt) call IO_error(301_pInt,ext_msg='itmin') - if (maxCutBack < 0_pInt) call IO_error(301_pInt,ext_msg='maxCutBack') - if (stagItMax < 0_pInt) call IO_error(301_pInt,ext_msg='maxStaggeredIter') - if (vacancyPolyOrder < 0_pInt) call IO_error(301_pInt,ext_msg='vacancyPolyOrder') - if (err_struct_tolRel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_struct_tolRel') - if (err_struct_tolAbs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_struct_tolAbs') - if (err_thermal_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_thermal_tolabs') - if (err_thermal_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_thermal_tolrel') - if (err_damage_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_damage_tolabs') - if (err_damage_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_damage_tolrel') - if (err_vacancyflux_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_vacancyflux_tolabs') - if (err_vacancyflux_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_vacancyflux_tolrel') - if (err_porosity_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_porosity_tolabs') - if (err_porosity_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_porosity_tolrel') - if (err_hydrogenflux_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_hydrogenflux_tolabs') - if (err_hydrogenflux_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_hydrogenflux_tolrel') -#ifdef Spectral - if (continueCalculation /= 0_pInt .and. & - continueCalculation /= 1_pInt) call IO_error(301_pInt,ext_msg='continueCalculation') - if (divergence_correction < 0_pInt .or. & - divergence_correction > 2_pInt) call IO_error(301_pInt,ext_msg='divergence_correction') - if (update_gamma .and. & - .not. memory_efficient) call IO_error(error_ID = 847_pInt) - if (err_stress_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_stress_tolRel') - if (err_stress_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_stress_tolAbs') - if (err_div_tolRel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_div_tolRel') - if (err_div_tolAbs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_div_tolAbs') - if (err_curl_tolRel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_curl_tolRel') - if (err_curl_tolAbs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_curl_tolAbs') - if (polarAlpha <= 0.0_pReal .or. & - polarAlpha > 2.0_pReal) call IO_error(301_pInt,ext_msg='polarAlpha') - if (polarBeta < 0.0_pReal .or. & - polarBeta > 2.0_pReal) call IO_error(301_pInt,ext_msg='polarBeta') -#endif - -end subroutine numerics_init - -end module numerics diff --git a/code/plastic_disloUCLA.f90 b/code/plastic_disloUCLA.f90 deleted file mode 100644 index d95a5e6a4..000000000 --- a/code/plastic_disloUCLA.f90 +++ /dev/null @@ -1,2116 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author David Cereceda, Lawrence Livermore National Laboratory -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incoprorating dislocation and twinning physics -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module plastic_disloUCLA - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_disloUCLA_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_disloUCLA_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_disloUCLA_output !< name of each post result output - - real(pReal), parameter, private :: & - kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_disloUCLA_Noutput !< number of outputs per instance of this plasticity - - integer(pInt), dimension(:), allocatable, private :: & - plastic_disloUCLA_totalNslip, & !< total number of active slip systems for each instance - plastic_disloUCLA_totalNtwin !< total number of active twin systems for each instance - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_disloUCLA_Nslip, & !< number of active slip systems for each family and instance - plastic_disloUCLA_Ntwin !< number of active twin systems for each family and instance - - real(pReal), dimension(:), allocatable, private :: & - plastic_disloUCLA_CAtomicVolume, & !< atomic volume in Bugers vector unit - plastic_disloUCLA_D0, & !< prefactor for self-diffusion coefficient - plastic_disloUCLA_Qsd, & !< activation energy for dislocation climb - plastic_disloUCLA_GrainSize, & !< grain size - plastic_disloUCLA_MaxTwinFraction, & !< maximum allowed total twin volume fraction - plastic_disloUCLA_CEdgeDipMinDistance, & !< - plastic_disloUCLA_Cmfptwin, & !< - plastic_disloUCLA_Cthresholdtwin, & !< - plastic_disloUCLA_SolidSolutionStrength, & !< Strength due to elements in solid solution - plastic_disloUCLA_L0, & !< Length of twin nuclei in Burgers vectors - plastic_disloUCLA_xc, & !< critical distance for formation of twin nucleus - plastic_disloUCLA_VcrossSlip, & !< cross slip volume - plastic_disloUCLA_SFE_0K, & !< stacking fault energy at zero K - plastic_disloUCLA_dSFE_dT, & !< temperature dependance of stacking fault energy - plastic_disloUCLA_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful - plastic_disloUCLA_aTolRho, & !< absolute tolerance for integration of dislocation density - plastic_disloUCLA_aTolTwinFrac !< absolute tolerance for integration of twin volume fraction - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_disloUCLA_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_disloUCLA_Ctwin3333 !< twin elasticity matrix for each instance - real(pReal), dimension(:,:), allocatable, private :: & - plastic_disloUCLA_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance - plastic_disloUCLA_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance - plastic_disloUCLA_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance - plastic_disloUCLA_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance - plastic_disloUCLA_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance - plastic_disloUCLA_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance - plastic_disloUCLA_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance - plastic_disloUCLA_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance - plastic_disloUCLA_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance - plastic_disloUCLA_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance - plastic_disloUCLA_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance - plastic_disloUCLA_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance - plastic_disloUCLA_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance - plastic_disloUCLA_tau_r, & !< stress to bring partial close together for each twin system and instance - plastic_disloUCLA_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance - plastic_disloUCLA_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance - plastic_disloUCLA_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_disloUCLA_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_disloUCLA_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance - plastic_disloUCLA_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance - plastic_disloUCLA_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_disloUCLA_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance - plastic_disloUCLA_pPerSlipFamily, & !< p-exponent in glide velocity - plastic_disloUCLA_qPerSlipFamily, & !< q-exponent in glide velocity - !* mobility law parameters - plastic_disloUCLA_kinkheight, & !< height of the kink pair - plastic_disloUCLA_omega, & !< attempt frequency for kink pair nucleation - plastic_disloUCLA_kinkwidth, & !< width of the kink pair - plastic_disloUCLA_dislolength, & !< dislocation length (lamda) - plastic_disloUCLA_friction, & !< friction coeff. B (kMC) - !* - plastic_disloUCLA_rPerTwinFamily, & !< r-exponent in twin nucleation rate - plastic_disloUCLA_nonSchmidCoeff !< non-Schmid coefficients (bcc) - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_disloUCLA_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance - plastic_disloUCLA_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance - plastic_disloUCLA_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance - plastic_disloUCLA_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance - plastic_disloUCLA_forestProjectionEdge !< matrix of forest projections of edge dislocations for each instance - - enum, bind(c) - enumerator :: undefined_ID, & - edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID, & - twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_disloUCLA_outputID !< ID of each post result output - - type, private :: tDisloUCLAState - real(pReal), pointer, dimension(:,:) :: & - rhoEdge, & - rhoEdgeDip, & - accshear_slip, & - twinFraction, & - accshear_twin, & - invLambdaSlip, & - invLambdaSlipTwin, & - invLambdaTwin, & - mfp_slip, & - mfp_twin, & - threshold_stress_slip, & - threshold_stress_twin, & - twinVolume - end type - type(tDisloUCLAState ), allocatable, dimension(:), private :: & - state, & - state0, & - dotState - - public :: & - plastic_disloUCLA_init, & - plastic_disloUCLA_homogenizedC, & - plastic_disloUCLA_microstructure, & - plastic_disloUCLA_LpAndItsTangent, & - plastic_disloUCLA_dotState, & - plastic_disloUCLA_postResults - private :: & - plastic_disloUCLA_stateInit, & - plastic_disloUCLA_aTolState - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333, & - math_mul3x3 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_DISLOUCLA_label, & - PLASTICITY_DISLOUCLA_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,& - f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & - offset_slip, index_myFamily, index_otherFamily, & - startIndex, endIndex - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOUCLA_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOUCLA_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_disloUCLA_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(plastic_disloUCLA_output(maxval(phase_Noutput),maxNinstance)) - plastic_disloUCLA_output = '' - allocate(plastic_disloUCLA_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_disloUCLA_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_disloUCLA_CAtomicVolume(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_D0(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Qsd(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_GrainSize(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_MaxTwinFraction(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Cmfptwin(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Cthresholdtwin(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_SolidSolutionStrength(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_L0(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_xc(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_VcrossSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_aTolRho(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_aTolTwinFrac(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_SFE_0K(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_dSFE_dT(maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default - allocate(plastic_disloUCLA_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_kinkheight(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_omega(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_kinkwidth(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_dislolength(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_friction(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_disloUCLA_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_disloUCLA_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) - allocate(plastic_disloUCLA_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), source=0.0_pReal) - - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - if(allocated(tempPerTwin)) deallocate(tempPerTwin) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - allocate(tempPerTwin(Nchunks_TwinFamilies)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('edge_density') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_density_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('dipole_density') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = dipole_density_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_slip','shearrate_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_slip') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_slip_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('edge_dipole_distance') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_dipole_distance_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stress_exponent') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = stress_exponent_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('twin_fraction') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = twin_fraction_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_twin','shearrate_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_twin') - plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt - plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_twin_ID - plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip system families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - plastic_disloUCLA_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip',& - 'kink_height','omega','kink_width','dislolength','friction_coeff') - do j = 1_pInt, Nchunks_SlipFamilies - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('rhoedge0') - plastic_disloUCLA_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('rhoedgedip0') - plastic_disloUCLA_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('slipburgers') - plastic_disloUCLA_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('qedge') - plastic_disloUCLA_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('v0') - plastic_disloUCLA_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('clambdaslip') - plastic_disloUCLA_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau_peierls') - if (lattice_structure(phase) /= LATTICE_bcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOUCLA_label//')') - plastic_disloUCLA_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('p_slip') - plastic_disloUCLA_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('q_slip') - plastic_disloUCLA_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('kink_height') - plastic_disloUCLA_kinkheight(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('omega') - plastic_disloUCLA_omega(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('kink_width') - plastic_disloUCLA_kinkwidth(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('dislolength') - plastic_disloUCLA_dislolength(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - case ('friction_coeff') - plastic_disloUCLA_friction(1:Nchunks_SlipFamilies,instance) = & - tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on slip number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_disloUCLA_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ndot0','twinsize','twinburgers','r_twin') - do j = 1_pInt, Nchunks_TwinFamilies - tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('ndot0') - if (lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOUCLA_label//')') - plastic_disloUCLA_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinsize') - plastic_disloUCLA_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinburgers') - plastic_disloUCLA_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('r_twin') - plastic_disloUCLA_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip','interactionslipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_disloUCLA_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin','interactionsliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_disloUCLA_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip','interactiontwinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_disloUCLA_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin','interactiontwintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_disloUCLA_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') - do j = 1_pInt,Nchunks_nonSchmid - plastic_disloUCLA_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin systems - case ('grainsize') - plastic_disloUCLA_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('maxtwinfraction') - plastic_disloUCLA_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('d0') - plastic_disloUCLA_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('qsd') - plastic_disloUCLA_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_rho') - plastic_disloUCLA_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_disloUCLA_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cmfptwin') - plastic_disloUCLA_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cthresholdtwin') - plastic_disloUCLA_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('solidsolutionstrength') - plastic_disloUCLA_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('l0') - plastic_disloUCLA_L0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('xc') - plastic_disloUCLA_xc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('vcrossslip') - plastic_disloUCLA_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cedgedipmindistance') - plastic_disloUCLA_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('catomicvolume') - plastic_disloUCLA_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('sfe_0k') - plastic_disloUCLA_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dsfe_dt') - plastic_disloUCLA_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dipoleformationfactor') - plastic_disloUCLA_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then - instance = phase_plasticityInstance(phase) - if (sum(plastic_disloUCLA_Nslip(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOUCLA_label//')') - if (sum(plastic_disloUCLA_Ntwin(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOUCLA_label//')') - do f = 1_pInt,lattice_maxNslipFamily - if (plastic_disloUCLA_Nslip(f,instance) > 0_pInt) then - if (plastic_disloUCLA_rhoEdge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_rhoEdgeDip0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_v0PerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOUCLA_label//')') - endif - enddo - do f = 1_pInt,lattice_maxNtwinFamily - if (plastic_disloUCLA_Ntwin(f,instance) > 0_pInt) then - if (plastic_disloUCLA_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='ndot0 ('//PLASTICITY_DISLOUCLA_label//')') - endif - enddo - if (plastic_disloUCLA_CAtomicVolume(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_D0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_Qsd(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOUCLA_label//')') - if (sum(plastic_disloUCLA_Ntwin(:,instance)) > 0_pInt) then - if (abs(plastic_disloUCLA_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & - abs(plastic_disloUCLA_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & - lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOUCLA_label//')') - if (plastic_disloUCLA_aTolTwinFrac(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOUCLA_label//')') - endif - if (abs(plastic_disloUCLA_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & - plastic_disloUCLA_dipoleFormationFactor(instance) /= 1.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOUCLA_label//')') - -!-------------------------------------------------------------------------------------------------- -! Determine total number of active slip or twin systems - plastic_disloUCLA_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_disloUCLA_Nslip(:,instance)) - plastic_disloUCLA_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_disloUCLA_Ntwin(:,instance)) - plastic_disloUCLA_totalNslip(instance) = sum(plastic_disloUCLA_Nslip(:,instance)) - plastic_disloUCLA_totalNtwin(instance) = sum(plastic_disloUCLA_Ntwin(:,instance)) - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - maxTotalNslip = maxval(plastic_disloUCLA_totalNslip) - maxTotalNtwin = maxval(plastic_disloUCLA_totalNtwin) - - allocate(plastic_disloUCLA_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_tau_r(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) - - allocate(plastic_disloUCLA_interactionMatrix_SlipSlip(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from slip activity - maxval(plastic_disloUCLA_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_interactionMatrix_SlipTwin(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from twin activity - maxval(plastic_disloUCLA_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_interactionMatrix_TwinSlip(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_disloUCLA_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_interactionMatrix_TwinTwin(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_disloUCLA_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & - source=0.0_pReal) - allocate(plastic_disloUCLA_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_disloUCLA_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) - - allocate(state(maxNinstance)) - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - myPhase2: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then - NofMyPhase=count(material_phase==phase) - instance = phase_plasticityInstance(phase) - - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputs: do o = 1_pInt,plastic_disloUCLA_Noutput(instance) - select case(plastic_disloUCLA_outputID(o,instance)) - case(edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID & - ) - mySize = ns - case(twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID & - ) - mySize = nt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - plastic_disloUCLA_sizePostResult(o,instance) = mySize - plastic_disloUCLA_sizePostResults(instance) = plastic_disloUCLA_sizePostResults(instance) + mySize - endif - enddo outputs - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - - sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & - + int(size(['twinFraction','accsheartwin']),pInt) * nt - sizeDeltaState = 0_pInt - sizeState = sizeDotState & - + int(size(['invLambdaSlip ','invLambdaSlipTwin ',& - 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & - + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& - 'twinVolume ']),pInt) * nt - - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_disloUCLA_sizePostResults(instance) - plasticState(phase)%nSlip = plastic_disloucla_totalNslip(instance) - plasticState(phase)%nTwin = plastic_disloucla_totalNtwin(instance) - plasticState(phase)%nTrans= 0_pInt - allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - offset_slip = 2_pInt*plasticState(phase)%nSlip - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) - !* Process slip related parameters ------------------------------------------------ - - mySlipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - mySlipSystems: do j = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - - !* Burgers vector, - ! dislocation velocity prefactor, - ! mean free path prefactor, - ! and minimum dipole distance - - plastic_disloUCLA_burgersPerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_burgersPerSlipFamily(f,instance) - - plastic_disloUCLA_QedgePerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_QedgePerSlipFamily(f,instance) - - plastic_disloUCLA_v0PerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_v0PerSlipFamily(f,instance) - - plastic_disloUCLA_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_CLambdaSlipPerSlipFamily(f,instance) - - !* Calculation of forest projections for edge dislocations - !* Interaction matrices - - otherSlipFamilies: do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) - otherSlipSystems: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) - plastic_disloUCLA_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & - abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & - lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) - plastic_disloUCLA_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo otherSlipSystems; enddo otherSlipFamilies - - otherTwinFamilies: do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) - otherTwinSystems: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) - plastic_disloUCLA_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo otherTwinSystems; enddo otherTwinFamilies - - enddo mySlipSystems - enddo mySlipFamilies - - !* Process twin related parameters ------------------------------------------------ - - myTwinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(plastic_disloUCLA_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list - myTwinSystems: do j = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) - - !* Burgers vector, - ! nucleation rate prefactor, - ! and twin size - - plastic_disloUCLA_burgersPerTwinSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_burgersPerTwinFamily(f,instance) - - plastic_disloUCLA_Ndot0PerTwinSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) - - plastic_disloUCLA_twinsizePerTwinSystem(index_myFamily+j,instance) = & - plastic_disloUCLA_twinsizePerTwinFamily(f,instance) - - !* Rotate twin elasticity matrices - index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list - do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt - do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt - plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & - plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & - lattice_C3333(p,q,r,s,instance) * & - lattice_Qtwin(l,p,index_otherFamily+j,phase) * & - lattice_Qtwin(m,q,index_otherFamily+j,phase) * & - lattice_Qtwin(n,r,index_otherFamily+j,phase) * & - lattice_Qtwin(o,s,index_otherFamily+j,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo; enddo - plastic_disloUCLA_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & - math_Mandel3333to66(plastic_disloUCLA_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) - - !* Interaction matrices - otherSlipFamilies2: do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) - otherSlipSystems2: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) - plastic_disloUCLA_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo otherSlipSystems2; enddo otherSlipFamilies2 - - otherTwinFamilies2: do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) - otherTwinSystems2: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) - plastic_disloUCLA_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_disloUCLA_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo otherTwinSystems2; enddo otherTwinFamilies2 - - enddo myTwinSystems - enddo myTwinFamilies - - startIndex=1_pInt - endIndex=ns - state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+ns - state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+ns - state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+nt - state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+nt - state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1_pInt - endIndex=endIndex+ns - state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) - - call plastic_disloUCLA_stateInit(phase,instance) - call plastic_disloUCLA_aTolState(phase,instance) - endif myPhase2 - - enddo initializeInstances - -end subroutine plastic_disloUCLA_init - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_stateInit(ph,instance) - use math, only: & - pi - use lattice, only: & - lattice_maxNslipFamily, & - lattice_mu - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - real(pReal), dimension(plasticState(ph)%sizeState) :: tempState - - integer(pInt) :: i,j,f,ns,nt, index_myFamily - real(pReal), dimension(plastic_disloUCLA_totalNslip(instance)) :: & - rhoEdge0, & - rhoEdgeDip0, & - invLambdaSlip0, & - MeanFreePathSlip0, & - tauSlipThreshold0 - real(pReal), dimension(plastic_disloUCLA_totalNtwin(instance)) :: & - MeanFreePathTwin0,TwinVolume0 - tempState = 0.0_pReal - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables - do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - rhoEdge0(index_myFamily+1_pInt: & - index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & - plastic_disloUCLA_rhoEdge0(f,instance) - rhoEdgeDip0(index_myFamily+1_pInt: & - index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & - plastic_disloUCLA_rhoEdgeDip0(f,instance) - enddo - - tempState(1_pInt:ns) = rhoEdge0 - tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent slip microstructural variables - forall (i = 1_pInt:ns) & - invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_forestProjectionEdge(1:ns,i,instance)))/ & - plastic_disloUCLA_CLambdaSlipPerSlipSystem(i,instance) - tempState(3_pInt*ns+2_pInt*nt+1:4_pInt*ns+2_pInt*nt) = invLambdaSlip0 - - forall (i = 1_pInt:ns) & - MeanFreePathSlip0(i) = & - plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_disloUCLA_GrainSize(instance)) - tempState(5_pInt*ns+3_pInt*nt+1:6_pInt*ns+3_pInt*nt) = MeanFreePathSlip0 - - forall (i = 1_pInt:ns) & - tauSlipThreshold0(i) = & - lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(i,instance) * & - sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_interactionMatrix_SlipSlip(i,1:ns,instance))) - - tempState(6_pInt*ns+4_pInt*nt+1:7_pInt*ns+4_pInt*nt) = tauSlipThreshold0 - - - -!-------------------------------------------------------------------------------------------------- -! initialize dependent twin microstructural variables - forall (j = 1_pInt:nt) & - MeanFreePathTwin0(j) = plastic_disloUCLA_GrainSize(instance) - tempState(6_pInt*ns+3_pInt*nt+1_pInt:6_pInt*ns+4_pInt*nt) = MeanFreePathTwin0 - - forall (j = 1_pInt:nt) & - TwinVolume0(j) = & - (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) - tempState(7_pInt*ns+5_pInt*nt+1_pInt:7_pInt*ns+6_pInt*nt) = TwinVolume0 - -plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) - -end subroutine plastic_disloUCLA_stateInit - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - ph, & - instance ! number specifying the current instance of the plasticity - - ! Tolerance state for dislocation densities - plasticState(ph)%aTolState(1_pInt:2_pInt*plastic_disloUCLA_totalNslip(instance)) = & - plastic_disloUCLA_aTolRho(instance) - - ! Tolerance state for accumulated shear due to slip - plasticState(ph)%aTolState(2_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & - 3_pInt*plastic_disloUCLA_totalNslip(instance))=1e6_pReal - - - ! Tolerance state for twin volume fraction - plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & - 3_pInt*plastic_disloUCLA_totalNslip(instance)+& - plastic_disloUCLA_totalNtwin(instance)) = & - plastic_disloUCLA_aTolTwinFrac(instance) - -! Tolerance state for accumulated shear due to twin - plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+ & - plastic_disloUCLA_totalNtwin(instance)+1_pInt: & - 3_pInt*plastic_disloUCLA_totalNslip(instance)+ & - 2_pInt*plastic_disloUCLA_totalNtwin(instance)) = 1e6_pReal - -end subroutine plastic_disloUCLA_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenized elasticity matrix -!-------------------------------------------------------------------------------------------------- -function plastic_disloUCLA_homogenizedC(ipc,ip,el) - use material, only: & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_C66 - - implicit none - real(pReal), dimension(6,6) :: & - plastic_disloUCLA_homogenizedC - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,i, & - ph, & - of - real(pReal) :: sumf - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - !* Homogenized elasticity matrix - plastic_disloUCLA_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) - do i=1_pInt,nt - plastic_disloUCLA_homogenizedC = plastic_disloUCLA_homogenizedC & - + state(instance)%twinFraction(i,of)*plastic_disloUCLA_Ctwin66(1:6,1:6,i,instance) - enddo - -end function plastic_disloUCLA_homogenizedC - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_microstructure(temperature,ipc,ip,el) - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - phaseAt, phasememberAt - use lattice, only: & - lattice_mu, & - lattice_nu - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - temperature !< temperature at IP - - integer(pInt) :: & - instance, & - ns,nt,s,t, & - ph, & - of - real(pReal) :: & - sumf,sfe,x0 - real(pReal), dimension(plastic_disloUCLA_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Stacking fault energy - sfe = plastic_disloUCLA_SFE_0K(instance) + & - plastic_disloUCLA_dSFE_dT(instance) * Temperature - - !* rescaled twin volume fraction for topology - forall (t = 1_pInt:nt) & - fOverStacksize(t) = & - state(instance)%twinFraction(t,of)/plastic_disloUCLA_twinsizePerTwinSystem(t,instance) - - !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation - forall (s = 1_pInt:ns) & - state(instance)%invLambdaSlip(s,of) = & - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_disloUCLA_forestProjectionEdge(1:ns,s,instance)))/ & - plastic_disloUCLA_CLambdaSlipPerSlipSystem(s,instance) - !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation - !$OMP CRITICAL (evilmatmul) - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal - if (nt > 0_pInt .and. ns > 0_pInt) & - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & - matmul(plastic_disloUCLA_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin - !$OMP CRITICAL (evilmatmul) - if (nt > 0_pInt) & - state(instance)%invLambdaTwin(1_pInt:nt,of) = & - matmul(plastic_disloUCLA_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* mean free path between 2 obstacles seen by a moving dislocation - do s = 1_pInt,ns - if (nt > 0_pInt) then - state(instance)%mfp_slip(s,of) = & - plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+plastic_disloUCLA_GrainSize(instance)*& - (state(instance)%invLambdaSlip(s,of)+state(instance)%invLambdaSlipTwin(s,of))) - else - state(instance)%mfp_slip(s,of) = & - plastic_disloUCLA_GrainSize(instance)/& - (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) - endif - enddo - - !* mean free path between 2 obstacles seen by a growing twin - forall (t = 1_pInt:nt) & - state(instance)%mfp_twin(t,of) = & - (plastic_disloUCLA_Cmfptwin(instance)*plastic_disloUCLA_GrainSize(instance))/& - (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*state(instance)%invLambdaTwin(t,of)) - - !* threshold stress for dislocation motion - forall (s = 1_pInt:ns) & - state(instance)%threshold_stress_slip(s,of) = & - lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(s,instance)*& - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_disloUCLA_interactionMatrix_SlipSlip(s,1:ns,instance))) - - !* threshold stress for growing twin - forall (t = 1_pInt:nt) & - state(instance)%threshold_stress_twin(t,of) = & - plastic_disloUCLA_Cthresholdtwin(instance)*& - (sfe/(3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance))+& - 3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& - (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(t,instance))) - - !* final twin volume after growth - forall (t = 1_pInt:nt) & - state(instance)%twinVolume(t,of) = & - (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(t,instance)*state(instance)%mfp_twin(t,of)**(2.0_pReal) - - !* equilibrium seperation of partial dislocations - do t = 1_pInt,nt - x0 = lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& - (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) - plastic_disloUCLA_tau_r(t,instance)= & - lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& - (1/(x0+plastic_disloUCLA_xc(instance))+cos(pi/3.0_pReal)/x0) !!! used where?? - enddo - -end subroutine plastic_disloUCLA_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - math_Plain3333to99, & - math_Mandel6to33, & - math_Mandel33to6, & - math_spectralDecompositionSym33, & - math_symmetric33, & - math_mul33x3 - use material, only: & - material_phase, & - phase_plasticityInstance, & - !plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily,& - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid, & - lattice_shearTwin, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - integer(pInt), intent(in) :: ipc,ip,el - real(pReal), intent(in) :: Temperature - real(pReal), dimension(6), intent(in) :: Tstar_v - real(pReal), dimension(3,3), intent(out) :: Lp - real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 - - integer(pInt) :: instance,ph,of,ns,nt,f,i,j,k,l,m,n,index_myFamily,s1,s2 - real(pReal) :: sumf,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0, & - tau_slip_pos,tau_slip_neg,vel_slip,dvel_slip,& - dgdot_dtauslip_pos,dgdot_dtauslip_neg,dgdot_dtautwin,tau_twin,gdot_twin,stressRatio - real(pReal), dimension(3,3,2) :: & - nonSchmid_tensor - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar3333 - real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip_pos,gdot_slip_neg - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Dislocation glide part - gdot_slip_pos = 0.0_pReal - gdot_slip_neg = 0.0_pReal - dgdot_dtauslip_pos = 0.0_pReal - dgdot_dtauslip_neg = 0.0_pReal - - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j+1_pInt - !* Boltzmann ratio - BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& - plastic_disloUCLA_v0PerSlipSystem(j,instance) - !* Resolved shear stress on slip system - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k, index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) - enddo nonSchmidSystems - - significantPostitiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratio - stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_pos & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_pos(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_pos) - - !* Derivatives of shear rates - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_pos & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_pos & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - dgdot_dtauslip_pos = DotGamma0 * dvel_slip - - endif significantPostitiveStress - significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratio - stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_neg & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_neg(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_neg) - - !* Derivatives of shear rates - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_neg & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_neg & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - - dgdot_dtauslip_neg = DotGamma0 * dvel_slip - - endif significantNegativeStress - !* Plastic velocity gradient for dislocation glide - Lp = Lp + (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + (dgdot_dtauslip_pos*nonSchmid_tensor(m,n,1)+& - dgdot_dtauslip_neg*nonSchmid_tensor(m,n,2))*0.5_pReal*& - lattice_Sslip(k,l,1,index_myFamily+i,ph) - enddo slipSystems - enddo slipFamilies - -!-------------------------------------------------------------------------------------------------- -! correct Lp and dLp_dTstar3333 for twinned fraction - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - Lp = Lp * (1.0_pReal - sumf) - dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf) - -!-------------------------------------------------------------------------------------------------- -! Mechanical twinning part - gdot_twin = 0.0_pReal - dgdot_dtautwin = 0.0_pReal - j = 0_pInt - twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) - j = j+1_pInt - !* Resolved shear stress on twin system - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_twin > tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then - Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive gdot_slip_pos (= gdot_slip_neg) - abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) - else - Ndot0=0.0_pReal - end if - case default - Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) - end select - gdot_twin = & - (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) - dgdot_dtautwin = ((gdot_twin*plastic_disloUCLA_rPerTwinFamily(f,instance))/tau_twin)*StressRatio_r - endif - - !* Plastic velocity gradient for mechanical twinning - Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin*& - lattice_Stwin(k,l,index_myFamily+i,ph)*& - lattice_Stwin(m,n,index_myFamily+i,ph) - enddo twinSystems - enddo twinFamilies - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - -end subroutine plastic_disloUCLA_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_disloUCLA_dotState(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid, & - lattice_sheartwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,f,i,j,k,index_myFamily,s1,s2, & - ph, & - of - real(pReal) :: & - sumf, & - stressRatio_p,& - BoltzmannRatio,& - DotGamma0,& - stressRatio, & - EdgeDipMinDistance,& - AtomicVolume,& - VacancyDiffusion,& - StressRatio_r,& - Ndot0,& - tau_slip_pos,& - tau_slip_neg,& - DotRhoMultiplication,& - EdgeDipDistance, & - DotRhoEdgeDipAnnihilation, & - DotRhoEdgeEdgeAnnihilation, & - ClimbVelocity, & - DotRhoEdgeDipClimb, & - DotRhoDipFormation, & - tau_twin, & - vel_slip, & - gdot_slip - real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip_pos, gdot_slip_neg - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - plasticState(ph)%dotState(:,of) = 0.0_pReal - - !* Dislocation density evolution - gdot_slip_pos = 0.0_pReal - gdot_slip_neg = 0.0_pReal - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j+1_pInt - !* Boltzmann ratio - BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& - plastic_disloUCLA_v0PerSlipSystem(j,instance) - !* Resolved shear stress on slip system - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - - significantPositiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_pos & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_pos(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_pos) - endif significantPositiveStress - significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_neg & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_neg(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_neg) - endif significantNegativeStress - gdot_slip = (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal - !* Multiplication - DotRhoMultiplication = abs(gdot_slip)/& - (plastic_disloUCLA_burgersPerSlipSystem(j,instance)* & - state(instance)%mfp_slip(j,of)) - - !* Dipole formation - EdgeDipMinDistance = & - plastic_disloUCLA_CEdgeDipMinDistance(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance) - if (abs(tau_slip_pos) <= tiny(0.0_pReal)) then - DotRhoDipFormation = 0.0_pReal - else - EdgeDipDistance = & - (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(tau_slip_pos)) - if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) - if (EdgeDipDistance tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then - Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) - abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) - else - Ndot0=0.0_pReal - end if - case default - Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) - end select - - dotState(instance)%twinFraction(j, of) = & - (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*& - state(instance)%twinVolume(j, of)*Ndot0*exp(-StressRatio_r) - !* Dotstate for accumulated shear due to twin - dotState(instance)%accshear_twin(j,of) = dotState(ph)%twinFraction(j,of) * & - lattice_sheartwin(index_myfamily+i,ph) - endif - enddo twinSystems - enddo twinFamilies - -end subroutine plastic_disloUCLA_dotState - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_disloUCLA_postResults(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance,& - !plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid, & - lattice_shearTwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(plastic_disloUCLA_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_disloUCLA_postResults - - integer(pInt) :: & - instance,& - ns,nt,& - f,o,i,c,j,k,index_myFamily,& - s1,s2, & - ph, & - of - real(pReal) :: sumf,tau_twin,StressRatio_p,StressRatio_pminus1,& - BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0,stressRatio - real(pReal) :: dvel_slip, vel_slip - real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip_pos,dgdot_dtauslip_pos,tau_slip_pos,gdot_slip_neg,dgdot_dtauslip_neg,tau_slip_neg - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_disloUCLA_totalNslip(instance) - nt = plastic_disloUCLA_totalNtwin(instance) - - !* Total twin volume fraction - sumf = sum(state(ph)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Required output - c = 0_pInt - plastic_disloUCLA_postResults = 0.0_pReal - - do o = 1_pInt,plastic_disloUCLA_Noutput(instance) - select case(plastic_disloUCLA_outputID(o,instance)) - - case (edge_density_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) - c = c + ns - case (dipole_density_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) - c = c + ns - case (shear_rate_slip_ID,shear_rate_twin_ID,stress_exponent_ID) - gdot_slip_pos = 0.0_pReal - gdot_slip_neg = 0.0_pReal - dgdot_dtauslip_pos = 0.0_pReal - dgdot_dtauslip_neg = 0.0_pReal - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j + 1_pInt - !* Boltzmann ratio - BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& - plastic_disloUCLA_v0PerSlipSystem(j,instance) - !* Resolved shear stress on slip system - tau_slip_pos(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - tau_slip_neg(j) = tau_slip_pos(j) - - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - - significantPositiveTau: if((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then - !* Stress ratio - stressRatio = ((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_pos(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_pos(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_pos(j)) - !* Derivatives of shear rates - - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_pos(j) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_pos(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - - dgdot_dtauslip_pos(j) = DotGamma0 * dvel_slip - - endif significantPositiveTau - significantNegativeTau: if((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of))/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+& - plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) - stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) - stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) - !* Shear rates due to slip - vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * (tau_slip_neg(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - / ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) - - gdot_slip_neg(j) = DotGamma0 & - * vel_slip & - * sign(1.0_pReal,tau_slip_neg(j)) - !* Derivatives of shear rates - dvel_slip = & - 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & - * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & - * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & - * ( & - (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - + tau_slip_neg(j) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) - ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - ) & - - (tau_slip_neg(j) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & - * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) - *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& - *plastic_disloUCLA_qPerSlipFamily(f,instance)/& - (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) - ) & - ) & - / ( & - ( & - 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & - + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & - *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & - )**2.0_pReal & - ) - - - dgdot_dtauslip_neg(j) = DotGamma0 * dvel_slip - - endif significantNegativeTau - enddo slipSystems - enddo slipFamilies - - if (plastic_disloUCLA_outputID(o,instance) == shear_rate_slip_ID) then - plastic_disloUCLA_postResults(c+1:c+ns) = (gdot_slip_pos + gdot_slip_neg)*0.5_pReal - c = c + ns - elseif (plastic_disloUCLA_outputID(o,instance) == shear_rate_twin_ID) then - if (nt > 0_pInt) then - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1,plastic_disloUCLA_Ntwin(f,instance) - j = j + 1_pInt - - !* Resolved shear stress on twin system - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - !* Stress ratios - StressRatio_r = (state(instance)%threshold_stress_twin(j, of)/ & - tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) - - !* Shear rates due to twin - if ( tau_twin > 0.0_pReal ) then - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then - Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) - abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_disloUCLA_L0(instance)*& - plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) - else - Ndot0=0.0_pReal - end if - - case default - Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) - end select - plastic_disloUCLA_postResults(c+j) = & - (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) - endif - enddo twinSystems1 - enddo twinFamilies1 - endif - c = c + nt - elseif(plastic_disloUCLA_outputID(o,instance) == stress_exponent_ID) then - do j = 1_pInt, ns - if (abs(gdot_slip_pos(j)+gdot_slip_neg(j))<=tiny(0.0_pReal)) then - plastic_disloUCLA_postResults(c+j) = 0.0_pReal - else - plastic_disloUCLA_postResults(c+j) = (tau_slip_pos(j)+tau_slip_neg(j))/& - (gdot_slip_pos(j)+gdot_slip_neg(j))*& - (dgdot_dtauslip_pos(j)+dgdot_dtauslip_neg(j))* 0.5_pReal - endif - enddo - c = c + ns - endif - - case (accumulated_shear_slip_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & - state(instance)%accshear_slip(1_pInt:ns, of) - c = c + ns - case (mfp_slip_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) =& - state(instance)%mfp_slip(1_pInt:ns, of) - c = c + ns - case (resolved_stress_slip_ID) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j + 1_pInt - plastic_disloUCLA_postResults(c+j) =& - dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - enddo slipSystems1; enddo slipFamilies1 - c = c + ns - case (threshold_stress_slip_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & - state(instance)%threshold_stress_slip(1_pInt:ns,of) - c = c + ns - case (edge_dipole_distance_ID) - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems2: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) - j = j + 1_pInt - plastic_disloUCLA_postResults(c+j) = & - (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) - plastic_disloUCLA_postResults(c+j)=min(plastic_disloUCLA_postResults(c+j),& - state(instance)%mfp_slip(j,of)) - enddo slipSystems2; enddo slipFamilies2 - c = c + ns - case (twin_fraction_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt, of) - c = c + nt - - case (accumulated_shear_twin_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt, of) - c = c + nt - - case (mfp_twin_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt, of) - c = c + nt - - case (resolved_stress_twin_ID) - if (nt > 0_pInt) then - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) - j = j + 1_pInt - plastic_disloUCLA_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - enddo twinSystems2; enddo twinFamilies2 - endif - c = c + nt - case (threshold_stress_twin_ID) - plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt, of) - c = c + nt - end select - enddo -end function plastic_disloUCLA_postResults - -end module plastic_disloUCLA diff --git a/code/plastic_dislotwin.f90 b/code/plastic_dislotwin.f90 deleted file mode 100644 index 532312bfd..000000000 --- a/code/plastic_dislotwin.f90 +++ /dev/null @@ -1,2542 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incoprorating dislocation and twinning physics -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module plastic_dislotwin - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_dislotwin_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_dislotwin_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_dislotwin_output !< name of each post result output - - real(pReal), parameter, private :: & - kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_dislotwin_Noutput !< number of outputs per instance of this plasticity - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_dislotwin_totalNslip, & !< total number of active slip systems for each instance - plastic_dislotwin_totalNtwin, & !< total number of active twin systems for each instance - plastic_dislotwin_totalNtrans !< number of active transformation systems - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_dislotwin_Nslip, & !< number of active slip systems for each family and instance - plastic_dislotwin_Ntwin, & !< number of active twin systems for each family and instance - plastic_dislotwin_Ntrans !< number of active transformation systems for each family and instance - - real(pReal), dimension(:), allocatable, private :: & - plastic_dislotwin_CAtomicVolume, & !< atomic volume in Bugers vector unit - plastic_dislotwin_D0, & !< prefactor for self-diffusion coefficient - plastic_dislotwin_Qsd, & !< activation energy for dislocation climb - plastic_dislotwin_GrainSize, & !< grain size - plastic_dislotwin_pShearBand, & !< p-exponent in shearband velocity - plastic_dislotwin_qShearBand, & !< q-exponent in shearband velocity - plastic_dislotwin_MaxTwinFraction, & !< maximum allowed total twin volume fraction - plastic_dislotwin_CEdgeDipMinDistance, & !< - plastic_dislotwin_Cmfptwin, & !< - plastic_dislotwin_Cthresholdtwin, & !< - plastic_dislotwin_SolidSolutionStrength, & !< Strength due to elements in solid solution - plastic_dislotwin_L0_twin, & !< Length of twin nuclei in Burgers vectors - plastic_dislotwin_L0_trans, & !< Length of trans nuclei in Burgers vectors - plastic_dislotwin_xc_twin, & !< critical distance for formation of twin nucleus - plastic_dislotwin_xc_trans, & !< critical distance for formation of trans nucleus - plastic_dislotwin_VcrossSlip, & !< cross slip volume - plastic_dislotwin_sbResistance, & !< value for shearband resistance (might become an internal state variable at some point) - plastic_dislotwin_sbVelocity, & !< value for shearband velocity_0 - plastic_dislotwin_sbQedge, & !< value for shearband systems Qedge - plastic_dislotwin_SFE_0K, & !< stacking fault energy at zero K - plastic_dislotwin_dSFE_dT, & !< temperature dependance of stacking fault energy - plastic_dislotwin_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful - plastic_dislotwin_aTolRho, & !< absolute tolerance for integration of dislocation density - plastic_dislotwin_aTolTwinFrac, & !< absolute tolerance for integration of twin volume fraction - plastic_dislotwin_aTolTransFrac, & !< absolute tolerance for integration of trans volume fraction - plastic_dislotwin_deltaG, & !< Free energy difference between austensite and martensite - plastic_dislotwin_Cmfptrans, & !< - plastic_dislotwin_Cthresholdtrans, & !< - plastic_dislotwin_transStackHeight !< Stack height of hex nucleus - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctwin3333 !< twin elasticity matrix for each instance - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctrans66 !< trans elasticity matrix in Mandel notation for each instance - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_dislotwin_Ctrans3333 !< trans elasticity matrix for each instance - real(pReal), dimension(:,:), allocatable, private :: & - plastic_dislotwin_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance - plastic_dislotwin_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance - plastic_dislotwin_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance - plastic_dislotwin_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance - plastic_dislotwin_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance - plastic_dislotwin_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance - plastic_dislotwin_burgersPerTransFamily, & !< absolute length of burgers vector [m] for each trans family and instance - plastic_dislotwin_burgersPerTransSystem, & !< absolute length of burgers vector [m] for each trans system and instance - plastic_dislotwin_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance - plastic_dislotwin_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance - plastic_dislotwin_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance - plastic_dislotwin_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance - plastic_dislotwin_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance - plastic_dislotwin_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance - plastic_dislotwin_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance - plastic_dislotwin_Ndot0PerTransFamily, & !< trans nucleation rate [1/m³s] for each trans family and instance - plastic_dislotwin_Ndot0PerTransSystem, & !< trans nucleation rate [1/m³s] for each trans system and instance - plastic_dislotwin_tau_r_twin, & !< stress to bring partial close together for each twin system and instance - plastic_dislotwin_tau_r_trans, & !< stress to bring partial close together for each trans system and instance - plastic_dislotwin_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance - plastic_dislotwin_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance - plastic_dislotwin_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_dislotwin_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_dislotwin_lamellarsizePerTransFamily, & !< martensite lamellar thickness [m] for each trans family and instance - plastic_dislotwin_lamellarsizePerTransSystem, & !< martensite lamellar thickness [m] for each trans system and instance - plastic_dislotwin_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance - plastic_dislotwin_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance - plastic_dislotwin_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_dislotwin_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance - plastic_dislotwin_interaction_SlipTrans, & !< coefficients for slip-trans interaction for each interaction type and instance - plastic_dislotwin_interaction_TransSlip, & !< coefficients for trans-slip interaction for each interaction type and instance - plastic_dislotwin_interaction_TransTrans, & !< coefficients for trans-trans interaction for each interaction type and instance - plastic_dislotwin_pPerSlipFamily, & !< p-exponent in glide velocity - plastic_dislotwin_qPerSlipFamily, & !< q-exponent in glide velocity - plastic_dislotwin_rPerTwinFamily, & !< r-exponent in twin nucleation rate - plastic_dislotwin_sPerTransFamily !< s-exponent in trans nucleation rate - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_dislotwin_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance - plastic_dislotwin_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance - plastic_dislotwin_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance - plastic_dislotwin_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance - plastic_dislotwin_interactionMatrix_SlipTrans, & !< interaction matrix of slip systems with trans systems for each instance - plastic_dislotwin_interactionMatrix_TransSlip, & !< interaction matrix of trans systems with slip systems for each instance - plastic_dislotwin_interactionMatrix_TransTrans, & !< interaction matrix of the different trans systems for each instance - plastic_dislotwin_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance - plastic_dislotwin_projectionMatrix_Trans !< matrix for projection of slip system shear on fault band (twin) systems for each instance - - real(pReal), dimension(:,:,:,:,:), allocatable, private :: & - plastic_dislotwin_sbSv - - enum, bind(c) - enumerator :: undefined_ID, & - edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID, & - twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID, & - resolved_stress_shearband_ID, & - shear_rate_shearband_ID, & - sb_eigenvalues_ID, & - sb_eigenvectors_ID, & - stress_trans_fraction_ID, & - strain_trans_fraction_ID, & - trans_fraction_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_dislotwin_outputID !< ID of each post result output - type, private :: tDislotwinState - real(pReal), pointer, dimension(:,:) :: & - rhoEdge, & - rhoEdgeDip, & - accshear_slip, & - twinFraction, & - accshear_twin, & - stressTransFraction, & - strainTransFraction , & - invLambdaSlip, & - invLambdaSlipTwin, & - invLambdaTwin, & - invLambdaSlipTrans, & - invLambdaTrans, & - mfp_slip, & - mfp_twin, & - mfp_trans, & - threshold_stress_slip, & - threshold_stress_twin, & - threshold_stress_trans, & - twinVolume, & - martensiteVolume - end type - type(tDislotwinState), allocatable, dimension(:), private :: & - state, & - state0, & - dotState - - public :: & - plastic_dislotwin_init, & - plastic_dislotwin_homogenizedC, & - plastic_dislotwin_microstructure, & - plastic_dislotwin_LpAndItsTangent, & - plastic_dislotwin_dotState, & - plastic_dislotwin_postResults - private :: & - plastic_dislotwin_stateInit, & - plastic_dislotwin_aTolState - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333, & - math_mul3x3 - use mesh, only: & - mesh_maxNips, & - mesh_NcpElems - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - homogenization_maxNgrains, & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_DISLOTWIN_label, & - PLASTICITY_DISLOTWIN_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,maxTotalNtrans,& - f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt,nr, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipTrans = 0_pInt, Nchunks_TransSlip = 0_pInt, Nchunks_TransTrans = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_TransFamilies = 0_pInt, & - offset_slip, index_myFamily, index_otherFamily, & - startIndex, endIndex - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin, tempPerTrans - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOTWIN_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOTWIN_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_dislotwin_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(plastic_dislotwin_output(maxval(phase_Noutput),maxNinstance)) - plastic_dislotwin_output = '' - allocate(plastic_dislotwin_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_dislotwin_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_totalNtrans(maxNinstance), source=0_pInt) - allocate(plastic_dislotwin_CAtomicVolume(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_D0(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Qsd(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_GrainSize(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_pShearBand(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_qShearBand(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_MaxTwinFraction(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cmfptwin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cthresholdtwin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_SolidSolutionStrength(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_L0_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_L0_trans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_xc_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_xc_trans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_VcrossSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_aTolRho(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_aTolTwinFrac(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_aTolTransFrac(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_sbResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_sbVelocity(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_sbQedge(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_SFE_0K(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_dSFE_dT(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default - allocate(plastic_dislotwin_deltaG(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cmfptrans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Cthresholdtrans(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_transStackHeight(maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTransFamily(lattice_maxNtransFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTransFamily(lattice_maxNtransFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_SlipTrans(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TransSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_interaction_TransTrans(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_sbSv(6,6,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) - allocate(plastic_dislotwin_lamellarsizePerTransFamily(lattice_maxNtransFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_sPerTransFamily(lattice_maxNtransFamily,maxNinstance),source=0.0_pReal) - - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) - Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase)> 0_pInt) - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_SlipTrans = maxval(lattice_interactionSlipTrans(:,:,phase)) - Nchunks_TransSlip = maxval(lattice_interactionTransSlip(:,:,phase)) - Nchunks_TransTrans = maxval(lattice_interactionTransTrans(:,:,phase)) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - if(allocated(tempPerTwin)) deallocate(tempPerTwin) - if(allocated(tempPerTrans)) deallocate(tempPerTrans) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - allocate(tempPerTwin(Nchunks_TwinFamilies)) - allocate(tempPerTrans(Nchunks_TransFamilies)) - endif - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('edge_density') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_density_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('dipole_density') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = dipole_density_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_slip','shearrate_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_slip') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_slip_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('edge_dipole_distance') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_dipole_distance_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stress_exponent') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_exponent_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('twin_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = twin_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_twin','shearrate_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulated_shear_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('mfp_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('threshold_stress_twin') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_twin_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolved_stress_shearband') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_shearband_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_rate_shearband','shearrate_shearband') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_shearband_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('sb_eigenvalues') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvalues_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('sb_eigenvectors') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvectors_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stress_trans_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_trans_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('strain_trans_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = strain_trans_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('trans_fraction','total_trans_fraction') - plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt - plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = trans_fraction_ID - plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip system families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - plastic_dislotwin_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip') - do j = 1_pInt, Nchunks_SlipFamilies - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('rhoedge0') - plastic_dislotwin_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('rhoedgedip0') - plastic_dislotwin_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('slipburgers') - plastic_dislotwin_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('qedge') - plastic_dislotwin_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('v0') - plastic_dislotwin_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('clambdaslip') - plastic_dislotwin_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau_peierls') - if (lattice_structure(phase) /= LATTICE_bcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOTWIN_label//')') - plastic_dislotwin_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('p_slip') - plastic_dislotwin_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('q_slip') - plastic_dislotwin_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on slip number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_dislotwin_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ndot0_twin','twinsize','twinburgers','r_twin') - do j = 1_pInt, Nchunks_TwinFamilies - tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('ndot0_twin') - if (lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') - plastic_dislotwin_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinsize') - plastic_dislotwin_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('twinburgers') - plastic_dislotwin_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - case ('r_twin') - plastic_dislotwin_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of transformation system families - case ('ntrans') - if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & - call IO_warning(53_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - Nchunks_TransFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TransFamilies - plastic_dislotwin_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ndot0_trans','lamellarsize','transburgers','s_trans') - do j = 1_pInt, Nchunks_TransFamilies - tempPerTrans(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('ndot0_trans') - if (lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') - plastic_dislotwin_Ndot0PerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - case ('lamellarsize') - plastic_dislotwin_lamellarsizePerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - case ('transburgers') - plastic_dislotwin_burgersPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - case ('s_trans') - plastic_dislotwin_sPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip','interactionslipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_dislotwin_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin','interactionsliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_dislotwin_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip','interactiontwinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_dislotwin_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin','interactiontwintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_dislotwin_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptrans','interactionsliptrans') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTrans) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_SlipTrans - plastic_dislotwin_interaction_SlipTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_transslip','interactiontransslip') - if (chunkPos(1) < 1_pInt + Nchunks_TransSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TransSlip - plastic_dislotwin_interaction_TransSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_transtrans','interactiontranstrans') - if (chunkPos(1) < 1_pInt + Nchunks_TransTrans) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') - do j = 1_pInt, Nchunks_TransTrans - plastic_dislotwin_interaction_TransTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin/trans systems - case ('grainsize') - plastic_dislotwin_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('maxtwinfraction') - plastic_dislotwin_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('p_shearband') - plastic_dislotwin_pShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('q_shearband') - plastic_dislotwin_qShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('d0') - plastic_dislotwin_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('qsd') - plastic_dislotwin_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_rho') - plastic_dislotwin_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_dislotwin_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_transfrac') - plastic_dislotwin_aTolTransFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cmfptwin') - plastic_dislotwin_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cthresholdtwin') - plastic_dislotwin_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('solidsolutionstrength') - plastic_dislotwin_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('l0_twin') - plastic_dislotwin_L0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('l0_trans') - plastic_dislotwin_L0_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('xc_twin') - plastic_dislotwin_xc_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('xc_trans') - plastic_dislotwin_xc_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('vcrossslip') - plastic_dislotwin_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cedgedipmindistance') - plastic_dislotwin_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('catomicvolume') - plastic_dislotwin_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('sfe_0k') - plastic_dislotwin_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dsfe_dt') - plastic_dislotwin_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('dipoleformationfactor') - plastic_dislotwin_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('shearbandresistance') - plastic_dislotwin_sbResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('shearbandvelocity') - plastic_dislotwin_sbVelocity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('qedgepersbsystem') - plastic_dislotwin_sbQedge(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('deltag') - plastic_dislotwin_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cmfptrans') - plastic_dislotwin_Cmfptrans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cthresholdtrans') - plastic_dislotwin_Cthresholdtrans(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('transstackheight') - plastic_dislotwin_transStackHeight(instance) = IO_floatValue(line,chunkPos,2_pInt) - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then - instance = phase_plasticityInstance(phase) - - if (sum(plastic_dislotwin_Nslip(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOTWIN_label//')') - if (sum(plastic_dislotwin_Ntwin(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOTWIN_label//')') - if (sum(plastic_dislotwin_Ntrans(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='Ntrans ('//PLASTICITY_DISLOTWIN_label//')') - do f = 1_pInt,lattice_maxNslipFamily - if (plastic_dislotwin_Nslip(f,instance) > 0_pInt) then - if (plastic_dislotwin_rhoEdge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_rhoEdgeDip0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_v0PerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOTWIN_label//')') - endif - enddo - do f = 1_pInt,lattice_maxNtwinFamily - if (plastic_dislotwin_Ntwin(f,instance) > 0_pInt) then - if (plastic_dislotwin_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='ndot0_twin ('//PLASTICITY_DISLOTWIN_label//')') - endif - enddo - if (plastic_dislotwin_CAtomicVolume(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_D0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_Qsd(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOTWIN_label//')') - if (sum(plastic_dislotwin_Ntwin(:,instance)) > 0_pInt) then - if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & - abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & - lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_aTolTwinFrac(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOTWIN_label//')') - endif - if (sum(plastic_dislotwin_Ntrans(:,instance)) > 0_pInt) then - if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & - abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & - lattice_structure(phase) == LATTICE_fcc_ID) & - call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_aTolTransFrac(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTolTransFrac ('//PLASTICITY_DISLOTWIN_label//')') - endif - if (plastic_dislotwin_sbResistance(instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sbResistance ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_sbVelocity(instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sbVelocity ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & - plastic_dislotwin_pShearBand(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='pShearBand ('//PLASTICITY_DISLOTWIN_label//')') - if (abs(plastic_dislotwin_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & - plastic_dislotwin_dipoleFormationFactor(instance) /= 1.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOTWIN_label//')') - if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & - plastic_dislotwin_qShearBand(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='qShearBand ('//PLASTICITY_DISLOTWIN_label//')') - -!-------------------------------------------------------------------------------------------------- -! Determine total number of active slip or twin systems - plastic_dislotwin_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_dislotwin_Nslip(:,instance)) - plastic_dislotwin_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_dislotwin_Ntwin(:,instance)) - plastic_dislotwin_Ntrans(:,instance)= min(lattice_NtransSystem(:,phase),plastic_dislotwin_Ntrans(:,instance)) - plastic_dislotwin_totalNslip(instance) = sum(plastic_dislotwin_Nslip(:,instance)) - plastic_dislotwin_totalNtwin(instance) = sum(plastic_dislotwin_Ntwin(:,instance)) - plastic_dislotwin_totalNtrans(instance) = sum(plastic_dislotwin_Ntrans(:,instance)) - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - maxTotalNslip = maxval(plastic_dislotwin_totalNslip) - maxTotalNtwin = maxval(plastic_dislotwin_totalNtwin) - maxTotalNtrans = maxval(plastic_dislotwin_totalNtrans) - - allocate(plastic_dislotwin_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_burgersPerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ndot0PerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_tau_r_twin(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_tau_r_trans(maxTotalNtrans, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) - allocate(plastic_dislotwin_lamellarsizePerTransSystem(maxTotalNtrans, maxNinstance),source=0.0_pReal) - - allocate(plastic_dislotwin_interactionMatrix_SlipSlip(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from slip activity - maxval(plastic_dislotwin_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_SlipTwin(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from twin activity - maxval(plastic_dislotwin_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TwinSlip(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_dislotwin_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TwinTwin(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_dislotwin_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_SlipTrans(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from trans activity - maxval(plastic_dislotwin_totalNtrans),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TransSlip(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from slip activity - maxval(plastic_dislotwin_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_interactionMatrix_TransTrans(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from trans activity - maxval(plastic_dislotwin_totalNtrans),& - maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_projectionMatrix_Trans(maxTotalNtrans,maxTotalNslip,maxNinstance), & - source=0.0_pReal) - allocate(plastic_dislotwin_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ctrans66(6,6,maxTotalNtrans,maxNinstance), source=0.0_pReal) - allocate(plastic_dislotwin_Ctrans3333(3,3,3,3,maxTotalNtrans,maxNinstance), source=0.0_pReal) - - allocate(state(maxNinstance)) - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - myPhase2: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then - NofMyPhase=count(material_phase==phase) - instance = phase_plasticityInstance(phase) - - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_dislotwin_Noutput(instance) - select case(plastic_dislotwin_outputID(o,instance)) - case(edge_density_ID, & - dipole_density_ID, & - shear_rate_slip_ID, & - accumulated_shear_slip_ID, & - mfp_slip_ID, & - resolved_stress_slip_ID, & - threshold_stress_slip_ID, & - edge_dipole_distance_ID, & - stress_exponent_ID & - ) - mySize = ns - case(twin_fraction_ID, & - shear_rate_twin_ID, & - accumulated_shear_twin_ID, & - mfp_twin_ID, & - resolved_stress_twin_ID, & - threshold_stress_twin_ID & - ) - mySize = nt - case(resolved_stress_shearband_ID, & - shear_rate_shearband_ID & - ) - mySize = 6_pInt - case(sb_eigenvalues_ID) - mySize = 3_pInt - case(sb_eigenvectors_ID) - mySize = 9_pInt - case(stress_trans_fraction_ID, & - strain_trans_fraction_ID, & - trans_fraction_ID & - ) - mySize = nr - end select - - if (mySize > 0_pInt) then ! any meaningful output found - plastic_dislotwin_sizePostResult(o,instance) = mySize - plastic_dislotwin_sizePostResults(instance) = plastic_dislotwin_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - - sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & - + int(size(['twinFraction','accsheartwin']),pInt) * nt & - + int(size(['stressTransFraction','strainTransFraction']),pInt) * nr - sizeDeltaState = 0_pInt - sizeState = sizeDotState & - + int(size(['invLambdaSlip ','invLambdaSlipTwin ','invLambdaSlipTrans',& - 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & - + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& - 'twinVolume ']),pInt) * nt & - + int(size(['invLambdaTrans ','meanFreePathTrans','tauTransThreshold', & - 'martensiteVolume ']),pInt) * nr - - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_dislotwin_sizePostResults(instance) - plasticState(phase)%nSlip = plastic_dislotwin_totalNslip(instance) - plasticState(phase)%nTwin = plastic_dislotwin_totalNtwin(instance) - plasticState(phase)%nTrans= plastic_dislotwin_totalNtrans(instance) - allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - offset_slip = 2_pInt*plasticState(phase)%nslip - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) - - !* Process slip related parameters ------------------------------------------------ - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - slipSystemsLoop: do j = 1_pInt,plastic_dislotwin_Nslip(f,instance) - - !* Burgers vector, - ! dislocation velocity prefactor, - ! mean free path prefactor, - ! and minimum dipole distance - - plastic_dislotwin_burgersPerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_burgersPerSlipFamily(f,instance) - - plastic_dislotwin_QedgePerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_QedgePerSlipFamily(f,instance) - - plastic_dislotwin_v0PerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_v0PerSlipFamily(f,instance) - - plastic_dislotwin_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & - plastic_dislotwin_CLambdaSlipPerSlipFamily(f,instance) - - !* Calculation of forest projections for edge dislocations - !* Interaction matrices - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_dislotwin_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & - abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & - lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) - plastic_dislotwin_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_dislotwin_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtransFamily - index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) - plastic_dislotwin_interactionMatrix_SlipTrans(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_SlipTrans(lattice_interactionSlipTrans( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo slipSystemsLoop - enddo slipFamiliesLoop - - !* Process twin related parameters ------------------------------------------------ - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(plastic_dislotwin_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list - twinSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntwin(f,instance) - - !* Burgers vector, - ! nucleation rate prefactor, - ! and twin size - - plastic_dislotwin_burgersPerTwinSystem(index_myFamily+j,instance) = & - plastic_dislotwin_burgersPerTwinFamily(f,instance) - - plastic_dislotwin_Ndot0PerTwinSystem(index_myFamily+j,instance) = & - plastic_dislotwin_Ndot0PerTwinFamily(f,instance) - - plastic_dislotwin_twinsizePerTwinSystem(index_myFamily+j,instance) = & - plastic_dislotwin_twinsizePerTwinFamily(f,instance) - - !* Rotate twin elasticity matrices - index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list - do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt - do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt - plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & - plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & - lattice_C3333(p,q,r,s,instance) * & - lattice_Qtwin(l,p,index_otherFamily+j,phase) * & - lattice_Qtwin(m,q,index_otherFamily+j,phase) * & - lattice_Qtwin(n,r,index_otherFamily+j,phase) * & - lattice_Qtwin(o,s,index_otherFamily+j,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo; enddo - plastic_dislotwin_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & - math_Mandel3333to66(plastic_dislotwin_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) - - !* Interaction matrices - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_dislotwin_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_dislotwin_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo twinSystemsLoop - enddo twinFamiliesLoop - - !* Process transformation related parameters ------------------------------------------------ - transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily - index_myFamily = sum(plastic_dislotwin_Ntrans(1:f-1_pInt,instance)) ! index in truncated trans system list - transSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntrans(f,instance) - - !* Burgers vector, - ! nucleation rate prefactor, - ! and martensite size - - plastic_dislotwin_burgersPerTransSystem(index_myFamily+j,instance) = & - plastic_dislotwin_burgersPerTransFamily(f,instance) - - plastic_dislotwin_Ndot0PerTransSystem(index_myFamily+j,instance) = & - plastic_dislotwin_Ndot0PerTransFamily(f,instance) - - plastic_dislotwin_lamellarsizePerTransSystem(index_myFamily+j,instance) = & - plastic_dislotwin_lamellarsizePerTransFamily(f,instance) - - !* Rotate trans elasticity matrices - index_otherFamily = sum(lattice_NtransSystem(1:f-1_pInt,phase)) ! index in full lattice trans list - do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt - do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt - plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) = & - plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) + & - lattice_trans_C3333(p,q,r,s,instance) * & - lattice_Qtrans(l,p,index_otherFamily+j,phase) * & - lattice_Qtrans(m,q,index_otherFamily+j,phase) * & - lattice_Qtrans(n,r,index_otherFamily+j,phase) * & - lattice_Qtrans(o,s,index_otherFamily+j,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo; enddo - plastic_dislotwin_Ctrans66(1:6,1:6,index_myFamily+j,instance) = & - math_Mandel3333to66(plastic_dislotwin_Ctrans3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) - - !* Interaction matrices - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_dislotwin_interactionMatrix_TransSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TransSlip(lattice_interactionTransSlip( & - sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtransFamily - index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) - plastic_dislotwin_interactionMatrix_TransTrans(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_dislotwin_interaction_TransTrans(lattice_interactionTransTrans( & - sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - !* Projection matrices for shear from slip systems to fault-band (twin) systems for strain-induced martensite nucleation - select case(trans_lattice_structure(phase)) - case (LATTICE_bcc_ID) - do o = 1_pInt,lattice_maxNtransFamily - index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (trans) - plastic_dislotwin_projectionMatrix_Trans(index_myFamily+j,index_otherFamily+k,instance) = & - lattice_projectionTrans( sum(lattice_NtransSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, phase) - enddo; enddo - end select - - enddo transSystemsLoop - enddo transFamiliesLoop - - startIndex=1_pInt - endIndex=ns - state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%stressTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%stressTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%stressTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%strainTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%strainTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) - dotState(instance)%strainTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%invLambdaSlipTrans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaSlipTrans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%invLambdaTrans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%invLambdaTrans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%mfp_trans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%mfp_trans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+ns - state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%threshold_stress_trans=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%threshold_stress_trans=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nt - state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) - - startIndex=endIndex+1 - endIndex=endIndex+nr - state(instance)%martensiteVolume=>plasticState(phase)%state(startIndex:endIndex,:) - state0(instance)%martensiteVolume=>plasticState(phase)%state0(startIndex:endIndex,:) - - call plastic_dislotwin_stateInit(phase,instance) - call plastic_dislotwin_aTolState(phase,instance) - endif myPhase2 - - enddo initializeInstances -end subroutine plastic_dislotwin_init - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_stateInit(ph,instance) - use math, only: & - pi - use lattice, only: & - lattice_maxNslipFamily, & - lattice_mu - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - real(pReal), dimension(plasticState(ph)%sizeState) :: tempState - - integer(pInt) :: i,j,f,ns,nt,nr, index_myFamily - real(pReal), dimension(plastic_dislotwin_totalNslip(instance)) :: & - rhoEdge0, & - rhoEdgeDip0, & - invLambdaSlip0, & - MeanFreePathSlip0, & - tauSlipThreshold0 - real(pReal), dimension(plastic_dislotwin_totalNtwin(instance)) :: & - MeanFreePathTwin0,TwinVolume0 - real(pReal), dimension(plastic_dislotwin_totalNtrans(instance)) :: & - MeanFreePathTrans0,MartensiteVolume0 - tempState = 0.0_pReal - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables - do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list - rhoEdge0(index_myFamily+1_pInt: & - index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & - plastic_dislotwin_rhoEdge0(f,instance) - rhoEdgeDip0(index_myFamily+1_pInt: & - index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & - plastic_dislotwin_rhoEdgeDip0(f,instance) - enddo - - tempState(1_pInt:ns) = rhoEdge0 - tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent slip microstructural variables - forall (i = 1_pInt:ns) & - invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_forestProjectionEdge(1:ns,i,instance)))/ & - plastic_dislotwin_CLambdaSlipPerSlipSystem(i,instance) - tempState(3_pInt*ns+2_pInt*nt+2_pInt*nr+1:4_pInt*ns+2_pInt*nt+2_pInt*nr) = invLambdaSlip0 - - forall (i = 1_pInt:ns) & - MeanFreePathSlip0(i) = & - plastic_dislotwin_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_dislotwin_GrainSize(instance)) - tempState(6_pInt*ns+3_pInt*nt+3_pInt*nr+1:7_pInt*ns+3_pInt*nt+3_pInt*nr) = MeanFreePathSlip0 - - forall (i = 1_pInt:ns) & - tauSlipThreshold0(i) = & - lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(i,instance) * & - sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_interactionMatrix_SlipSlip(i,1:ns,instance))) - - tempState(7_pInt*ns+4_pInt*nt+4_pInt*nr+1:8_pInt*ns+4_pInt*nt+4_pInt*nr) = tauSlipThreshold0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent twin microstructural variables - forall (j = 1_pInt:nt) & - MeanFreePathTwin0(j) = plastic_dislotwin_GrainSize(instance) - tempState(7_pInt*ns+3_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+3_pInt*nr) = MeanFreePathTwin0 - - forall (j = 1_pInt:nt) & - TwinVolume0(j) = & - (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) - tempState(8_pInt*ns+5_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+5_pInt*nr) = TwinVolume0 - -!-------------------------------------------------------------------------------------------------- -! initialize dependent trans microstructural variables - forall (j = 1_pInt:nr) & - MeanFreePathTrans0(j) = plastic_dislotwin_GrainSize(instance) - tempState(7_pInt*ns+4_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+4_pInt*nr) = MeanFreePathTrans0 - - forall (j = 1_pInt:nr) & - MartensiteVolume0(j) = & - (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(j,instance)*MeanFreePathTrans0(j)**(2.0_pReal) - tempState(8_pInt*ns+6_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+6_pInt*nr) = MartensiteVolume0 - -plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) - -end subroutine plastic_dislotwin_stateInit - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - ph, & - instance ! number specifying the current instance of the plasticity - - integer(pInt) :: ns, nt, nr - - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - ! Tolerance state for dislocation densities - plasticState(ph)%aTolState(1_pInt: & - 2_pInt*ns) = plastic_dislotwin_aTolRho(instance) - - ! Tolerance state for accumulated shear due to slip - plasticState(ph)%aTolState(2_pInt*ns+1_pInt: & - 3_pInt*ns)=1.0e6_pReal - - ! Tolerance state for twin volume fraction - plasticState(ph)%aTolState(3_pInt*ns+1_pInt: & - 3_pInt*ns+nt) = plastic_dislotwin_aTolTwinFrac(instance) - - ! Tolerance state for accumulated shear due to twin - plasticState(ph)%aTolState(3_pInt*ns+nt+1_pInt: & - 3_pInt*ns+2_pInt*nt) = 1.0e6_pReal - -! Tolerance state for stress-assisted martensite volume fraction - plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+1_pInt: & - 3_pInt*ns+2_pInt*nt+nr) = plastic_dislotwin_aTolTransFrac(instance) - -! Tolerance state for strain-induced martensite volume fraction - plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+nr+1_pInt: & - 3_pInt*ns+2_pInt*nt+2_pInt*nr) = plastic_dislotwin_aTolTransFrac(instance) - -end subroutine plastic_dislotwin_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenized elasticity matrix -!-------------------------------------------------------------------------------------------------- -function plastic_dislotwin_homogenizedC(ipc,ip,el) - use material, only: & - phase_plasticityInstance, & - phaseAt, phasememberAt - use lattice, only: & - lattice_C66 - - implicit none - real(pReal), dimension(6,6) :: & - plastic_dislotwin_homogenizedC - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,nr,i, & - ph, & - of - real(pReal) :: sumf, sumftr - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - - !* Homogenized elasticity matrix - plastic_dislotwin_homogenizedC = (1.0_pReal-sumf-sumftr)*lattice_C66(1:6,1:6,ph) - do i=1_pInt,nt - plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & - + state(instance)%twinFraction(i,of)*plastic_dislotwin_Ctwin66(1:6,1:6,i,instance) - enddo - do i=1_pInt,nr - plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & - + (state(instance)%stressTransFraction(i,of) + state(instance)%strainTransFraction(i,of))*& - plastic_dislotwin_Ctrans66(1:6,1:6,i,instance) - enddo - - end function plastic_dislotwin_homogenizedC - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_microstructure(temperature,ipc,ip,el) - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - !plasticState, & !!!!delete - phaseAt, phasememberAt - use lattice, only: & - lattice_mu, & - lattice_nu - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - temperature !< temperature at IP - - integer(pInt) :: & - instance, & - ns,nt,nr,s,t,r, & - ph, & - of - real(pReal) :: & - sumf,sfe,x0,sumftr - real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize - real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - ftransOverLamellarSize - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - - !* Stacking fault energy - sfe = plastic_dislotwin_SFE_0K(instance) + & - plastic_dislotwin_dSFE_dT(instance) * Temperature - - !* rescaled twin volume fraction for topology - forall (t = 1_pInt:nt) & - fOverStacksize(t) = & - state(instance)%twinFraction(t,of)/plastic_dislotwin_twinsizePerTwinSystem(t,instance) - - !* rescaled trans volume fraction for topology - forall (r = 1_pInt:nr) & - ftransOverLamellarSize(r) = & - (state(instance)%stressTransFraction(r,of)+state(instance)%strainTransFraction(r,of))/& - plastic_dislotwin_lamellarsizePerTransSystem(r,instance) - - !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation - forall (s = 1_pInt:ns) & - state(instance)%invLambdaSlip(s,of) = & - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_dislotwin_forestProjectionEdge(1:ns,s,instance)))/ & - plastic_dislotwin_CLambdaSlipPerSlipSystem(s,instance) - - !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation - !$OMP CRITICAL (evilmatmul) - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal - if (nt > 0_pInt .and. ns > 0_pInt) & - state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & - matmul(plastic_dislotwin_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin - !$OMP CRITICAL (evilmatmul) - if (nt > 0_pInt) & - state(instance)%invLambdaTwin(1_pInt:nt,of) = & - matmul(plastic_dislotwin_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) - !$OMP END CRITICAL (evilmatmul) - - !* 1/mean free distance between 2 martensite lamellar from different systems seen by a moving dislocation - state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = 0.0_pReal - if (nr > 0_pInt .and. ns > 0_pInt) & - state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = & - matmul(plastic_dislotwin_interactionMatrix_SlipTrans(1:ns,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) - - !* 1/mean free distance between 2 martensite stacks from different systems seen by a growing martensite (1/lambda_trans) - if (nr > 0_pInt) & - state(instance)%invLambdaTrans(1_pInt:nr,of) = & - matmul(plastic_dislotwin_interactionMatrix_TransTrans(1:nr,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) - - !* mean free path between 2 obstacles seen by a moving dislocation - do s = 1_pInt,ns - if ((nt > 0_pInt) .or. (nr > 0_pInt)) then - state(instance)%mfp_slip(s,of) = & - plastic_dislotwin_GrainSize(instance)/(1.0_pReal+plastic_dislotwin_GrainSize(instance)*& - (state(instance)%invLambdaSlip(s,of) + & - state(instance)%invLambdaSlipTwin(s,of) + & - state(instance)%invLambdaSlipTrans(s,of))) - else - state(instance)%mfp_slip(s,of) = & - plastic_dislotwin_GrainSize(instance)/& - (1.0_pReal+plastic_dislotwin_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) !!!!!! correct? - endif - enddo - - !* mean free path between 2 obstacles seen by a growing twin - forall (t = 1_pInt:nt) & - state(instance)%mfp_twin(t,of) = & - plastic_dislotwin_Cmfptwin(instance)*plastic_dislotwin_GrainSize(instance)/& - (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(ph)%invLambdaTwin(t,of)) - - !* mean free path between 2 obstacles seen by a growing martensite - forall (r = 1_pInt:nr) & - state(instance)%mfp_trans(r,of) = & - plastic_dislotwin_Cmfptrans(instance)*plastic_dislotwin_GrainSize(instance)/& - (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(instance)%invLambdaTrans(r,of)) - - !* threshold stress for dislocation motion - forall (s = 1_pInt:ns) & - state(instance)%threshold_stress_slip(s,of) = & - lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(s,instance)*& - sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& - plastic_dislotwin_interactionMatrix_SlipSlip(s,1:ns,instance))) - - !* threshold stress for growing twin - forall (t = 1_pInt:nt) & - state(instance)%threshold_stress_twin(t,of) = & - plastic_dislotwin_Cthresholdtwin(instance)* & - (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)) & - + 3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& - (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(t,instance)) & - ) - - !* threshold stress for growing martensite - forall (r = 1_pInt:nr) & - state(instance)%threshold_stress_trans(r,of) = & - plastic_dislotwin_Cthresholdtrans(instance)* & - (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & - + 3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)*lattice_mu(ph)/& - (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(r,instance))& - + plastic_dislotwin_transStackHeight(instance)*plastic_dislotwin_deltaG(instance)/ & - (3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & - ) - - !* final twin volume after growth - forall (t = 1_pInt:nt) & - state(instance)%twinVolume(t,of) = & - (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(t,instance)*& - state(instance)%mfp_twin(t,of)**(2.0_pReal) - - !* final martensite volume after growth - forall (r = 1_pInt:nr) & - state(instance)%martensiteVolume(r,of) = & - (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(r,instance)*& - state(instance)%mfp_trans(r,of)**(2.0_pReal) - - !* equilibrium separation of partial dislocations (twin) - do t = 1_pInt,nt - x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& - (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) - plastic_dislotwin_tau_r_twin(t,instance)= & - lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& - (1/(x0+plastic_dislotwin_xc_twin(instance))+cos(pi/3.0_pReal)/x0) - enddo - - !* equilibrium separation of partial dislocations (trans) - do r = 1_pInt,nr - x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)**(2.0_pReal)/& - (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) - plastic_dislotwin_tau_r_trans(r,instance)= & - lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)/(2.0_pReal*pi)*& - (1/(x0+plastic_dislotwin_xc_trans(instance))+cos(pi/3.0_pReal)/x0) - enddo - -end subroutine plastic_dislotwin_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - math_Plain3333to99, & - math_Mandel6to33, & - math_Mandel33to6, & - math_spectralDecompositionSym, & - math_tensorproduct33, & - math_symmetric33, & - math_mul33x3 - use material, only: & - material_phase, & - phase_plasticityInstance, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_Strans, & - lattice_Strans_v, & - lattice_maxNslipFamily,& - lattice_maxNtwinFamily, & - lattice_maxNtransFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NtransSystem, & - lattice_shearTwin, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - integer(pInt), intent(in) :: ipc,ip,el - real(pReal), intent(in) :: Temperature - real(pReal), dimension(6), intent(in) :: Tstar_v - real(pReal), dimension(3,3), intent(out) :: Lp - real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 - - integer(pInt) :: instance,ph,of,ns,nt,nr,f,i,j,k,l,m,n,index_myFamily,s1,s2 - real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0_twin,stressRatio, & - Ndot0_trans,StressRatio_s - real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 - real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,dgdot_dtauslip,tau_slip - real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,dgdot_dtautwin,tau_twin - real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_trans,dgdot_dtautrans,tau_trans - real(pReal), dimension(6) :: gdot_sb,dgdot_dtausb,tau_sb - real(pReal), dimension(3,3) :: eigVectors, sb_Smatrix - real(pReal), dimension(3) :: eigValues, sb_s, sb_m - logical :: error - real(pReal), dimension(3,6), parameter :: & - sb_sComposition = & - reshape(real([& - 1, 0, 1, & - 1, 0,-1, & - 1, 1, 0, & - 1,-1, 0, & - 0, 1, 1, & - 0, 1,-1 & - ],pReal),[ 3,6]), & - sb_mComposition = & - reshape(real([& - 1, 0,-1, & - 1, 0,+1, & - 1,-1, 0, & - 1, 1, 0, & - 0, 1,-1, & - 0, 1, 1 & - ],pReal),[ 3,6]) - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Dislocation glide part - gdot_slip = 0.0_pReal - dgdot_dtauslip = 0.0_pReal - j = 0_pInt - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystemsLoop: do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on slip system - tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - - if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) - StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0 & - * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_dislotwin_qPerSlipFamily(f,instance)) & - * sign(1.0_pReal,tau_slip(j)) - - !* Derivatives of shear rates - dgdot_dtauslip(j) = & - abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& - *plastic_dislotwin_qPerSlipFamily(f,instance)/& - (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) - endif - - !* Plastic velocity gradient for dislocation glide - Lp = Lp + gdot_slip(j)*lattice_Sslip(:,:,1,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& - lattice_Sslip(k,l,1,index_myFamily+i,ph)*& - lattice_Sslip(m,n,1,index_myFamily+i,ph) - enddo slipSystemsLoop - enddo slipFamiliesLoop - -!-------------------------------------------------------------------------------------------------- -! correct Lp and dLp_dTstar3333 for twinned and transformed fraction - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - Lp = Lp * (1.0_pReal - sumf - sumftr) - dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf - sumftr) - -!-------------------------------------------------------------------------------------------------- -! Shear banding (shearband) part - if(abs(plastic_dislotwin_sbVelocity(instance)) > tiny(0.0_pReal) .and. & - abs(plastic_dislotwin_sbResistance(instance)) > tiny(0.0_pReal)) then - gdot_sb = 0.0_pReal - dgdot_dtausb = 0.0_pReal - call math_spectralDecompositionSym(math_Mandel6to33(Tstar_v),eigValues,eigVectors,error) - do j = 1_pInt,6_pInt - sb_s = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_sComposition(1:3,j)) - sb_m = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_mComposition(1:3,j)) - sb_Smatrix = math_tensorproduct33(sb_s,sb_m) - plastic_dislotwin_sbSv(1:6,j,ipc,ip,el) = math_Mandel33to6(math_symmetric33(sb_Smatrix)) - - !* Calculation of Lp - !* Resolved shear stress on shear banding system - tau_sb(j) = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) - - !* Stress ratios - if (abs(tau_sb(j)) < tol_math_check) then - StressRatio_p = 0.0_pReal - StressRatio_pminus1 = 0.0_pReal - else - StressRatio_p = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& - **plastic_dislotwin_pShearBand(instance) - StressRatio_pminus1 = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& - **(plastic_dislotwin_pShearBand(instance)-1.0_pReal) - endif - - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = plastic_dislotwin_sbVelocity(instance) - - !* Shear rates due to shearband - gdot_sb(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qShearBand(instance))*sign(1.0_pReal,tau_sb(j)) - - !* Derivatives of shear rates - dgdot_dtausb(j) = & - ((abs(gdot_sb(j))*BoltzmannRatio*& - plastic_dislotwin_pShearBand(instance)*plastic_dislotwin_qShearBand(instance))/& - plastic_dislotwin_sbResistance(instance))*& - StressRatio_pminus1*(1_pInt-StressRatio_p)**(plastic_dislotwin_qShearBand(instance)-1.0_pReal) - - !* Plastic velocity gradient for shear banding - Lp = Lp + gdot_sb(j)*sb_Smatrix - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtausb(j)*& - sb_Smatrix(k,l)*& - sb_Smatrix(m,n) - enddo - end if - -!-------------------------------------------------------------------------------------------------- -! Mechanical twinning part - gdot_twin = 0.0_pReal - dgdot_dtautwin = 0.0_pReal - j = 0_pInt - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on twin system - tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_twin(j) > tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then - Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(ph)%rhoEdgeDip(s2,of))+& !!!!! correct? - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) - else - Ndot0_twin=0.0_pReal - end if - case default - Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) - end select - gdot_twin(j) = & - (1.0_pReal-sumf-sumftr)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) - dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_dislotwin_rPerTwinFamily(f,instance))/tau_twin(j))*StressRatio_r - endif - - !* Plastic velocity gradient for mechanical twinning - Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& - lattice_Stwin(k,l,index_myFamily+i,ph)*& - lattice_Stwin(m,n,index_myFamily+i,ph) - enddo twinSystemsLoop - enddo twinFamiliesLoop - - !* Phase transformation part - gdot_trans = 0.0_pReal - dgdot_dtautrans = 0.0_pReal - j = 0_pInt - transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily - index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family - transSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) - j = j+1_pInt - - !* Resolved shear stress on transformation system - tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_trans(j) > tol_math_check) then - StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) - !* Shear rates and their derivatives due to transformation - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then - Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !!!!! correct? - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) - else - Ndot0_trans=0.0_pReal - end if - case default - Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) - end select - gdot_trans(j) = & - (1.0_pReal-sumf-sumftr)*& - state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) - dgdot_dtautrans(j) = ((gdot_trans(j)*plastic_dislotwin_sPerTransFamily(f,instance))/tau_trans(j))*StressRatio_s - endif - - !* Plastic velocity gradient for phase transformation - Lp = Lp + gdot_trans(j)*lattice_Strans(:,:,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautrans(j)*& - lattice_Strans(k,l,index_myFamily+i,ph)*& - lattice_Strans(m,n,index_myFamily+i,ph) - - enddo transSystemsLoop - enddo transFamiliesLoop - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - -end subroutine plastic_dislotwin_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_dislotwin_dotState(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_Strans_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_maxNtransFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NtransSystem, & - lattice_sheartwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - lattice_fccTobcc_transNucleationTwinPair, & - lattice_fccTobcc_shearCritTrans, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: instance,ns,nt,nr,f,i,j,index_myFamily,s1,s2, & - ph, & - of - real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,& - EdgeDipMinDistance,AtomicVolume,VacancyDiffusion,StressRatio_r,Ndot0_twin,stressRatio,& - Ndot0_trans,StressRatio_s,EdgeDipDistance, ClimbVelocity,DotRhoEdgeDipClimb,DotRhoEdgeDipAnnihilation, & - DotRhoDipFormation,DotRhoMultiplication,DotRhoEdgeEdgeAnnihilation - real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,tau_slip - - real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - tau_twin - real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - tau_trans - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - plasticState(instance)%dotState(:,of) = 0.0_pReal - - !* Total transformed volume fraction - sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & - sum(state(instance)%strainTransFraction(1_pInt:nr,of)) - - !* Dislocation density evolution - gdot_slip = 0.0_pReal - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - !* Resolved shear stress on slip system - tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - - if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) - StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - plasticState(ph)%state(j, of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)** & - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau_slip(j)) - endif - !* Multiplication - DotRhoMultiplication = abs(gdot_slip(j))/& - (plastic_dislotwin_burgersPerSlipSystem(j,instance)*state(instance)%mfp_slip(j,of)) - !* Dipole formation - EdgeDipMinDistance = & - plastic_dislotwin_CEdgeDipMinDistance(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance) - if (abs(tau_slip(j)) <= tiny(0.0_pReal)) then - DotRhoDipFormation = 0.0_pReal - else - EdgeDipDistance = & - (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(tau_slip(j))) - if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) - if (EdgeDipDistance tol_math_check) then - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/& - tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) - !* Shear rates and their derivatives due to twin - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then - Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) - else - Ndot0_twin=0.0_pReal - end if - case default - Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) - end select - dotState(instance)%twinFraction(j,of) = & - (1.0_pReal-sumf-sumftr)*& - state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) - !* Dotstate for accumulated shear due to twin - dotState(instance)%accshear_twin(j,of) = dotState(instance)%twinFraction(j,of) * & - lattice_sheartwin(index_myfamily+i,ph) - endif - enddo - enddo - - !* Transformation volume fraction evolution - j = 0_pInt - do f = 1_pInt,lattice_maxNtransFamily ! loop over all trans families - index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) ! process each (active) trans system in family - j = j+1_pInt - - !* Resolved shear stress on transformation system - tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) - - !* Stress ratios - if (tau_trans(j) > tol_math_check) then - StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/& - tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) - !* Shear rates and their derivatives due to transformation - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then - Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) - else - Ndot0_trans=0.0_pReal - end if - case default - Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) - end select - dotState(instance)%strainTransFraction(j,of) = & - (1.0_pReal-sumf-sumftr)*& - state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) - !* Dotstate for accumulated shear due to transformation - !dotState(instance)%accshear_trans(j,of) = dotState(instance)%strainTransFraction(j,of) * & - ! lattice_sheartrans(index_myfamily+i,ph) - endif - - enddo - enddo - -end subroutine plastic_dislotwin_dotState - - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_dislotwin_postResults(Tstar_v,Temperature,ipc,ip,el) - use prec, only: & - tol_math_check - use math, only: & - pi, & - math_Mandel6to33, & - math_eigenvaluesSym33, & - math_spectralDecompositionSym33 - use material, only: & - material_phase, & - phase_plasticityInstance,& - phaseAt, phasememberAt - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_shearTwin, & - lattice_mu, & - lattice_structure, & - lattice_fcc_twinNucleationSlipPair, & - LATTICE_fcc_ID - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(plastic_dislotwin_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_dislotwin_postResults - integer(pInt) :: & - instance,& - ns,nt,nr,& - f,o,i,c,j,index_myFamily,& - s1,s2, & - ph, & - of - real(pReal) :: sumf,tau,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0_twin,dgdot_dtauslip, & - stressRatio - real(preal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip - real(pReal), dimension(3,3) :: eigVectors - real(pReal), dimension (3) :: eigValues - - !* Shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_dislotwin_totalNslip(instance) - nt = plastic_dislotwin_totalNtwin(instance) - nr = plastic_dislotwin_totalNtrans(instance) - - !* Total twin volume fraction - sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 - - !* Required output - c = 0_pInt - plastic_dislotwin_postResults = 0.0_pReal - do o = 1_pInt,plastic_dislotwin_Noutput(instance) - select case(plastic_dislotwin_outputID(o,instance)) - - case (edge_density_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) - c = c + ns - case (dipole_density_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) - c = c + ns - case (shear_rate_slip_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt ! could be taken from state by now! - - !* Resolved shear stress on slip system - tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - !* Stress ratios - if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - stressRatio = ((abs(tau)-state(ph)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) - StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - plastic_dislotwin_postResults(c+j) = & - DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) - else - plastic_dislotwin_postResults(c+j) = 0.0_pReal - endif - - enddo ; enddo - c = c + ns - case (accumulated_shear_slip_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = & - state(instance)%accshear_slip(1_pInt:ns,of) - c = c + ns - case (mfp_slip_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) =& - state(instance)%mfp_slip(1_pInt:ns,of) - c = c + ns - case (resolved_stress_slip_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - plastic_dislotwin_postResults(c+j) =& - dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - enddo; enddo - c = c + ns - case (threshold_stress_slip_ID) - plastic_dislotwin_postResults(c+1_pInt:c+ns) = & - state(instance)%threshold_stress_slip(1_pInt:ns,of) - c = c + ns - case (edge_dipole_distance_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - plastic_dislotwin_postResults(c+j) = & - (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& - (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) - plastic_dislotwin_postResults(c+j)=min(plastic_dislotwin_postResults(c+j),& - state(instance)%mfp_slip(j,of)) - ! plastic_dislotwin_postResults(c+j)=max(plastic_dislotwin_postResults(c+j),& - ! plasticState(ph)%state(4*ns+2*nt+2*nr+j, of)) - enddo; enddo - c = c + ns - case (resolved_stress_shearband_ID) - do j = 1_pInt,6_pInt ! loop over all shearband families - plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v, & - plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) - enddo - c = c + 6_pInt - case (shear_rate_shearband_ID) - do j = 1_pInt,6_pInt ! loop over all shearbands - !* Resolved shear stress on shearband system - tau = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) - !* Stress ratios - if (abs(tau) < tol_math_check) then - StressRatio_p = 0.0_pReal - StressRatio_pminus1 = 0.0_pReal - else - StressRatio_p = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& - plastic_dislotwin_pShearBand(instance) - StressRatio_pminus1 = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& - (plastic_dislotwin_pShearBand(instance)-1.0_pReal) - endif - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = plastic_dislotwin_sbVelocity(instance) - ! Shear rate due to shear band - plastic_dislotwin_postResults(c+j) = & - DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**plastic_dislotwin_qShearBand(instance))*& - sign(1.0_pReal,tau) - enddo - c = c + 6_pInt - case (twin_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt,of) - c = c + nt - case (shear_rate_twin_ID) - if (nt > 0_pInt) then - - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - - !* Resolved shear stress on slip system - tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - !* Stress ratios - if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) - else - gdot_slip(j) = 0.0_pReal - endif - enddo;enddo - - j = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily ! loop over all twin families - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1,plastic_dislotwin_Ntwin(f,instance) ! process each (active) twin system in family - j = j + 1_pInt - - tau = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - - !* Shear rates due to twin - if ( tau > 0.0_pReal ) then - select case(lattice_structure(ph)) - case (LATTICE_fcc_ID) - s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) - s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) - if (tau < plastic_dislotwin_tau_r_twin(j,instance)) then - Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& - abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& - (plastic_dislotwin_L0_twin(instance)*& - plastic_dislotwin_burgersPerSlipSystem(j,instance))*& - (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& - (plastic_dislotwin_tau_r_twin(j,instance)-tau))) - else - Ndot0_twin=0.0_pReal - end if - case default - Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) - end select - StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau) & - **plastic_dislotwin_rPerTwinFamily(f,instance) - plastic_dislotwin_postResults(c+j) = & - (plastic_dislotwin_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& - state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) - endif - - enddo ; enddo - endif - c = c + nt - case (accumulated_shear_twin_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt,of) - c = c + nt - case (mfp_twin_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt,of) - c = c + nt - case (resolved_stress_twin_ID) - if (nt > 0_pInt) then - j = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily ! loop over all slip families - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - enddo; enddo - endif - c = c + nt - case (threshold_stress_twin_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt,of) - c = c + nt - case (stress_exponent_ID) - j = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family - j = j + 1_pInt - - !* Resolved shear stress on slip system - tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then - !* Stress ratios - StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **plastic_dislotwin_pPerSlipFamily(f,instance) - StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& - **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) - !* Boltzmann ratio - BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) - !* Initial shear rates - DotGamma0 = & - state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & - plastic_dislotwin_v0PerSlipSystem(j,instance) - - !* Shear rates due to slip - gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& - plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) - - !* Derivatives of shear rates - dgdot_dtauslip = & - abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& - *plastic_dislotwin_qPerSlipFamily(f,instance)/& - (plastic_dislotwin_SolidSolutionStrength(instance)+& - plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& - StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) - - else - gdot_slip(j) = 0.0_pReal - dgdot_dtauslip = 0.0_pReal - endif - - !* Stress exponent - if (abs(gdot_slip(j))<=tiny(0.0_pReal)) then - plastic_dislotwin_postResults(c+j) = 0.0_pReal - else - plastic_dislotwin_postResults(c+j) = (tau/gdot_slip(j))*dgdot_dtauslip - endif - enddo ; enddo - c = c + ns - case (sb_eigenvalues_ID) - plastic_dislotwin_postResults(c+1_pInt:c+3_pInt) = math_eigenvaluesSym33(math_Mandel6to33(Tstar_v)) - c = c + 3_pInt - case (sb_eigenvectors_ID) - call math_spectralDecompositionSym33(math_Mandel6to33(Tstar_v),eigValues,eigVectors) - plastic_dislotwin_postResults(c+1_pInt:c+9_pInt) = reshape(eigVectors,[9]) - c = c + 9_pInt - case (stress_trans_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nr) = & - state(instance)%stressTransFraction(1_pInt:nr,of) - c = c + nr - case (strain_trans_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nr) = & - state(instance)%strainTransFraction(1_pInt:nr,of) - c = c + nr - case (trans_fraction_ID) - plastic_dislotwin_postResults(c+1_pInt:c+nr) = & - state(instance)%stressTransFraction(1_pInt:nr,of) + & - state(instance)%strainTransFraction(1_pInt:nr,of) - c = c + nr - end select - enddo -end function plastic_dislotwin_postResults - -end module plastic_dislotwin \ No newline at end of file diff --git a/code/plastic_isotropic.f90 b/code/plastic_isotropic.f90 deleted file mode 100644 index 13481b9a7..000000000 --- a/code/plastic_isotropic.f90 +++ /dev/null @@ -1,678 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for isotropic (ISOTROPIC) plasticity -!> @details Isotropic (ISOTROPIC) Plasticity which resembles the phenopowerlaw plasticity without -!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an -!! untextured polycrystal -!-------------------------------------------------------------------------------------------------- -module plastic_isotropic -#ifdef HDF - use hdf5, only: & - HID_T -#endif - - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_isotropic_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_isotropic_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_isotropic_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_isotropic_Noutput !< number of outputs per instance - - enum, bind(c) - enumerator :: undefined_ID, & - flowstress_ID, & - strainrate_ID - end enum - - type, private :: tParameters !< container type for internal constitutive parameters - integer(kind(undefined_ID)), allocatable, dimension(:) :: & - outputID - real(pReal) :: & - fTaylor, & - tau0, & - gdot0, & - n, & - h0, & - h0_slopeLnRate, & - tausat, & - a, & - aTolFlowstress, & - aTolShear , & - tausat_SinhFitA, & - tausat_SinhFitB, & - tausat_SinhFitC, & - tausat_SinhFitD - logical :: & - dilatation - end type - - type(tParameters), dimension(:), allocatable, private :: param !< containers of constitutive parameters (len Ninstance) - - type, private :: tIsotropicState !< internal state aliases - real(pReal), pointer, dimension(:) :: & ! scalars along NipcMyInstance - flowstress, & - accumulatedShear - end type - type, private :: tIsotropicAbsTol !< internal alias for abs tolerance in state - real(pReal), pointer :: & ! scalars along NipcMyInstance - flowstress, & - accumulatedShear - end type - type(tIsotropicState), allocatable, dimension(:), private :: & !< state aliases per instance - state, & - state0, & - dotState - type(tIsotropicAbsTol), allocatable, dimension(:), private :: & !< state aliases per instance - stateAbsTol - - public :: & - plastic_isotropic_init, & - plastic_isotropic_LpAndItsTangent, & - plastic_isotropic_LiAndItsTangent, & - plastic_isotropic_dotState, & - plastic_isotropic_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic - use numerics, only: & - analyticJaco, & - worldrank, & - numerics_integrator - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_ISOTROPIC_label, & - PLASTICITY_ISOTROPIC_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - - use lattice - - implicit none - integer(pInt), intent(in) :: fileUnit - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - o, & - phase, & - instance, & - maxNinstance, & - mySize, & - sizeDotState, & - sizeState, & - sizeDeltaState - character(len=65536) :: & - tag = '', & - outputtag = '', & - line = '', & - extmsg = '' - integer(pInt) :: NipcMyPhase - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_ISOTROPIC_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_ISOTROPIC_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_isotropic_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_isotropic_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) - allocate(plastic_isotropic_output(maxval(phase_Noutput), maxNinstance)) - plastic_isotropic_output = '' - allocate(plastic_isotropic_Noutput(maxNinstance), source=0_pInt) - - allocate(param(maxNinstance)) ! one container of parameters per instance - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - phase = phase + 1_pInt ! advance section counter - if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then - instance = phase_plasticityInstance(phase) - - endif - cycle ! skip to next line - endif - if (phase > 0_pInt) then; if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - allocate(param(instance)%outputID(phase_Noutput(phase))) ! allocate space for IDs of every requested output - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - extmsg = trim(tag)//' ('//PLASTICITY_ISOTROPIC_label//')' ! prepare error message identifier - - select case(tag) - case ('(output)') - outputtag = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - select case(outputtag) - case ('flowstress') - plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt - param(instance)%outputID (plastic_isotropic_Noutput(instance)) = flowstress_ID - plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag - case ('strainrate') - plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt - param(instance)%outputID (plastic_isotropic_Noutput(instance)) = strainrate_ID - plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag - - end select - - case ('/dilatation/') - param(instance)%dilatation = .true. - - case ('tau0') - param(instance)%tau0 = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%tau0 < 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('gdot0') - param(instance)%gdot0 = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%gdot0 <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('n') - param(instance)%n = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%n <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('h0') - param(instance)%h0 = IO_floatValue(line,chunkPos,2_pInt) - - case ('h0_slope','slopelnrate') - param(instance)%h0_slopeLnRate = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat') - param(instance)%tausat = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%tausat <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('tausat_sinhfita') - param(instance)%tausat_SinhFitA = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat_sinhfitb') - param(instance)%tausat_SinhFitB = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat_sinhfitc') - param(instance)%tausat_SinhFitC = IO_floatValue(line,chunkPos,2_pInt) - - case ('tausat_sinhfitd') - param(instance)%tausat_SinhFitD = IO_floatValue(line,chunkPos,2_pInt) - - case ('a', 'w0') - param(instance)%a = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%a <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('taylorfactor') - param(instance)%fTaylor = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%fTaylor <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('atol_flowstress') - param(instance)%aTolFlowstress = IO_floatValue(line,chunkPos,2_pInt) - if (param(instance)%aTolFlowstress <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) - - case ('atol_shear') - param(instance)%aTolShear = IO_floatValue(line,chunkPos,2_pInt) - - case default - - end select - endif; endif - enddo parsingFile - - allocate(state(maxNinstance)) ! internal state aliases - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - allocate(stateAbsTol(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop over every plasticity - myPhase: if (phase_plasticity(phase) == PLASTICITY_isotropic_ID) then ! isolate instances of own constitutive description - NipcMyPhase = count(material_phase == phase) ! number of own material points (including point components ipc) - instance = phase_plasticityInstance(phase) -!-------------------------------------------------------------------------------------------------- -! sanity checks - if (param(instance)%aTolShear <= 0.0_pReal) & - param(instance)%aTolShear = 1.0e-6_pReal ! default absolute tolerance 1e-6 - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) - select case(param(instance)%outputID(o)) - case(flowstress_ID,strainrate_ID) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_isotropic_sizePostResult(o,instance) = mySize - plastic_isotropic_sizePostResults(instance) = & - plastic_isotropic_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = 2_pInt ! flowstress, accumulated_shear - sizeDotState = sizeState ! both evolve - sizeDeltaState = 0_pInt ! no sudden jumps in state - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_isotropic_sizePostResults(instance) - plasticState(phase)%nSlip = 1 - plasticState(phase)%nTwin = 0 - plasticState(phase)%nTrans= 0 - allocate(plasticState(phase)%aTolState ( sizeState)) - - allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase),source=0.0_pReal) - - allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase),source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase),source=0.0_pReal) - -!-------------------------------------------------------------------------------------------------- -! globally required state aliases - plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NipcMyPhase) - plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NipcMyPhase) - -!-------------------------------------------------------------------------------------------------- -! locally defined state aliases - state(instance)%flowstress => plasticState(phase)%state (1,1:NipcMyPhase) - state0(instance)%flowstress => plasticState(phase)%state0 (1,1:NipcMyPhase) - dotState(instance)%flowstress => plasticState(phase)%dotState (1,1:NipcMyPhase) - stateAbsTol(instance)%flowstress => plasticState(phase)%aTolState(1) - - state(instance)%accumulatedShear => plasticState(phase)%state (2,1:NipcMyPhase) - state0(instance)%accumulatedShear => plasticState(phase)%state0 (2,1:NipcMyPhase) - dotState(instance)%accumulatedShear => plasticState(phase)%dotState (2,1:NipcMyPhase) - stateAbsTol(instance)%accumulatedShear => plasticState(phase)%aTolState(2) - -!-------------------------------------------------------------------------------------------------- -! init state - state0(instance)%flowstress = param(instance)%tau0 - state0(instance)%accumulatedShear = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! init absolute state tolerances - stateAbsTol(instance)%flowstress = param(instance)%aTolFlowstress - stateAbsTol(instance)%accumulatedShear = param(instance)%aTolShear - - endif myPhase - enddo initializeInstances - -end subroutine plastic_isotropic_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_e, & - debug_i, & - debug_g - use math, only: & - math_mul6x6, & - math_Mandel6to33, & - math_Plain3333to99, & - math_deviatoric33, & - math_mul33xx33, & - math_transpose33 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(3,3) :: & - Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal) :: & - gamma_dot, & !< strainrate - norm_Tstar_dev, & !< euclidean norm of Tstar_dev - squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev - integer(pInt) :: & - instance, of, & - k, l, m, n - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - - Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress - squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) - norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) - - if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero - Lp = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - else - gamma_dot = param(instance)%gdot0 & - * ( sqrt(1.5_pReal) * norm_Tstar_dev / param(instance)%fTaylor / state(instance)%flowstress(of) ) & - **param(instance)%n - - Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/param(instance)%fTaylor - - if (iand(debug_level(debug_constitutive), debug_levelExtensive) /= 0_pInt & - .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then - write(6,'(a,i8,1x,i2,1x,i3)') '<< CONST isotropic >> at el ip g ',el,ip,ipc - write(6,'(/,a,/,3(12x,3(f12.4,1x)/))') '<< CONST isotropic >> Tstar (dev) / MPa', & - math_transpose33(Tstar_dev_33(1:3,1:3))*1.0e-6_pReal - write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> norm Tstar / MPa', norm_Tstar_dev*1.0e-6_pReal - write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> gdot', gamma_dot - end if -!-------------------------------------------------------------------------------------------------- -! Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & - Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal - forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & - dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal - dLp_dTstar99 = math_Plain3333to99(gamma_dot / param(instance)%fTaylor * & - dLp_dTstar_3333 / norm_Tstar_dev) - end if -end subroutine plastic_isotropic_LpAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_LiAndItsTangent(Li,dLi_dTstar_3333,Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6, & - math_Mandel6to33, & - math_Plain3333to99, & - math_spherical33, & - math_mul33xx33 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Li !< plastic velocity gradient - - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(3,3) :: & - Tstar_sph_33 !< sphiatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor - real(pReal), dimension(3,3,3,3), intent(out) :: & - dLi_dTstar_3333 !< derivative of Li with respect to Tstar as 4th order tensor - real(pReal) :: & - gamma_dot, & !< strainrate - norm_Tstar_sph, & !< euclidean norm of Tstar_sph - squarenorm_Tstar_sph !< square of the euclidean norm of Tstar_sph - integer(pInt) :: & - instance, of, & - k, l, m, n - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - - Tstar_sph_33 = math_spherical33(math_Mandel6to33(Tstar_v)) ! spherical part of 2nd Piola-Kirchhoff stress - squarenorm_Tstar_sph = math_mul33xx33(Tstar_sph_33,Tstar_sph_33) - norm_Tstar_sph = sqrt(squarenorm_Tstar_sph) - - if (param(instance)%dilatation) then - if (norm_Tstar_sph <= 0.0_pReal) then ! Tstar == 0 --> both Li and dLi_dTstar are zero - Li = 0.0_pReal - dLi_dTstar_3333 = 0.0_pReal - else - gamma_dot = param(instance)%gdot0 & - * (sqrt(1.5_pReal) * norm_Tstar_sph / param(instance)%fTaylor / state(instance)%flowstress(of) ) & - **param(instance)%n - - Li = Tstar_sph_33/norm_Tstar_sph * gamma_dot/param(instance)%fTaylor - - !-------------------------------------------------------------------------------------------------- - ! Calculation of the tangent of Li - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLi_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & - Tstar_sph_33(k,l)*Tstar_sph_33(m,n) / squarenorm_Tstar_sph - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLi_dTstar_3333(k,l,k,l) = dLi_dTstar_3333(k,l,k,l) + 1.0_pReal - - dLi_dTstar_3333 = gamma_dot / param(instance)%fTaylor * & - dLi_dTstar_3333 / norm_Tstar_sph - endif - endif - -end subroutine plastic_isotropic_LiAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_isotropic_dotState(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6) :: & - Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - gamma_dot, & !< strainrate - hardening, & !< hardening coefficient - saturation, & !< saturation flowstress - norm_Tstar_v !< euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of !< shortcut notation for offset position in state array - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - -!-------------------------------------------------------------------------------------------------- -! norm of (deviatoric) 2nd Piola-Kirchhoff stress - if (param(instance)%dilatation) then - norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) - else - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - end if -!-------------------------------------------------------------------------------------------------- -! strain rate - gamma_dot = param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & - / &!----------------------------------------------------------------------------------- - (param(instance)%fTaylor*state(instance)%flowstress(of) ))**param(instance)%n - -!-------------------------------------------------------------------------------------------------- -! hardening coefficient - if (abs(gamma_dot) > 1e-12_pReal) then - if (abs(param(instance)%tausat_SinhFitA) <= tiny(0.0_pReal)) then - saturation = param(instance)%tausat - else - saturation = ( param(instance)%tausat & - + ( log( ( gamma_dot / param(instance)%tausat_SinhFitA& - )**(1.0_pReal / param(instance)%tausat_SinhFitD)& - + sqrt( ( gamma_dot / param(instance)%tausat_SinhFitA & - )**(2.0_pReal / param(instance)%tausat_SinhFitD) & - + 1.0_pReal ) & - ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) - )**(1.0_pReal / param(instance)%tausat_SinhFitC) & - / ( param(instance)%tausat_SinhFitB & - * (gamma_dot / param(instance)%gdot0)**(1.0_pReal / param(instance)%n) & - ) & - ) - endif - hardening = ( param(instance)%h0 + param(instance)%h0_slopeLnRate * log(gamma_dot) ) & - * abs( 1.0_pReal - state(instance)%flowstress(of)/saturation )**param(instance)%a & - * sign(1.0_pReal, 1.0_pReal - state(instance)%flowstress(of)/saturation) - else - hardening = 0.0_pReal - endif - - dotState(instance)%flowstress (of) = hardening * gamma_dot - dotState(instance)%accumulatedShear(of) = gamma_dot - -end subroutine plastic_isotropic_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_isotropic_postResults(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(plastic_isotropic_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_isotropic_postResults - - real(pReal), dimension(6) :: & - Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - norm_Tstar_v ! euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of, & !< shortcut notation for offset position in state array - c, & - o - - of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember - instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! - -!-------------------------------------------------------------------------------------------------- -! norm of (deviatoric) 2nd Piola-Kirchhoff stress - if (param(instance)%dilatation) then - norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) - else - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - end if - - c = 0_pInt - plastic_isotropic_postResults = 0.0_pReal - - outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) - select case(param(instance)%outputID(o)) - case (flowstress_ID) - plastic_isotropic_postResults(c+1_pInt) = state(instance)%flowstress(of) - c = c + 1_pInt - case (strainrate_ID) - plastic_isotropic_postResults(c+1_pInt) = & - param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & - / &!---------------------------------------------------------------------------------- - (param(instance)%fTaylor * state(instance)%flowstress(of)) ) ** param(instance)%n - c = c + 1_pInt - end select - enddo outputsLoop - -end function plastic_isotropic_postResults - - -end module plastic_isotropic diff --git a/code/plastic_j2.f90 b/code/plastic_j2.f90 deleted file mode 100644 index 89c022cc9..000000000 --- a/code/plastic_j2.f90 +++ /dev/null @@ -1,579 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for isotropic (J2) plasticity -!> @details Isotropic (J2) Plasticity which resembles the phenopowerlaw plasticity without -!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an -!! untextured polycrystal -!-------------------------------------------------------------------------------------------------- -module plastic_j2 -#ifdef HDF - use hdf5, only: & - HID_T -#endif - - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_j2_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_j2_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_j2_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_j2_Noutput !< number of outputs per instance - real(pReal), dimension(:), allocatable, private :: & - plastic_j2_fTaylor, & !< Taylor factor - plastic_j2_tau0, & !< initial plastic stress - plastic_j2_gdot0, & !< reference velocity - plastic_j2_n, & !< Visco-plastic parameter -!-------------------------------------------------------------------------------------------------- -! h0 as function of h0 = A + B log (gammadot) - plastic_j2_h0, & - plastic_j2_h0_slopeLnRate, & - plastic_j2_tausat, & !< final plastic stress - plastic_j2_a, & - plastic_j2_aTolResistance, & - plastic_j2_aTolShear, & -!-------------------------------------------------------------------------------------------------- -! tausat += (asinh((gammadot / SinhFitA)**(1 / SinhFitD)))**(1 / SinhFitC) / (SinhFitB * (gammadot / gammadot0)**(1/n)) - plastic_j2_tausat_SinhFitA, & !< fitting parameter for normalized strain rate vs. stress function - plastic_j2_tausat_SinhFitB, & !< fitting parameter for normalized strain rate vs. stress function - plastic_j2_tausat_SinhFitC, & !< fitting parameter for normalized strain rate vs. stress function - plastic_j2_tausat_SinhFitD !< fitting parameter for normalized strain rate vs. stress function - - enum, bind(c) - enumerator :: undefined_ID, & - flowstress_ID, & - strainrate_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_j2_outputID !< ID of each post result output - - -#ifdef HDF - type plastic_j2_tOutput - real(pReal), dimension(:), allocatable, private :: & - flowstress, & - strainrate - logical :: flowstressActive = .false., strainrateActive = .false. ! if we can write the output block wise, this is not needed anymore because we can do an if(allocated(xxx)) - end type plastic_j2_tOutput - type(plastic_j2_tOutput), allocatable, dimension(:) :: plastic_j2_Output2 -integer(HID_T), allocatable, dimension(:) :: outID -#endif - - - public :: & - plastic_j2_init, & - plastic_j2_LpAndItsTangent, & - plastic_j2_dotState, & - plastic_j2_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_j2_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) -#ifdef HDF - use hdf5 -#endif - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic - use numerics, only: & - analyticJaco, & - worldrank, & - numerics_integrator - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_error, & - IO_timeStamp, & -#ifdef HDF - tempResults, & - HDF5_addGroup, & - HDF5_addScalarDataset,& -#endif - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_J2_label, & - PLASTICITY_J2_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - - use lattice - - implicit none - integer(pInt), intent(in) :: fileUnit - - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - o, & - phase, & - maxNinstance, & - instance, & - mySize, & - sizeDotState, & - sizeState, & - sizeDeltaState - character(len=65536) :: & - tag = '', & - line = '' - integer(pInt) :: NofMyPhase - -#ifdef HDF - character(len=5) :: & - str1 - integer(HID_T) :: ID,ID2,ID4 -#endif - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_J2_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_J2_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - -#ifdef HDF - allocate(plastic_j2_Output2(maxNinstance)) - allocate(outID(maxNinstance)) -#endif - - allocate(plastic_j2_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_j2_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) - allocate(plastic_j2_output(maxval(phase_Noutput), maxNinstance)) - plastic_j2_output = '' - allocate(plastic_j2_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_j2_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_j2_fTaylor(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tau0(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_gdot0(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_n(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_h0(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_h0_slopeLnRate(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_a(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_aTolResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_aTolShear (maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitA(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitB(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitC(maxNinstance), source=0.0_pReal) - allocate(plastic_j2_tausat_SinhFitD(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - phase = phase + 1_pInt ! advance section counter - if (phase_plasticity(phase) == PLASTICITY_J2_ID) then - instance = phase_plasticityInstance(phase) -#ifdef HDF - outID(instance)=HDF5_addGroup(str1,tempResults) -#endif - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_J2_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('flowstress') - plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt - plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = flowstress_ID - plastic_j2_output(plastic_j2_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) -#ifdef HDF - call HDF5_addScalarDataset(outID(instance),myConstituents,'flowstress','MPa') - allocate(plastic_j2_Output2(instance)%flowstress(myConstituents)) - plastic_j2_Output2(instance)%flowstressActive = .true. -#endif - case ('strainrate') - plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt - plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = strainrate_ID - plastic_j2_output(plastic_j2_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) -#ifdef HDF - call HDF5_addScalarDataset(outID(instance),myConstituents,'strainrate','1/s') - allocate(plastic_j2_Output2(instance)%strainrate(myConstituents)) - plastic_j2_Output2(instance)%strainrateActive = .true. -#endif - case default - - end select - case ('tau0') - plastic_j2_tau0(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_tau0(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('gdot0') - plastic_j2_gdot0(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_gdot0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('n') - plastic_j2_n(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_n(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('h0') - plastic_j2_h0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_slope','slopelnrate') - plastic_j2_h0_slopeLnRate(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat') - plastic_j2_tausat(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_tausat(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('tausat_sinhfita') - plastic_j2_tausat_SinhFitA(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat_sinhfitb') - plastic_j2_tausat_SinhFitB(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat_sinhfitc') - plastic_j2_tausat_SinhFitC(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('tausat_sinhfitd') - plastic_j2_tausat_SinhFitD(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('a', 'w0') - plastic_j2_a(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_a(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('taylorfactor') - plastic_j2_fTaylor(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_fTaylor(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('atol_resistance') - plastic_j2_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - if (plastic_j2_aTolResistance(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') - case ('atol_shear') - plastic_j2_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case default - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_j2_ID) then - NofMyPhase=count(material_phase==phase) - instance = phase_plasticityInstance(phase) -!-------------------------------------------------------------------------------------------------- -! sanity checks - if (plastic_j2_aTolShear(instance) <= 0.0_pReal) & - plastic_j2_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) - select case(plastic_j2_outputID(o,instance)) - case(flowstress_ID,strainrate_ID) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_j2_sizePostResult(o,instance) = mySize - plastic_j2_sizePostResults(instance) = & - plastic_j2_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = 2_pInt - sizeDotState = sizeState - sizeDeltaState = 0_pInt - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_j2_sizePostResults(instance) - plasticState(phase)%nSlip = 1 - plasticState(phase)%nTwin = 0 - plasticState(phase)%nTrans= 0 - allocate(plasticState(phase)%aTolState ( sizeState)) - plasticState(phase)%aTolState(1) = plastic_j2_aTolResistance(instance) - plasticState(phase)%aTolState(2) = plastic_j2_aTolShear(instance) - allocate(plasticState(phase)%state0 ( sizeState,NofMyPhase)) - plasticState(phase)%state0(1,1:NofMyPhase) = plastic_j2_tau0(instance) - plasticState(phase)%state0(2,1:NofMyPhase) = 0.0_pReal - allocate(plasticState(phase)%partionedState0 ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase),source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase),source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NofMyPhase) - endif myPhase - enddo initializeInstances - -end subroutine plastic_j2_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_j2_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6, & - math_Mandel6to33, & - math_Plain3333to99, & - math_deviatoric33, & - math_mul33xx33 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - real(pReal), dimension(3,3) :: & - Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal) :: & - gamma_dot, & !< strainrate - norm_Tstar_dev, & !< euclidean norm of Tstar_dev - squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & - k, l, m, n - - instance = phase_plasticityInstance(material_phase(ipc,ip,el)) - Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress - squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) - norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) - - if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero - Lp = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - else - gamma_dot = plastic_j2_gdot0(instance) & - * (sqrt(1.5_pReal) * norm_Tstar_dev / (plastic_j2_fTaylor(instance) * & - plasticState(phaseAt(ipc,ip,el))%state(1,phasememberAt(ipc,ip,el)))) & - **plastic_j2_n(instance) - - Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/plastic_j2_fTaylor(instance) - -!-------------------------------------------------------------------------------------------------- -! Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,m,n) = (plastic_j2_n(instance)-1.0_pReal) * & - Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal - forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & - dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal - dLp_dTstar99 = math_Plain3333to99(gamma_dot / plastic_j2_fTaylor(instance) * & - dLp_dTstar_3333 / norm_Tstar_dev) - end if -end subroutine plastic_j2_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_j2_dotState(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - material_phase, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6) :: & - Tstar_dev_v !< deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - gamma_dot, & !< strainrate - hardening, & !< hardening coefficient - saturation, & !< saturation resistance - norm_Tstar_dev !< euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of, & !< shortcut notation for offset position in state array - ph !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(material_phase(ipc,ip,el)) - -!-------------------------------------------------------------------------------------------------- -! norm of deviatoric part of 2nd Piola-Kirchhoff stress - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - -!-------------------------------------------------------------------------------------------------- -! strain rate - gamma_dot = plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & - / &!----------------------------------------------------------------------------------- - (plastic_j2_fTaylor(instance)*plasticState(ph)%state(1,of)) )**plastic_j2_n(instance) - -!-------------------------------------------------------------------------------------------------- -! hardening coefficient - if (abs(gamma_dot) > 1e-12_pReal) then - if (abs(plastic_j2_tausat_SinhFitA(instance)) <= tiny(0.0_pReal)) then - saturation = plastic_j2_tausat(instance) - else - saturation = ( plastic_j2_tausat(instance) & - + ( log( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance)& - )**(1.0_pReal / plastic_j2_tausat_SinhFitD(instance))& - + sqrt( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance) & - )**(2.0_pReal / plastic_j2_tausat_SinhFitD(instance)) & - + 1.0_pReal ) & - ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) - )**(1.0_pReal / plastic_j2_tausat_SinhFitC(instance)) & - / ( plastic_j2_tausat_SinhFitB(instance) & - * (gamma_dot / plastic_j2_gdot0(instance))**(1.0_pReal / plastic_j2_n(instance)) & - ) & - ) - endif - hardening = ( plastic_j2_h0(instance) + plastic_j2_h0_slopeLnRate(instance) * log(gamma_dot) ) & - * abs( 1.0_pReal - plasticState(ph)%state(1,of)/saturation )**plastic_j2_a(instance) & - * sign(1.0_pReal, 1.0_pReal - plasticState(ph)%state(1,of)/saturation) - else - hardening = 0.0_pReal - endif - - plasticState(ph)%dotState(1,of) = hardening * gamma_dot - plasticState(ph)%dotState(2,of) = gamma_dot - -end subroutine plastic_j2_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_j2_postResults(Tstar_v,ipc,ip,el) - use math, only: & - math_mul6x6 - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(plastic_j2_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_j2_postResults - - real(pReal), dimension(6) :: & - Tstar_dev_v ! deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal) :: & - norm_Tstar_dev ! euclidean norm of Tstar_dev - integer(pInt) :: & - instance, & !< instance of my instance (unique number of my constitutive model) - of, & !< shortcut notation for offset position in state array - ph, & !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) - c, & - o - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(material_phase(ipc,ip,el)) - -!-------------------------------------------------------------------------------------------------- -! calculate deviatoric part of 2nd Piola-Kirchhoff stress and its norm - Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal - Tstar_dev_v(4:6) = Tstar_v(4:6) - norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) - - c = 0_pInt - plastic_j2_postResults = 0.0_pReal - - outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) - select case(plastic_j2_outputID(o,instance)) - case (flowstress_ID) - plastic_j2_postResults(c+1_pInt) = plasticState(ph)%state(1,of) - c = c + 1_pInt - case (strainrate_ID) - plastic_j2_postResults(c+1_pInt) = & - plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & - / &!---------------------------------------------------------------------------------- - (plastic_j2_fTaylor(instance) * plasticState(ph)%state(1,of)) ) ** plastic_j2_n(instance) - c = c + 1_pInt - end select - enddo outputsLoop - -end function plastic_j2_postResults - - -end module plastic_j2 diff --git a/code/plastic_none.f90 b/code/plastic_none.f90 deleted file mode 100644 index f624a80a2..000000000 --- a/code/plastic_none.f90 +++ /dev/null @@ -1,109 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for purely elastic material -!-------------------------------------------------------------------------------------------------- -module plastic_none - use prec, only: & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_none_sizePostResults - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_none_sizePostResult !< size of each post result output - - public :: & - plastic_none_init - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_none_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelBasic - use IO, only: & - IO_timeStamp - use numerics, only: & - worldrank, & - numerics_integrator - use material, only: & - phase_plasticity, & - PLASTICITY_NONE_label, & - material_phase, & - plasticState, & - PLASTICITY_none_ID - - implicit none - - integer(pInt) :: & - maxNinstance, & - phase, & - NofMyPhase, & - sizeState, & - sizeDotState, & - sizeDeltaState - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONE_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_none_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - if (phase_plasticity(phase) == PLASTICITY_none_ID) then - NofMyPhase=count(material_phase==phase) - - sizeState = 0_pInt - plasticState(phase)%sizeState = sizeState - sizeDotState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - sizeDeltaState = 0_pInt - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = 0_pInt - plasticState(phase)%nSlip = 0_pInt - plasticState(phase)%nTwin = 0_pInt - plasticState(phase)%nTrans = 0_pInt - allocate(plasticState(phase)%aTolState (sizeState)) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase)) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase)) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase)) - allocate(plasticState(phase)%state (sizeState,NofMyPhase)) - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase)) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase)) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase)) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase)) - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase)) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase)) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase)) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase)) - endif - enddo initializeInstances - - allocate(plastic_none_sizePostResults(maxNinstance), source=0_pInt) - -end subroutine plastic_none_init - -end module plastic_none diff --git a/code/plastic_nonlocal.f90 b/code/plastic_nonlocal.f90 deleted file mode 100644 index 1922c08e2..000000000 --- a/code/plastic_nonlocal.f90 +++ /dev/null @@ -1,4031 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Christoph Kords, 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 -!> @brief material subroutine for plasticity including dislocation flux -!-------------------------------------------------------------------------------------------------- -module plastic_nonlocal - use prec, only: & - pReal, & - pInt - - implicit none - private - character(len=22), dimension(11), parameter, private :: & - BASICSTATES = ['rhoSglEdgePosMobile ', & - 'rhoSglEdgeNegMobile ', & - 'rhoSglScrewPosMobile ', & - 'rhoSglScrewNegMobile ', & - 'rhoSglEdgePosImmobile ', & - 'rhoSglEdgeNegImmobile ', & - 'rhoSglScrewPosImmobile', & - 'rhoSglScrewNegImmobile', & - 'rhoDipEdge ', & - 'rhoDipScrew ', & - 'accumulatedshear ' ] !< list of "basic" microstructural state variables that are independent from other state variables - - character(len=16), dimension(3), parameter, private :: & - DEPENDENTSTATES = ['rhoForest ', & - 'tauThreshold ', & - 'tauBack ' ] !< list of microstructural state variables that depend on other state variables - - character(len=20), dimension(6), parameter, private :: & - OTHERSTATES = ['velocityEdgePos ', & - 'velocityEdgeNeg ', & - 'velocityScrewPos ', & - 'velocityScrewNeg ', & - 'maxDipoleHeightEdge ', & - 'maxDipoleHeightScrew' ] !< list of other dependent state variables that are not updated by microstructure - - real(pReal), parameter, private :: & - KB = 1.38e-23_pReal !< Physical parameter, Boltzmann constant in J/Kelvin - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_nonlocal_sizeDotState, & !< number of dotStates = number of basic state variables - plastic_nonlocal_sizeDependentState, & !< number of dependent state variables - plastic_nonlocal_sizeState, & !< total number of state variables - plastic_nonlocal_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_nonlocal_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_nonlocal_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_nonlocal_Noutput !< number of outputs per instance of this plasticity - - integer(pInt), dimension(:,:), allocatable, private :: & - iGamma, & !< state indices for accumulated shear - iRhoF, & !< state indices for forest density - iTauF, & !< state indices for critical resolved shear stress - iTauB !< state indices for backstress - integer(pInt), dimension(:,:,:), allocatable, private :: & - iRhoU, & !< state indices for unblocked density - iRhoB, & !< state indices for blocked density - iRhoD, & !< state indices for dipole density - iV, & !< state indices for dislcation velocities - iD !< state indices for stable dipole height - - integer(pInt), dimension(:), allocatable, public, protected :: & - totalNslip !< total number of active slip systems for each instance - - integer(pInt), dimension(:,:), allocatable, private :: & - Nslip, & !< number of active slip systems for each family and instance - slipFamily, & !< lookup table relating active slip system to slip family for each instance - slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance - colinearSystem !< colinear system to the active slip system (only valid for fcc!) - - real(pReal), dimension(:), allocatable, private :: & - atomicVolume, & !< atomic volume - Dsd0, & !< prefactor for self-diffusion coefficient - selfDiffusionEnergy, & !< activation enthalpy for diffusion - aTolRho, & !< absolute tolerance for dislocation density in state integration - aTolShear, & !< absolute tolerance for accumulated shear in state integration - significantRho, & !< density considered significant - significantN, & !< number of dislocations considered significant - cutoffRadius, & !< cutoff radius for dislocation stress - doublekinkwidth, & !< width of a doubkle kink in multiples of the burgers vector length b - solidSolutionEnergy, & !< activation energy for solid solution in J - solidSolutionSize, & !< solid solution obstacle size in multiples of the burgers vector length - solidSolutionConcentration, & !< concentration of solid solution in atomic parts - pParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) - qParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) - viscosity, & !< viscosity for dislocation glide in Pa s - fattack, & !< attack frequency in Hz - rhoSglScatter, & !< standard deviation of scatter in initial dislocation density - surfaceTransmissivity, & !< transmissivity at free surface - grainboundaryTransmissivity, & !< transmissivity at grain boundary (identified by different texture) - CFLfactor, & !< safety factor for CFL flux condition - fEdgeMultiplication, & !< factor that determines how much edge dislocations contribute to multiplication (0...1) - rhoSglRandom, & - rhoSglRandomBinning, & - linetensionEffect, & - edgeJogFactor - - real(pReal), dimension(:,:), allocatable, private :: & - rhoSglEdgePos0, & !< initial edge_pos dislocation density per slip system for each family and instance - rhoSglEdgeNeg0, & !< initial edge_neg dislocation density per slip system for each family and instance - rhoSglScrewPos0, & !< initial screw_pos dislocation density per slip system for each family and instance - rhoSglScrewNeg0, & !< initial screw_neg dislocation density per slip system for each family and instance - rhoDipEdge0, & !< initial edge dipole dislocation density per slip system for each family and instance - rhoDipScrew0, & !< initial screw dipole dislocation density per slip system for each family and instance - lambda0PerSlipFamily, & !< mean free path prefactor for each family and instance - lambda0, & !< mean free path prefactor for each slip system and instance - burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each family and instance - burgers, & !< absolute length of burgers vector [m] for each slip system and instance - interactionSlipSlip !< coefficients for slip-slip interaction for each interaction type and instance - - real(pReal), dimension(:,:,:), allocatable, private :: & - minDipoleHeightPerSlipFamily, & !< minimum stable edge/screw dipole height for each family and instance - minDipoleHeight, & !< minimum stable edge/screw dipole height for each slip system and instance - peierlsStressPerSlipFamily, & !< Peierls stress (edge and screw) - peierlsStress, & !< Peierls stress (edge and screw) - forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance - forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance - interactionMatrixSlipSlip !< interaction matrix of the different slip systems for each instance - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - lattice2slip, & !< orthogonal transformation matrix from lattice coordinate system to slip coordinate system (passive rotation !!!) - rhoDotEdgeJogsOutput, & - sourceProbability - - real(pReal), dimension(:,:,:,:,:), allocatable, private :: & - rhoDotFluxOutput, & - rhoDotMultiplicationOutput, & - rhoDotSingle2DipoleGlideOutput, & - rhoDotAthermalAnnihilationOutput, & - rhoDotThermalAnnihilationOutput, & - nonSchmidProjection !< combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) - - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - compatibility !< slip system compatibility between me and my neighbors - - real(pReal), dimension(:,:), allocatable, private :: & - nonSchmidCoeff - - logical, dimension(:), allocatable, private :: & - shortRangeStressCorrection, & !< flag indicating the use of the short range stress correction by a excess density gradient term - probabilisticMultiplication - - enum, bind(c) - enumerator :: undefined_ID, & - rho_ID, & - delta_ID, & - rho_edge_ID, & - rho_screw_ID, & - rho_sgl_ID, & - delta_sgl_ID, & - rho_sgl_edge_ID, & - rho_sgl_edge_pos_ID, & - rho_sgl_edge_neg_ID, & - rho_sgl_screw_ID, & - rho_sgl_screw_pos_ID, & - rho_sgl_screw_neg_ID, & - rho_sgl_mobile_ID, & - rho_sgl_edge_mobile_ID, & - rho_sgl_edge_pos_mobile_ID, & - rho_sgl_edge_neg_mobile_ID, & - rho_sgl_screw_mobile_ID, & - rho_sgl_screw_pos_mobile_ID, & - rho_sgl_screw_neg_mobile_ID, & - rho_sgl_immobile_ID, & - rho_sgl_edge_immobile_ID, & - rho_sgl_edge_pos_immobile_ID, & - rho_sgl_edge_neg_immobile_ID, & - rho_sgl_screw_immobile_ID, & - rho_sgl_screw_pos_immobile_ID, & - rho_sgl_screw_neg_immobile_ID, & - rho_dip_ID, & - delta_dip_ID, & - rho_dip_edge_ID, & - rho_dip_screw_ID, & - excess_rho_ID, & - excess_rho_edge_ID, & - excess_rho_screw_ID, & - rho_forest_ID, & - shearrate_ID, & - resolvedstress_ID, & - resolvedstress_external_ID, & - resolvedstress_back_ID, & - resistance_ID, & - rho_dot_ID, & - rho_dot_sgl_ID, & - rho_dot_sgl_mobile_ID, & - rho_dot_dip_ID, & - rho_dot_gen_ID, & - rho_dot_gen_edge_ID, & - rho_dot_gen_screw_ID, & - rho_dot_sgl2dip_ID, & - rho_dot_sgl2dip_edge_ID, & - rho_dot_sgl2dip_screw_ID, & - rho_dot_ann_ath_ID, & - rho_dot_ann_the_ID, & - rho_dot_ann_the_edge_ID, & - rho_dot_ann_the_screw_ID, & - rho_dot_edgejogs_ID, & - rho_dot_flux_ID, & - rho_dot_flux_mobile_ID, & - rho_dot_flux_edge_ID, & - rho_dot_flux_screw_ID, & - velocity_edge_pos_ID, & - velocity_edge_neg_ID, & - velocity_screw_pos_ID, & - velocity_screw_neg_ID, & - slipdirectionx_ID, & - slipdirectiony_ID, & - slipdirectionz_ID, & - slipnormalx_ID, & - slipnormaly_ID, & - slipnormalz_ID, & - fluxdensity_edge_posx_ID, & - fluxdensity_edge_posy_ID, & - fluxdensity_edge_posz_ID, & - fluxdensity_edge_negx_ID, & - fluxdensity_edge_negy_ID, & - fluxdensity_edge_negz_ID, & - fluxdensity_screw_posx_ID, & - fluxdensity_screw_posy_ID, & - fluxdensity_screw_posz_ID, & - fluxdensity_screw_negx_ID, & - fluxdensity_screw_negy_ID, & - fluxdensity_screw_negz_ID, & - maximumdipoleheight_edge_ID, & - maximumdipoleheight_screw_ID, & - accumulatedshear_ID, & - dislocationstress_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_nonlocal_outputID !< ID of each post result output - - public :: & - plastic_nonlocal_init, & - plastic_nonlocal_stateInit, & - plastic_nonlocal_aTolState, & - plastic_nonlocal_microstructure, & - plastic_nonlocal_LpAndItsTangent, & - plastic_nonlocal_dotState, & - plastic_nonlocal_deltaState, & - plastic_nonlocal_updateCompatibility, & - plastic_nonlocal_postResults - - private :: & - plastic_nonlocal_kinetics, & - plastic_nonlocal_dislocationstress - - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_init(fileUnit) -use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) -use math, only: math_Mandel3333to66, & - math_Voigt66to3333, & - math_mul3x3, & - math_transpose33 -use IO, only: IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF -use debug, only: debug_level, & - debug_constitutive, & - debug_levelBasic -use mesh, only: mesh_NcpElems, & - mesh_maxNips, & - mesh_maxNipNeighbors -use material, only: phase_plasticity, & - homogenization_maxNgrains, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_NONLOCAL_label, & - PLASTICITY_NONLOCAL_ID, & - plasticState, & - MATERIAL_partPhase ,& - material_phase -use lattice -use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - -implicit none -integer(pInt), intent(in) :: fileUnit - -!*** local variables -integer(pInt), allocatable, dimension(:) :: chunkPos -integer(pInt) :: phase, & - maxNinstances, & - maxTotalNslip, & - f, & ! index of my slip family - instance, & ! index of my instance of this plasticity - l, & - ns, & ! short notation for total number of active slip systems for the current instance - o, & ! index of my output - s, & ! index of my slip system - s1, & ! index of my slip system - s2, & ! index of my slip system - it, & ! index of my interaction type - t, & ! index of dislocation type - c, & ! index of dislocation character - Nchunks_SlipSlip = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, & - Nchunks_nonSchmid = 0_pInt, & - mySize = 0_pInt ! to suppress warnings, safe as init is called only once - character(len=65536) :: & - tag = '', & - line = '' - - integer(pInt) :: sizeState, sizeDotState,sizeDependentState, sizeDeltaState - - - integer(pInt) :: NofMyPhase - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONLOCAL_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) - if (maxNinstances == 0) return ! we don't have to do anything if there's no instance for this constitutive law - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstances - -!*** memory allocation for global variables - -allocate(plastic_nonlocal_sizeDotState(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizeDependentState(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizeState(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizePostResults(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_sizePostResult(maxval(phase_Noutput), maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_Noutput(maxNinstances), source=0_pInt) -allocate(plastic_nonlocal_output(maxval(phase_Noutput), maxNinstances)) - plastic_nonlocal_output = '' -allocate(plastic_nonlocal_outputID(maxval(phase_Noutput), maxNinstances), source=undefined_ID) -allocate(Nslip(lattice_maxNslipFamily,maxNinstances), source=0_pInt) -allocate(slipFamily(lattice_maxNslip,maxNinstances), source=0_pInt) -allocate(slipSystemLattice(lattice_maxNslip,maxNinstances), source=0_pInt) -allocate(totalNslip(maxNinstances), source=0_pInt) -allocate(atomicVolume(maxNinstances), source=0.0_pReal) -allocate(Dsd0(maxNinstances), source=-1.0_pReal) -allocate(selfDiffusionEnergy(maxNinstances), source=0.0_pReal) -allocate(aTolRho(maxNinstances), source=0.0_pReal) -allocate(aTolShear(maxNinstances), source=0.0_pReal) -allocate(significantRho(maxNinstances), source=0.0_pReal) -allocate(significantN(maxNinstances), source=0.0_pReal) -allocate(cutoffRadius(maxNinstances), source=-1.0_pReal) -allocate(doublekinkwidth(maxNinstances), source=0.0_pReal) -allocate(solidSolutionEnergy(maxNinstances), source=0.0_pReal) -allocate(solidSolutionSize(maxNinstances), source=0.0_pReal) -allocate(solidSolutionConcentration(maxNinstances), source=0.0_pReal) -allocate(pParam(maxNinstances), source=1.0_pReal) -allocate(qParam(maxNinstances), source=1.0_pReal) -allocate(viscosity(maxNinstances), source=0.0_pReal) -allocate(fattack(maxNinstances), source=0.0_pReal) -allocate(rhoSglScatter(maxNinstances), source=0.0_pReal) -allocate(rhoSglRandom(maxNinstances), source=0.0_pReal) -allocate(rhoSglRandomBinning(maxNinstances), source=1.0_pReal) -allocate(surfaceTransmissivity(maxNinstances), source=1.0_pReal) -allocate(grainboundaryTransmissivity(maxNinstances), source=-1.0_pReal) -allocate(CFLfactor(maxNinstances), source=2.0_pReal) -allocate(fEdgeMultiplication(maxNinstances), source=0.0_pReal) -allocate(linetensionEffect(maxNinstances), source=0.0_pReal) -allocate(edgeJogFactor(maxNinstances), source=1.0_pReal) -allocate(shortRangeStressCorrection(maxNinstances), source=.false.) -allocate(probabilisticMultiplication(maxNinstances), source=.false.) - -allocate(rhoSglEdgePos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoSglEdgeNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoSglScrewPos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoSglScrewNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoDipEdge0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(rhoDipScrew0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) -allocate(burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) -allocate(lambda0PerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) -allocate(interactionSlipSlip(lattice_maxNinteraction,maxNinstances), source=0.0_pReal) -allocate(minDipoleHeightPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=-1.0_pReal) -allocate(peierlsStressPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=0.0_pReal) -allocate(nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstances), source=0.0_pReal) - - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through phases of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_SlipSlip = maxval(lattice_InteractionSlipSlip(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - endif - cycle - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then ! one of my phases. do not short-circuit here (.and. with next if statement). It's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('rho') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('delta') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('delta_sgl') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_sgl_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_pos_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_neg_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_pos_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_neg_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_pos_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_edge_neg_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_pos_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_sgl_screw_neg_immobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_immobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('delta_dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dip_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dip_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('excess_rho') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('excess_rho_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('excess_rho_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_forest') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_forest_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = shearrate_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_external') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_external_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_back') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_back_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resistance_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_gen') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_gen_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_gen_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl2dip') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl2dip_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_sgl2dip_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_ath') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_ath_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_the') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_the_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_ann_the_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_edgejogs') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_edgejogs_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux_mobile') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_mobile_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rho_dot_flux_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_edge_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_edge_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_screw_pos') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_pos_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_screw_neg') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_neg_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipdirection.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipdirection.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectiony_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipdirection.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipnormal.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipnormal.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormaly_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('slipnormal.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_pos.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_pos.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_pos.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_neg.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_neg.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_edge_neg.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_pos.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_pos.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_pos.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_neg.x') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negx_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_neg.y') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negy_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('fluxdensity_screw_neg.z') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negz_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('maximumdipoleheight_edge') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_edge_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('maximumdipoleheight_screw') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_screw_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear','accumulated_shear') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = accumulatedshear_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('dislocationstress') - plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt - plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = dislocationstress_ID - plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - case ('nslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do f = 1_pInt, Nchunks_SlipFamilies - Nslip(f,instance) = IO_intValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosgledgepos0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglEdgePos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosgledgeneg0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglEdgeNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosglscrewpos0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglScrewPos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhosglscrewneg0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoSglScrewNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhodipedge0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoDipEdge0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('rhodipscrew0') - do f = 1_pInt, Nchunks_SlipFamilies - rhoDipScrew0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('lambda0') - do f = 1_pInt, Nchunks_SlipFamilies - lambda0PerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case ('burgers') - do f = 1_pInt, Nchunks_SlipFamilies - burgersPerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('cutoffradius','r') - cutoffRadius(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('minimumdipoleheightedge','ddipminedge') - do f = 1_pInt, Nchunks_SlipFamilies - minDipoleHeightPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('minimumdipoleheightscrew','ddipminscrew') - do f = 1_pInt, Nchunks_SlipFamilies - minDipoleHeightPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('atomicvolume') - atomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('selfdiffusionprefactor','dsd0') - Dsd0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('selfdiffusionenergy','qsd') - selfDiffusionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('atol_rho','atol_density','absolutetolerancedensity','absolutetolerance_density') - aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('atol_shear','atol_plasticshear','atol_accumulatedshear','absolutetoleranceshear','absolutetolerance_shear') - aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('significantrho','significant_rho','significantdensity','significant_density') - significantRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('significantn','significant_n','significantdislocations','significant_dislcations') - significantN(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('interaction_slipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') - do it = 1_pInt,Nchunks_SlipSlip - interactionSlipSlip(it,instance) = IO_floatValue(line,chunkPos,1_pInt+it) - enddo - case('linetension','linetensioneffect','linetension_effect') - linetensionEffect(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('edgejog','edgejogs','edgejogeffect','edgejog_effect') - edgeJogFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('peierlsstressedge','peierlsstress_edge') - do f = 1_pInt, Nchunks_SlipFamilies - peierlsStressPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('peierlsstressscrew','peierlsstress_screw') - do f = 1_pInt, Nchunks_SlipFamilies - peierlsStressPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('doublekinkwidth') - doublekinkwidth(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('solidsolutionenergy') - solidSolutionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('solidsolutionsize') - solidSolutionSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('solidsolutionconcentration') - solidSolutionConcentration(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('p') - pParam(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('q') - qParam(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('viscosity','glideviscosity') - viscosity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('attackfrequency','fattack') - fattack(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('rhosglscatter') - rhoSglScatter(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('rhosglrandom') - rhoSglRandom(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('rhosglrandombinning') - rhoSglRandomBinning(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('surfacetransmissivity') - surfaceTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('grainboundarytransmissivity') - grainboundaryTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('cflfactor') - CFLfactor(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('fedgemultiplication','edgemultiplicationfactor','edgemultiplication') - fEdgeMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) - case('shortrangestresscorrection') - shortRangeStressCorrection(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_label//')') - do f = 1_pInt,Nchunks_nonSchmid - nonSchmidCoeff(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) - enddo - case('probabilisticmultiplication','randomsources','randommultiplication','discretesources') - probabilisticMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then - instance = phase_plasticityInstance(phase) - if (sum(Nslip(:,instance)) <= 0_pInt) & - call IO_error(211_pInt,ext_msg='Nslip ('//PLASTICITY_NONLOCAL_label//')') - do o = 1_pInt,maxval(phase_Noutput) - if(len(plastic_nonlocal_output(o,instance)) > 64_pInt) & - call IO_error(666_pInt) - enddo - do f = 1_pInt,lattice_maxNslipFamily - if (Nslip(f,instance) > 0_pInt) then - if (rhoSglEdgePos0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglEdgePos0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglEdgeNeg0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglEdgeNeg0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglScrewPos0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglScrewPos0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglScrewNeg0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglScrewNeg0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoDipEdge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoDipEdge0 ('//PLASTICITY_NONLOCAL_label//')') - if (rhoDipScrew0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoDipScrew0 ('//PLASTICITY_NONLOCAL_label//')') - if (burgersPerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='Burgers ('//PLASTICITY_NONLOCAL_label//')') - if (lambda0PerSlipFamily(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='lambda0 ('//PLASTICITY_NONLOCAL_label//')') - if (minDipoleHeightPerSlipFamily(f,1,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='minimumDipoleHeightEdge ('//PLASTICITY_NONLOCAL_label//')') - if (minDipoleHeightPerSlipFamily(f,2,instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='minimumDipoleHeightScrew ('//PLASTICITY_NONLOCAL_label//')') - if (peierlsStressPerSlipFamily(f,1,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='peierlsStressEdge ('//PLASTICITY_NONLOCAL_label//')') - if (peierlsStressPerSlipFamily(f,2,instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='peierlsStressScrew ('//PLASTICITY_NONLOCAL_label//')') - endif - enddo - if (any(interactionSlipSlip(1:maxval(lattice_interactionSlipSlip(:,:,phase)),instance) < 0.0_pReal)) & - call IO_error(211_pInt,ext_msg='interaction_SlipSlip ('//PLASTICITY_NONLOCAL_label//')') - if (linetensionEffect(instance) < 0.0_pReal .or. linetensionEffect(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='linetension ('//PLASTICITY_NONLOCAL_label//')') - if (edgeJogFactor(instance) < 0.0_pReal .or. edgeJogFactor(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='edgejog ('//PLASTICITY_NONLOCAL_label//')') - if (cutoffRadius(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='r ('//PLASTICITY_NONLOCAL_label//')') - if (atomicVolume(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='atomicVolume ('//PLASTICITY_NONLOCAL_label//')') - if (Dsd0(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='selfDiffusionPrefactor ('//PLASTICITY_NONLOCAL_label//')') - if (selfDiffusionEnergy(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='selfDiffusionEnergy ('//PLASTICITY_NONLOCAL_label//')') - if (aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='aTol_rho ('//PLASTICITY_NONLOCAL_label//')') - if (aTolShear(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='aTol_shear ('//PLASTICITY_NONLOCAL_label//')') - if (significantRho(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='significantRho ('//PLASTICITY_NONLOCAL_label//')') - if (significantN(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='significantN ('//PLASTICITY_NONLOCAL_label//')') - if (doublekinkwidth(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='doublekinkwidth ('//PLASTICITY_NONLOCAL_label//')') - if (solidSolutionEnergy(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='solidSolutionEnergy ('//PLASTICITY_NONLOCAL_label//')') - if (solidSolutionSize(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='solidSolutionSize ('//PLASTICITY_NONLOCAL_label//')') - if (solidSolutionConcentration(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='solidSolutionConcentration ('//PLASTICITY_NONLOCAL_label//')') - if (pParam(instance) <= 0.0_pReal .or. pParam(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='p ('//PLASTICITY_NONLOCAL_label//')') - if (qParam(instance) < 1.0_pReal .or. qParam(instance) > 2.0_pReal) & - call IO_error(211_pInt,ext_msg='q ('//PLASTICITY_NONLOCAL_label//')') - if (viscosity(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='viscosity ('//PLASTICITY_NONLOCAL_label//')') - if (fattack(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='attackFrequency ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglScatter(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglScatter ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglRandom(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglRandom ('//PLASTICITY_NONLOCAL_label//')') - if (rhoSglRandomBinning(instance) <= 0.0_pReal) & - call IO_error(211_pInt,ext_msg='rhoSglRandomBinning ('//PLASTICITY_NONLOCAL_label//')') - if (surfaceTransmissivity(instance) < 0.0_pReal .or. surfaceTransmissivity(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='surfaceTransmissivity ('//PLASTICITY_NONLOCAL_label//')') - if (grainboundaryTransmissivity(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='grainboundaryTransmissivity ('//PLASTICITY_NONLOCAL_label//')') - if (CFLfactor(instance) < 0.0_pReal) & - call IO_error(211_pInt,ext_msg='CFLfactor ('//PLASTICITY_NONLOCAL_label//')') - if (fEdgeMultiplication(instance) < 0.0_pReal .or. fEdgeMultiplication(instance) > 1.0_pReal) & - call IO_error(211_pInt,ext_msg='edgemultiplicationfactor ('//PLASTICITY_NONLOCAL_label//')') - - - !*** determine total number of active slip systems - Nslip(1:lattice_maxNslipFamily,instance) = min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase), & - Nslip(1:lattice_maxNslipFamily,instance) ) ! we can't use more slip systems per family than specified in lattice - totalNslip(instance) = sum(Nslip(1:lattice_maxNslipFamily,instance)) - endif myPhase -enddo sanityChecks - - -!*** allocation of variables whose size depends on the total number of active slip systems - -maxTotalNslip = maxval(totalNslip) - -allocate(iRhoU(maxTotalNslip,4,maxNinstances), source=0_pInt) -allocate(iRhoB(maxTotalNslip,4,maxNinstances), source=0_pInt) -allocate(iRhoD(maxTotalNslip,2,maxNinstances), source=0_pInt) -allocate(iV(maxTotalNslip,4,maxNinstances), source=0_pInt) -allocate(iD(maxTotalNslip,2,maxNinstances), source=0_pInt) -allocate(iGamma(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(iRhoF(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(iTauF(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(iTauB(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(burgers(maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(lambda0(maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(minDipoleHeight(maxTotalNslip,2,maxNinstances), source=-1.0_pReal) -allocate(forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(lattice2slip(1:3, 1:3, maxTotalNslip,maxNinstances), source=0.0_pReal) -allocate(sourceProbability(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=2.0_pReal) - -allocate(rhoDotFluxOutput(maxTotalNslip,8,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotMultiplicationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotSingle2DipoleGlideOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotAthermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotThermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(rhoDotEdgeJogsOutput(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) - -allocate(compatibility(2,maxTotalNslip,maxTotalNslip,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems), & - source=0.0_pReal) -allocate(peierlsStress(maxTotalNslip,2,maxNinstances), source=0.0_pReal) -allocate(colinearSystem(maxTotalNslip,maxNinstances), source=0_pInt) -allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - NofMyPhase=count(material_phase==phase) - myPhase2: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID .and. NofMyPhase/=0) then - instance = phase_plasticityInstance(phase) - !*** Inverse lookup of my slip system family and the slip system in lattice - - l = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily - do s = 1_pInt,Nslip(f,instance) - l = l + 1_pInt - slipFamily(l,instance) = f - slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt, phase)) + s - enddo; enddo - - - !*** determine size of state array - - ns = totalNslip(instance) - - sizeDotState = int(size(BASICSTATES),pInt) * ns - sizeDependentState = int(size(DEPENDENTSTATES),pInt) * ns - sizeState = sizeDotState + sizeDependentState & - + int(size(OTHERSTATES),pInt) * ns - sizeDeltaState = sizeDotState - - !*** determine indices to state array - - l = 0_pInt - do t = 1_pInt,4_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iRhoU(s,t,instance) = l - enddo - enddo - do t = 1_pInt,4_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iRhoB(s,t,instance) = l - enddo - enddo - do c = 1_pInt,2_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iRhoD(s,c,instance) = l - enddo - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iGamma(s,instance) = l - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iRhoF(s,instance) = l - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iTauF(s,instance) = l - enddo - do s = 1_pInt,ns - l = l + 1_pInt - iTauB(s,instance) = l - enddo - do t = 1_pInt,4_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iV(s,t,instance) = l - enddo - enddo - do c = 1_pInt,2_pInt - do s = 1_pInt,ns - l = l + 1_pInt - iD(s,c,instance) = l - enddo - enddo - if (iD(ns,2,instance) /= sizeState) & ! check if last index is equal to size of state - call IO_error(0_pInt, ext_msg = 'state indices not properly set ('//PLASTICITY_NONLOCAL_label//')') - - - !*** determine size of postResults array - - outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) - select case(plastic_nonlocal_outputID(o,instance)) - case( rho_ID, & - delta_ID, & - rho_edge_ID, & - rho_screw_ID, & - rho_sgl_ID, & - delta_sgl_ID, & - rho_sgl_edge_ID, & - rho_sgl_edge_pos_ID, & - rho_sgl_edge_neg_ID, & - rho_sgl_screw_ID, & - rho_sgl_screw_pos_ID, & - rho_sgl_screw_neg_ID, & - rho_sgl_mobile_ID, & - rho_sgl_edge_mobile_ID, & - rho_sgl_edge_pos_mobile_ID, & - rho_sgl_edge_neg_mobile_ID, & - rho_sgl_screw_mobile_ID, & - rho_sgl_screw_pos_mobile_ID, & - rho_sgl_screw_neg_mobile_ID, & - rho_sgl_immobile_ID, & - rho_sgl_edge_immobile_ID, & - rho_sgl_edge_pos_immobile_ID, & - rho_sgl_edge_neg_immobile_ID, & - rho_sgl_screw_immobile_ID, & - rho_sgl_screw_pos_immobile_ID, & - rho_sgl_screw_neg_immobile_ID, & - rho_dip_ID, & - delta_dip_ID, & - rho_dip_edge_ID, & - rho_dip_screw_ID, & - excess_rho_ID, & - excess_rho_edge_ID, & - excess_rho_screw_ID, & - rho_forest_ID, & - shearrate_ID, & - resolvedstress_ID, & - resolvedstress_external_ID, & - resolvedstress_back_ID, & - resistance_ID, & - rho_dot_ID, & - rho_dot_sgl_ID, & - rho_dot_sgl_mobile_ID, & - rho_dot_dip_ID, & - rho_dot_gen_ID, & - rho_dot_gen_edge_ID, & - rho_dot_gen_screw_ID, & - rho_dot_sgl2dip_ID, & - rho_dot_sgl2dip_edge_ID, & - rho_dot_sgl2dip_screw_ID, & - rho_dot_ann_ath_ID, & - rho_dot_ann_the_ID, & - rho_dot_ann_the_edge_ID, & - rho_dot_ann_the_screw_ID, & - rho_dot_edgejogs_ID, & - rho_dot_flux_ID, & - rho_dot_flux_mobile_ID, & - rho_dot_flux_edge_ID, & - rho_dot_flux_screw_ID, & - velocity_edge_pos_ID, & - velocity_edge_neg_ID, & - velocity_screw_pos_ID, & - velocity_screw_neg_ID, & - slipdirectionx_ID, & - slipdirectiony_ID, & - slipdirectionz_ID, & - slipnormalx_ID, & - slipnormaly_ID, & - slipnormalz_ID, & - fluxdensity_edge_posx_ID, & - fluxdensity_edge_posy_ID, & - fluxdensity_edge_posz_ID, & - fluxdensity_edge_negx_ID, & - fluxdensity_edge_negy_ID, & - fluxdensity_edge_negz_ID, & - fluxdensity_screw_posx_ID, & - fluxdensity_screw_posy_ID, & - fluxdensity_screw_posz_ID, & - fluxdensity_screw_negx_ID, & - fluxdensity_screw_negy_ID, & - fluxdensity_screw_negz_ID, & - maximumdipoleheight_edge_ID, & - maximumdipoleheight_screw_ID, & - accumulatedshear_ID ) - mySize = totalNslip(instance) - case(dislocationstress_ID) - mySize = 6_pInt - case default - end select - - if (mySize > 0_pInt) then ! any meaningful output found - plastic_nonlocal_sizePostResult(o,instance) = mySize - plastic_nonlocal_sizePostResults(instance) = plastic_nonlocal_sizePostResults(instance) + mySize - endif - enddo outputsLoop - - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_nonlocal_sizePostResults(instance) - plasticState(phase)%nonlocal = .true. - plasticState(phase)%nSlip = totalNslip(instance) - plasticState(phase)%nTwin = 0_pInt - plasticState(phase)%nTrans= 0_pInt - allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) - - do s1 = 1_pInt,ns - f = slipFamily(s1,instance) - - !*** burgers vector, mean free path prefactor and minimum dipole distance for each slip system - - burgers(s1,instance) = burgersPerSlipFamily(f,instance) - lambda0(s1,instance) = lambda0PerSlipFamily(f,instance) - minDipoleHeight(s1,1:2,instance) = minDipoleHeightPerSlipFamily(f,1:2,instance) - peierlsStress(s1,1:2,instance) = peierlsStressPerSlipFamily(f,1:2,instance) - - do s2 = 1_pInt,ns - - !*** calculation of forest projections for edge and screw dislocations. s2 acts as forest for s1 - - forestProjectionEdge(s1,s2,instance) & - = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & - lattice_st(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of edge dislocations is the projection of (t = b x n) onto the slip normal of the respective slip plane - - forestProjectionScrew(s1,s2,instance) & - = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & - lattice_sd(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of screw dislocations is the projection of b onto the slip normal of the respective splip plane - - !*** calculation of interaction matrices - - interactionMatrixSlipSlip(s1,s2,instance) & - = interactionSlipSlip(lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & - slipSystemLattice(s2,instance), & - phase), instance) - - !*** colinear slip system (only makes sense for fcc like it is defined here) - - if (lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & - slipSystemLattice(s2,instance), & - phase) == 3_pInt) then - colinearSystem(s1,instance) = s2 - endif - - enddo - - !*** rotation matrix from lattice configuration to slip system - - lattice2slip(1:3,1:3,s1,instance) & - = math_transpose33( reshape([ lattice_sd(1:3, slipSystemLattice(s1,instance), phase), & - -lattice_st(1:3, slipSystemLattice(s1,instance), phase), & - lattice_sn(1:3, slipSystemLattice(s1,instance), phase)], [3,3])) - enddo - - - !*** combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) - !* four types t: - !* 1) positive screw at positive resolved stress - !* 2) positive screw at negative resolved stress - !* 3) negative screw at positive resolved stress - !* 4) negative screw at negative resolved stress - - do s = 1_pInt,ns - do l = 1_pInt,lattice_NnonSchmid(phase) - nonSchmidProjection(1:3,1:3,1,s,instance) = nonSchmidProjection(1:3,1:3,1,s,instance) & - + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l,slipSystemLattice(s,instance),phase) - nonSchmidProjection(1:3,1:3,2,s,instance) = nonSchmidProjection(1:3,1:3,2,s,instance) & - + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l+1,slipSystemLattice(s,instance),phase) - enddo - nonSchmidProjection(1:3,1:3,3,s,instance) = -nonSchmidProjection(1:3,1:3,2,s,instance) - nonSchmidProjection(1:3,1:3,4,s,instance) = -nonSchmidProjection(1:3,1:3,1,s,instance) - forall (t = 1:4) & - nonSchmidProjection(1:3,1:3,t,s,instance) = nonSchmidProjection(1:3,1:3,t,s,instance) & - + lattice_Sslip(1:3,1:3,1,slipSystemLattice(s,instance),phase) - enddo - - call plastic_nonlocal_aTolState(phase,instance) - endif myPhase2 - - enddo initializeInstances - -end subroutine plastic_nonlocal_init - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- - -subroutine plastic_nonlocal_stateInit() -use IO, only: IO_error -use lattice, only: lattice_maxNslipFamily -use math, only: math_sampleGaussVar -use mesh, only: mesh_ipVolume, & - mesh_NcpElems, & - mesh_element, & - FE_Nips, & - FE_geomtype -use material, only: material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticity ,& - PLASTICITY_NONLOCAL_ID -implicit none - -integer(pInt) :: e, & - i, & - ns, & ! short notation for total number of active slip systems - f, & ! index of lattice family - from, & - upto, & - s, & ! index of slip system - t, & - j, & - instance, & - maxNinstances -real(pReal), dimension(2) :: noise -real(pReal), dimension(4) :: rnd -real(pReal) meanDensity, & - totalVolume, & - densityBinning, & - minimumIpVolume - -maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) - -do instance = 1_pInt,maxNinstances - ns = totalNslip(instance) - - ! randomly distribute dislocation segments on random slip system and of random type in the volume - if (rhoSglRandom(instance) > 0.0_pReal) then - - ! get the total volume of the instance - - minimumIpVolume = huge(1.0_pReal) - totalVolume = 0.0_pReal - do e = 1_pInt,mesh_NcpElems - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & - .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then - totalVolume = totalVolume + mesh_ipVolume(i,e) - minimumIpVolume = min(minimumIpVolume, mesh_ipVolume(i,e)) - endif - enddo - enddo - densityBinning = rhoSglRandomBinning(instance) / minimumIpVolume ** (2.0_pReal / 3.0_pReal) - - ! subsequently fill random ips with dislocation segments until we reach the desired overall density - - meanDensity = 0.0_pReal - do while(meanDensity < rhoSglRandom(instance)) - call random_number(rnd) - e = nint(rnd(1)*real(mesh_NcpElems,pReal)+0.5_pReal,pInt) - i = nint(rnd(2)*real(FE_Nips(FE_geomtype(mesh_element(2,e))),pReal)+0.5_pReal,pInt) - if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & - .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then - s = nint(rnd(3)*real(ns,pReal)+0.5_pReal,pInt) - t = nint(rnd(4)*4.0_pReal+0.5_pReal,pInt) - meanDensity = meanDensity + densityBinning * mesh_ipVolume(i,e) / totalVolume - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) = & - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) & - + densityBinning - endif - enddo - ! homogeneous distribution of density with some noise - else - do e = 1_pInt,mesh_NcpElems - do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) - if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & - .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then - do f = 1_pInt,lattice_maxNslipFamily - from = 1_pInt + sum(Nslip(1:f-1_pInt,instance)) - upto = sum(Nslip(1:f,instance)) - do s = from,upto - do j = 1_pInt,2_pInt - noise(j) = math_sampleGaussVar(0.0_pReal, rhoSglScatter(instance)) - enddo - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,1,instance),phasememberAt(1,i,e)) = & - rhoSglEdgePos0(f,instance) + noise(1) - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,2,instance),phasememberAt(1,i,e)) = & - rhoSglEdgeNeg0(f,instance) + noise(1) - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,3,instance),phasememberAt(1,i,e)) = & - rhoSglScrewPos0(f,instance) + noise(2) - plasticState(phaseAt(1,i,e))%state0(iRhoU(s,4,instance),phasememberAt(1,i,e)) = & - rhoSglScrewNeg0(f,instance) + noise(2) - enddo - plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,1,instance),phasememberAt(1,i,e)) = & - rhoDipEdge0(f,instance) - plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,2,instance),phasememberAt(1,i,e)) = & - rhoDipScrew0(f,instance) - enddo - endif - enddo - enddo - endif -enddo - -end subroutine plastic_nonlocal_stateInit - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - integer(pInt) :: & - ns, & - t, c - - ns = totalNslip(instance) - forall (t = 1_pInt:4_pInt) - plasticState(ph)%aTolState(iRhoU(1:ns,t,instance)) = aTolRho(instance) - plasticState(ph)%aTolState(iRhoB(1:ns,t,instance)) = aTolRho(instance) - end forall - forall (c = 1_pInt:2_pInt) & - plasticState(ph)%aTolState(iRhoD(1:ns,c,instance)) = aTolRho(instance) - - plasticState(ph)%aTolState(iGamma(1:ns,instance)) = aTolShear(instance) - -end subroutine plastic_nonlocal_aTolState - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates quantities characterizing the microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_microstructure(Fe, Fp, ip, el) -use IO, only: & - IO_error -use math, only: & - pi, & - math_mul33x3, & - math_mul3x3, & - math_inv33, & - math_transpose33 -use debug, only: & - debug_level, & - debug_constitutive, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use mesh, only: & - mesh_element, & - mesh_ipNeighborhood, & - mesh_ipCoordinates, & - mesh_ipVolume, & - mesh_ipAreaNormal, & - mesh_ipArea, & - FE_NipNeighbors, & - mesh_maxNipNeighbors, & - FE_geomtype, & - FE_celltype -use material, only: & - material_phase, & - phase_localPlasticity, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance -use lattice, only: & - lattice_sd, & - lattice_st, & - lattice_mu, & - lattice_nu, & - lattice_structure, & - LATTICE_bcc_ID, & - LATTICE_fcc_ID - -implicit none - -integer(pInt), intent(in) :: ip, & ! current integration point - el ! current element -real(pReal), dimension(3,3), intent(in) :: & - Fe, & ! elastic deformation gradient - Fp ! elastic deformation gradient - - integer(pInt) :: & - ph, & !< phase - of, & !< offset - np, & !< neighbor phase - no !< nieghbor offset - -integer(pInt) neighbor_el, & ! element number of neighboring material point - neighbor_ip, & ! integration point of neighboring material point - instance, & ! my instance of this plasticity - neighbor_instance, & ! instance of this plasticity of neighboring material point - neighbor_phase, & - ns, & ! total number of active slip systems at my material point - neighbor_ns, & ! total number of active slip systems at neighboring material point - c, & ! index of dilsocation character (edge, screw) - s, & ! slip system index - t, & ! index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) - dir, & - n, & - nRealNeighbors ! number of really existing neighbors -integer(pInt), dimension(2) :: neighbors -real(pReal) FVsize, & - correction, & - myRhoForest -real(pReal), dimension(2) :: rhoExcessGradient, & - rhoExcessGradient_over_rho, & - rhoTotal -real(pReal), dimension(3) :: rhoExcessDifferences, & - normal_latticeConf -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoForest, & ! forest dislocation density - tauBack, & ! back stress from pileup on same slip system - tauThreshold ! threshold shear stress -real(pReal), dimension(3,3) :: invFe, & ! inverse of elastic deformation gradient - invFp, & ! inverse of plastic deformation gradient - connections, & - invConnections -real(pReal), dimension(3,mesh_maxNipNeighbors) :: & - connection_latticeConf -real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoExcess -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - rhoDip ! dipole dislocation density (edge, screw) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))), & - totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - myInteractionMatrix ! corrected slip interaction matrix -real(pReal), dimension(2,maxval(totalNslip),mesh_maxNipNeighbors) :: & - neighbor_rhoExcess, & ! excess density at neighboring material point - neighbor_rhoTotal ! total density at neighboring material point -real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - m ! direction of dislocation motion - -ph = phaseAt(1,ip,el) -of = phasememberAt(1,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - -!*** get basic states - - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities - -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal -where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoDip) < significantRho(instance)) & - rhoDip = 0.0_pReal - -!*** calculate the forest dislocation density -!*** (= projection of screw and edge dislocations) - -forall (s = 1_pInt:ns) & - rhoForest(s) = dot_product((sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1)), & - forestProjectionEdge(s,1:ns,instance)) & - + dot_product((sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2)), & - forestProjectionScrew(s,1:ns,instance)) - - -!*** calculate the threshold shear stress for dislocation slip -!*** coefficients are corrected for the line tension effect -!*** (see Kubin,Devincre,Hoc; 2008; Modeling dislocation storage rates and mean free paths in face-centered cubic crystals) - -myInteractionMatrix = 0.0_pReal -myInteractionMatrix(1:ns,1:ns) = interactionMatrixSlipSlip(1:ns,1:ns,instance) -if (lattice_structure(ph) == LATTICE_bcc_ID .or. lattice_structure(ph) == LATTICE_fcc_ID) then ! only fcc and bcc - do s = 1_pInt,ns - myRhoForest = max(rhoForest(s),significantRho(instance)) - correction = ( 1.0_pReal - linetensionEffect(instance) & - + linetensionEffect(instance) & - * log(0.35_pReal * burgers(s,instance) * sqrt(myRhoForest)) & - / log(0.35_pReal * burgers(s,instance) * 1e6_pReal)) ** 2.0_pReal - myInteractionMatrix(s,1:ns) = correction * myInteractionMatrix(s,1:ns) - enddo -endif -forall (s = 1_pInt:ns) & - tauThreshold(s) = lattice_mu(ph) * burgers(s,instance) & - * sqrt(dot_product((sum(abs(rhoSgl),2) + sum(abs(rhoDip),2)), myInteractionMatrix(s,1:ns))) - - -!*** calculate the dislocation stress of the neighboring excess dislocation densities -!*** zero for material points of local plasticity - -tauBack = 0.0_pReal - -if (.not. phase_localPlasticity(ph) .and. shortRangeStressCorrection(instance)) then - invFe = math_inv33(Fe) - invFp = math_inv33(Fp) - rhoExcess(1,1:ns) = rhoSgl(1:ns,1) - rhoSgl(1:ns,2) - rhoExcess(2,1:ns) = rhoSgl(1:ns,3) - rhoSgl(1:ns,4) - FVsize = mesh_ipVolume(ip,el) ** (1.0_pReal/3.0_pReal) - - !* loop through my neighborhood and get the connection vectors (in lattice frame) and the excess densities - - nRealNeighbors = 0_pInt - neighbor_rhoTotal = 0.0_pReal - do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) - neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - np = phaseAt(1,neighbor_ip,neighbor_el) - no = phasememberAt(1,neighbor_ip,neighbor_el) - if (neighbor_el > 0 .and. neighbor_ip > 0) then - neighbor_phase = material_phase(1,neighbor_ip,neighbor_el) - neighbor_instance = phase_plasticityInstance(neighbor_phase) - neighbor_ns = totalNslip(neighbor_instance) - if (.not. phase_localPlasticity(neighbor_phase) & - .and. neighbor_instance == instance) then ! same instance should be same structure - if (neighbor_ns == ns) then - nRealNeighbors = nRealNeighbors + 1_pInt - forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - - neighbor_rhoExcess(c,s,n) = & - max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles - - max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) ! negative mobiles - neighbor_rhoTotal(c,s,n) = & - max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles - + max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) & ! negative mobiles - + abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads - + abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance), no)) & ! negative deads - + max(plasticState(np)%state(iRhoD(s,c,neighbor_instance), no), 0.0_pReal) ! dipoles - - endforall - connection_latticeConf(1:3,n) = & - math_mul33x3(invFe, mesh_ipCoordinates(1:3,neighbor_ip,neighbor_el) & - - mesh_ipCoordinates(1:3,ip,el)) - normal_latticeConf = math_mul33x3(math_transpose33(invFp), mesh_ipAreaNormal(1:3,n,ip,el)) - if (math_mul3x3(normal_latticeConf,connection_latticeConf(1:3,n)) < 0.0_pReal) then ! neighboring connection points in opposite direction to face normal: must be periodic image - connection_latticeConf(1:3,n) = normal_latticeConf * mesh_ipVolume(ip,el) & - / mesh_ipArea(n,ip,el) ! instead take the surface normal scaled with the diameter of the cell - endif - else - ! different number of active slip systems - call IO_error(-1_pInt,ext_msg='different number of active slip systems in neighboring IPs of same crystal structure') - endif - else - ! local neighbor or different lattice structure or different constitution instance -> use central values instead - connection_latticeConf(1:3,n) = 0.0_pReal - neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess - endif - else - ! free surface -> use central values instead - connection_latticeConf(1:3,n) = 0.0_pReal - neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess - endif - enddo - - - !* loop through the slip systems and calculate the dislocation gradient by - !* 1. interpolation of the excess density in the neighorhood - !* 2. interpolation of the dead dislocation density in the central volume - - m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) - m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) - - do s = 1_pInt,ns - - !* gradient from interpolation of neighboring excess density - - do c = 1_pInt,2_pInt - do dir = 1_pInt,3_pInt - neighbors(1) = 2_pInt * dir - 1_pInt - neighbors(2) = 2_pInt * dir - connections(dir,1:3) = connection_latticeConf(1:3,neighbors(1)) & - - connection_latticeConf(1:3,neighbors(2)) - rhoExcessDifferences(dir) = neighbor_rhoExcess(c,s,neighbors(1)) & - - neighbor_rhoExcess(c,s,neighbors(2)) - enddo - invConnections = math_inv33(connections) - if (all(abs(invConnections) <= tiny(0.0_pReal))) & ! check for failed in version (math_inv33 returns 0) and avoid floating point equality comparison - call IO_error(-1_pInt,ext_msg='back stress calculation: inversion error') - rhoExcessGradient(c) = math_mul3x3(m(1:3,s,c), & - math_mul33x3(invConnections,rhoExcessDifferences)) - enddo - - !* plus gradient from deads - - do t = 1_pInt,4_pInt - c = (t - 1_pInt) / 2_pInt + 1_pInt - rhoExcessGradient(c) = rhoExcessGradient(c) + rhoSgl(s,t+4_pInt) / FVsize - enddo - - !* normalized with the total density - - rhoExcessGradient_over_rho = 0.0_pReal - forall (c = 1_pInt:2_pInt) & - rhoTotal(c) = (sum(abs(rhoSgl(s,[2*c-1,2*c,2*c+3,2*c+4]))) + rhoDip(s,c) & - + sum(neighbor_rhoTotal(c,s,:))) / real(1_pInt + nRealNeighbors,pReal) - forall (c = 1_pInt:2_pInt, rhoTotal(c) > 0.0_pReal) & - rhoExcessGradient_over_rho(c) = rhoExcessGradient(c) / rhoTotal(c) - - !* gives the local stress correction when multiplied with a factor - - tauBack(s) = - lattice_mu(ph) * burgers(s,instance) / (2.0_pReal * pi) & - * (rhoExcessGradient_over_rho(1) / (1.0_pReal - lattice_nu(ph)) & - + rhoExcessGradient_over_rho(2)) - - enddo -endif - - -!*** set dependent states -plasticState(ph)%state(iRhoF(1:ns,instance),of) = rhoForest -plasticState(ph)%state(iTauF(1:ns,instance),of) = tauThreshold -plasticState(ph)%state(iTauB(1:ns,instance),of) = tauBack - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_microstructure at el ip ',el,ip - write(6,'(a,/,12x,12(e10.3,1x))') '<< CONST >> rhoForest', rhoForest - write(6,'(a,/,12x,12(f10.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold/1e6 - write(6,'(a,/,12x,12(f10.5,1x),/)') '<< CONST >> tauBack / MPa', tauBack/1e6 - endif -#endif - -end subroutine plastic_nonlocal_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates kinetics -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_kinetics(v, dv_dtau, dv_dtauNS, tau, tauNS, & - tauThreshold, c, Temperature, ip, el) - -use debug, only: debug_level, & - debug_constitutive, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use material, only: material_phase, & - phase_plasticityInstance - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el, & !< current element number - c !< dislocation character (1:edge, 2:screw) -real(pReal), intent(in) :: Temperature !< temperature -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & - intent(in) :: tau, & !< resolved external shear stress (without non Schmid effects) - tauNS, & !< resolved external shear stress (including non Schmid effects) - tauThreshold !< threshold shear stress - -!*** output variables -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & - intent(out) :: v, & !< velocity - dv_dtau, & !< velocity derivative with respect to resolved shear stress (without non Schmid contributions) - dv_dtauNS !< velocity derivative with respect to resolved shear stress (including non Schmid contributions) - -!*** local variables -integer(pInt) :: instance, & !< current instance of this plasticity - ns, & !< short notation for the total number of active slip systems - s !< index of my current slip system -real(pReal) tauRel_P, & - tauRel_S, & - tauEff, & !< effective shear stress - tPeierls, & !< waiting time in front of a peierls barriers - tSolidSolution, & !< waiting time in front of a solid solution obstacle - vViscous, & !< viscous glide velocity - dtPeierls_dtau, & !< derivative with respect to resolved shear stress - dtSolidSolution_dtau, & !< derivative with respect to resolved shear stress - meanfreepath_S, & !< mean free travel distance for dislocations between two solid solution obstacles - meanfreepath_P, & !< mean free travel distance for dislocations between two Peierls barriers - jumpWidth_P, & !< depth of activated area - jumpWidth_S, & !< depth of activated area - activationLength_P, & !< length of activated dislocation line - activationLength_S, & !< length of activated dislocation line - activationVolume_P, & !< volume that needs to be activated to overcome barrier - activationVolume_S, & !< volume that needs to be activated to overcome barrier - activationEnergy_P, & !< energy that is needed to overcome barrier - activationEnergy_S, & !< energy that is needed to overcome barrier - criticalStress_P, & !< maximum obstacle strength - criticalStress_S, & !< maximum obstacle strength - mobility !< dislocation mobility - - -instance = phase_plasticityInstance(material_phase(1_pInt,ip,el)) -ns = totalNslip(instance) - -v = 0.0_pReal -dv_dtau = 0.0_pReal -dv_dtauNS = 0.0_pReal - - -if (Temperature > 0.0_pReal) then - do s = 1_pInt,ns - if (abs(tau(s)) > tauThreshold(s)) then - - !* Peierls contribution - !* Effective stress includes non Schmid constributions - !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity - - tauEff = max(0.0_pReal, abs(tauNS(s)) - tauThreshold(s)) ! ensure that the effective stress is positive - meanfreepath_P = burgers(s,instance) - jumpWidth_P = burgers(s,instance) - activationLength_P = doublekinkwidth(instance) * burgers(s,instance) - activationVolume_P = activationLength_P * jumpWidth_P * burgers(s,instance) - criticalStress_P = peierlsStress(s,c,instance) - activationEnergy_P = criticalStress_P * activationVolume_P - tauRel_P = min(1.0_pReal, tauEff / criticalStress_P) ! ensure that the activation probability cannot become greater than one - tPeierls = 1.0_pReal / fattack(instance) & - * exp(activationEnergy_P / (KB * Temperature) & - * (1.0_pReal - tauRel_P**pParam(instance))**qParam(instance)) - if (tauEff < criticalStress_P) then - dtPeierls_dtau = tPeierls * pParam(instance) * qParam(instance) * activationVolume_P / (KB * Temperature) & - * (1.0_pReal - tauRel_P**pParam(instance))**(qParam(instance)-1.0_pReal) & - * tauRel_P**(pParam(instance)-1.0_pReal) - else - dtPeierls_dtau = 0.0_pReal - endif - - - !* Contribution from solid solution strengthening - !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity - - tauEff = abs(tau(s)) - tauThreshold(s) - meanfreepath_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) - jumpWidth_S = solidSolutionSize(instance) * burgers(s,instance) - activationLength_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) - activationVolume_S = activationLength_S * jumpWidth_S * burgers(s,instance) - activationEnergy_S = solidSolutionEnergy(instance) - criticalStress_S = activationEnergy_S / activationVolume_S - tauRel_S = min(1.0_pReal, tauEff / criticalStress_S) ! ensure that the activation probability cannot become greater than one - tSolidSolution = 1.0_pReal / fattack(instance) & - * exp(activationEnergy_S / (KB * Temperature) & - * (1.0_pReal - tauRel_S**pParam(instance))**qParam(instance)) - if (tauEff < criticalStress_S) then - dtSolidSolution_dtau = tSolidSolution * pParam(instance) * qParam(instance) & - * activationVolume_S / (KB * Temperature) & - * (1.0_pReal - tauRel_S**pParam(instance))**(qParam(instance)-1.0_pReal) & - * tauRel_S**(pParam(instance)-1.0_pReal) - else - dtSolidSolution_dtau = 0.0_pReal - endif - - - !* viscous glide velocity - - tauEff = abs(tau(s)) - tauThreshold(s) - mobility = burgers(s,instance) / viscosity(instance) - vViscous = mobility * tauEff - - - !* Mean velocity results from waiting time at peierls barriers and solid solution obstacles with respective meanfreepath of - !* free flight at glide velocity in between. - !* adopt sign from resolved stress - - v(s) = sign(1.0_pReal,tau(s)) & - / (tPeierls / meanfreepath_P + tSolidSolution / meanfreepath_S + 1.0_pReal / vViscous) - dv_dtau(s) = v(s) * v(s) * (dtSolidSolution_dtau / meanfreepath_S & - + mobility / (vViscous * vViscous)) - dv_dtauNS(s) = v(s) * v(s) * dtPeierls_dtau / meanfreepath_P - endif - enddo -endif - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_kinetics at el ip',el,ip - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold / 1e6_pReal - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tau / MPa', tau / 1e6_pReal - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauNS / MPa', tauNS / 1e6_pReal - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> v / 1e-3m/s', v * 1e3 - write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtau', dv_dtau - write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtauNS', dv_dtauNS - endif -#endif - -end subroutine plastic_nonlocal_kinetics - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_LpAndItsTangent(Lp, dLp_dTstar99, Tstar_v, Temperature, ip, el) - -use math, only: math_Plain3333to99, & - math_mul6x6, & - math_mul33xx33, & - math_Mandel6to33 -use debug, only: debug_level, & - debug_constitutive, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use material, only: material_phase, & - plasticState, & - phaseAt, phasememberAt,& - phase_plasticityInstance -use lattice, only: lattice_Sslip, & - lattice_Sslip_v, & - lattice_NnonSchmid -use mesh, only: mesh_ipVolume - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el !< current element number -real(pReal), intent(in) :: Temperature !< temperature -real(pReal), dimension(6), intent(in) :: Tstar_v !< 2nd Piola-Kirchhoff stress in Mandel notation - - -!*** output variables -real(pReal), dimension(3,3), intent(out) :: Lp !< plastic velocity gradient -real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 !< derivative of Lp with respect to Tstar (9x9 matrix) - -!*** local variables -integer(pInt) instance, & !< current instance of this plasticity - ns, & !< short notation for the total number of active slip systems - i, & - j, & - k, & - l, & - ph, & !phase number - of, & !offset - t, & !< dislocation type - s, & !< index of my current slip system - sLattice !< index of my current slip system according to lattice order -real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 !< derivative of Lp with respect to Tstar (3x3x3x3 matrix) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl !< single dislocation densities (including blocked) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - v, & !< velocity - tauNS, & !< resolved shear stress including non Schmid and backstress terms - dv_dtau, & !< velocity derivative with respect to the shear stress - dv_dtauNS !< velocity derivative with respect to the shear stress -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - tau, & !< resolved shear stress including backstress terms - gdotTotal, & !< shear rate - tauBack, & !< back stress from dislocation gradients on same slip system - tauThreshold !< threshold shear stress -!*** shortcut for mapping -ph = phaseAt(1_pInt,ip,el) -of = phasememberAt(1_pInt,ip,el) - -!*** initialize local variables - -Lp = 0.0_pReal -dLp_dTstar3333 = 0.0_pReal - -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - - -!*** shortcut to state variables - - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - - rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) -endforall -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal - -tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) -tauThreshold = plasticState(ph)%state(iTauF(1:ns,instance),of) - - -!*** get resolved shear stress -!*** for screws possible non-schmid contributions are also taken into account - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) - tauNS(s,1) = tau(s) - tauNS(s,2) = tau(s) - if (tau(s) > 0.0_pReal) then - tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,1,s,instance)) - tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,3,s,instance)) - else - tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,2,s,instance)) - tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,4,s,instance)) - endif -enddo -forall (t = 1_pInt:4_pInt) & - tauNS(1:ns,t) = tauNS(1:ns,t) + tauBack ! add backstress -tau = tau + tauBack ! add backstress - - -!*** get dislocation velocity and its tangent and store the velocity in the state array - -! edges -call plastic_nonlocal_kinetics(v(1:ns,1), dv_dtau(1:ns,1), dv_dtauNS(1:ns,1), & - tau(1:ns), tauNS(1:ns,1), tauThreshold(1:ns), & - 1_pInt, Temperature, ip, el) -v(1:ns,2) = v(1:ns,1) -dv_dtau(1:ns,2) = dv_dtau(1:ns,1) -dv_dtauNS(1:ns,2) = dv_dtauNS(1:ns,1) - -!screws -if (lattice_NnonSchmid(ph) == 0_pInt) then ! no non-Schmid contributions - forall(t = 3_pInt:4_pInt) - v(1:ns,t) = v(1:ns,1) - dv_dtau(1:ns,t) = dv_dtau(1:ns,1) - dv_dtauNS(1:ns,t) = dv_dtauNS(1:ns,1) - endforall -else ! take non-Schmid contributions into account - do t = 3_pInt,4_pInt - call plastic_nonlocal_kinetics(v(1:ns,t), dv_dtau(1:ns,t), dv_dtauNS(1:ns,t), & - tau(1:ns), tauNS(1:ns,t), tauThreshold(1:ns), & - 2_pInt , Temperature, ip, el) - enddo -endif - - -!*** store velocity in state - -forall (t = 1_pInt:4_pInt) & - plasticState(ph)%state(iV(1:ns,t,instance),of) = v(1:ns,t) -!*** Bauschinger effect - -forall (s = 1_pInt:ns, t = 5_pInt:8_pInt, rhoSgl(s,t) * v(s,t-4_pInt) < 0.0_pReal) & - rhoSgl(s,t-4_pInt) = rhoSgl(s,t-4_pInt) + abs(rhoSgl(s,t)) - - -!*** Calculation of Lp and its tangent - -gdotTotal = sum(rhoSgl(1:ns,1:4) * v, 2) * burgers(1:ns,instance) - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - Lp = Lp + gdotTotal(s) * lattice_Sslip(1:3,1:3,1,sLattice,ph) - - ! Schmid contributions to tangent - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & - + lattice_Sslip(i,j,1,sLattice,ph) * lattice_Sslip(k,l,1,sLattice,ph) & - * sum(rhoSgl(s,1:4) * dv_dtau(s,1:4)) * burgers(s,instance) - - ! non Schmid contributions to tangent - if (tau(s) > 0.0_pReal) then - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & - + lattice_Sslip(i,j,1,sLattice,ph) & - * ( nonSchmidProjection(k,l,1,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & - + nonSchmidProjection(k,l,3,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & - * burgers(s,instance) - else - forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & - dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & - + lattice_Sslip(i,j,1,sLattice,ph) & - * ( nonSchmidProjection(k,l,2,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & - + nonSchmidProjection(k,l,4,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & - * burgers(s,instance) - endif -enddo -dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_LpandItsTangent at el ip',el,ip - write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> gdot total / 1e-3',gdotTotal*1e3_pReal - write(6,'(a,/,3(12x,3(f12.7,1x),/))') '<< CONST >> Lp',transpose(Lp) - endif -#endif - -end subroutine plastic_nonlocal_LpAndItsTangent - - - -!-------------------------------------------------------------------------------------------------- -!> @brief (instantaneous) incremental change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_deltaState(Tstar_v,ip,el) -use debug, only: debug_level, & - debug_constitutive, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_i, & - debug_e -use math, only: pi, & - math_mul6x6 -use lattice, only: lattice_Sslip_v ,& - lattice_mu, & - lattice_nu -use mesh, only: mesh_ipVolume -use material, only: material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - -implicit none -integer(pInt), intent(in) :: ip, & ! current grain number - el ! current element number -real(pReal), dimension(6), intent(in) :: Tstar_v ! current 2nd Piola-Kirchhoff stress in Mandel notation - - - integer(pInt) :: & - ph, & !< phase - of !< offset - -integer(pInt) ::instance, & ! current instance of this plasticity - ns, & ! short notation for the total number of active slip systems - c, & ! character of dislocation - t, & ! type of dislocation - s, & ! index of my current slip system - sLattice ! index of my current slip system according to lattice order -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),10) :: & - deltaRho, & ! density increment - deltaRhoRemobilization, & ! density increment by remobilization - deltaRhoDipole2SingleStress ! density increment by dipole dissociation (by stress change) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),8) :: & - rhoSgl ! current single dislocation densities (positive/negative screw and edge without dipoles) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),4) :: & - v ! dislocation glide velocity -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - tau, & ! current resolved shear stress - tauBack ! current back stress from pileups on same slip system -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),2) :: & - rhoDip, & ! current dipole dislocation densities (screw and edge dipoles) - dLower, & ! minimum stable dipole distance for edges and screws - dUpper, & ! current maximum stable dipole distance for edges and screws - dUpperOld, & ! old maximum stable dipole distance for edges and screws - deltaDUpper ! change in maximum stable dipole distance for edges and screws - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_deltaState at el ip ',el,ip -#endif - - ph = phaseAt(1,ip,el) - of = phasememberAt(1,ip,el) - instance = phase_plasticityInstance(ph) - ns = totalNslip(instance) - - -!*** shortcut to state variables - - forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) - v(s,t) = plasticState(ph)%state(iV(s,t,instance),of) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities - dUpperOld(s,c) = plasticState(ph)%state(iD(s,c,instance),of) -endforall - tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) - -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal -where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoDip) < significantRho(instance)) & - rhoDip = 0.0_pReal - - - - -!**************************************************************************** -!*** dislocation remobilization (bauschinger effect) - -deltaRhoRemobilization = 0.0_pReal -do t = 1_pInt,4_pInt - do s = 1_pInt,ns - if (rhoSgl(s,t+4_pInt) * v(s,t) < 0.0_pReal) then - deltaRhoRemobilization(s,t) = abs(rhoSgl(s,t+4_pInt)) - rhoSgl(s,t) = rhoSgl(s,t) + abs(rhoSgl(s,t+4_pInt)) - deltaRhoRemobilization(s,t+4_pInt) = - rhoSgl(s,t+4_pInt) - rhoSgl(s,t+4_pInt) = 0.0_pReal - endif - enddo -enddo - - - -!**************************************************************************** -!*** calculate dipole formation and dissociation by stress change - -!*** calculate limits for stable dipole height - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) - if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal -enddo -dLower = minDipoleHeight(1:ns,1:2,instance) -dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & - / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) -dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) / (4.0_pReal * pi * abs(tau)) - - -forall (c = 1_pInt:2_pInt) - where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& - abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & - + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & - dUpper(1:ns,c)) -end forall -dUpper = max(dUpper,dLower) -deltaDUpper = dUpper - dUpperOld - - -!*** dissociation by stress increase -deltaRhoDipole2SingleStress = 0.0_pReal -forall (c=1_pInt:2_pInt, s=1_pInt:ns, deltaDUpper(s,c) < 0.0_pReal .and. & - abs(dUpperOld(s,c) - dLower(s,c)) > tiny(0.0_pReal)) & - deltaRhoDipole2SingleStress(s,8_pInt+c) = rhoDip(s,c) * deltaDUpper(s,c) & - / (dUpperOld(s,c) - dLower(s,c)) - -forall (t=1_pInt:4_pInt) & - deltaRhoDipole2SingleStress(1_pInt:ns,t) = -0.5_pReal & - * deltaRhoDipole2SingleStress(1_pInt:ns,(t-1_pInt)/2_pInt+9_pInt) - - -!*** store new maximum dipole height in state - -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - plasticState(ph)%state(iD(s,c,instance),of) = dUpper(s,c) - - - -!**************************************************************************** -!*** assign the changes in the dislocation densities to deltaState - -deltaRho = deltaRhoRemobilization & - + deltaRhoDipole2SingleStress -plasticState(ph)%deltaState(:,of) = 0.0_pReal -forall (s = 1:ns, t = 1_pInt:4_pInt) - plasticState(ph)%deltaState(iRhoU(s,t,instance),of)= deltaRho(s,t) - plasticState(ph)%deltaState(iRhoB(s,t,instance),of) = deltaRho(s,t+4_pInt) -endforall -forall (s = 1:ns, c = 1_pInt:2_pInt) & - plasticState(ph)%deltaState(iRhoD(s,c,instance),of) = deltaRho(s,c+8_pInt) - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation remobilization', deltaRhoRemobilization(1:ns,1:8) - write(6,'(a,/,10(12x,12(e12.5,1x),/),/)') '<< CONST >> dipole dissociation by stress increase', deltaRhoDipole2SingleStress - endif -#endif - -end subroutine plastic_nonlocal_deltaState - -!--------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!--------------------------------------------------------------------------------------------------- -subroutine plastic_nonlocal_dotState(Tstar_v, Fe, Fp, Temperature, & - timestep,subfrac, ip,el) - -use prec, only: DAMASK_NaN -use numerics, only: numerics_integrationMode, & - numerics_timeSyncing -use IO, only: IO_error -use debug, only: debug_level, & - debug_constitutive, & - debug_levelBasic, & - debug_levelExtensive, & - debug_levelSelective, & - debug_g, & - debug_i, & - debug_e -use math, only: math_mul6x6, & - math_mul3x3, & - math_mul33x3, & - math_mul33x33, & - math_inv33, & - math_det33, & - math_transpose33, & - pi -use mesh, only: mesh_NcpElems, & - mesh_maxNips, & - mesh_element, & - mesh_ipNeighborhood, & - mesh_ipVolume, & - mesh_ipArea, & - mesh_ipAreaNormal, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype -use material, only: homogenization_maxNgrains, & - material_phase, & - phase_plasticityInstance, & - phase_localPlasticity, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticity ,& - PLASTICITY_NONLOCAL_ID -use lattice, only: lattice_Sslip_v, & - lattice_sd, & - lattice_st ,& - lattice_mu, & - lattice_nu, & - lattice_structure, & - LATTICE_bcc_ID, & - LATTICE_fcc_ID - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el !< current element number -real(pReal), intent(in) :: Temperature, & !< temperature - timestep !< substepped crystallite time increment -real(pReal), dimension(6), intent(in) :: Tstar_v !< current 2nd Piola-Kirchhoff stress in Mandel notation -real(pReal), dimension(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - subfrac !< fraction of timestep at the beginning of the substepped crystallite time increment -real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - Fe, & !< elastic deformation gradient - Fp !< plastic deformation gradient - - -!*** local variables -integer(pInt) :: ph, & - instance, & !< current instance of this plasticity - neighbor_instance, & !< instance of my neighbor's plasticity - ns, & !< short notation for the total number of active slip systems - c, & !< character of dislocation - n, & !< index of my current neighbor - neighbor_el, & !< element number of my neighbor - neighbor_ip, & !< integration point of my neighbor - neighbor_n, & !< neighbor index pointing to me when looking from my neighbor - opposite_neighbor, & !< index of my opposite neighbor - opposite_ip, & !< ip of my opposite neighbor - opposite_el, & !< element index of my opposite neighbor - opposite_n, & !< neighbor index pointing to me when looking from my opposite neighbor - t, & !< type of dislocation - o,& !< offset shortcut - no,& !< neighbour offset shortcut - p,& !< phase shortcut - np,& !< neighbour phase shortcut - topp, & !< type of dislocation with opposite sign to t - s, & !< index of my current slip system - sLattice !< index of my current slip system according to lattice order -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),10) :: & - rhoDot, & !< density evolution - rhoDotMultiplication, & !< density evolution by multiplication - rhoDotFlux, & !< density evolution by flux - rhoDotSingle2DipoleGlide, & !< density evolution by dipole formation (by glide) - rhoDotAthermalAnnihilation, & !< density evolution by athermal annihilation - rhoDotThermalAnnihilation !< density evolution by thermal annihilation -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) - rhoSglOriginal, & - neighbor_rhoSgl, & !< current single dislocation densities of neighboring ip (positive/negative screw and edge without dipoles) - rhoSgl0, & !< single dislocation densities at start of cryst inc (positive/negative screw and edge without dipoles) - my_rhoSgl !< single dislocation densities of central ip (positive/negative screw and edge without dipoles) -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - v, & !< current dislocation glide velocity - v0, & !< dislocation glide velocity at start of cryst inc - my_v, & !< dislocation glide velocity of central ip - neighbor_v, & !< dislocation glide velocity of enighboring ip - gdot !< shear rates -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoForest, & !< forest dislocation density - tauThreshold, & !< threshold shear stress - tau, & !< current resolved shear stress - tauBack, & !< current back stress from pileups on same slip system - vClimb, & !< climb velocity of edge dipoles - nSources -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) - rhoDipOriginal, & - dLower, & !< minimum stable dipole distance for edges and screws - dUpper !< current maximum stable dipole distance for edges and screws -real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - m !< direction of dislocation motion -real(pReal), dimension(3,3) :: my_F, & !< my total deformation gradient - neighbor_F, & !< total deformation gradient of my neighbor - my_Fe, & !< my elastic deformation gradient - neighbor_Fe, & !< elastic deformation gradient of my neighbor - Favg !< average total deformation gradient of me and my neighbor -real(pReal), dimension(3) :: normal_neighbor2me, & !< interface normal pointing from my neighbor to me in neighbor's lattice configuration - normal_neighbor2me_defConf, & !< interface normal pointing from my neighbor to me in shared deformed configuration - normal_me2neighbor, & !< interface normal pointing from me to my neighbor in my lattice configuration - normal_me2neighbor_defConf !< interface normal pointing from me to my neighbor in shared deformed configuration -real(pReal) area, & !< area of the current interface - transmissivity, & !< overall transmissivity of dislocation flux to neighboring material point - lineLength, & !< dislocation line length leaving the current interface - selfDiffusion, & !< self diffusion - rnd, & - meshlength -logical considerEnteringFlux, & - considerLeavingFlux - - - p = phaseAt(1,ip,el) - o = phasememberAt(1,ip,el) - - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & - write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_dotState at el ip ',el,ip -#endif - -ph = material_phase(1_pInt,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - -tau = 0.0_pReal -gdot = 0.0_pReal - - -!*** shortcut to state variables - - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) - v(s,t) = plasticState(p)%state(iV (s,t,instance),o) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - rhoDip(s,c) = max(plasticState(p)%state(iRhoD(s,c,instance),o), 0.0_pReal) ! ensure positive dipole densities -endforall -rhoForest = plasticState(p)%state(iRhoF(1:ns,instance),o) -tauThreshold = plasticState(p)%state(iTauF(1:ns,instance),o) -tauBack = plasticState(p)%state(iTauB(1:ns,instance),o) - -rhoSglOriginal = rhoSgl -rhoDipOriginal = rhoDip -where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl) < significantRho(instance)) & - rhoSgl = 0.0_pReal -where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoDip) < significantRho(instance)) & - rhoDip = 0.0_pReal - -if (numerics_timeSyncing) then - forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl0(s,t) = max(plasticState(p)%state0(iRhoU(s,t,instance),o), 0.0_pReal) - rhoSgl0(s,t+4_pInt) = plasticState(p)%state0(iRhoB(s,t,instance),o) - v0(s,t) = plasticState(p)%state0(iV (s,t,instance),o) - endforall - where (abs(rhoSgl0) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & - .or. abs(rhoSgl0) < significantRho(instance)) & - rhoSgl0 = 0.0_pReal -endif - - - -!*** sanity check for timestep - -if (timestep <= 0.0_pReal) then ! if illegal timestep... Why here and not on function entry?? - plasticState(p)%dotState = 0.0_pReal ! ...return without doing anything (-> zero dotState) - return -endif - - - -!**************************************************************************** -!*** Calculate shear rate - -forall (t = 1_pInt:4_pInt) & - gdot(1_pInt:ns,t) = rhoSgl(1_pInt:ns,t) * burgers(1:ns,instance) * v(1:ns,t) - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> rho / 1/m^2', rhoSgl, rhoDip - write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> gdot / 1/s',gdot - endif -#endif - - - -!**************************************************************************** -!*** calculate limits for stable dipole height - -do s = 1_pInt,ns ! loop over slip systems - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) - if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal -enddo - -dLower = minDipoleHeight(1:ns,1:2,instance) -dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & - / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) -dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & - / (4.0_pReal * pi * abs(tau)) -forall (c = 1_pInt:2_pInt) - where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& - abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & - + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & - dUpper(1:ns,c)) -end forall -dUpper = max(dUpper,dLower) - -!**************************************************************************** -!*** calculate dislocation multiplication - -rhoDotMultiplication = 0.0_pReal -if (lattice_structure(ph) == LATTICE_bcc_ID) then ! BCC - forall (s = 1:ns, sum(abs(v(s,1:4))) > 0.0_pReal) - rhoDotMultiplication(s,1:2) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication - * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path - ! * 2.0_pReal * sum(abs(v(s,3:4))) / sum(abs(v(s,1:4))) ! ratio of screw to overall velocity determines edge generation - rhoDotMultiplication(s,3:4) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication - * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path - ! * 2.0_pReal * sum(abs(v(s,1:2))) / sum(abs(v(s,1:4))) ! ratio of edge to overall velocity determines screw generation - endforall - -else ! ALL OTHER STRUCTURES - if (probabilisticMultiplication(instance)) then - meshlength = mesh_ipVolume(ip,el)**0.333_pReal - where(sum(rhoSgl(1:ns,1:4),2) > 0.0_pReal) - nSources = (sum(rhoSgl(1:ns,1:2),2) * fEdgeMultiplication(instance) + sum(rhoSgl(1:ns,3:4),2)) & - / sum(rhoSgl(1:ns,1:4),2) * meshlength / lambda0(1:ns,instance)*sqrt(rhoForest(1:ns)) - elsewhere - nSources = meshlength / lambda0(1:ns,instance) * sqrt(rhoForest(1:ns)) - endwhere - do s = 1_pInt,ns - if (nSources(s) < 1.0_pReal) then - if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal) then - call random_number(rnd) - sourceProbability(s,1_pInt,ip,el) = rnd - !$OMP FLUSH(sourceProbability) - endif - if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal - nSources(s)) then - rhoDotMultiplication(s,1:4) = sum(rhoSglOriginal(s,1:4) * abs(v(s,1:4))) / meshlength - endif - else - sourceProbability(s,1_pInt,ip,el) = 2.0_pReal - rhoDotMultiplication(s,1:4) = & - (sum(abs(gdot(s,1:2))) * fEdgeMultiplication(instance) + sum(abs(gdot(s,3:4)))) & - / burgers(s,instance) * sqrt(rhoForest(s)) / lambda0(s,instance) - endif - enddo -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) & - write(6,'(a,/,4(12x,12(f12.5,1x),/,/))') '<< CONST >> sources', nSources -#endif - else - rhoDotMultiplication(1:ns,1:4) = spread( & - (sum(abs(gdot(1:ns,1:2)),2) * fEdgeMultiplication(instance) + sum(abs(gdot(1:ns,3:4)),2)) & - * sqrt(rhoForest(1:ns)) / lambda0(1:ns,instance) / burgers(1:ns,instance), 2, 4) - endif -endif - - - -!**************************************************************************** -!*** calculate dislocation fluxes (only for nonlocal plasticity) - -rhoDotFlux = 0.0_pReal -!? why needed here -if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then ! only for nonlocal plasticity - - !*** check CFL (Courant-Friedrichs-Lewy) condition for flux - - if (any( abs(gdot) > 0.0_pReal & ! any active slip system ... - .and. CFLfactor(instance) * abs(v) * timestep & - > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el)))) then ! ...with velocity above critical value (we use the reference volume and area for simplicity here) -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then - write(6,'(a,i5,a,i2)') '<< CONST >> CFL condition not fullfilled at el ',el,' ip ',ip - write(6,'(a,e10.3,a,e10.3)') '<< CONST >> velocity is at ', & - maxval(abs(v), abs(gdot) > 0.0_pReal & - .and. CFLfactor(instance) * abs(v) * timestep & - > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el))), & - ' at a timestep of ',timestep - write(6,'(a)') '<< CONST >> enforcing cutback !!!' - endif -#endif - plasticState(p)%dotState = DAMASK_NaN ! -> return NaN and, hence, enforce cutback - return - endif - - - !*** be aware of the definition of lattice_st = lattice_sd x lattice_sn !!! - !*** opposite sign to our p vector in the (s,p,n) triplet !!! - - m(1:3,1:ns,1) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) - m(1:3,1:ns,2) = -lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) - m(1:3,1:ns,3) = -lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) - m(1:3,1:ns,4) = lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) - - my_Fe = Fe(1:3,1:3,1_pInt,ip,el) - my_F = math_mul33x33(my_Fe, Fp(1:3,1:3,1_pInt,ip,el)) - - do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) ! loop through my neighbors -! write(6,*) 'c' - neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - neighbor_n = mesh_ipNeighborhood(3,n,ip,el) - np = phaseAt(1,neighbor_ip,neighbor_el) - no = phasememberAt(1,neighbor_ip,neighbor_el) - - opposite_neighbor = n + mod(n,2_pInt) - mod(n+1_pInt,2_pInt) - opposite_el = mesh_ipNeighborhood(1,opposite_neighbor,ip,el) - opposite_ip = mesh_ipNeighborhood(2,opposite_neighbor,ip,el) - opposite_n = mesh_ipNeighborhood(3,opposite_neighbor,ip,el) - - if (neighbor_n > 0_pInt) then ! if neighbor exists, average deformation gradient - neighbor_instance = phase_plasticityInstance(material_phase(1_pInt,neighbor_ip,neighbor_el)) - neighbor_Fe = Fe(1:3,1:3,1_pInt,neighbor_ip,neighbor_el) - neighbor_F = math_mul33x33(neighbor_Fe, Fp(1:3,1:3,1_pInt,neighbor_ip,neighbor_el)) - Favg = 0.5_pReal * (my_F + neighbor_F) - else ! if no neighbor, take my value as average - Favg = my_F - endif - - - !* FLUX FROM MY NEIGHBOR TO ME - !* This is only considered, if I have a neighbor of nonlocal plasticity - !* (also nonlocal constitutive law with local properties) that is at least a little bit - !* compatible. - !* If it's not at all compatible, no flux is arriving, because everything is dammed in front of - !* my neighbor's interface. - !* The entering flux from my neighbor will be distributed on my slip systems according to the - !*compatibility - - considerEnteringFlux = .false. - neighbor_v = 0.0_pReal ! needed for check of sign change in flux density below - neighbor_rhoSgl = 0.0_pReal - if (neighbor_n > 0_pInt) then - if (phase_plasticity(material_phase(1,neighbor_ip,neighbor_el)) == PLASTICITY_NONLOCAL_ID & - .and. any(compatibility(:,:,:,n,ip,el) > 0.0_pReal)) & - considerEnteringFlux = .true. - endif - - if (considerEnteringFlux) then - if(numerics_timeSyncing .and. (subfrac(1_pInt,neighbor_ip,neighbor_el) /= subfrac(1_pInt,ip,el))) & - then ! for timesyncing: in case of a timestep at the interface we have to use "state0" to make sure that fluxes n both sides are equal - forall (s = 1:ns, t = 1_pInt:4_pInt) - - neighbor_v(s,t) = plasticState(np)%state0(iV (s,t,neighbor_instance),no) - neighbor_rhoSgl(s,t) = max(plasticState(np)%state0(iRhoU(s,t,neighbor_instance),no),0.0_pReal) - - endforall - else - forall (s = 1:ns, t = 1_pInt:4_pInt) - neighbor_v(s,t) = plasticState(np)%state(iV (s,t,neighbor_instance),no) - neighbor_rhoSgl(s,t) = max(plasticState(np)%state(iRhoU(s,t,neighbor_instance),no), & - 0.0_pReal) - endforall - endif - - where (neighbor_rhoSgl * mesh_ipVolume(neighbor_ip,neighbor_el) ** 0.667_pReal < significantN(instance) & - .or. neighbor_rhoSgl < significantRho(instance)) & - neighbor_rhoSgl = 0.0_pReal - normal_neighbor2me_defConf = math_det33(Favg) * math_mul33x3(math_inv33(transpose(Favg)), & - mesh_ipAreaNormal(1:3,neighbor_n,neighbor_ip,neighbor_el)) ! calculate the normal of the interface in (average) deformed configuration (now pointing from my neighbor to me!!!) - normal_neighbor2me = math_mul33x3(transpose(neighbor_Fe), normal_neighbor2me_defConf) & - / math_det33(neighbor_Fe) ! interface normal in the lattice configuration of my neighbor - area = mesh_ipArea(neighbor_n,neighbor_ip,neighbor_el) * norm2(normal_neighbor2me) - normal_neighbor2me = normal_neighbor2me / norm2(normal_neighbor2me) ! normalize the surface normal to unit length - do s = 1_pInt,ns - do t = 1_pInt,4_pInt - c = (t + 1_pInt) / 2 - topp = t + mod(t,2_pInt) - mod(t+1_pInt,2_pInt) - if (neighbor_v(s,t) * math_mul3x3(m(1:3,s,t), normal_neighbor2me) > 0.0_pReal & ! flux from my neighbor to me == entering flux for me - .and. v(s,t) * neighbor_v(s,t) >= 0.0_pReal ) then ! ... only if no sign change in flux density - lineLength = neighbor_rhoSgl(s,t) * neighbor_v(s,t) & - * math_mul3x3(m(1:3,s,t), normal_neighbor2me) * area ! positive line length that wants to enter through this interface - where (compatibility(c,1_pInt:ns,s,n,ip,el) > 0.0_pReal) & ! positive compatibility... - rhoDotFlux(1_pInt:ns,t) = rhoDotFlux(1_pInt:ns,t) & - + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to equally signed mobile dislocation type - * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal - where (compatibility(c,1_pInt:ns,s,n,ip,el) < 0.0_pReal) & ! ..negative compatibility... - rhoDotFlux(1_pInt:ns,topp) = rhoDotFlux(1_pInt:ns,topp) & - + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to opposite signed mobile dislocation type - * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal - endif - enddo - enddo - endif - - - !* FLUX FROM ME TO MY NEIGHBOR - !* This is not considered, if my opposite neighbor has a different constitutive law than nonlocal (still considered for nonlocal law with lcal properties). - !* Then, we assume, that the opposite(!) neighbor sends an equal amount of dislocations to me. - !* So the net flux in the direction of my neighbor is equal to zero: - !* leaving flux to neighbor == entering flux from opposite neighbor - !* In case of reduced transmissivity, part of the leaving flux is stored as dead dislocation density. - !* That means for an interface of zero transmissivity the leaving flux is fully converted to dead dislocations. - - considerLeavingFlux = .true. - if (opposite_n > 0_pInt) then - if (phase_plasticity(material_phase(1,opposite_ip,opposite_el)) /= PLASTICITY_NONLOCAL_ID) & - considerLeavingFlux = .false. - endif - - if (considerLeavingFlux) then - - !* timeSyncing mode: If the central ip has zero subfraction, always use "state0". This is needed in case of - !* a synchronization step for the central ip, because then "state" contains the values at the end of the - !* previously converged full time step. Also, if either me or my neighbor has zero subfraction, we have to - !* use "state0" to make sure that fluxes on both sides of the (potential) timestep are equal. - my_rhoSgl = rhoSgl - my_v = v - if(numerics_timeSyncing) then - if (abs(subfrac(1_pInt,ip,el))<= tiny(0.0_pReal)) then - my_rhoSgl = rhoSgl0 - my_v = v0 - elseif (neighbor_n > 0_pInt) then - if (abs(subfrac(1_pInt,neighbor_ip,neighbor_el))<= tiny(0.0_pReal)) then - my_rhoSgl = rhoSgl0 - my_v = v0 - endif - endif - endif - - normal_me2neighbor_defConf = math_det33(Favg) & - * math_mul33x3(math_inv33(math_transpose33(Favg)), & - mesh_ipAreaNormal(1:3,n,ip,el)) ! calculate the normal of the interface in (average) deformed configuration (pointing from me to my neighbor!!!) - normal_me2neighbor = math_mul33x3(math_transpose33(my_Fe), normal_me2neighbor_defConf) & - / math_det33(my_Fe) ! interface normal in my lattice configuration - area = mesh_ipArea(n,ip,el) * norm2(normal_me2neighbor) - normal_me2neighbor = normal_me2neighbor / norm2(normal_me2neighbor) ! normalize the surface normal to unit length - do s = 1_pInt,ns - do t = 1_pInt,4_pInt - c = (t + 1_pInt) / 2_pInt - if (my_v(s,t) * math_mul3x3(m(1:3,s,t), normal_me2neighbor) > 0.0_pReal ) then ! flux from me to my neighbor == leaving flux for me (might also be a pure flux from my mobile density to dead density if interface not at all transmissive) - if (my_v(s,t) * neighbor_v(s,t) >= 0.0_pReal) then ! no sign change in flux density - transmissivity = sum(compatibility(c,1_pInt:ns,s,n,ip,el)**2.0_pReal) ! overall transmissivity from this slip system to my neighbor - else ! sign change in flux density means sign change in stress which does not allow for dislocations to arive at the neighbor - transmissivity = 0.0_pReal - endif - lineLength = my_rhoSgl(s,t) * my_v(s,t) & - * math_mul3x3(m(1:3,s,t), normal_me2neighbor) * area ! positive line length of mobiles that wants to leave through this interface - rhoDotFlux(s,t) = rhoDotFlux(s,t) - lineLength / mesh_ipVolume(ip,el) ! subtract dislocation flux from current type - rhoDotFlux(s,t+4_pInt) = rhoDotFlux(s,t+4_pInt) & - + lineLength / mesh_ipVolume(ip,el) * (1.0_pReal - transmissivity) & - * sign(1.0_pReal, my_v(s,t)) ! dislocation flux that is not able to leave through interface (because of low transmissivity) will remain as immobile single density at the material point - endif - enddo - enddo - endif - - enddo ! neighbor loop -endif - - - -!**************************************************************************** -!*** calculate dipole formation and annihilation - -!*** formation by glide - -do c = 1_pInt,2_pInt - rhoDotSingle2DipoleGlide(1:ns,2*c-1) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile - + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile - + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) ! positive mobile --> negative immobile - - rhoDotSingle2DipoleGlide(1:ns,2*c) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile - + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile - + abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c))) ! negative mobile --> positive immobile - - rhoDotSingle2DipoleGlide(1:ns,2*c+3) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * rhoSgl(1:ns,2*c+3) * abs(gdot(1:ns,2*c)) ! negative mobile --> positive immobile - - rhoDotSingle2DipoleGlide(1:ns,2*c+4) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & - * rhoSgl(1:ns,2*c+4) * abs(gdot(1:ns,2*c-1)) ! positive mobile --> negative immobile - - rhoDotSingle2DipoleGlide(1:ns,c+8) = - rhoDotSingle2DipoleGlide(1:ns,2*c-1) & - - rhoDotSingle2DipoleGlide(1:ns,2*c) & - + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+3)) & - + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+4)) -enddo - - -!*** athermal annihilation - -rhoDotAthermalAnnihilation = 0.0_pReal - -forall (c=1_pInt:2_pInt) & - rhoDotAthermalAnnihilation(1:ns,c+8_pInt) = -2.0_pReal * dLower(1:ns,c) / burgers(1:ns,instance) & - * ( 2.0_pReal * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1))) & ! was single hitting single - + 2.0_pReal * (abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c)) + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) & ! was single hitting immobile single or was immobile single hit by single - + rhoDip(1:ns,c) * (abs(gdot(1:ns,2*c-1)) + abs(gdot(1:ns,2*c)))) ! single knocks dipole constituent -! annihilated screw dipoles leave edge jogs behind on the colinear system -if (lattice_structure(ph) == LATTICE_fcc_ID) & ! only fcc - forall (s = 1:ns, colinearSystem(s,instance) > 0_pInt) & - rhoDotAthermalAnnihilation(colinearSystem(s,instance),1:2) = - rhoDotAthermalAnnihilation(s,10) & - * 0.25_pReal * sqrt(rhoForest(s)) * (dUpper(s,2) + dLower(s,2)) * edgeJogFactor(instance) - - - -!*** thermally activated annihilation of edge dipoles by climb - -rhoDotThermalAnnihilation = 0.0_pReal -selfDiffusion = Dsd0(instance) * exp(-selfDiffusionEnergy(instance) / (KB * Temperature)) -vClimb = atomicVolume(instance) * selfDiffusion / ( KB * Temperature ) & - * lattice_mu(ph) / ( 2.0_pReal * PI * (1.0_pReal-lattice_nu(ph)) ) & - * 2.0_pReal / ( dUpper(1:ns,1) + dLower(1:ns,1) ) -forall (s = 1_pInt:ns, dUpper(s,1) > dLower(s,1)) & - rhoDotThermalAnnihilation(s,9) = max(- 4.0_pReal * rhoDip(s,1) * vClimb(s) / (dUpper(s,1) - dLower(s,1)), & - - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & - - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have - - - -!**************************************************************************** -!*** assign the rates of dislocation densities to my dotState -!*** if evolution rates lead to negative densities, a cutback is enforced - -rhoDot = 0.0_pReal -rhoDot = rhoDotFlux & - + rhoDotMultiplication & - + rhoDotSingle2DipoleGlide & - + rhoDotAthermalAnnihilation & - + rhoDotThermalAnnihilation - -if (numerics_integrationMode == 1_pInt) then ! save rates for output if in central integration mode - rhoDotFluxOutput(1:ns,1:8,1_pInt,ip,el) = rhoDotFlux(1:ns,1:8) - rhoDotMultiplicationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotMultiplication(1:ns,[1,3]) - rhoDotSingle2DipoleGlideOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotSingle2DipoleGlide(1:ns,9:10) - rhoDotAthermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotAthermalAnnihilation(1:ns,9:10) - rhoDotThermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotThermalAnnihilation(1:ns,9:10) - rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) = 2.0_pReal * rhoDotThermalAnnihilation(1:ns,1) -endif - - -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & - .and. ((debug_e == el .and. debug_i == ip .and. debug_g == 1_pInt)& - .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then - write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> dislocation multiplication', & - rhoDotMultiplication(1:ns,1:4) * timestep - write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation flux', & - rhoDotFlux(1:ns,1:8) * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> dipole formation by glide', & - rhoDotSingle2DipoleGlide * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> athermal dipole annihilation', & - rhoDotAthermalAnnihilation * timestep - write(6,'(a,/,2(12x,12(e12.5,1x),/))') '<< CONST >> thermally activated dipole annihilation', & - rhoDotThermalAnnihilation(1:ns,9:10) * timestep - write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> total density change', & - rhoDot * timestep - write(6,'(a,/,10(12x,12(f12.5,1x),/))') '<< CONST >> relative density change', & - rhoDot(1:ns,1:8) * timestep / (abs(rhoSglOriginal)+1.0e-10), & - rhoDot(1:ns,9:10) * timestep / (rhoDipOriginal+1.0e-10) - write(6,*) - endif -#endif - - -if ( any(rhoSglOriginal(1:ns,1:4) + rhoDot(1:ns,1:4) * timestep < -aTolRho(instance)) & - .or. any(rhoDipOriginal(1:ns,1:2) + rhoDot(1:ns,9:10) * timestep < -aTolRho(instance))) then -#ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then - write(6,'(a,i5,a,i2)') '<< CONST >> evolution rate leads to negative density at el ',el,' ip ',ip - write(6,'(a)') '<< CONST >> enforcing cutback !!!' - endif -#endif - plasticState(p)%dotState = DAMASK_NaN - return -else - forall (s = 1:ns, t = 1_pInt:4_pInt) - plasticState(p)%dotState(iRhoU(s,t,instance),o) = rhoDot(s,t) - plasticState(p)%dotState(iRhoB(s,t,instance),o) = rhoDot(s,t+4_pInt) - endforall - forall (s = 1:ns, c = 1_pInt:2_pInt) & - plasticState(p)%dotState(iRhoD(s,c,instance),o) = rhoDot(s,c+8_pInt) - forall (s = 1:ns) & - plasticState(p)%dotState(iGamma(s,instance),o) = sum(gdot(s,1:4)) -endif - -end subroutine plastic_nonlocal_dotState - - -!********************************************************************* -!* COMPATIBILITY UPDATE * -!* Compatibility is defined as normalized product of signed cosine * -!* of the angle between the slip plane normals and signed cosine of * -!* the angle between the slip directions. Only the largest values * -!* that sum up to a total of 1 are considered, all others are set to * -!* zero. * -!********************************************************************* -subroutine plastic_nonlocal_updateCompatibility(orientation,i,e) - -use math, only: math_mul3x3, & - math_qRot -use material, only: material_phase, & - material_texture, & - phase_localPlasticity, & - phase_plasticityInstance, & - homogenization_maxNgrains -use mesh, only: mesh_element, & - mesh_ipNeighborhood, & - mesh_maxNips, & - mesh_NcpElems, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype -use lattice, only: lattice_sn, & - lattice_sd, & - lattice_qDisorientation - -implicit none - -!* input variables -integer(pInt), intent(in) :: i, & ! ip index - e ! element index -real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - orientation ! crystal orientation in quaternions - -!* local variables -integer(pInt) Nneighbors, & ! number of neighbors - n, & ! neighbor index - neighbor_e, & ! element index of my neighbor - neighbor_i, & ! integration point index of my neighbor - ph, & - neighbor_phase, & - textureID, & - neighbor_textureID, & - instance, & ! instance of plasticity - ns, & ! number of active slip systems - s1, & ! slip system index (me) - s2 ! slip system index (my neighbor) -real(pReal), dimension(4) :: absoluteMisorientation ! absolute misorientation (without symmetry) between me and my neighbor -real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& - totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& - FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e))))) :: & - my_compatibility ! my_compatibility for current element and ip -real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & - slipNormal, & - slipDirection -real(pReal) my_compatibilitySum, & - thresholdValue, & - nThresholdValues -logical, dimension(totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & - belowThreshold - - -Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) -ph = material_phase(1,i,e) -textureID = material_texture(1,i,e) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) -slipNormal(1:3,1:ns) = lattice_sn(1:3, slipSystemLattice(1:ns,instance), ph) -slipDirection(1:3,1:ns) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) - - -!*** start out fully compatible - -my_compatibility = 0.0_pReal -forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,1:Nneighbors) = 1.0_pReal - - -!*** Loop thrugh neighbors and check whether there is any my_compatibility. - -do n = 1_pInt,Nneighbors - neighbor_e = mesh_ipNeighborhood(1,n,i,e) - neighbor_i = mesh_ipNeighborhood(2,n,i,e) - - - !* FREE SURFACE - !* Set surface transmissivity to the value specified in the material.config - - if (neighbor_e <= 0_pInt .or. neighbor_i <= 0_pInt) then - forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,n) = sqrt(surfaceTransmissivity(instance)) - cycle - endif - - - !* PHASE BOUNDARY - !* If we encounter a different nonlocal "cpfem" phase at the neighbor, - !* we consider this to be a real "physical" phase boundary, so completely incompatible. - !* If one of the two "CPFEM" phases has a local plasticity law, - !* we do not consider this to be a phase boundary, so completely compatible. - - neighbor_phase = material_phase(1,neighbor_i,neighbor_e) - if (neighbor_phase /= ph) then - if (.not. phase_localPlasticity(neighbor_phase) .and. .not. phase_localPlasticity(ph)) then - forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,n) = 0.0_pReal ! = sqrt(0.0) - endif - cycle - endif - - - !* GRAIN BOUNDARY ! - !* fixed transmissivity for adjacent ips with different texture (only if explicitly given in material.config) - - if (grainboundaryTransmissivity(instance) >= 0.0_pReal) then - neighbor_textureID = material_texture(1,neighbor_i,neighbor_e) - if (neighbor_textureID /= textureID) then - if (.not. phase_localPlasticity(neighbor_phase)) then - forall(s1 = 1_pInt:ns) & - my_compatibility(1:2,s1,s1,n) = sqrt(grainboundaryTransmissivity(instance)) - endif - cycle - endif - - - !* GRAIN BOUNDARY ? - !* Compatibility defined by relative orientation of slip systems: - !* The my_compatibility value is defined as the product of the slip normal projection and the slip direction projection. - !* Its sign is always positive for screws, for edges it has the same sign as the slip normal projection. - !* Since the sum for each slip system can easily exceed one (which would result in a transmissivity larger than one), - !* only values above or equal to a certain threshold value are considered. This threshold value is chosen, such that - !* the number of compatible slip systems is minimized with the sum of the original my_compatibility values exceeding one. - !* Finally the smallest my_compatibility value is decreased until the sum is exactly equal to one. - !* All values below the threshold are set to zero. - else - absoluteMisorientation = lattice_qDisorientation(orientation(1:4,1,i,e), & - orientation(1:4,1,neighbor_i,neighbor_e)) ! no symmetry - do s1 = 1_pInt,ns ! my slip systems - do s2 = 1_pInt,ns ! my neighbor's slip systems - my_compatibility(1,s2,s1,n) = math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2))) & - * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) - my_compatibility(2,s2,s1,n) = abs(math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2)))) & - * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) - enddo - - my_compatibilitySum = 0.0_pReal - belowThreshold = .true. - do while (my_compatibilitySum < 1.0_pReal .and. any(belowThreshold(1:ns))) - thresholdValue = maxval(my_compatibility(2,1:ns,s1,n), belowThreshold(1:ns)) ! screws always positive - nThresholdValues = real(count(my_compatibility(2,1:ns,s1,n) == thresholdValue),pReal) - where (my_compatibility(2,1:ns,s1,n) >= thresholdValue) & - belowThreshold(1:ns) = .false. - if (my_compatibilitySum + thresholdValue * nThresholdValues > 1.0_pReal) & - where (abs(my_compatibility(1:2,1:ns,s1,n)) == thresholdValue) & ! MD: rather check below threshold? - my_compatibility(1:2,1:ns,s1,n) = sign((1.0_pReal - my_compatibilitySum) & - / nThresholdValues, my_compatibility(1:2,1:ns,s1,n)) - my_compatibilitySum = my_compatibilitySum + nThresholdValues * thresholdValue - enddo - where (belowThreshold(1:ns)) my_compatibility(1,1:ns,s1,n) = 0.0_pReal - where (belowThreshold(1:ns)) my_compatibility(2,1:ns,s1,n) = 0.0_pReal - enddo ! my slip systems cycle - endif - -enddo ! neighbor cycle - -compatibility(1:2,1:ns,1:ns,1:Nneighbors,i,e) = my_compatibility - -end subroutine plastic_nonlocal_updateCompatibility - -!********************************************************************* -!* calculates quantities characterizing the microstructure * -!********************************************************************* -function plastic_nonlocal_dislocationstress(Fe, ip, el) -use math, only: math_mul33x33, & - math_mul33x3, & - math_inv33, & - math_transpose33, & - pi -use mesh, only: mesh_NcpElems, & - mesh_maxNips, & - mesh_element, & - mesh_node0, & - mesh_cellCenterCoordinates, & - mesh_ipVolume, & - mesh_periodicSurface, & - FE_Nips, & - FE_geomtype -use material, only: homogenization_maxNgrains, & - material_phase, & - plasticState, & - phaseAt, phasememberAt,& - phase_localPlasticity, & - phase_plasticityInstance -use lattice, only: lattice_mu, & - lattice_nu - -implicit none - -!*** input variables -integer(pInt), intent(in) :: ip, & !< current integration point - el !< current element -real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - Fe !< elastic deformation gradient - -!*** output variables -real(pReal), dimension(3,3) :: plastic_nonlocal_dislocationstress - -!*** local variables -integer(pInt) neighbor_el, & !< element number of neighbor material point - neighbor_ip, & !< integration point of neighbor material point - instance, & !< my instance of this plasticity - neighbor_instance, & !< instance of this plasticity of neighbor material point - ph, & - neighbor_phase, & - ns, & !< total number of active slip systems at my material point - neighbor_ns, & !< total number of active slip systems at neighbor material point - c, & !< index of dilsocation character (edge, screw) - s, & !< slip system index - o,& !< offset shortcut - no,& !< neighbour offset shortcut - p,& !< phase shortcut - np,& !< neighbour phase shortcut - t, & !< index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) - dir, & - deltaX, deltaY, deltaZ, & - side, & - j -integer(pInt), dimension(2,3) :: periodicImages -real(pReal) x, y, z, & !< coordinates of connection vector in neighbor lattice frame - xsquare, ysquare, zsquare, & !< squares of respective coordinates - distance, & !< length of connection vector - segmentLength, & !< segment length of dislocations - lambda, & - R, Rsquare, Rcube, & - denominator, & - flipSign, & - neighbor_ipVolumeSideLength -real(pReal), dimension(3) :: connection, & !< connection vector between me and my neighbor in the deformed configuration - connection_neighborLattice, & !< connection vector between me and my neighbor in the lattice configuration of my neighbor - connection_neighborSlip, & !< connection vector between me and my neighbor in the slip system frame of my neighbor - maxCoord, minCoord, & - meshSize, & - coords, & !< x,y,z coordinates of cell center of ip volume - neighbor_coords !< x,y,z coordinates of cell center of neighbor ip volume -real(pReal), dimension(3,3) :: sigma, & !< dislocation stress for one slip system in neighbor material point's slip system frame - Tdislo_neighborLattice, & !< dislocation stress as 2nd Piola-Kirchhoff stress at neighbor material point - invFe, & !< inverse of my elastic deformation gradient - neighbor_invFe, & - neighborLattice2myLattice !< mapping from neighbor MPs lattice configuration to my lattice configuration -real(pReal), dimension(2,2,maxval(totalNslip)) :: & - neighbor_rhoExcess !< excess density at neighbor material point (edge/screw,mobile/dead,slipsystem) -real(pReal), dimension(2,maxval(totalNslip)) :: & - rhoExcessDead -real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) - -ph = material_phase(1_pInt,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) -p = phaseAt(1,ip,el) -o = phasememberAt(1,ip,el) - -!*** get basic states - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities - rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) -endforall - - - -!*** calculate the dislocation stress of the neighboring excess dislocation densities -!*** zero for material points of local plasticity - -plastic_nonlocal_dislocationstress = 0.0_pReal - -if (.not. phase_localPlasticity(ph)) then - invFe = math_inv33(Fe(1:3,1:3,1_pInt,ip,el)) - - !* in case of periodic surfaces we have to find out how many periodic images in each direction we need - - do dir = 1_pInt,3_pInt - maxCoord(dir) = maxval(mesh_node0(dir,:)) - minCoord(dir) = minval(mesh_node0(dir,:)) - enddo - meshSize = maxCoord - minCoord - coords = mesh_cellCenterCoordinates(ip,el) - periodicImages = 0_pInt - do dir = 1_pInt,3_pInt - if (mesh_periodicSurface(dir)) then - periodicImages(1,dir) = floor((coords(dir) - cutoffRadius(instance) - minCoord(dir)) / meshSize(dir), pInt) - periodicImages(2,dir) = ceiling((coords(dir) + cutoffRadius(instance) - maxCoord(dir)) / meshSize(dir), pInt) - endif - enddo - - - !* loop through all material points (also through their periodic images if present), - !* but only consider nonlocal neighbors within a certain cutoff radius R - - do neighbor_el = 1_pInt,mesh_NcpElems - ipLoop: do neighbor_ip = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,neighbor_el))) - neighbor_phase = material_phase(1_pInt,neighbor_ip,neighbor_el) - np = phaseAt(1,neighbor_ip,neighbor_el) - no = phasememberAt(1,neighbor_ip,neighbor_el) - - if (phase_localPlasticity(neighbor_phase)) cycle - neighbor_instance = phase_plasticityInstance(neighbor_phase) - neighbor_ns = totalNslip(neighbor_instance) - neighbor_invFe = math_inv33(Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) - neighbor_ipVolumeSideLength = mesh_ipVolume(neighbor_ip,neighbor_el) ** (1.0_pReal/3.0_pReal) ! reference volume used here - - forall (s = 1_pInt:neighbor_ns, c = 1_pInt:2_pInt) - neighbor_rhoExcess(c,1,s) = plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no) & ! positive mobiles - - plasticState(np)%state(iRhoU(s,2*c,neighbor_instance),no) ! negative mobiles - neighbor_rhoExcess(c,2,s) = abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads - - abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance),no)) ! negative deads - - endforall - Tdislo_neighborLattice = 0.0_pReal - do deltaX = periodicImages(1,1),periodicImages(2,1) - do deltaY = periodicImages(1,2),periodicImages(2,2) - do deltaZ = periodicImages(1,3),periodicImages(2,3) - - - !* regular case - - if (neighbor_el /= el .or. neighbor_ip /= ip & - .or. deltaX /= 0_pInt .or. deltaY /= 0_pInt .or. deltaZ /= 0_pInt) then - - neighbor_coords = mesh_cellCenterCoordinates(neighbor_ip,neighbor_el) & - + [real(deltaX,pReal), real(deltaY,pReal), real(deltaZ,pReal)] * meshSize - connection = neighbor_coords - coords - distance = sqrt(sum(connection * connection)) - if (distance > cutoffRadius(instance)) cycle - - - !* the segment length is the minimum of the third root of the control volume and the ip distance - !* this ensures, that the central MP never sits on a neighbor dislocation segment - - connection_neighborLattice = math_mul33x3(neighbor_invFe, connection) - segmentLength = min(neighbor_ipVolumeSideLength, distance) - - - !* loop through all slip systems of the neighbor material point - !* and add up the stress contributions from egde and screw excess on these slip systems (if significant) - - do s = 1_pInt,neighbor_ns - if (all(abs(neighbor_rhoExcess(:,:,s)) < significantRho(instance))) cycle ! not significant - - - !* map the connection vector from the lattice into the slip system frame - - connection_neighborSlip = math_mul33x3(lattice2slip(1:3,1:3,s,neighbor_instance), & - connection_neighborLattice) - - - !* edge contribution to stress - sigma = 0.0_pReal - - x = connection_neighborSlip(1) - y = connection_neighborSlip(2) - z = connection_neighborSlip(3) - xsquare = x * x - ysquare = y * y - zsquare = z * z - - do j = 1_pInt,2_pInt - if (abs(neighbor_rhoExcess(1,j,s)) < significantRho(instance)) then - cycle - elseif (j > 1_pInt) then - x = connection_neighborSlip(1) & - + sign(0.5_pReal * segmentLength, & - plasticState(np)%state(iRhoB(s,1,neighbor_instance),no) & - - plasticState(np)%state(iRhoB(s,2,neighbor_instance),no)) - - xsquare = x * x - endif - - flipSign = sign(1.0_pReal, -y) - do side = 1_pInt,-1_pInt,-2_pInt - lambda = real(side,pReal) * 0.5_pReal * segmentLength - y - R = sqrt(xsquare + zsquare + lambda * lambda) - Rsquare = R * R - Rcube = Rsquare * R - denominator = R * (R + flipSign * lambda) - if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop - - sigma(1,1) = sigma(1,1) - real(side,pReal) & - * flipSign * z / denominator & - * (1.0_pReal + xsquare / Rsquare + xsquare / denominator) & - * neighbor_rhoExcess(1,j,s) - sigma(2,2) = sigma(2,2) - real(side,pReal) & - * (flipSign * 2.0_pReal * lattice_nu(ph) * z / denominator + z * lambda / Rcube) & - * neighbor_rhoExcess(1,j,s) - sigma(3,3) = sigma(3,3) + real(side,pReal) & - * flipSign * z / denominator & - * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & - * neighbor_rhoExcess(1,j,s) - sigma(1,2) = sigma(1,2) + real(side,pReal) & - * x * z / Rcube * neighbor_rhoExcess(1,j,s) - sigma(1,3) = sigma(1,3) + real(side,pReal) & - * flipSign * x / denominator & - * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & - * neighbor_rhoExcess(1,j,s) - sigma(2,3) = sigma(2,3) - real(side,pReal) & - * (lattice_nu(ph) / R - zsquare / Rcube) * neighbor_rhoExcess(1,j,s) - enddo - enddo - - !* screw contribution to stress - - x = connection_neighborSlip(1) ! have to restore this value, because position might have been adapted for edge deads before - do j = 1_pInt,2_pInt - if (abs(neighbor_rhoExcess(2,j,s)) < significantRho(instance)) then - cycle - elseif (j > 1_pInt) then - y = connection_neighborSlip(2) & - + sign(0.5_pReal * segmentLength, & - plasticState(np)%state(iRhoB(s,3,neighbor_instance),no) & - - plasticState(np)%state(iRhoB(s,4,neighbor_instance),no)) - ysquare = y * y - endif - - flipSign = sign(1.0_pReal, x) - do side = 1_pInt,-1_pInt,-2_pInt - lambda = x + real(side,pReal) * 0.5_pReal * segmentLength - R = sqrt(ysquare + zsquare + lambda * lambda) - Rsquare = R * R - Rcube = Rsquare * R - denominator = R * (R + flipSign * lambda) - if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop - - sigma(1,2) = sigma(1,2) - real(side,pReal) * flipSign * z & - * (1.0_pReal - lattice_nu(ph)) / denominator & - * neighbor_rhoExcess(2,j,s) - sigma(1,3) = sigma(1,3) + real(side,pReal) * flipSign * y & - * (1.0_pReal - lattice_nu(ph)) / denominator & - * neighbor_rhoExcess(2,j,s) - enddo - enddo - - if (all(abs(sigma) < 1.0e-10_pReal)) cycle ! SIGMA IS NOT A REAL STRESS, THATS WHY WE NEED A REALLY SMALL VALUE HERE - - !* copy symmetric parts - - sigma(2,1) = sigma(1,2) - sigma(3,1) = sigma(1,3) - sigma(3,2) = sigma(2,3) - - - !* scale stresses and map them into the neighbor material point's lattice configuration - - sigma = sigma * lattice_mu(neighbor_phase) * burgers(s,neighbor_instance) & - / (4.0_pReal * pi * (1.0_pReal - lattice_nu(neighbor_phase))) & - * mesh_ipVolume(neighbor_ip,neighbor_el) / segmentLength ! reference volume is used here (according to the segment length calculation) - Tdislo_neighborLattice = Tdislo_neighborLattice & - + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,neighbor_instance)), & - math_mul33x33(sigma, lattice2slip(1:3,1:3,s,neighbor_instance))) - - enddo ! slip system loop - - - !* special case of central ip volume - !* only consider dead dislocations - !* we assume that they all sit at a distance equal to half the third root of V - !* in direction of the according slip direction - - else - - forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - - rhoExcessDead(c,s) = plasticState(p)%state(iRhoB(s,2*c-1,instance),o) & ! positive deads (here we use symmetry: if this has negative sign it is - !treated as negative density at positive position instead of positive - !density at negative position) - + plasticState(p)%state(iRhoB(s,2*c,instance),o) ! negative deads (here we use symmetry: if this has negative sign it is - !treated as positive density at positive position instead of negative - !density at negative position) - do s = 1_pInt,ns - if (all(abs(rhoExcessDead(:,s)) < significantRho(instance))) cycle ! not significant - sigma = 0.0_pReal ! all components except for sigma13 are zero - sigma(1,3) = - (rhoExcessDead(1,s) + rhoExcessDead(2,s) * (1.0_pReal - lattice_nu(ph))) & - * neighbor_ipVolumeSideLength * lattice_mu(ph) * burgers(s,instance) & - / (sqrt(2.0_pReal) * pi * (1.0_pReal - lattice_nu(ph))) - sigma(3,1) = sigma(1,3) - - Tdislo_neighborLattice = Tdislo_neighborLattice & - + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,instance)), & - math_mul33x33(sigma, lattice2slip(1:3,1:3,s,instance))) - - enddo ! slip system loop - - endif - - enddo ! deltaZ loop - enddo ! deltaY loop - enddo ! deltaX loop - - - !* map the stress from the neighbor MP's lattice configuration into the deformed configuration - !* and back into my lattice configuration - - neighborLattice2myLattice = math_mul33x33(invFe, Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) - plastic_nonlocal_dislocationstress = plastic_nonlocal_dislocationstress & - + math_mul33x33(neighborLattice2myLattice, & - math_mul33x33(Tdislo_neighborLattice, & - math_transpose33(neighborLattice2myLattice))) - - enddo ipLoop - enddo ! element loop - -endif - -end function plastic_nonlocal_dislocationstress - - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_nonlocal_postResults(Tstar_v,Fe,ip,el) - use math, only: & - math_mul6x6, & - math_mul33x3, & - math_mul33x33, & - pi - use mesh, only: & - mesh_NcpElems, & - mesh_maxNips - use material, only: & - homogenization_maxNgrains, & - material_phase, & - phaseAt, phasememberAt, & - plasticState, & - phase_plasticityInstance - use lattice, only: & - lattice_Sslip_v, & - lattice_sd, & - lattice_st, & - lattice_sn, & - lattice_mu, & - lattice_nu - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - Fe !< elastic deformation gradient - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - - real(pReal), dimension(plastic_nonlocal_sizePostResults(& - phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - plastic_nonlocal_postResults - - integer(pInt) :: & - ph, & - instance, & !< current instance of this plasticity - ns, & !< short notation for the total number of active slip systems - c, & !< character of dislocation - cs, & !< constitutive result index - o, & !< index of current output - of,& !< offset shortcut - t, & !< type of dislocation - s, & !< index of my current slip system - sLattice !< index of my current slip system according to lattice order - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) - rhoDotSgl !< evolution rate of single dislocation densities (positive/negative screw and edge without dipoles) - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & - gdot, & !< shear rates - v !< velocities - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - rhoForest, & !< forest dislocation density - tauThreshold, & !< threshold shear stress - tau, & !< current resolved shear stress - tauBack !< back stress from pileups on same slip system - real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) - rhoDotDip, & !< evolution rate of dipole dislocation densities (screw and edge dipoles) - dLower, & !< minimum stable dipole distance for edges and screws - dUpper !< current maximum stable dipole distance for edges and screws - real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & - m, & !< direction of dislocation motion for edge and screw (unit vector) - m_currentconf !< direction of dislocation motion for edge and screw (unit vector) in current configuration - real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & - n_currentconf !< slip system normal (unit vector) in current configuration - real(pReal), dimension(3,3) :: & - sigma - -ph = phaseAt(1,ip,el) -of = phasememberAt(1,ip,el) -instance = phase_plasticityInstance(ph) -ns = totalNslip(instance) - -cs = 0_pInt -plastic_nonlocal_postResults = 0.0_pReal - - -!* short hand notations for state variables - -forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) - rhoSgl(s,t) = plasticState(ph)%State(iRhoU(s,t,instance),of) - rhoSgl(s,t+4_pInt) = plasticState(ph)%State(iRhoB(s,t,instance),of) - v(s,t) = plasticState(ph)%State(iV(s,t,instance),of) - rhoDotSgl(s,t) = plasticState(ph)%dotState(iRhoU(s,t,instance),of) - rhoDotSgl(s,t+4_pInt) = plasticState(ph)%dotState(iRhoB(s,t,instance),of) -endforall -forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) - rhoDip(s,c) = plasticState(ph)%State(iRhoD(s,c,instance),of) - rhoDotDip(s,c) = plasticState(ph)%dotState(iRhoD(s,c,instance),of) -endforall -rhoForest = plasticState(ph)%State(iRhoF(1:ns,instance),of) -tauThreshold = plasticState(ph)%State(iTauF(1:ns,instance),of) -tauBack = plasticState(ph)%State(iTauB(1:ns,instance),of) - -!* Calculate shear rate - -forall (t = 1_pInt:4_pInt) & - gdot(1:ns,t) = rhoSgl(1:ns,t) * burgers(1:ns,instance) * v(1:ns,t) - - -!* calculate limits for stable dipole height - -do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) - if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal -enddo - -dLower = minDipoleHeight(1:ns,1:2,instance) -dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & - / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) -dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & - / (4.0_pReal * pi * abs(tau)) -forall (c = 1_pInt:2_pInt) - where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& - abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & - + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & - dUpper(1:ns,c)) -end forall -dUpper = max(dUpper,dLower) - - -!*** dislocation motion - -m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) -m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) -forall (c = 1_pInt:2_pInt, s = 1_pInt:ns) & - m_currentconf(1:3,s,c) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), m(1:3,s,c)) -forall (s = 1_pInt:ns) & - n_currentconf(1:3,s) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), & - lattice_sn(1:3,slipSystemLattice(s,instance),ph)) - - -outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) - select case(plastic_nonlocal_outputID(o,instance)) - case (rho_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) + sum(rhoDip,2) - cs = cs + ns - - case (rho_sgl_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) - cs = cs + ns - - case (rho_sgl_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,1:4)),2) - cs = cs + ns - - case (rho_sgl_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:8),2) - cs = cs + ns - - case (rho_dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDip,2) - cs = cs + ns - - case (rho_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1) - cs = cs + ns - - case (rho_sgl_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) - cs = cs + ns - - case (rho_sgl_edge_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,1:2),2) - cs = cs + ns - - case (rho_sgl_edge_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:6),2) - cs = cs + ns - - case (rho_sgl_edge_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5)) - cs = cs + ns - - case (rho_sgl_edge_pos_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) - cs = cs + ns - - case (rho_sgl_edge_pos_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,5) - cs = cs + ns - - case (rho_sgl_edge_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6)) - cs = cs + ns - - case (rho_sgl_edge_neg_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) - cs = cs + ns - - case (rho_sgl_edge_neg_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,6) - cs = cs + ns - - case (rho_dip_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,1) - cs = cs + ns - - case (rho_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2) - cs = cs + ns - - case (rho_sgl_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) - cs = cs + ns - - case (rho_sgl_screw_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,3:4),2) - cs = cs + ns - - case (rho_sgl_screw_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,7:8),2) - cs = cs + ns - - case (rho_sgl_screw_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7)) - cs = cs + ns - - case (rho_sgl_screw_pos_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) - cs = cs + ns - - case (rho_sgl_screw_pos_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,7) - cs = cs + ns - - case (rho_sgl_screw_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8)) - cs = cs + ns - - case (rho_sgl_screw_neg_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) - cs = cs + ns - - case (rho_sgl_screw_neg_immobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,8) - cs = cs + ns - - case (rho_dip_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,2) - cs = cs + ns - - case (excess_rho_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & - - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) & - + (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & - - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) - cs = cs + ns - - case (excess_rho_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & - - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) - cs = cs + ns - - case (excess_rho_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & - - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) - cs = cs + ns - - case (rho_forest_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoForest - cs = cs + ns - - case (delta_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2) + sum(rhoDip,2)) - cs = cs + ns - - case (delta_sgl_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2)) - cs = cs + ns - - case (delta_dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(rhoDip,2)) - cs = cs + ns - - case (shearrate_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(gdot,2) - cs = cs + ns - - case (resolvedstress_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tau - cs = cs + ns - - case (resolvedstress_back_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauBack - cs = cs + ns - - case (resolvedstress_external_ID) - do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) - plastic_nonlocal_postResults(cs+s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) - enddo - cs = cs + ns - - case (resistance_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauThreshold - cs = cs + ns - - case (rho_dot_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & - + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) & - + sum(rhoDotDip,2) - cs = cs + ns - - case (rho_dot_sgl_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & - + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) - cs = cs + ns - - case (rho_dot_sgl_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) - cs = cs + ns - - case (rho_dot_dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotDip,2) - cs = cs + ns - - case (rho_dot_gen_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_gen_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_gen_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_sgl2dip_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_sgl2dip_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_sgl2dip_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_ath_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotAthermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotAthermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_the_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & - + rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_the_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_ann_the_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_edgejogs_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) - cs = cs + ns - - case (rho_dot_flux_mobile_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) - cs = cs + ns - - case (rho_dot_flux_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) & - + sum(rhoDotFluxOutput(1:ns,5:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) - cs = cs + ns - - case (rho_dot_flux_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:2,1_pInt,ip,el),2) & - + sum(rhoDotFluxOutput(1:ns,5:6,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:6)),2) - cs = cs + ns - - case (rho_dot_flux_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,3:4,1_pInt,ip,el),2) & - + sum(rhoDotFluxOutput(1:ns,7:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,7:8)),2) - cs = cs + ns - - case (velocity_edge_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,1) - cs = cs + ns - - case (velocity_edge_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,2) - cs = cs + ns - - case (velocity_screw_pos_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,3) - cs = cs + ns - - case (velocity_screw_neg_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,4) - cs = cs + ns - - case (slipdirectionx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(1,1:ns,1) - cs = cs + ns - - case (slipdirectiony_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(2,1:ns,1) - cs = cs + ns - - case (slipdirectionz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(3,1:ns,1) - cs = cs + ns - - case (slipnormalx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(1,1:ns) - cs = cs + ns - - case (slipnormaly_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(2,1:ns) - cs = cs + ns - - case (slipnormalz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(3,1:ns) - cs = cs + ns - - case (fluxdensity_edge_posx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(1,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_posy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(2,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_posz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(3,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_negx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(1,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_negy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(2,1:ns,1) - cs = cs + ns - - case (fluxdensity_edge_negz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(3,1:ns,1) - cs = cs + ns - - case (fluxdensity_screw_posx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(1,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_posy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(2,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_posz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(3,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_negx_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(1,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_negy_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(2,1:ns,2) - cs = cs + ns - - case (fluxdensity_screw_negz_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(3,1:ns,2) - cs = cs + ns - - case (maximumdipoleheight_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,1) - cs = cs + ns - - case (maximumdipoleheight_screw_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,2) - cs = cs + ns - - case(dislocationstress_ID) - sigma = plastic_nonlocal_dislocationstress(Fe, ip, el) - plastic_nonlocal_postResults(cs+1_pInt) = sigma(1,1) - plastic_nonlocal_postResults(cs+2_pInt) = sigma(2,2) - plastic_nonlocal_postResults(cs+3_pInt) = sigma(3,3) - plastic_nonlocal_postResults(cs+4_pInt) = sigma(1,2) - plastic_nonlocal_postResults(cs+5_pInt) = sigma(2,3) - plastic_nonlocal_postResults(cs+6_pInt) = sigma(3,1) - cs = cs + 6_pInt - - case(accumulatedshear_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = plasticState(ph)%state(iGamma(1:ns,instance),of) - cs = cs + ns - - end select -enddo outputsLoop - -end function plastic_nonlocal_postResults - -end module plastic_nonlocal diff --git a/code/plastic_phenoplus.f90 b/code/plastic_phenoplus.f90 deleted file mode 100644 index 0a40edd84..000000000 --- a/code/plastic_phenoplus.f90 +++ /dev/null @@ -1,1419 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Chen Zhang, Michigan State University -!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw -!... fitting -!-------------------------------------------------------------------------------------------------- -module plastic_phenoplus - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenoplus_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_phenoplus_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_phenoplus_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_phenoplus_Noutput !< number of outputs per instance of this constitution - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenoplus_totalNslip, & !< no. of slip system used in simulation - plastic_phenoplus_totalNtwin, & !< no. of twin system used in simulation - plastic_phenoplus_totalNtrans !< no. of trans system used in simulation - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_phenoplus_Nslip, & !< active number of slip systems per family (input parameter, per family) - plastic_phenoplus_Ntwin, & !< active number of twin systems per family (input parameter, per family) - plastic_phenoplus_Ntrans !< active number of trans systems per family (input parameter, per family) - - real(pReal), dimension(:), allocatable, private :: & - plastic_phenoplus_gdot0_slip, & !< reference shear strain rate for slip (input parameter) - plastic_phenoplus_gdot0_twin, & !< reference shear strain rate for twin (input parameter) - plastic_phenoplus_n_slip, & !< stress exponent for slip (input parameter) - plastic_phenoplus_n_twin, & !< stress exponent for twin (input parameter) - plastic_phenoplus_spr, & !< push-up factor for slip saturation due to twinning - plastic_phenoplus_twinB, & - plastic_phenoplus_twinC, & - plastic_phenoplus_twinD, & - plastic_phenoplus_twinE, & - plastic_phenoplus_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) - plastic_phenoplus_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) - plastic_phenoplus_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) - plastic_phenoplus_a_slip, & - plastic_phenoplus_aTolResistance, & - plastic_phenoplus_aTolShear, & - plastic_phenoplus_aTolTwinfrac, & - plastic_phenoplus_aTolTransfrac, & - plastic_phenoplus_Cnuc, & !< coefficient for strain-induced martensite nucleation - plastic_phenoplus_Cdwp, & !< coefficient for double well potential - plastic_phenoplus_Cgro, & !< coefficient for stress-assisted martensite growth - plastic_phenoplus_deltaG, & !< free energy difference between austensite and martensite [MPa] - plastic_phenoplus_kappa_max !< capped kappa for each slip system - - real(pReal), dimension(:,:), allocatable, private :: & - plastic_phenoplus_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) - plastic_phenoplus_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) - plastic_phenoplus_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) - plastic_phenoplus_nonSchmidCoeff, & - - plastic_phenoplus_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) - plastic_phenoplus_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) - plastic_phenoplus_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) - plastic_phenoplus_interaction_TwinTwin !< interaction factors twin - twin (input parameter) - - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_phenoplus_hardeningMatrix_SlipSlip, & - plastic_phenoplus_hardeningMatrix_SlipTwin, & - plastic_phenoplus_hardeningMatrix_TwinSlip, & - plastic_phenoplus_hardeningMatrix_TwinTwin - - enum, bind(c) - enumerator :: undefined_ID, & - resistance_slip_ID, & - accumulatedshear_slip_ID, & - shearrate_slip_ID, & - resolvedstress_slip_ID, & - kappa_slip_ID, & - totalshear_ID, & - resistance_twin_ID, & - accumulatedshear_twin_ID, & - shearrate_twin_ID, & - resolvedstress_twin_ID, & - totalvolfrac_twin_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_phenoplus_outputID !< ID of each post result output - - public :: & - plastic_phenoplus_init, & - plastic_phenoplus_microstructure, & - plastic_phenoplus_LpAndItsTangent, & - plastic_phenoplus_dotState, & - plastic_phenoplus_postResults - private :: & - plastic_phenoplus_aTolState, & - plastic_phenoplus_stateInit - - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_PHENOPLUS_label, & - PLASTICITY_PHENOPLUS_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - maxNinstance, & - instance,phase,j,k, f,o, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & - Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & - NipcMyPhase, & - offset_slip, index_myFamily, index_otherFamily, & - mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPLUS_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPLUS_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_phenoplus_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_sizePostResult(maxval(phase_Noutput),maxNinstance), & - source=0_pInt) - allocate(plastic_phenoplus_output(maxval(phase_Noutput),maxNinstance)) - plastic_phenoplus_output = '' - allocate(plastic_phenoplus_outputID(maxval(phase_Noutput),maxNinstance),source=undefined_ID) - allocate(plastic_phenoplus_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_Ntrans(lattice_maxNtransFamily,maxNinstance),source=0_pInt) - allocate(plastic_phenoplus_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_totalNtrans(maxNinstance), source=0_pInt) - allocate(plastic_phenoplus_gdot0_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_n_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_tau0_slip(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_tausat_slip(lattice_maxNslipFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_gdot0_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_n_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_tau0_twin(lattice_maxNtwinFamily,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_spr(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinB(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinC(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinD(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_twinE(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_h0_SlipSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_h0_TwinSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_h0_TwinTwin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_a_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolShear(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolTwinfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_aTolTransfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenoplus_Cnuc(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_Cdwp(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_Cgro(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_deltaG(maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_kappa_max(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase - Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('resistance_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_slip','accumulated_shear_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('kappa_slip') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = kappa_slip_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalshear') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalshear_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_twin','accumulated_shear_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalvolfrac_twin') - plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt - plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalvolfrac_twin_ID - plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case default - - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) - do j = 1_pInt, Nchunks_SlipFamilies - plastic_phenoplus_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tausat_slip','tau0_slip') - tempPerSlip = 0.0_pReal - do j = 1_pInt, Nchunks_SlipFamilies - if (plastic_phenoplus_Nslip(j,instance) > 0_pInt) & - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('tausat_slip') - plastic_phenoplus_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau0_slip') - plastic_phenoplus_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_phenoplus_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0_twin') - do j = 1_pInt, Nchunks_TwinFamilies - if (plastic_phenoplus_Ntwin(j,instance) > 0_pInt) & - plastic_phenoplus_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of transformation families - case ('ntrans') - if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - Nchunks_TransFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TransFamilies - plastic_phenoplus_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_phenoplus_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_phenoplus_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_phenoplus_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_phenoplus_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') - do j = 1_pInt,Nchunks_nonSchmid - plastic_phenoplus_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin systems - case ('gdot0_slip') - plastic_phenoplus_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_slip') - plastic_phenoplus_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('a_slip', 'w0_slip') - plastic_phenoplus_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('gdot0_twin') - plastic_phenoplus_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_twin') - plastic_phenoplus_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('s_pr') - plastic_phenoplus_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_b') - plastic_phenoplus_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_c') - plastic_phenoplus_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_d') - plastic_phenoplus_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_e') - plastic_phenoplus_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_slipslip') - plastic_phenoplus_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twinslip') - plastic_phenoplus_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twintwin') - plastic_phenoplus_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_resistance') - plastic_phenoplus_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_shear') - plastic_phenoplus_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_phenoplus_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_transfrac') - plastic_phenoplus_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('kappa_max') - plastic_phenoplus_kappa_max(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cnuc') - plastic_phenoplus_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cdwp') - plastic_phenoplus_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cgro') - plastic_phenoplus_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('deltag') - plastic_phenoplus_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) - case default - - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then - instance = phase_plasticityInstance(phase) - plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested - plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance)) - plastic_phenoplus_Ntwin(1:lattice_maxNtwinFamily,instance) = & - min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested - plastic_phenoplus_Ntwin(:,instance)) - plastic_phenoplus_totalNslip(instance) = sum(plastic_phenoplus_Nslip(:,instance)) ! how many slip systems altogether - plastic_phenoplus_totalNtwin(instance) = sum(plastic_phenoplus_Ntwin(:,instance)) ! how many twin systems altogether - plastic_phenoplus_totalNtrans(instance) = sum(plastic_phenoplus_Ntrans(:,instance)) ! how many trans systems altogether - - if (any(plastic_phenoplus_tau0_slip(:,instance) < 0.0_pReal .and. & - plastic_phenoplus_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (plastic_phenoplus_gdot0_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (plastic_phenoplus_n_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (any(plastic_phenoplus_tausat_slip(:,instance) <= 0.0_pReal .and. & - plastic_phenoplus_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (any(abs(plastic_phenoplus_a_slip(instance)) <= tiny(0.0_pReal) .and. & - plastic_phenoplus_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPLUS_label//')') - if (any(plastic_phenoplus_tau0_twin(:,instance) < 0.0_pReal .and. & - plastic_phenoplus_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPLUS_label//')') - if ( plastic_phenoplus_gdot0_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenoplus_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPLUS_label//')') - if ( plastic_phenoplus_n_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenoplus_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPLUS_label//')') - if (plastic_phenoplus_aTolResistance(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa - if (plastic_phenoplus_aTolShear(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenoplus_aTolTwinfrac(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenoplus_aTolTransfrac(instance) <= 0.0_pReal) & - plastic_phenoplus_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - allocate(plastic_phenoplus_hardeningMatrix_SlipSlip(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from slip activity - maxval(plastic_phenoplus_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_hardeningMatrix_SlipTwin(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from twin activity - maxval(plastic_phenoplus_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_hardeningMatrix_TwinSlip(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_phenoplus_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenoplus_hardeningMatrix_TwinTwin(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_phenoplus_totalNtwin),& - maxNinstance), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config - myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then ! only consider my phase - NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase - instance = phase_plasticityInstance(phase) ! which instance of my phase - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) - select case(plastic_phenoplus_outputID(o,instance)) - case(resistance_slip_ID, & - shearrate_slip_ID, & - accumulatedshear_slip_ID, & - resolvedstress_slip_ID, & - kappa_slip_ID & - ) - mySize = plastic_phenoplus_totalNslip(instance) - case(resistance_twin_ID, & - shearrate_twin_ID, & - accumulatedshear_twin_ID, & - resolvedstress_twin_ID & - ) - mySize = plastic_phenoplus_totalNtwin(instance) - case(totalshear_ID, & - totalvolfrac_twin_ID & - ) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_phenoplus_sizePostResult(o,instance) = mySize - plastic_phenoplus_sizePostResults(instance) = plastic_phenoplus_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = plastic_phenoplus_totalNslip(instance) & ! s_slip - + plastic_phenoplus_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) - + plastic_phenoplus_totalNslip(instance) & ! accshear_slip - + plastic_phenoplus_totalNtwin(instance) & ! accshear_twin - + plastic_phenoplus_totalNslip(instance) ! kappa - - !sizeDotState = sizeState ! same as sizeState - !QUICK FIX: the dotState cannot have redundancy, which could cause unknown error - ! explicitly specify the size of the dotState to avoid this potential - ! memory leak issue. - sizeDotState = plastic_phenoplus_totalNslip(instance) & ! s_slip - + plastic_phenoplus_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) - + plastic_phenoplus_totalNslip(instance) & ! accshear_slip - + plastic_phenoplus_totalNtwin(instance) ! accshear_twin - - sizeDeltaState = 0_pInt - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_phenoplus_sizePostResults(instance) - plasticState(phase)%nSlip =plastic_phenoplus_totalNslip(instance) - plasticState(phase)%nTwin =plastic_phenoplus_totalNtwin(instance) - plasticState(phase)%nTrans=plastic_phenoplus_totalNtrans(instance) - allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) - - offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - - do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X - index_myFamily = sum(plastic_phenoplus_Nslip(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenoplus_Nslip(f,instance) ! loop over (active) systems in my family (slip) - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenoplus_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenoplus_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - - do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X - index_myFamily = sum(plastic_phenoplus_Ntwin(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenoplus_Ntwin(f,instance) ! loop over (active) systems in my family (twin) - - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenoplus_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenoplus_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenoplus_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - - call plastic_phenoplus_stateInit(phase,instance) - call plastic_phenoplus_aTolState(phase,instance) - endif myPhase2 - enddo initializeInstances - -end subroutine plastic_phenoplus_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_stateInit(ph,instance) - use lattice, only: & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - integer(pInt) :: & - i - real(pReal), dimension(plasticState(ph)%sizeState) :: & - tempState - - tempState = 0.0_pReal - do i = 1_pInt,lattice_maxNslipFamily - tempState(1+sum(plastic_phenoplus_Nslip(1:i-1,instance)) : & - sum(plastic_phenoplus_Nslip(1:i ,instance))) = & - plastic_phenoplus_tau0_slip(i,instance) - enddo - - do i = 1_pInt,lattice_maxNtwinFamily - tempState(1+sum(plastic_phenoplus_Nslip(:,instance))+& - sum(plastic_phenoplus_Ntwin(1:i-1,instance)) : & - sum(plastic_phenoplus_Nslip(:,instance))+& - sum(plastic_phenoplus_Ntwin(1:i ,instance))) = & - plastic_phenoplus_tau0_twin(i,instance) - enddo - - plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array - 2, & ! along dimension 2 - size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) - -end subroutine plastic_phenoplus_stateInit - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - plasticState(ph)%aTolState(1:plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance)) = & - plastic_phenoplus_aTolResistance(instance) - plasticState(ph)%aTolState(1+plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance)) = & - plastic_phenoplus_aTolShear(instance) - plasticState(ph)%aTolState(2+plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance)) = & - plastic_phenoplus_aTolTwinFrac(instance) - plasticState(ph)%aTolState(3+plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance): & - 2+2*(plastic_phenoplus_totalNslip(instance)+ & - plastic_phenoplus_totalNtwin(instance))) = & - plastic_phenoplus_aTolShear(instance) - -end subroutine plastic_phenoplus_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate push-up factors (kappa) for each voxel based on its neighbors -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el) - use math, only: pi, & - math_mul33x33, & - math_mul3x3, & - math_transpose33, & - math_qDot, & - math_qRot, & - indeg - - use mesh, only: mesh_element, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype, & - mesh_maxNips, & - mesh_NcpElems, & - mesh_ipNeighborhood - - use material, only: material_phase, & - material_texture, & - phase_plasticityInstance, & - phaseAt, phasememberAt, & - homogenization_maxNgrains, & - plasticState - - use lattice, only: lattice_sn, & - lattice_sd, & - lattice_qDisorientation - - !***input variables - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - orientation ! crystal orientation in quaternions - - !***local variables - integer(pInt) instance, & !my instance of this plasticity - ph, & !my phase - of, & !my spatial position in memory (offset) - textureID, & !my texture - Nneighbors, & !number of neighbors (<= 6) - vld_Nneighbors, & !number of my valid neighbors - n, & !neighbor index (for iterating through all neighbors) - ns, & !number of slip system - nt, & !number of twin system - me_slip, & !my slip system index - neighbor_el, & !element number of neighboring material point - neighbor_ip, & !integration point of neighboring material point - neighbor_n, & !I have no idea what is this - neighbor_of, & !spatial position in memory for this neighbor (offset) - neighbor_ph, & !neighbor's phase - neighbor_tex, & !neighbor's texture ID - ne_slip_ac, & !loop to find neighbor shear - ne_slip, & !slip system index for neighbor - index_kappa, & !index of pushup factors in plasticState - offset_acshear_slip, & !offset in PlasticState for the accumulative shear - j !quickly loop through slip families - - real(pReal) kappa_max, & ! - tmp_myshear_slip, & !temp storage for accumulative shear for me - mprime_cut, & !m' cutoff to consider neighboring effect - avg_acshear_ne, & !the average accumulative shear from my neighbor - tmp_mprime, & !temp holder for m' value - tmp_acshear !temp holder for accumulative shear for m' - - - real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - m_primes, & !m' between me_alpha(one) and neighbor beta(all) - me_acshear, & !temp storage for ac_shear of one particular system for me - ne_acshear !temp storage for ac_shear of one particular system for one of my neighbor - - real(pReal), dimension(3,plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - slipNormal, & - slipDirect - - real(pReal), dimension(4) :: my_orientation, & !store my orientation - neighbor_orientation, & !store my neighbor orientation - absMisorientation - - real(pReal), dimension(FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) :: & - ne_mprimes !m' between each neighbor - - !***Get my properties - Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) - ph = phaseAt(ipc,ip,el) !get my phase - of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory - textureID = material_texture(1,ip,el) !get my texture ID - instance = phase_plasticityInstance(ph) !get my instance based on phase ID - ns = plastic_phenoplus_totalNslip(instance) - nt = plastic_phenoplus_totalNtwin(instance) - offset_acshear_slip = ns + nt + 2_pInt - index_kappa = ns + nt + 2_pInt + ns + nt !location of kappa in plasticState - mprime_cut = 0.7_pReal !set by Dr.Bieler - - !***gather my accumulative shear from palsticState - FINDMYSHEAR: do j = 1_pInt,ns - me_acshear(j) = plasticState(ph)%state(offset_acshear_slip+j, of) - enddo FINDMYSHEAR - - !***gather my orientation and slip systems - my_orientation = orientation(1:4, ipc, ip, el) - slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) - slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) - kappa_max = plastic_phenoplus_kappa_max(instance) !maximum pushups allowed (READIN) - - !***calculate kappa between me and all my neighbors - LOOPMYSLIP: DO me_slip=1_pInt,ns - vld_Nneighbors = Nneighbors - tmp_myshear_slip = me_acshear(me_slip) - tmp_mprime = 0.0_pReal !highest m' from all neighbors - tmp_acshear = 0.0_pReal !accumulative shear from highest m' - - !***go through my neighbors to find highest m' - LOOPNEIGHBORS: DO n=1_pInt,Nneighbors - neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - neighbor_n = 1 !It is ipc - neighbor_of = phasememberAt( neighbor_n, neighbor_ip, neighbor_el) - neighbor_ph = phaseAt( neighbor_n, neighbor_ip, neighbor_el) - neighbor_tex = material_texture(1,neighbor_ip,neighbor_el) - neighbor_orientation = orientation(1:4, neighbor_n, neighbor_ip, neighbor_el) !ipc is always 1. - absMisorientation = lattice_qDisorientation(my_orientation, & - neighbor_orientation, & - 0_pInt) !no need for explicit calculation of symmetry - - !***find the accumulative shear for this neighbor - LOOPFINDNEISHEAR: DO ne_slip_ac=1_pInt, ns - ne_acshear(ne_slip_ac) = plasticState(ph)%state(offset_acshear_slip+ne_slip_ac, & - neighbor_of) - ENDDO LOOPFINDNEISHEAR - - !***calculate the average accumulative shear and use it as cutoff - avg_acshear_ne = SUM(ne_acshear)/ns - - !*** - IF (ph==neighbor_ph) THEN - !***walk through all the - LOOPNEIGHBORSLIP: DO ne_slip=1_pInt,ns - !***only consider slip system that is active (above average accumulative shear) - IF (ne_acshear(ne_slip) > avg_acshear_ne) THEN - m_primes(ne_slip) = abs(math_mul3x3(slipNormal(1:3,me_slip), & - math_qRot(absMisorientation, slipNormal(1:3,ne_slip)))) & - *abs(math_mul3x3(slipDirect(1:3,me_slip), & - math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) - !***find the highest m' and corresponding accumulative shear - IF (m_primes(ne_slip) > tmp_mprime) THEN - tmp_mprime = m_primes(ne_slip) - tmp_acshear = ne_acshear(ne_slip) - ENDIF - ENDIF - ENDDO LOOPNEIGHBORSLIP - - ELSE - ne_mprimes(n) = 0.0_pReal - vld_Nneighbors = vld_Nneighbors - 1_pInt - ENDIF - - ENDDO LOOPNEIGHBORS - - !***check if this element close to rim - IF (vld_Nneighbors < Nneighbors) THEN - !***rim voxel, no modification allowed - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal - ELSE - !***patch voxel, started to calculate push up factor for gamma_dot - IF ((tmp_mprime > mprime_cut) .AND. (tmp_acshear > tmp_myshear_slip)) THEN - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal / tmp_mprime - ELSE - !***minimum damping factor is 0.5 - plasticState(ph)%state(index_kappa+me_slip, of) = 0.5_pReal + tmp_mprime * 0.5_pReal - ENDIF - ENDIF - - ENDDO LOOPMYSLIP - -end subroutine plastic_phenoplus_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use math, only: & - math_Plain3333to99, & - math_Mandel6to33 - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - use material, only: & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - - integer(pInt) :: & - instance, & - nSlip, & - nTwin,index_Gamma,index_F,index_myFamily, index_kappa, & - f,i,j,k,l,m,n, & - of, & - ph - real(pReal) :: & - tau_slip_pos,tau_slip_neg, & - gdot_slip_pos,gdot_slip_neg, & - dgdot_dtauslip_pos,dgdot_dtauslip_neg, & - gdot_twin,dgdot_dtautwin,tau_twin - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal), dimension(3,3,2) :: & - nonSchmid_tensor - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - nSlip = plastic_phenoplus_totalNslip(instance) - nTwin = plastic_phenoplus_totalNtwin(instance) - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - index_kappa = nSlip + nTwin + 2_pInt +nSlip + nTwin - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Slip part - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) - enddo - - !***insert non-local effect here by modify gdot with kappa in plastic state - !***this implementation will most likely cause convergence issue - ! gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ! ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of)* & - ! plasticState(ph)%state(j+index_kappa, of))) & !in-place modification of gdot - ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) - - ! gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ! ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of)* & - ! plasticState(ph)%state(j+index_kappa, of))) & !?should we make it direction aware - ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) - - !***original calculation - gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of))) & !in-place modification of gdot - **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) - - gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & - ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of))) & !?should we make it direction aware - **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) - - !***MAGIC HERE***! - !***directly modify the amount of shear happens considering neighborhood - gdot_slip_pos = gdot_slip_pos * plasticState(ph)%state(j+index_kappa, of) - gdot_slip_neg = gdot_slip_neg * plasticState(ph)%state(j+index_kappa, of) - - Lp = Lp + (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then - dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenoplus_n_slip(instance)/tau_slip_pos - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,1) - endif - - if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then - dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenoplus_n_slip(instance)/tau_slip_neg - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,2) - endif - enddo slipSystems - enddo slipFamilies - -!-------------------------------------------------------------------------------------------------- -! Twinning part - j = 0_pInt - twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenoplus_gdot0_twin(instance)*& - (abs(tau_twin)/plasticState(ph)%state(nSlip+j,of))**& - plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_twin) > tiny(0.0_pReal)) then - dgdot_dtautwin = gdot_twin*plastic_phenoplus_n_twin(instance)/tau_twin - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & - lattice_Stwin(m,n,index_myFamily+i,ph) - endif - enddo twinSystems - enddo twinFamilies - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - - -end subroutine plastic_phenoplus_LpAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_dotState(Tstar_v,ipc,ip,el) - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_shearTwin, & - lattice_NnonSchmid - use material, only: & - material_phase, & - phaseAt, phasememberAt, & - plasticState, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - integer(pInt) :: & - instance,ph, & - nSlip,nTwin, & - f,i,j,k, & - index_Gamma,index_F,index_myFamily,& - offset_accshear_slip,offset_accshear_twin, offset_kappa, & - of - real(pReal) :: & - c_SlipSlip,c_TwinSlip,c_TwinTwin, & - ssat_offset, & - tau_slip_pos,tau_slip_neg,tau_twin - - real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip - real(pReal), dimension(plastic_phenoplus_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenoplus_totalNslip(instance) - nTwin = plastic_phenoplus_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - offset_accshear_slip = nSlip + nTwin + 2_pInt - offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip - offset_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin - plasticState(ph)%dotState(:,of) = 0.0_pReal - - -!-------------------------------------------------------------------------------------------------- -! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices - c_SlipSlip = plastic_phenoplus_h0_SlipSlip(instance)*& - (1.0_pReal + plastic_phenoplus_twinC(instance)*plasticState(ph)%state(index_F,of)**& - plastic_phenoplus_twinB(instance)) - c_TwinSlip = plastic_phenoplus_h0_TwinSlip(instance)*& - plasticState(ph)%state(index_Gamma,of)**plastic_phenoplus_twinE(instance) - c_TwinTwin = plastic_phenoplus_h0_TwinTwin(instance)*& - plasticState(ph)%state(index_F,of)**plastic_phenoplus_twinD(instance) - -!-------------------------------------------------------------------------------------------------- -! calculate left and right vectors and calculate dot gammas - ssat_offset = plastic_phenoplus_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j+1_pInt - left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part - left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part - !***original implementation - right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & - **plastic_phenoplus_a_slip(instance)& - *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) - !***modify a_slip to get nonlocal effect - ! right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & - ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & - ! **(plastic_phenoplus_a_slip(instance)*plasticState(ph)%state(j+offset_kappa, of))& - ! *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & - ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) - right_TwinSlip(j) = 1.0_pReal ! no system-dependent part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot gamma - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - gdot_slip(j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance) & - +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - enddo slipSystems1 - enddo slipFamilies1 - - - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j+1_pInt - left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part - left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part - right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part - right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot vol frac - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenoplus_gdot0_twin(instance)*& - (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& - plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - enddo twinSystems1 - enddo twinFamilies1 - -!-------------------------------------------------------------------------------------------------- -! calculate the overall hardening based on above - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j - c_SlipSlip * left_SlipSlip(j) * & - dot_product(plastic_phenoplus_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & - right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - dot_product(plastic_phenoplus_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & - right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & - abs(gdot_slip(j)) - plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) - enddo slipSystems2 - enddo slipFamilies2 - - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j - c_TwinSlip * left_TwinSlip(j) * & - dot_product(plastic_phenoplus_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & - right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - c_TwinTwin * left_TwinTwin(j) * & - dot_product(plastic_phenoplus_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & - right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 - plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & - gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) - plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) - enddo twinSystems2 - enddo twinFamilies2 - - -end subroutine plastic_phenoplus_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_phenoplus_postResults(Tstar_v,ipc,ip,el) - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - real(pReal), dimension(plastic_phenoplus_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_phenoplus_postResults - - integer(pInt) :: & - instance,ph, of, & - nSlip,nTwin, & - o,f,i,c,j,k, & - index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily,index_kappa - real(pReal) :: & - tau_slip_pos,tau_slip_neg,tau - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenoplus_totalNslip(instance) - nTwin = plastic_phenoplus_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - index_accshear_slip = nSlip + nTwin + 2_pInt + 1_pInt - index_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + 1_pInt - index_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin + 1_pInt - - plastic_phenoplus_postResults = 0.0_pReal - c = 0_pInt - - outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) - select case(plastic_phenoplus_outputID(o,instance)) - case (resistance_slip_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) - c = c + nSlip - - case (accumulatedshear_slip_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& - index_accshear_slip+nSlip-1_pInt,of) - c = c + nSlip - - case (shearrate_slip_ID) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j + 1_pInt - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo - plastic_phenoplus_postResults(c+j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance) & - +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - - enddo slipSystems1 - enddo slipFamilies1 - c = c + nSlip - - case (resolvedstress_slip_ID) - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) - j = j + 1_pInt - plastic_phenoplus_postResults(c+j) = & - dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - enddo slipSystems2 - enddo slipFamilies2 - c = c + nSlip - - case (kappa_slip_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = & - plasticState(ph)%state(index_kappa:index_kappa+nSlip-1_pInt,of) - c = c + nSlip - - case (totalshear_ID) - plastic_phenoplus_postResults(c+1_pInt) = & - plasticState(ph)%state(index_Gamma,of) - c = c + 1_pInt - - case (resistance_twin_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) - c = c + nTwin - - case (accumulatedshear_twin_ID) - plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) - c = c + nTwin - - case (shearrate_twin_ID) - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j + 1_pInt - tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - plastic_phenoplus_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenoplus_gdot0_twin(instance)*& - (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& - plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) - enddo twinSystems1 - enddo twinFamilies1 - c = c + nTwin - - case (resolvedstress_twin_ID) - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) - j = j + 1_pInt - plastic_phenoplus_postResults(c+j) = & - dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - enddo twinSystems2 - enddo twinFamilies2 - c = c + nTwin - - case (totalvolfrac_twin_ID) - plastic_phenoplus_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) - c = c + 1_pInt - - end select - enddo outputsLoop - -end function plastic_phenoplus_postResults - -end module plastic_phenoplus diff --git a/code/plastic_phenopowerlaw.f90 b/code/plastic_phenopowerlaw.f90 deleted file mode 100644 index 1f8e16250..000000000 --- a/code/plastic_phenopowerlaw.f90 +++ /dev/null @@ -1,1226 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw -!! fitting -!-------------------------------------------------------------------------------------------------- -module plastic_phenopowerlaw - use prec, only: & - pReal,& - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenopowerlaw_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_phenopowerlaw_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_phenopowerlaw_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_phenopowerlaw_Noutput !< number of outputs per instance of this constitution - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_phenopowerlaw_totalNslip, & !< no. of slip system used in simulation - plastic_phenopowerlaw_totalNtwin, & !< no. of twin system used in simulation - plastic_phenopowerlaw_totalNtrans !< no. of trans system used in simulation - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_phenopowerlaw_Nslip, & !< active number of slip systems per family (input parameter, per family) - plastic_phenopowerlaw_Ntwin, & !< active number of twin systems per family (input parameter, per family) - plastic_phenopowerlaw_Ntrans !< active number of trans systems per family (input parameter, per family) - - real(pReal), dimension(:), allocatable, private :: & - plastic_phenopowerlaw_gdot0_slip, & !< reference shear strain rate for slip (input parameter) - plastic_phenopowerlaw_gdot0_twin, & !< reference shear strain rate for twin (input parameter) - plastic_phenopowerlaw_n_slip, & !< stress exponent for slip (input parameter) - plastic_phenopowerlaw_n_twin, & !< stress exponent for twin (input parameter) - plastic_phenopowerlaw_spr, & !< push-up factor for slip saturation due to twinning - plastic_phenopowerlaw_twinB, & - plastic_phenopowerlaw_twinC, & - plastic_phenopowerlaw_twinD, & - plastic_phenopowerlaw_twinE, & - plastic_phenopowerlaw_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) - plastic_phenopowerlaw_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) - plastic_phenopowerlaw_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) - plastic_phenopowerlaw_a_slip, & - plastic_phenopowerlaw_aTolResistance, & - plastic_phenopowerlaw_aTolShear, & - plastic_phenopowerlaw_aTolTwinfrac, & - plastic_phenopowerlaw_aTolTransfrac, & - plastic_phenopowerlaw_Cnuc, & !< coefficient for strain-induced martensite nucleation - plastic_phenopowerlaw_Cdwp, & !< coefficient for double well potential - plastic_phenopowerlaw_Cgro, & !< coefficient for stress-assisted martensite growth - plastic_phenopowerlaw_deltaG !< free energy difference between austensite and martensite [MPa] - - real(pReal), dimension(:,:), allocatable, private :: & - plastic_phenopowerlaw_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) - plastic_phenopowerlaw_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) - plastic_phenopowerlaw_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) - plastic_phenopowerlaw_nonSchmidCoeff, & - - plastic_phenopowerlaw_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) - plastic_phenopowerlaw_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) - plastic_phenopowerlaw_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) - plastic_phenopowerlaw_interaction_TwinTwin !< interaction factors twin - twin (input parameter) - - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_phenopowerlaw_hardeningMatrix_SlipSlip, & - plastic_phenopowerlaw_hardeningMatrix_SlipTwin, & - plastic_phenopowerlaw_hardeningMatrix_TwinSlip, & - plastic_phenopowerlaw_hardeningMatrix_TwinTwin - - enum, bind(c) - enumerator :: undefined_ID, & - resistance_slip_ID, & - accumulatedshear_slip_ID, & - shearrate_slip_ID, & - resolvedstress_slip_ID, & - totalshear_ID, & - resistance_twin_ID, & - accumulatedshear_twin_ID, & - shearrate_twin_ID, & - resolvedstress_twin_ID, & - totalvolfrac_twin_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_phenopowerlaw_outputID !< ID of each post result output - - type, private :: tPhenopowerlawState - real(pReal), pointer, dimension(:,:) :: & - s_slip, & - s_twin, & - accshear_slip, & - accshear_twin - real(pReal), pointer, dimension(:) :: & - sumGamma, & - sumF - end type - - type(tPhenopowerlawState), allocatable, dimension(:), private :: & - dotState, & - state, & - state0 - - public :: & - plastic_phenopowerlaw_init, & - plastic_phenopowerlaw_LpAndItsTangent, & - plastic_phenopowerlaw_dotState, & - plastic_phenopowerlaw_postResults - private :: & - plastic_phenopowerlaw_aTolState, & - plastic_phenopowerlaw_stateInit - - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level, & - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66, & - math_Voigt66to3333 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_PHENOPOWERLAW_label, & - PLASTICITY_PHENOPOWERLAW_ID, & - material_phase, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - maxNinstance, & - instance,phase,j,k, f,o, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & - Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & - Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & - NipcMyPhase, & - offset_slip, index_myFamily, index_otherFamily, & - mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState, & - startIndex, endIndex - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), dimension(:), allocatable :: tempPerSlip - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPOWERLAW_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPOWERLAW_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - - allocate(plastic_phenopowerlaw_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_sizePostResult(maxval(phase_Noutput),maxNinstance), & - source=0_pInt) - allocate(plastic_phenopowerlaw_output(maxval(phase_Noutput),maxNinstance)) - plastic_phenopowerlaw_output = '' - allocate(plastic_phenopowerlaw_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_phenopowerlaw_Noutput(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_totalNtrans(maxNinstance), source=0_pInt) - allocate(plastic_phenopowerlaw_gdot0_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_n_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_tau0_slip(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_tausat_slip(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(plastic_phenopowerlaw_gdot0_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_n_twin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_tau0_twin(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_spr(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinB(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinC(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinD(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_twinE(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_h0_SlipSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_h0_TwinSlip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_h0_TwinTwin(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_a_slip(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolResistance(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolShear(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolTwinfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_aTolTransfrac(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & - source=0.0_pReal) - allocate(plastic_phenopowerlaw_Cnuc(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_Cdwp(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_Cgro(maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_deltaG(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase - phase = phase + 1_pInt ! advance phase section counter - if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase - Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - Nchunks_nonSchmid = lattice_NnonSchmid(phase) - if(allocated(tempPerSlip)) deallocate(tempPerSlip) - allocate(tempPerSlip(Nchunks_SlipFamilies)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('resistance_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_slip','accumulated_shear_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_slip') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_slip_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalshear') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalshear_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('accumulatedshear_twin','accumulated_shear_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shearrate_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resolvedstress_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('totalvolfrac_twin') - plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt - plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalvolfrac_twin_ID - plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case default - - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of slip families - case ('nslip') - if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) - do j = 1_pInt, Nchunks_SlipFamilies - plastic_phenopowerlaw_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tausat_slip','tau0_slip') - tempPerSlip = 0.0_pReal - do j = 1_pInt, Nchunks_SlipFamilies - if (plastic_phenopowerlaw_Nslip(j,instance) > 0_pInt) & - tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - select case(tag) - case ('tausat_slip') - plastic_phenopowerlaw_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - case ('tau0_slip') - plastic_phenopowerlaw_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) - end select -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of twin families - case ('ntwin') - if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - Nchunks_TwinFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TwinFamilies - plastic_phenopowerlaw_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0_twin') - do j = 1_pInt, Nchunks_TwinFamilies - if (plastic_phenopowerlaw_Ntwin(j,instance) > 0_pInt) & - plastic_phenopowerlaw_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of transformation families - case ('ntrans') - if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - Nchunks_TransFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_TransFamilies - plastic_phenopowerlaw_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters depending on number of interactions - case ('interaction_slipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_phenopowerlaw_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_phenopowerlaw_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_phenopowerlaw_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_phenopowerlaw_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('nonschmid_coefficients') - if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') - do j = 1_pInt,Nchunks_nonSchmid - plastic_phenopowerlaw_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo -!-------------------------------------------------------------------------------------------------- -! parameters independent of number of slip/twin systems - case ('gdot0_slip') - plastic_phenopowerlaw_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_slip') - plastic_phenopowerlaw_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('a_slip', 'w0_slip') - plastic_phenopowerlaw_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('gdot0_twin') - plastic_phenopowerlaw_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('n_twin') - plastic_phenopowerlaw_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('s_pr') - plastic_phenopowerlaw_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_b') - plastic_phenopowerlaw_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_c') - plastic_phenopowerlaw_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_d') - plastic_phenopowerlaw_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twin_e') - plastic_phenopowerlaw_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_slipslip') - plastic_phenopowerlaw_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twinslip') - plastic_phenopowerlaw_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('h0_twintwin') - plastic_phenopowerlaw_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_resistance') - plastic_phenopowerlaw_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_shear') - plastic_phenopowerlaw_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_twinfrac') - plastic_phenopowerlaw_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_transfrac') - plastic_phenopowerlaw_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cnuc') - plastic_phenopowerlaw_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cdwp') - plastic_phenopowerlaw_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('cgro') - plastic_phenopowerlaw_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('deltag') - plastic_phenopowerlaw_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) - case default - - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then - instance = phase_plasticityInstance(phase) - plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested - plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance)) - plastic_phenopowerlaw_Ntwin(1:lattice_maxNtwinFamily,instance) = & - min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested - plastic_phenopowerlaw_Ntwin(:,instance)) - plastic_phenopowerlaw_totalNslip(instance) = sum(plastic_phenopowerlaw_Nslip(:,instance)) ! how many slip systems altogether - plastic_phenopowerlaw_totalNtwin(instance) = sum(plastic_phenopowerlaw_Ntwin(:,instance)) ! how many twin systems altogether - plastic_phenopowerlaw_totalNtrans(instance) = sum(plastic_phenopowerlaw_Ntrans(:,instance)) ! how many trans systems altogether - - if (any(plastic_phenopowerlaw_tau0_slip(:,instance) < 0.0_pReal .and. & - plastic_phenopowerlaw_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (plastic_phenopowerlaw_gdot0_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (plastic_phenopowerlaw_n_slip(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (any(plastic_phenopowerlaw_tausat_slip(:,instance) <= 0.0_pReal .and. & - plastic_phenopowerlaw_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (any(abs(plastic_phenopowerlaw_a_slip(instance)) <= tiny(0.0_pReal) .and. & - plastic_phenopowerlaw_Nslip(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (any(plastic_phenopowerlaw_tau0_twin(:,instance) < 0.0_pReal .and. & - plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') - if ( plastic_phenopowerlaw_gdot0_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') - if ( plastic_phenopowerlaw_n_twin(instance) <= 0.0_pReal .and. & - any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & - call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') - if (plastic_phenopowerlaw_aTolResistance(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa - if (plastic_phenopowerlaw_aTolShear(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenopowerlaw_aTolTwinfrac(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - if (plastic_phenopowerlaw_aTolTransfrac(instance) <= 0.0_pReal) & - plastic_phenopowerlaw_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - allocate(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from slip activity - maxval(plastic_phenopowerlaw_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from twin activity - maxval(plastic_phenopowerlaw_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from slip activity - maxval(plastic_phenopowerlaw_totalNslip),& - maxNinstance), source=0.0_pReal) - allocate(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from twin activity - maxval(plastic_phenopowerlaw_totalNtwin),& - maxNinstance), source=0.0_pReal) - allocate(state(maxNinstance)) - allocate(state0(maxNinstance)) - allocate(dotState(maxNinstance)) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config - myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then ! only consider my phase - NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase - instance = phase_plasticityInstance(phase) ! which instance of my phase - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) - select case(plastic_phenopowerlaw_outputID(o,instance)) - case(resistance_slip_ID, & - shearrate_slip_ID, & - accumulatedshear_slip_ID, & - resolvedstress_slip_ID & - ) - mySize = plastic_phenopowerlaw_totalNslip(instance) - case(resistance_twin_ID, & - shearrate_twin_ID, & - accumulatedshear_twin_ID, & - resolvedstress_twin_ID & - ) - mySize = plastic_phenopowerlaw_totalNtwin(instance) - case(totalshear_ID, & - totalvolfrac_twin_ID & - ) - mySize = 1_pInt - case default - end select - - outputFound: if (mySize > 0_pInt) then - plastic_phenopowerlaw_sizePostResult(o,instance) = mySize - plastic_phenopowerlaw_sizePostResults(instance) = plastic_phenopowerlaw_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop -!-------------------------------------------------------------------------------------------------- -! allocate state arrays - sizeState = plastic_phenopowerlaw_totalNslip(instance) & ! s_slip - + plastic_phenopowerlaw_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) - + plastic_phenopowerlaw_totalNslip(instance) & ! accshear_slip - + plastic_phenopowerlaw_totalNtwin(instance) ! accshear_twin - - sizeDotState = sizeState - sizeDeltaState = 0_pInt - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_phenopowerlaw_sizePostResults(instance) - plasticState(phase)%nSlip =plastic_phenopowerlaw_totalNslip(instance) - plasticState(phase)%nTwin =plastic_phenopowerlaw_totalNtwin(instance) - plasticState(phase)%nTrans=plastic_phenopowerlaw_totalNtrans(instance) - allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) - allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) - - offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) - - do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X - index_myFamily = sum(plastic_phenopowerlaw_Nslip(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) ! loop over (active) systems in my family (slip) - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenopowerlaw_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_SlipSlip(lattice_interactionSlipSlip( & - sum(lattice_NslipSystem(1:f-1,phase))+j, & - sum(lattice_NslipSystem(1:o-1,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenopowerlaw_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_SlipTwin(lattice_interactionSlipTwin( & - sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - - do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X - index_myFamily = sum(plastic_phenopowerlaw_Ntwin(1:f-1_pInt,instance)) - do j = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) ! loop over (active) systems in my family (twin) - - do o = 1_pInt,lattice_maxNslipFamily - index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) - plastic_phenopowerlaw_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_TwinSlip(lattice_interactionTwinSlip( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - do o = 1_pInt,lattice_maxNtwinFamily - index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) - do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) - plastic_phenopowerlaw_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & - plastic_phenopowerlaw_interaction_TwinTwin(lattice_interactionTwinTwin( & - sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & - sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & - phase), instance ) - enddo; enddo - - enddo; enddo - startIndex = 1_pInt - endIndex = plastic_phenopowerlaw_totalNslip(instance) - state (instance)%s_slip=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%s_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%s_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex + plastic_phenopowerlaw_totalNtwin(instance) - state (instance)%s_twin=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%s_twin=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%s_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex + 1_pInt - state (instance)%sumGamma=>plasticState(phase)%state (startIndex,:) - state0 (instance)%sumGamma=>plasticState(phase)%state0 (startIndex,:) - dotState(instance)%sumGamma=>plasticState(phase)%dotState(startIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex + 1_pInt - state (instance)%sumF=>plasticState(phase)%state (startIndex,:) - state0 (instance)%sumF=>plasticState(phase)%state0 (startIndex,:) - dotState(instance)%sumF=>plasticState(phase)%dotState(startIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex +plastic_phenopowerlaw_totalNslip(instance) - state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - startIndex = endIndex + 1_pInt - endIndex = endIndex +plastic_phenopowerlaw_totalNtwin(instance) - state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) - state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) - dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) - - - call plastic_phenopowerlaw_stateInit(phase,instance) - call plastic_phenopowerlaw_aTolState(phase,instance) - endif myPhase2 - enddo initializeInstances - -end subroutine plastic_phenopowerlaw_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_stateInit(ph,instance) - use lattice, only: & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - integer(pInt) :: & - i - real(pReal), dimension(plasticState(ph)%sizeState) :: & - tempState - - tempState = 0.0_pReal - do i = 1_pInt,lattice_maxNslipFamily - tempState(1+sum(plastic_phenopowerlaw_Nslip(1:i-1,instance)) : & - sum(plastic_phenopowerlaw_Nslip(1:i ,instance))) = & - plastic_phenopowerlaw_tau0_slip(i,instance) - enddo - - do i = 1_pInt,lattice_maxNtwinFamily - tempState(1+sum(plastic_phenopowerlaw_Nslip(:,instance))+& - sum(plastic_phenopowerlaw_Ntwin(1:i-1,instance)) : & - sum(plastic_phenopowerlaw_Nslip(:,instance))+& - sum(plastic_phenopowerlaw_Ntwin(1:i ,instance))) = & - plastic_phenopowerlaw_tau0_twin(i,instance) - enddo - - plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array - 2, & ! along dimension 2 - size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) - -end subroutine plastic_phenopowerlaw_stateInit - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the relevant state values for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_aTolState(ph,instance) - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: & - instance, & !< number specifying the instance of the plasticity - ph - - plasticState(ph)%aTolState(1:plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance)) = & - plastic_phenopowerlaw_aTolResistance(instance) - plasticState(ph)%aTolState(1+plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance)) = & - plastic_phenopowerlaw_aTolShear(instance) - plasticState(ph)%aTolState(2+plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance)) = & - plastic_phenopowerlaw_aTolTwinFrac(instance) - plasticState(ph)%aTolState(3+plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance): & - 2+2*(plastic_phenopowerlaw_totalNslip(instance)+ & - plastic_phenopowerlaw_totalNtwin(instance))) = & - plastic_phenopowerlaw_aTolShear(instance) - -end subroutine plastic_phenopowerlaw_aTolState - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) - use math, only: & - math_Plain3333to99, & - math_Mandel6to33 - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - use material, only: & - phaseAt, phasememberAt, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - - integer(pInt) :: & - instance, & - index_myFamily, & - f,i,j,k,l,m,n, & - of, & - ph - real(pReal) :: & - tau_slip_pos,tau_slip_neg, & - gdot_slip_pos,gdot_slip_neg, & - dgdot_dtauslip_pos,dgdot_dtauslip_neg, & - gdot_twin,dgdot_dtautwin,tau_twin - real(pReal), dimension(3,3,3,3) :: & - dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor - real(pReal), dimension(3,3,2) :: & - nonSchmid_tensor - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! Slip part - j = 0_pInt - slipFamilies: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) - nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& - lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) - enddo - gdot_slip_pos = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & - ((abs(tau_slip_pos)/(state(instance)%s_slip(j,of))) & - **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) - - gdot_slip_neg = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & - ((abs(tau_slip_neg)/(state(instance)%s_slip(j,of))) & - **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) - - Lp = Lp + (1.0_pReal-state(instance)%sumF(of))*& ! 1-F - (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then - dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenopowerlaw_n_slip(instance)/tau_slip_pos - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,1) - endif - - if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then - dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenopowerlaw_n_slip(instance)/tau_slip_neg - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & - nonSchmid_tensor(m,n,2) - endif - enddo slipSystems - enddo slipFamilies - -!-------------------------------------------------------------------------------------------------- -! Twinning part - j = 0_pInt - twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j+1_pInt - - ! Calculation of Lp - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin = (1.0_pReal-state(instance)%sumF(of))*& ! 1-F - plastic_phenopowerlaw_gdot0_twin(instance)*& - (abs(tau_twin)/state(instance)%s_twin(j,of))**& - plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) - - ! Calculation of the tangent of Lp - if (abs(gdot_twin) > tiny(0.0_pReal)) then - dgdot_dtautwin = gdot_twin*plastic_phenopowerlaw_n_twin(instance)/tau_twin - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & - dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & - lattice_Stwin(m,n,index_myFamily+i,ph) - endif - enddo twinSystems - enddo twinFamilies - - dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) - - -end subroutine plastic_phenopowerlaw_LpAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_phenopowerlaw_dotState(Tstar_v,ipc,ip,el) - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_shearTwin, & - lattice_NnonSchmid - use material, only: & - material_phase, & - phaseAt, phasememberAt, & - plasticState, & - phase_plasticityInstance - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - integer(pInt) :: & - instance,ph, & - nSlip,nTwin, & - f,i,j,k, & - index_Gamma,index_F,index_myFamily, & - offset_accshear_slip,offset_accshear_twin, & - of - real(pReal) :: & - c_SlipSlip,c_TwinSlip,c_TwinTwin, & - ssat_offset, & - tau_slip_pos,tau_slip_neg,tau_twin - - real(pReal), dimension(plastic_phenopowerlaw_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip - real(pReal), dimension(plastic_phenopowerlaw_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenopowerlaw_totalNslip(instance) - nTwin = plastic_phenopowerlaw_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - offset_accshear_slip = nSlip + nTwin + 2_pInt - offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip - plasticState(ph)%dotState(:,of) = 0.0_pReal - - -!-------------------------------------------------------------------------------------------------- -! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices - c_SlipSlip = plastic_phenopowerlaw_h0_SlipSlip(instance)*& - (1.0_pReal + plastic_phenopowerlaw_twinC(instance)*plasticState(ph)%state(index_F,of)**& - plastic_phenopowerlaw_twinB(instance)) - c_TwinSlip = plastic_phenopowerlaw_h0_TwinSlip(instance)*& - plasticState(ph)%state(index_Gamma,of)**plastic_phenopowerlaw_twinE(instance) - c_TwinTwin = plastic_phenopowerlaw_h0_TwinTwin(instance)*& - plasticState(ph)%state(index_F,of)**plastic_phenopowerlaw_twinD(instance) - -!-------------------------------------------------------------------------------------------------- -! calculate left and right vectors and calculate dot gammas - ssat_offset = plastic_phenopowerlaw_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j+1_pInt - left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part - left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part - right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) & - **plastic_phenopowerlaw_a_slip(instance)& - *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & - (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) - right_TwinSlip(j) = 1.0_pReal ! no system-dependent part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot gamma - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo nonSchmidSystems - gdot_slip(j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance) & - +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - enddo slipSystems1 - enddo slipFamilies1 - - - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j+1_pInt - left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part - left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part - right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part - right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part - -!-------------------------------------------------------------------------------------------------- -! Calculation of dot vol frac - tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenopowerlaw_gdot0_twin(instance)*& - (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& - plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) - enddo twinSystems1 - enddo twinFamilies1 - -!-------------------------------------------------------------------------------------------------- -! calculate the overall hardening based on above - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j - c_SlipSlip * left_SlipSlip(j) * & - dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & - right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & - right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & - abs(gdot_slip(j)) - plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) - enddo slipSystems2 - enddo slipFamilies2 - - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j+1_pInt - plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j - c_TwinSlip * left_TwinSlip(j) * & - dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & - right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor - c_TwinTwin * left_TwinTwin(j) * & - dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & - right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor - if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 - plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & - gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) - plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) - enddo twinSystems2 - enddo twinFamilies2 - - -end subroutine plastic_phenopowerlaw_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_phenopowerlaw_postResults(Tstar_v,ipc,ip,el) - use material, only: & - material_phase, & - plasticState, & - phaseAt, phasememberAt, & - phase_plasticityInstance - use lattice, only: & - lattice_Sslip_v, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_NnonSchmid - - implicit none - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element !< microstructure state - - real(pReal), dimension(plastic_phenopowerlaw_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_phenopowerlaw_postResults - - integer(pInt) :: & - instance,ph, of, & - nSlip,nTwin, & - o,f,i,c,j,k, & - index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily - real(pReal) :: & - tau_slip_pos,tau_slip_neg,tau - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - - nSlip = plastic_phenopowerlaw_totalNslip(instance) - nTwin = plastic_phenopowerlaw_totalNtwin(instance) - - index_Gamma = nSlip + nTwin + 1_pInt - index_F = nSlip + nTwin + 2_pInt - index_accshear_slip = nSlip + nTwin + 3_pInt - index_accshear_twin = nSlip + nTwin + 3_pInt + nSlip - - plastic_phenopowerlaw_postResults = 0.0_pReal - c = 0_pInt - - outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) - select case(plastic_phenopowerlaw_outputID(o,instance)) - case (resistance_slip_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) - c = c + nSlip - - case (accumulatedshear_slip_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& - index_accshear_slip+nSlip-1_pInt,of) - c = c + nSlip - - case (shearrate_slip_ID) - j = 0_pInt - slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j + 1_pInt - tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_pos - do k = 1,lattice_NnonSchmid(ph) - tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) - tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & - dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) - enddo - plastic_phenopowerlaw_postResults(c+j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & - ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance) & - +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance))& - *sign(1.0_pReal,tau_slip_pos) - - enddo slipSystems1 - enddo slipFamilies1 - c = c + nSlip - - case (resolvedstress_slip_ID) - j = 0_pInt - slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) - j = j + 1_pInt - plastic_phenopowerlaw_postResults(c+j) = & - dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) - enddo slipSystems2 - enddo slipFamilies2 - c = c + nSlip - - case (totalshear_ID) - plastic_phenopowerlaw_postResults(c+1_pInt) = & - plasticState(ph)%state(index_Gamma,of) - c = c + 1_pInt - - case (resistance_twin_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) - c = c + nTwin - - case (accumulatedshear_twin_ID) - plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & - plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) - c = c + nTwin - case (shearrate_twin_ID) - j = 0_pInt - twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j + 1_pInt - tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - plastic_phenopowerlaw_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F - plastic_phenopowerlaw_gdot0_twin(instance)*& - (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& - plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) - enddo twinSystems1 - enddo twinFamilies1 - c = c + nTwin - - case (resolvedstress_twin_ID) - j = 0_pInt - twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) - j = j + 1_pInt - plastic_phenopowerlaw_postResults(c+j) = & - dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) - enddo twinSystems2 - enddo twinFamilies2 - c = c + nTwin - - case (totalvolfrac_twin_ID) - plastic_phenopowerlaw_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) - c = c + 1_pInt - - end select - enddo outputsLoop - -end function plastic_phenopowerlaw_postResults - -end module plastic_phenopowerlaw diff --git a/code/plastic_titanmod.f90 b/code/plastic_titanmod.f90 deleted file mode 100644 index abc6d661b..000000000 --- a/code/plastic_titanmod.f90 +++ /dev/null @@ -1,1913 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Alankar Alankar, 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 -!> @brief material subroutine for titanium -!-------------------------------------------------------------------------------------------------- -module plastic_titanmod - use prec, only: & - pReal, & - pInt - - implicit none - private - character(len=18), dimension(3), parameter, private :: & - plastic_titanmod_listBasicSlipStates = & - ['rho_edge ', 'rho_screw ', 'shear_system'] - character(len=18), dimension(1), parameter, private :: & - plastic_titanmod_listBasicTwinStates = ['gdot_twin'] - character(len=19), dimension(11), parameter, private :: & - plastic_titanmod_listDependentSlipStates = & - ['segment_edge ', 'segment_screw ', & - 'resistance_edge ', 'resistance_screw ', & - 'tau_slip ', & - 'velocity_edge ', 'velocity_screw ', & - 'gdot_slip_edge ', 'gdot_slip_screw ', & - 'stressratio_edge_p ', 'stressratio_screw_p' ] - character(len=18), dimension(2), parameter, private :: & - plastic_titanmod_listDependentTwinStates = & - ['twin_fraction', 'tau_twin '] - real(pReal), parameter, private :: & - kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin - - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_titanmod_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - plastic_titanmod_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - plastic_titanmod_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - plastic_titanmod_Noutput !< number of outputs per instance of this plasticity !< ID of the lattice structure - - integer(pInt), dimension(:), allocatable, public, protected :: & - plastic_titanmod_totalNslip, & !< total number of active slip systems for each instance - plastic_titanmod_totalNtwin !< total number of active twin systems for each instance - - integer(pInt), dimension(:,:), allocatable, private :: & - plastic_titanmod_Nslip, & !< number of active slip systems for each family and instance - plastic_titanmod_Ntwin, & !< number of active twin systems for each family and instance - plastic_titanmod_slipFamily, & !< lookup table relating active slip system to slip family for each instance - plastic_titanmod_twinFamily, & !< lookup table relating active twin system to twin family for each instance - plastic_titanmod_slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance - plastic_titanmod_twinSystemLattice !< lookup table relating active twin system index to lattice twin system index for each instance - - real(pReal), dimension(:), allocatable, private :: & - plastic_titanmod_debyefrequency, & !< Debye frequency - plastic_titanmod_kinkf0, & !< - plastic_titanmod_CAtomicVolume, & !< atomic volume in Bugers vector unit - plastic_titanmod_dc, & !< prefactor for self-diffusion coefficient - plastic_titanmod_twinhpconstant, & !< activation energy for dislocation climb - plastic_titanmod_GrainSize, & !< grain size - Not being used - plastic_titanmod_MaxTwinFraction, & !< maximum allowed total twin volume fraction - plastic_titanmod_r, & !< r-exponent in twin nucleation rate - plastic_titanmod_CEdgeDipMinDistance, & !< Not being used - plastic_titanmod_Cmfptwin, & !< Not being used - plastic_titanmod_Cthresholdtwin, & !< Not being used - plastic_titanmod_aTolRho !< absolute tolerance for integration of dislocation density - - real(pReal), dimension(:,:), allocatable, private :: & - plastic_titanmod_rho_edge0, & !< initial edge dislocation density per slip system for each family and instance - plastic_titanmod_rho_screw0, & !< initial screw dislocation density per slip system for each family and instance - plastic_titanmod_shear_system0, & !< accumulated shear on each system - plastic_titanmod_burgersPerSlipFam, & !< absolute length of burgers vector [m] for each slip family and instance - plastic_titanmod_burgersPerSlipSys, & !< absolute length of burgers vector [m] for each slip system and instance - plastic_titanmod_burgersPerTwinFam, & !< absolute length of burgers vector [m] for each twin family and instance - plastic_titanmod_burgersPerTwinSys, & !< absolute length of burgers vector [m] for each twin system and instance - plastic_titanmod_f0_PerSlipFam, & !< activation energy for glide [J] for each slip family and instance - plastic_titanmod_f0_PerSlipSys, & !< activation energy for glide [J] for each slip system and instance - plastic_titanmod_twinf0_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance - plastic_titanmod_twinf0_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance - plastic_titanmod_twinshearconstant_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance - plastic_titanmod_twinshearconstant_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance - plastic_titanmod_tau0e_PerSlipFam, & !< Initial yield stress for edge dislocations per slip family - plastic_titanmod_tau0e_PerSlipSys, & !< Initial yield stress for edge dislocations per slip system - plastic_titanmod_tau0s_PerSlipFam, & !< Initial yield stress for screw dislocations per slip family - plastic_titanmod_tau0s_PerSlipSys, & !< Initial yield stress for screw dislocations per slip system - plastic_titanmod_twintau0_PerTwinFam, & !< Initial yield stress for edge dislocations per twin family - plastic_titanmod_twintau0_PerTwinSys, & !< Initial yield stress for edge dislocations per twin system - plastic_titanmod_capre_PerSlipFam, & !< Capture radii for edge dislocations per slip family - plastic_titanmod_capre_PerSlipSys, & !< Capture radii for edge dislocations per slip system - plastic_titanmod_caprs_PerSlipFam, & !< Capture radii for screw dislocations per slip family - plastic_titanmod_caprs_PerSlipSys, & !< Capture radii for screw dislocations per slip system - plastic_titanmod_pe_PerSlipFam, & !< p-exponent in glide velocity - plastic_titanmod_ps_PerSlipFam, & !< p-exponent in glide velocity - plastic_titanmod_qe_PerSlipFam, & !< q-exponent in glide velocity - plastic_titanmod_qs_PerSlipFam, & !< q-exponent in glide velocity - plastic_titanmod_pe_PerSlipSys, & !< p-exponent in glide velocity - plastic_titanmod_ps_PerSlipSys, & !< p-exponent in glide velocity - plastic_titanmod_qe_PerSlipSys, & !< q-exponent in glide velocity - plastic_titanmod_qs_PerSlipSys, & !< q-exponent in glide velocity - plastic_titanmod_twinp_PerTwinFam, & !< p-exponent in glide velocity - plastic_titanmod_twinq_PerTwinFam, & !< q-exponent in glide velocity - plastic_titanmod_twinp_PerTwinSys, & !< p-exponent in glide velocity - plastic_titanmod_twinq_PerTwinSys, & !< p-exponent in glide velocity - plastic_titanmod_v0e_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance - plastic_titanmod_v0e_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance - plastic_titanmod_v0s_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance - plastic_titanmod_v0s_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance - plastic_titanmod_twingamma0_PerTwinFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance - plastic_titanmod_twingamma0_PerTwinSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance - plastic_titanmod_kinkcriticallength_PerSlipFam, & !< screw dislocation mobility prefactor for kink-pairs per slip family - plastic_titanmod_kinkcriticallength_PerSlipSys, & !< screw dislocation mobility prefactor for kink-pairs per slip system - plastic_titanmod_twinsizePerTwinFam, & !< twin thickness [m] for each twin family and instance - plastic_titanmod_twinsizePerTwinSys, & !< twin thickness [m] for each twin system and instance - plastic_titanmod_CeLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_titanmod_CeLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_titanmod_CsLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_titanmod_CsLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_titanmod_twinLambdaSlipPerTwinFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance - plastic_titanmod_twinLambdaSlipPerTwinSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance - plastic_titanmod_interactionSlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance - plastic_titanmod_interaction_ee, & !< coefficients for e-e interaction for each interaction type and instance - plastic_titanmod_interaction_ss, & !< coefficients for s-s interaction for each interaction type and instance - plastic_titanmod_interaction_es, & !< coefficients for e-s-twin interaction for each interaction type and instance - plastic_titanmod_interactionSlipTwin, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_titanmod_interactionTwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance - plastic_titanmod_interactionTwinTwin !< coefficients for twin-twin interaction for each interaction type and instance - - real(pReal), dimension(:,:,:), allocatable, private :: & - plastic_titanmod_interactionMatrixSlipSlip, & !< interaction matrix of the different slip systems for each instance - plastic_titanmod_interactionMatrix_ee, & !< interaction matrix of e-e for each instance - plastic_titanmod_interactionMatrix_ss, & !< interaction matrix of s-s for each instance - plastic_titanmod_interactionMatrix_es, & !< interaction matrix of e-s for each instance - plastic_titanmod_interactionMatrixSlipTwin, & !< interaction matrix of slip systems with twin systems for each instance - plastic_titanmod_interactionMatrixTwinSlip, & !< interaction matrix of twin systems with slip systems for each instance - plastic_titanmod_interactionMatrixTwinTwin, & !< interaction matrix of the different twin systems for each instance - plastic_titanmod_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance - plastic_titanmod_forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance - plastic_titanmod_TwinforestProjectionEdge, & !< matrix of forest projections of edge dislocations in twin system for each instance - plastic_titanmod_TwinforestProjectionScrew !< matrix of forest projections of screw dislocations in twin system for each instance - - real(pReal), dimension(:,:,:,:), allocatable, private :: & - plastic_titanmod_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance - - real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & - plastic_titanmod_Ctwin3333 !< twin elasticity matrix for each instance - - enum, bind(c) - enumerator :: undefined_ID, & - rhoedge_ID, rhoscrew_ID, & - segment_edge_ID, segment_screw_ID, & - resistance_edge_ID, resistance_screw_ID, & - velocity_edge_ID, velocity_screw_ID, & - tau_slip_ID, & - gdot_slip_edge_ID, gdot_slip_screw_ID, & - gdot_slip_ID, & - stressratio_edge_p_ID, stressratio_screw_p_ID, & - shear_system_ID, & - twin_fraction_ID, & - shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & - rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & - rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & - shear_total_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - plastic_titanmod_outputID !< ID of each post result output - - public :: & - plastic_titanmod_microstructure, & - plastic_titanmod_stateInit, & - plastic_titanmod_init, & - plastic_titanmod_LpAndItsTangent, & - plastic_titanmod_dotState, & - plastic_titanmod_postResults, & - plastic_titanmod_homogenizedC - - contains - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use math, only: & - math_Mandel3333to66,& - math_Voigt66to3333,& - math_mul3x3 - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_plasticity, & - phase_plasticityInstance, & - phase_Noutput, & - PLASTICITY_TITANMOD_label, & - PLASTICITY_TITANMOD_ID, & - plasticState, & - MATERIAL_partPhase - use lattice - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: & - phase, & - instance, j, k, l, m, n, p, q, r, & - f, o, & - s, s1, s2, & - t, t1, t2, & - ns, nt, & - Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & - Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & - offset_slip, mySize, & - maxTotalNslip,maxTotalNtwin, maxNinstance - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase = 0_pInt - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_TITANMOD_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_plasticity == PLASTICITY_TITANMOD_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(plastic_titanmod_sizePostResults(maxNinstance), source=0_pInt) - allocate(plastic_titanmod_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) - allocate(plastic_titanmod_output(maxval(phase_Noutput),maxNinstance)) - plastic_titanmod_output = '' - allocate(plastic_titanmod_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(plastic_titanmod_Noutput(maxNinstance), source=0_pInt) - - allocate(plastic_titanmod_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_slipFamily(lattice_maxNslip,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_twinFamily(lattice_maxNtwin,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_slipSystemLattice(lattice_maxNslip,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_twinSystemLattice(lattice_maxNtwin,maxNinstance), source=0_pInt) - allocate(plastic_titanmod_totalNslip(maxNinstance), source=0_pInt) - allocate(plastic_titanmod_totalNtwin(maxNinstance), source=0_pInt) - allocate(plastic_titanmod_debyefrequency(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_kinkf0(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CAtomicVolume(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_dc(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinhpconstant(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_GrainSize(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_MaxTwinFraction(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_r(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Cmfptwin(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Cthresholdtwin(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_aTolRho(maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_rho_edge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_rho_screw0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_shear_system0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_burgersPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_burgersPerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_f0_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_capre_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_caprs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_pe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_ps_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_kinkcriticallength_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinsizePerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CeLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CsLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_twinf0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinshearconstant_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twintau0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinp_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinq_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twingamma0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinLambdaSlipPerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_interactionSlipSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interaction_ee(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interaction_ss(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interaction_es(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionSlipTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionTwinSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionTwinTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next section - phase = phase + 1_pInt ! advance section counter - if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then - Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) - Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) - Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) - Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) - Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) - Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) - endif - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then ! one of my sections. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran - instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('rhoedge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('segment_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('segment_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('resistance_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('velocity_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('tau_slip') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = tau_slip_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('gdot_slip_edge') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_edge_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('gdot_slip_screw') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_screw_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('gdot_slip') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stressratio_edge_p') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_edge_p_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('stressratio_screw_p') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_screw_p_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_system') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_system_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('twin_fraction') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = twin_fraction_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_basal') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_basal_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_prism') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_prism_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_pyra') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyra_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_pyrca') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyrca_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_basal') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_basal_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_prism') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_prism_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_pyra') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyra_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoedge_pyrca') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyrca_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_basal') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_basal_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_prism') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_prism_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_pyra') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyra_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('rhoscrew_pyrca') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyrca_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - case ('shear_total') - plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt - plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_total_ID - plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - case ('debyefrequency') - plastic_titanmod_debyefrequency(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('kinkf0') - plastic_titanmod_kinkf0(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('nslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & - call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('ntwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinFamilies) & - call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - case ('rho_edge0') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_rho_edge0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('rho_screw0') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_rho_screw0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('slipburgers') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_burgersPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinburgers') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_burgersPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('f0') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_f0_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinf0') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinf0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0e') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_tau0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twintau0') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twintau0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('tau0s') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_tau0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('capre') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_capre_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('caprs') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_caprs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('v0e') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_v0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twingamma0') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twingamma0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('v0s') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_v0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('kinkcriticallength') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_kinkcriticallength_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinsize') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinsizePerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('celambdaslip') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_CeLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinlambdaslip') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinlambdaslipPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('cslambdaslip') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_CsLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('grainsize') - plastic_titanmod_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('maxtwinfraction') - plastic_titanmod_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('pe') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_pe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinp') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinp_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('ps') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_ps_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('qe') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_qe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinq') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinq_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('qs') - do j = 1_pInt, Nchunks_SlipFamilies - plastic_titanmod_qs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('twinshearconstant') - do j = 1_pInt, Nchunks_TwinFamilies - plastic_titanmod_twinshearconstant_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('dc') - plastic_titanmod_dc(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('twinhpconstant') - plastic_titanmod_twinhpconstant(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('atol_rho') - plastic_titanmod_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) - case ('interactionee') - do j = 1_pInt, lattice_maxNinteraction - plastic_titanmod_interaction_ee(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interactionss') - do j = 1_pInt, lattice_maxNinteraction - plastic_titanmod_interaction_ss(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interactiones') - do j = 1_pInt, lattice_maxNinteraction - plastic_titanmod_interaction_es(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_slipslip','interactionslipslip') - if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_SlipSlip - plastic_titanmod_interactionSlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_sliptwin','interactionsliptwin') - if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_SlipTwin - plastic_titanmod_interactionSlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twinslip','interactiontwinslip') - if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_TwinSlip - plastic_titanmod_interactionTwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - case ('interaction_twintwin','interactiontwintwin') - if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & - call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') - do j = 1_pInt, Nchunks_TwinTwin - plastic_titanmod_interactionTwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - end select - endif; endif - enddo parsingFile - - sanityChecks: do phase = 1_pInt, size(phase_plasticity) - myPhase: if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then - instance = phase_plasticityInstance(phase) - if (sum(plastic_titanmod_Nslip(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='nslip ('//PLASTICITY_TITANMOD_label//')') - if (sum(plastic_titanmod_Ntwin(:,instance)) < 0_pInt) & - call IO_error(211_pInt,el=instance,ext_msg='ntwin ('//PLASTICITY_TITANMOD_label//')') - do f = 1_pInt,lattice_maxNslipFamily - if (plastic_titanmod_Nslip(f,instance) > 0_pInt) then - if (plastic_titanmod_rho_edge0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rho_edge0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_rho_screw0(f,instance) < 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rho_screw0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_burgersPerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='slipburgers ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_f0_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='f0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_tau0e_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau0e ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_tau0s_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='tau0s ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_capre_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='capre ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_caprs_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='caprs ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_v0e_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0e ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_v0s_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='v0s ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='kinkCriticalLength ('//PLASTICITY_TITANMOD_label//')') - endif - enddo - do f = 1_pInt,lattice_maxNtwinFamily - if (plastic_titanmod_Ntwin(f,instance) > 0_pInt) then - if (plastic_titanmod_burgersPerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twinf0_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinf0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinshearconstant ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twintau0_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twintau0 ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twingamma0_PerTwinFam(f,instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twingamma0 ('//PLASTICITY_TITANMOD_label//')') - endif - enddo - if (plastic_titanmod_dc(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='dc ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_twinhpconstant(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='twinhpconstant ('//PLASTICITY_TITANMOD_label//')') - if (plastic_titanmod_aTolRho(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='aTol_rho ('//PLASTICITY_TITANMOD_label//')') - -!-------------------------------------------------------------------------------------------------- -! determine total number of active slip or twin systems - plastic_titanmod_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_titanmod_Nslip(:,instance)) - plastic_titanmod_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_titanmod_Ntwin(:,instance)) - plastic_titanmod_totalNslip(instance) = sum(plastic_titanmod_Nslip(:,instance)) - plastic_titanmod_totalNtwin(instance) = sum(plastic_titanmod_Ntwin(:,instance)) - endif myPhase - enddo sanityChecks - -!-------------------------------------------------------------------------------------------------- -! allocation of variables whose size depends on the total number of active slip systems - maxTotalNslip = maxval(plastic_titanmod_totalNslip) - maxTotalNtwin = maxval(plastic_titanmod_totalNtwin) - - allocate(plastic_titanmod_burgersPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_f0_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_tau0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_capre_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_caprs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_pe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_ps_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_qs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_v0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_kinkcriticallength_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CeLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_CsLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_burgersPerTwinSys(maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinf0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinshearconstant_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twintau0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinp_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinq_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twingamma0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinsizePerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_twinLambdaSlipPerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Ctwin66 (6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_Ctwin3333 (3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) - - allocate(plastic_titanmod_interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrix_ee(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrix_ss(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrix_es(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrixSlipTwin(maxTotalNslip,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrixTwinSlip(maxTotalNtwin,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_interactionMatrixTwinTwin(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_TwinforestProjectionEdge(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) - allocate(plastic_titanmod_TwinforestProjectionScrew(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, size(phase_plasticity) - if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then - instance = phase_plasticityInstance(phase) - -!-------------------------------------------------------------------------------------------------- -! inverse lookup of slip system family - l = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily - do s = 1_pInt,plastic_titanmod_Nslip(f,instance) - l = l + 1_pInt - plastic_titanmod_slipFamily(l,instance) = f - plastic_titanmod_slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt,phase)) + s - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! inverse lookup of twin system family - l = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily - do t = 1_pInt,plastic_titanmod_Ntwin(f,instance) - l = l + 1_pInt - plastic_titanmod_twinFamily(l,instance) = f - plastic_titanmod_twinSystemLattice(l,instance) = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) + t - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! determine size of state array - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - sizeDotState = & - size(plastic_titanmod_listBasicSlipStates)*ns + & - size(plastic_titanmod_listBasicTwinStates)*nt - sizeState = sizeDotState+ & - size(plastic_titanmod_listDependentSlipStates)*ns + & - size(plastic_titanmod_listDependentTwinStates)*nt - sizeDeltaState = 0_pInt - -!-------------------------------------------------------------------------------------------------- -! determine size of postResults array - outputsLoop: do o = 1_pInt,plastic_titanmod_Noutput(instance) - mySize = 0_pInt - select case(plastic_titanmod_outputID(o,instance)) - case(rhoedge_ID, rhoscrew_ID, & - segment_edge_ID, segment_screw_ID, & - resistance_edge_ID, resistance_screw_ID, & - velocity_edge_ID, velocity_screw_ID, & - tau_slip_ID, & - gdot_slip_edge_ID, gdot_slip_screw_ID, & - gdot_slip_ID, & - stressratio_edge_p_ID, stressratio_screw_p_ID, & - shear_system_ID) - mySize = plastic_titanmod_totalNslip(instance) - case(twin_fraction_ID) - mySize = plastic_titanmod_totalNtwin(instance) - case(shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & ! use only if all 4 slip families in hex are considered - rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & - rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & - shear_total_ID) - mySize = 1_pInt - case default - call IO_error(105_pInt,ext_msg=plastic_titanmod_output(o,instance)// & - ' ('//PLASTICITY_TITANMOD_label//')') - end select - - outputFound: if (mySize > 0_pInt) then - plastic_titanmod_sizePostResult(o,instance) = mySize - plastic_titanmod_sizePostResults(instance) = plastic_titanmod_sizePostResults(instance) + mySize - endif outputFound - enddo outputsLoop -! Determine size of state array - plasticState(phase)%sizeState = sizeState - plasticState(phase)%sizeDotState = sizeDotState - plasticState(phase)%sizeDeltaState = sizeDeltaState - plasticState(phase)%sizePostResults = plastic_titanmod_sizePostResults(instance) - plasticState(phase)%nSlip =plastic_titanmod_totalNslip(instance) - plasticState(phase)%nTwin = 0_pInt - plasticState(phase)%nTrans= 0_pInt - allocate(plasticState(phase)%aTolState (sizeState), source=plastic_titanmod_aTolRho(instance)) - allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - offset_slip = 2_pInt*plasticState(phase)%nSlip+1 - plasticState(phase)%slipRate => & - plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) - plasticState(phase)%accumulatedSlip => & - plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) -!-------------------------------------------------------------------------------------------------- -! construction of the twin elasticity matrices - do j=1_pInt,lattice_maxNtwinFamily - do k=1_pInt,plastic_titanmod_Ntwin(j,instance) - do l=1_pInt,3_pInt ; do m=1_pInt,3_pInt ; do n=1_pInt,3_pInt ; do o=1_pInt,3_pInt - do p=1_pInt,3_pInt ; do q=1_pInt,3_pInt ; do r=1_pInt,3_pInt ; do s=1_pInt,3_pInt - plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) = & - plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) + & - lattice_C3333(p,q,r,s,phase)*& - lattice_Qtwin(l,p,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & - lattice_Qtwin(m,q,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & - lattice_Qtwin(n,r,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & - lattice_Qtwin(o,s,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase) - enddo; enddo; enddo; enddo - enddo; enddo; enddo ; enddo - plastic_titanmod_Ctwin66(1:6,1:6,k,instance) = & - math_Mandel3333to66(plastic_titanmod_Ctwin3333(1:3,1:3,1:3,1:3,k,instance)) - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! Burgers vector, dislocation velocity prefactor for each slip system - do s = 1_pInt,plastic_titanmod_totalNslip(instance) - f = plastic_titanmod_slipFamily(s,instance) - - plastic_titanmod_burgersPerSlipSys(s,instance) = & - plastic_titanmod_burgersPerSlipFam(f,instance) - - plastic_titanmod_f0_PerSlipSys(s,instance) = & - plastic_titanmod_f0_PerSlipFam(f,instance) - - plastic_titanmod_tau0e_PerSlipSys(s,instance) = & - plastic_titanmod_tau0e_PerSlipFam(f,instance) - - plastic_titanmod_tau0s_PerSlipSys(s,instance) = & - plastic_titanmod_tau0s_PerSlipFam(f,instance) - - plastic_titanmod_capre_PerSlipSys(s,instance) = & - plastic_titanmod_capre_PerSlipFam(f,instance) - - plastic_titanmod_caprs_PerSlipSys(s,instance) = & - plastic_titanmod_caprs_PerSlipFam(f,instance) - - plastic_titanmod_v0e_PerSlipSys(s,instance) = & - plastic_titanmod_v0e_PerSlipFam(f,instance) - - plastic_titanmod_v0s_PerSlipSys(s,instance) = & - plastic_titanmod_v0s_PerSlipFam(f,instance) - - plastic_titanmod_kinkcriticallength_PerSlipSys(s,instance) = & - plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) - - plastic_titanmod_pe_PerSlipSys(s,instance) = & - plastic_titanmod_pe_PerSlipFam(f,instance) - - plastic_titanmod_ps_PerSlipSys(s,instance) = & - plastic_titanmod_ps_PerSlipFam(f,instance) - - plastic_titanmod_qe_PerSlipSys(s,instance) = & - plastic_titanmod_qe_PerSlipFam(f,instance) - - plastic_titanmod_qs_PerSlipSys(s,instance) = & - plastic_titanmod_qs_PerSlipFam(f,instance) - - plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance) = & - plastic_titanmod_CeLambdaSlipPerSlipFam(f,instance) - - plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance) = & - plastic_titanmod_CsLambdaSlipPerSlipFam(f,instance) - enddo - -!-------------------------------------------------------------------------------------------------- -! Burgers vector, nucleation rate prefactor and twin size for each twin system - do t = 1_pInt,plastic_titanmod_totalNtwin(instance) - f = plastic_titanmod_twinFamily(t,instance) - - plastic_titanmod_burgersPerTwinSys(t,instance) = & - plastic_titanmod_burgersPerTwinFam(f,instance) - - plastic_titanmod_twinsizePerTwinSys(t,instance) = & - plastic_titanmod_twinsizePerTwinFam(f,instance) - - plastic_titanmod_twinf0_PerTwinSys(t,instance) = & - plastic_titanmod_twinf0_PerTwinFam(f,instance) - - plastic_titanmod_twinshearconstant_PerTwinSys(t,instance) = & - plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) - - plastic_titanmod_twintau0_PerTwinSys(t,instance) = & - plastic_titanmod_twintau0_PerTwinFam(f,instance) - - plastic_titanmod_twingamma0_PerTwinSys(t,instance) = & - plastic_titanmod_twingamma0_PerTwinFam(f,instance) - - plastic_titanmod_twinp_PerTwinSys(t,instance) = & - plastic_titanmod_twinp_PerTwinFam(f,instance) - - plastic_titanmod_twinq_PerTwinSys(t,instance) = & - plastic_titanmod_twinq_PerTwinFam(f,instance) - - plastic_titanmod_twinLambdaSlipPerTwinSys(t,instance) = & - plastic_titanmod_twinLambdaSlipPerTwinFam(f,instance) - enddo - -!-------------------------------------------------------------------------------------------------- -! Construction of interaction matrices - do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) - do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) - plastic_titanmod_interactionMatrixSlipSlip(s1,s2,instance) = & - plastic_titanmod_interactionSlipSlip(lattice_interactionSlipSlip( & - plastic_titanmod_slipSystemLattice(s1,instance),& - plastic_titanmod_slipSystemLattice(s2,instance),phase),instance) - - plastic_titanmod_interactionMatrix_ee(s1,s2,instance) = & - plastic_titanmod_interaction_ee(lattice_interactionSlipSlip ( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - - plastic_titanmod_interactionMatrix_ss(s1,s2,instance) = & - plastic_titanmod_interaction_ss(lattice_interactionSlipSlip( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - - plastic_titanmod_interactionMatrix_es(s1,s2,instance) = & - plastic_titanmod_interaction_es(lattice_interactionSlipSlip( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - enddo; enddo - - do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) - do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) - plastic_titanmod_interactionMatrixSlipTwin(s1,t2,instance) = & - plastic_titanmod_interactionSlipTwin(lattice_interactionSlipTwin( & - plastic_titanmod_slipSystemLattice(s1,instance), & - plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) - enddo; enddo - - do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) - do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) - plastic_titanmod_interactionMatrixTwinSlip(t1,s2,instance) = & - plastic_titanmod_interactionTwinSlip(lattice_interactionTwinSlip( & - plastic_titanmod_twinSystemLattice(t1,instance), & - plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) - enddo; enddo - - do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) - do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) - plastic_titanmod_interactionMatrixTwinTwin(t1,t2,instance) = & - plastic_titanmod_interactionTwinTwin(lattice_interactionTwinTwin( & - plastic_titanmod_twinSystemLattice(t1,instance), & - plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) - enddo; enddo - - do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) - do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for edge dislocations - plastic_titanmod_forestProjectionEdge(s1,s2,instance) = & - abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & - lattice_st(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) - -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for screw dislocations - plastic_titanmod_forestProjectionScrew(s1,s2,instance) = & - abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & - lattice_sd(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for edge dislocations in twin system - do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) - do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) - plastic_titanmod_TwinforestProjectionEdge(t1,t2,instance) = & - abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & - lattice_tt(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) - -!-------------------------------------------------------------------------------------------------- -! calculation of forest projections for screw dislocations in twin system - plastic_titanmod_TwinforestProjectionScrew(t1,t2,instance) = & - abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & - lattice_td(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) - enddo; enddo - call plastic_titanmod_stateInit(phase,instance) - endif - enddo initializeInstances - -end subroutine plastic_titanmod_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief sets the initial microstructural state for a given instance of this plasticity -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_stateInit(ph,instance) - use lattice, only: & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_mu - - use material, only: & - plasticState - - implicit none - integer(pInt), intent(in) :: instance !< number specifying the instance of the plasticity - integer(pInt), intent(in) :: ph !< number specifying the phase of the plasticity - - - integer(pInt) :: & - s,s0,s1, & - t,t0,t1, & - ns,nt,f - real(pReal), dimension(plastic_titanmod_totalNslip(instance)) :: & - rho_edge0, & - rho_screw0, & - shear_system0, & - segment_edge0, & - segment_screw0, & - resistance_edge0, & - resistance_screw0 - real(pReal), dimension(plastic_titanmod_totalNtwin(instance)) :: & - twingamma_dot0, & - resistance_twin0 - real(pReal), dimension(plasticState(ph)%sizeState) :: tempState !!!!!!!!!????????? check - - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - tempState = 0.0_pReal -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables for slip - s1 = 0_pInt - do f = 1_pInt,lattice_maxNslipFamily - s0 = s1 + 1_pInt - s1 = s0 + plastic_titanmod_Nslip(f,instance) - 1_pInt - do s = s0,s1 - rho_edge0(s) = plastic_titanmod_rho_edge0(f,instance) - rho_screw0(s) = plastic_titanmod_rho_screw0(f,instance) - shear_system0(s) = 0.0_pReal - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! initialize basic slip state variables for twin - t1 = 0_pInt - do f = 1_pInt,lattice_maxNtwinFamily - t0 = t1 + 1_pInt - t1 = t0 + plastic_titanmod_Ntwin(f,instance) - 1_pInt - do t = t0,t1 - twingamma_dot0(t)=0.0_pReal - enddo - enddo - -!-------------------------------------------------------------------------------------------------- -! initialize dependent slip microstructural variables - forall (s = 1_pInt:ns) - segment_edge0(s) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) - segment_screw0(s) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) - resistance_edge0(s) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & - sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & - dot_product((rho_screw0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) - resistance_screw0(s) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & - sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & - dot_product((rho_screw0), plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) - end forall - - forall (t = 1_pInt:nt) & - resistance_twin0(t) = 0.0_pReal - -tempState = 0.0_pReal -tempState (1:ns) = rho_edge0 -tempState (1_pInt*ns+1_pInt:2_pInt*ns) = rho_screw0 -tempState (2_pInt*ns+1_pInt:3_pInt*ns) = shear_system0 -tempState (3_pInt*ns+1_pInt:3_pInt*ns+nt) = twingamma_dot0 -tempState (3_pInt*ns+nt+1_pInt:4_pInt*ns+nt) = segment_edge0 -tempState (4_pInt*ns+nt+1_pInt:5_pInt*ns+nt) = segment_screw0 -tempState (5_pInt*ns+nt+1_pInt:6_pInt*ns+nt) = resistance_edge0 -tempState (6_pInt*ns+nt+1_pInt:7_pInt*ns+nt) = resistance_screw0 -tempState (7_pInt*ns+nt+1_pInt:7_pInt*ns+2_pInt*nt)=resistance_twin0 - -plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) -end subroutine plastic_titanmod_stateInit - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenized elasticity matrix -!-------------------------------------------------------------------------------------------------- -function plastic_titanmod_homogenizedC(ipc,ip,el) - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_C66 - -implicit none - real(pReal), dimension(6,6) :: & - plastic_titanmod_homogenizedC - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element -real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - volumefraction_PerTwinSys - integer(pInt) :: & - ph, & - of, & - instance, & - ns, nt, & - i - real(pReal) :: & - sumf - -!-------------------------------------------------------------------------------------------------- -! shortened notation -! ph = material_phase(ipc,ip,el) - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! total twin volume fraction - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - enddo - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - -!-------------------------------------------------------------------------------------------------- -! homogenized elasticity matrix - plastic_titanmod_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) - do i=1_pInt,nt - plastic_titanmod_homogenizedC = plastic_titanmod_homogenizedC & - + volumefraction_PerTwinSys(i)*& - plastic_titanmod_Ctwin66(1:6,1:6,i,instance) - enddo - -end function plastic_titanmod_homogenizedC - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_microstructure(temperature,ipc,ip,el) - - use material, only: & - material_phase,& - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - use lattice, only: & - lattice_mu - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - temperature !< temperature at IP - integer(pInt) :: & - instance, & - ns, nt, s, t, & - i, & - ph, & - of - real(pReal) :: & - sumf, & - sfe ! stacking fault energy - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - volumefraction_PerTwinSys - -!-------------------------------------------------------------------------------------------------- - -!Shortened notation - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - -!-------------------------------------------------------------------------------------------------- -! total twin volume fraction - forall (i = 1_pInt:nt) & - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - - sfe = 0.0002_pReal*Temperature-0.0396_pReal - -!-------------------------------------------------------------------------------------------------- -! average segment length for edge dislocations in matrix - forall (s = 1_pInt:ns) & - plasticState(ph)%state(3_pInt*ns+nt+s, of) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product(plasticState(ph)%state(1:ns, of), & - plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & - plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! average segment length for screw dislocations in matrix - forall (s = 1_pInt:ns) & - plasticState(ph)%state(4_pInt*ns+nt+s, of) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & - sqrt(dot_product(plasticState(ph)%state(1:ns, of), & - plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & - dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & - plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! threshold stress or slip resistance for edge dislocation motion - forall (s = 1_pInt:ns) & - plasticState(ph)%state(5_pInt*ns+nt+s, of) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& - sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& - plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & - dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& - plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! threshold stress or slip resistance for screw dislocation motion - forall (s = 1_pInt:ns) & - plasticState(ph)%state(6_pInt*ns+nt+s, of) = & - lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& - sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& - plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & - dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& - plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) -!-------------------------------------------------------------------------------------------------- -! threshold stress or slip resistance for dislocation motion in twin - forall (t = 1_pInt:nt) & - plasticState(ph)%state(7_pInt*ns+nt+t, of) = & - lattice_mu(ph)*plastic_titanmod_burgersPerTwinSys(t,instance)*& - (dot_product((abs(plasticState(ph)%state(2_pInt*ns+1_pInt:2_pInt*ns+nt, of))),& - plastic_titanmod_interactionMatrixTwinTwin(1:nt,t,instance))) - -! state=tempState - -end subroutine plastic_titanmod_microstructure - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates plastic velocity gradient and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,temperature,ipc,ip,el) - use math, only: & - math_Plain3333to99, & - math_Mandel6to33 - use lattice, only: & - lattice_Sslip, & - lattice_Sslip_v, & - lattice_Stwin, & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem, & - lattice_structure, & - LATTICE_hex_ID - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - - implicit none - real(pReal), dimension(3,3), intent(out) :: & - Lp !< plastic velocity gradient - real(pReal), dimension(9,9), intent(out) :: & - dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress - - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(6), intent(in) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at IP - integer(pInt) :: & - index_myFamily, instance, & - ns,nt, & - f,i,j,k,l,m,n, & - ph, & - of - real(pReal) :: sumf, & - StressRatio_edge_p, minusStressRatio_edge_p, StressRatio_edge_pminus1, BoltzmannRatioedge, & - StressRatio_screw_p, minusStressRatio_screw_p, StressRatio_screw_pminus1, BoltzmannRatioscrew, & - twinStressRatio_p, twinminusStressRatio_p, twinStressRatio_pminus1, BoltzmannRatiotwin, & - twinDotGamma0, bottomstress_edge, bottomstress_screw, screwvelocity_prefactor - real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 - real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_slip,dgdot_dtauslip,tau_slip, & - edge_velocity, screw_velocity, & - gdot_slip_edge, gdot_slip_screw - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin,dgdot_dtautwin,tau_twin, volumefraction_PerTwinSys - -! tempState=state - - - -!-------------------------------------------------------------------------------------------------- -! shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - - enddo - - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - - - Lp = 0.0_pReal - dLp_dTstar3333 = 0.0_pReal - dLp_dTstar99 = 0.0_pReal - - !* Dislocation glide part - gdot_slip = 0.0_pReal - gdot_slip_edge = 0.0_pReal - gdot_slip_screw = 0.0_pReal - dgdot_dtauslip = 0.0_pReal - j = 0_pInt - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on slip system - tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) - if(lattice_structure(ph)==LATTICE_hex_ID) then ! only for prismatic and pyr systems in hex - screwvelocity_prefactor=plastic_titanmod_debyefrequency(instance)* & - plasticState(ph)%state(4_pInt*ns+nt+j, of)*(plastic_titanmod_burgersPerSlipSys(j,instance)/ & - plastic_titanmod_kinkcriticallength_PerSlipSys(j,instance))**2 - - !* Stress ratio for screw ! No slip resistance for screw dislocations, only Peierls stress - bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) - StressRatio_screw_p = ((abs(tau_slip(j)))/ & - ( bottomstress_screw) & - )**plastic_titanmod_ps_PerSlipSys(j,instance) - - if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then - minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p - else - minusStressRatio_screw_p=0.001_pReal - endif - - bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) - StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/ & - ( bottomstress_screw) & - )**(plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio for screw - BoltzmannRatioscrew = plastic_titanmod_kinkf0(instance)/(kB*Temperature) - - else ! if the structure is not hex or the slip family is basal - screwvelocity_prefactor=plastic_titanmod_v0s_PerSlipSys(j,instance) - bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance)+ & - plasticState(ph)%state(6*ns+nt+j, of) - StressRatio_screw_p = ((abs(tau_slip(j)))/( bottomstress_screw ))**plastic_titanmod_ps_PerSlipSys(j,instance) - - if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then - minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p - else - minusStressRatio_screw_p=0.001_pReal - endif - - StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/( bottomstress_screw))** & - (plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio for screw - BoltzmannRatioscrew = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) - - endif - - !* Stress ratio for edge - bottomstress_edge=plastic_titanmod_tau0e_PerSlipSys(j,instance)+ & - plasticState(ph)%state(5*ns+nt+j, of) - StressRatio_edge_p = ((abs(tau_slip(j)))/ & - ( bottomstress_edge) & - )**plastic_titanmod_pe_PerSlipSys(j,instance) - - if((1.0_pReal-StressRatio_edge_p)>0.001_pReal) then - minusStressRatio_edge_p=1.0_pReal-StressRatio_edge_p - else - minusStressRatio_edge_p=0.001_pReal - endif - - StressRatio_edge_pminus1 = ((abs(tau_slip(j)))/( bottomstress_edge))** & - (plastic_titanmod_pe_PerSlipSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio for edge. For screws it is defined above - BoltzmannRatioedge = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) - - screw_velocity(j) =screwvelocity_prefactor * & ! there is no v0 for screw now because it is included in the prefactor - exp(-BoltzmannRatioscrew*(minusStressRatio_screw_p)** & - plastic_titanmod_qs_PerSlipSys(j,instance)) - - edge_velocity(j) =plastic_titanmod_v0e_PerSlipSys(j,instance)*exp(-BoltzmannRatioedge* & - (minusStressRatio_edge_p)** & - plastic_titanmod_qe_PerSlipSys(j,instance)) - - !* Shear rates due to edge slip - gdot_slip_edge(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(j, of)* & - edge_velocity(j))* sign(1.0_pReal,tau_slip(j)) - !* Shear rates due to screw slip - gdot_slip_screw(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(ns+j, of) * & - screw_velocity(j))* sign(1.0_pReal,tau_slip(j)) - !Total shear rate - - gdot_slip(j) = gdot_slip_edge(j) + gdot_slip_screw(j) - - plasticState(ph)%state( 7*ns+2*nt+j, of)= edge_velocity(j) - plasticState(ph)%state( 8*ns+2*nt+j, of)= screw_velocity(j) - plasticState(ph)%state( 9*ns+2*nt+j, of)= tau_slip(j) - plasticState(ph)%state(10*ns+2*nt+j, of)= gdot_slip_edge(j) - plasticState(ph)%state(11*ns+2*nt+j, of)= gdot_slip_screw(j) - plasticState(ph)%state(12*ns+2*nt+j, of)= StressRatio_edge_p - plasticState(ph)%state(13*ns+2*nt+j, of)= StressRatio_screw_p - - !* Derivatives of shear rates - dgdot_dtauslip(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(( & - ( & - ( & - ( & - (edge_velocity(j)*plasticState(ph)%state(j, of))) * & - BoltzmannRatioedge*& - plastic_titanmod_pe_PerSlipSys(j,instance)* & - plastic_titanmod_qe_PerSlipSys(j,instance) & - )/ & - bottomstress_edge & - )*& - StressRatio_edge_pminus1*(minusStressRatio_edge_p)** & - (plastic_titanmod_qe_PerSlipSys(j,instance)-1.0_pReal) & - ) + & - ( & - ( & - ( & - (plasticState(ph)%state(ns+j, of) * screw_velocity(j)) * & - BoltzmannRatioscrew* & - plastic_titanmod_ps_PerSlipSys(j,instance)* & - plastic_titanmod_qs_PerSlipSys(j,instance) & - )/ & - bottomstress_screw & - )*& - StressRatio_screw_pminus1*(minusStressRatio_screw_p)**(plastic_titanmod_qs_PerSlipSys(j,instance)-1.0_pReal) & - ) & - ) !* sign(1.0_pReal,tau_slip(j)) - - - -!************************************************* -!sumf=0.0_pReal - !* Plastic velocity gradient for dislocation glide - Lp = Lp + (1.0_pReal - sumf)*gdot_slip(j)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& - lattice_Sslip(k,l,1,index_myFamily+i,ph)*& - lattice_Sslip(m,n,1,index_myFamily+i,ph) - enddo - enddo slipFamiliesLoop - -!* Mechanical twinning part - gdot_twin = 0.0_pReal - dgdot_dtautwin = 0.0_pReal - j = 0_pInt - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - !* Calculation of Lp - !* Resolved shear stress on twin system - tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - -!************************************************************************************** - !* Stress ratios -! StressRatio_r = (plasticState(ph)%state6*ns+3*nt+j, of)/tau_twin(j))**plastic_titanmod_r(instance) - - !* Shear rates and their derivatives due to twin -! if ( tau_twin(j) > 0.0_pReal ) !then -! gdot_twin(j) = 0.0_pReal!& -! (plastic_titanmod_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& -! plasticState(ph)%state(6*ns+4*nt+j, of)*plastic_titanmod_Ndot0PerTwinSys(f,instance)*exp(-StressRatio_r) -! dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_titanmod_r(instance))/tau_twin(j))*StressRatio_r -! endif -!************************************************************************************** - - !* Stress ratio for edge - twinStressRatio_p = ((abs(tau_twin(j)))/ & - ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & - )**plastic_titanmod_twinp_PerTwinSys(j,instance) - - if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then - twinminusStressRatio_p=1.0_pReal-twinStressRatio_p - else - twinminusStressRatio_p=0.001_pReal - endif - - twinStressRatio_pminus1 = ((abs(tau_twin(j)))/ & - ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & - )**(plastic_titanmod_twinp_PerTwinSys(j,instance)-1.0_pReal) - - !* Boltzmann ratio - BoltzmannRatiotwin = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) - - !* Initial twin shear rates - TwinDotGamma0 = & - plastic_titanmod_twingamma0_PerTwinSys(j,instance) - - !* Shear rates due to twin - gdot_twin(j) =sign(1.0_pReal,tau_twin(j))*plastic_titanmod_twingamma0_PerTwinSys(j,instance)* & - exp(-BoltzmannRatiotwin*(twinminusStressRatio_p)**plastic_titanmod_twinq_PerTwinSys(j,instance)) - - - !* Derivatives of shear rates in twin - dgdot_dtautwin(j) = ( & - ( & - ( & - (abs(gdot_twin(j))) * & - BoltzmannRatiotwin*& - plastic_titanmod_twinp_PerTwinSys(j,instance)* & - plastic_titanmod_twinq_PerTwinSys(j,instance) & - )/ & - plastic_titanmod_twintau0_PerTwinSys(j,instance) & - )*& - twinStressRatio_pminus1*(twinminusStressRatio_p)** & - (plastic_titanmod_twinq_PerTwinSys(j,instance)-1.0_pReal) & - ) !* sign(1.0_pReal,tau_slip(j)) - - !* Plastic velocity gradient for mechanical twinning -! Lp = Lp + sumf*gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) - Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) - - !* Calculation of the tangent of Lp - forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & - dLp_dTstar3333(k,l,m,n) = & - dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& - lattice_Stwin(k,l,index_myFamily+i,ph)*& - lattice_Stwin(m,n,index_myFamily+i,ph) - enddo - enddo twinFamiliesLoop - -dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) -! tempState=state - - -end subroutine plastic_titanmod_LpAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates the rate of change of microstructure -!-------------------------------------------------------------------------------------------------- -subroutine plastic_titanmod_dotState(Tstar_v,temperature,ipc,ip,el) - use lattice, only: & - lattice_Stwin_v, & - lattice_maxNslipFamily, & - lattice_maxNtwinFamily, & - lattice_NslipSystem, & - lattice_NtwinSystem - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - -implicit none - real(pReal), dimension(6), intent(in):: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation - real(pReal), intent(in) :: & - temperature !< temperature at integration point - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - integer(pInt) :: & - index_myFamily, instance, & - ns,nt,& - f,i,j, & - ph, & - of - real(pReal) :: & - sumf,BoltzmannRatio, & - twinStressRatio_p,twinminusStressRatio_p - real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - DotRhoEdgeGeneration, & - DotRhoEdgeAnnihilation, & - DotRhoScrewGeneration, & - DotRhoScrewAnnihilation - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - gdot_twin, & - tau_twin, & - volumefraction_PerTwinSys - -!-------------------------------------------------------------------------------------------------- -! shortened notation - - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - - enddo - - sumf = sum(abs(volumefraction_PerTwinSys(1_pInt:nt))) ! safe for nt == 0 - - plasticState(ph)%dotState(:,of) = 0.0_pReal - j = 0_pInt - slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily - index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family - j = j+1_pInt - - DotRhoEdgeGeneration(j) = & ! multiplication of edge dislocations - plasticState(ph)%state(ns+j, of)*plasticState(ph)%state(8*ns+2*nt+j, of)/plasticState(ph)%state(4*ns+nt+j, of) - DotRhoScrewGeneration(j) = & ! multiplication of screw dislocations - plasticState(ph)%state(j, of)*plasticState(ph)%state(7*ns+2*nt+j, of)/plasticState(ph)%state(3*ns+nt+j, of) - DotRhoEdgeAnnihilation(j) = -((plasticState(ph)%state(j, of))**2)* & ! annihilation of edge dislocations - plastic_titanmod_capre_PerSlipSys(j,instance)*plasticState(ph)%state(7*ns+2*nt+j, of)*0.5_pReal - DotRhoScrewAnnihilation(j) = -((plasticState(ph)%state(ns+j, of))**2)* & ! annihilation of screw dislocations - plastic_titanmod_caprs_PerSlipSys(j,instance)*plasticState(ph)%state(8*ns+2*nt+j, of)*0.5_pReal - plasticState(ph)%dotState(j, of) = & ! edge dislocation density rate of change - DotRhoEdgeGeneration(j)+DotRhoEdgeAnnihilation(j) - - plasticState(ph)%dotState(ns+j, of) = & ! screw dislocation density rate of change - DotRhoScrewGeneration(j)+DotRhoScrewAnnihilation(j) - - plasticState(ph)%dotState(2*ns+j, of) = & ! sum of shear due to edge and screw - plasticState(ph)%state(10*ns+2*nt+j, of)+plasticState(ph)%state(11*ns+2*nt+j, of) - enddo - enddo slipFamiliesLoop - -!* Twin fraction evolution - j = 0_pInt - twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily - index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family - do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) twin system in family - j = j+1_pInt - - !* Resolved shear stress on twin system - tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) - - !* Stress ratio for edge - twinStressRatio_p = ((abs(tau_twin(j)))/ & - ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & - )**(plastic_titanmod_twinp_PerTwinSys(j,instance)) - - - if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then - twinminusStressRatio_p=1.0_pReal-twinStressRatio_p - else - twinminusStressRatio_p=0.001_pReal - endif - - BoltzmannRatio = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) - - gdot_twin(j) =plastic_titanmod_twingamma0_PerTwinSys(j,instance)*exp(-BoltzmannRatio* & - (twinminusStressRatio_p)** & - plastic_titanmod_twinq_PerTwinSys(j,instance))*sign(1.0_pReal,tau_twin(j)) - - plasticState(ph)%dotState(3*ns+j, of)=gdot_twin(j) - - enddo - enddo twinFamiliesLoop - -end subroutine plastic_titanmod_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of constitutive results -!-------------------------------------------------------------------------------------------------- -function plastic_titanmod_postResults(ipc,ip,el) - use material, only: & - material_phase, & - phase_plasticityInstance, & - plasticState, & - phaseAt, phasememberAt - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(plastic_titanmod_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - plastic_titanmod_postResults - - integer(pInt) :: & - instance, & - ns,nt,& - o,i,c, & - ph, & - of - real(pReal) :: sumf - - real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & - volumefraction_PerTwinSys - -!-------------------------------------------------------------------------------------------------- -! shortened notation - of = phasememberAt(ipc,ip,el) - ph = phaseAt(ipc,ip,el) - instance = phase_plasticityInstance(ph) - ns = plastic_titanmod_totalNslip(instance) - nt = plastic_titanmod_totalNtwin(instance) - - do i=1_pInt,nt - volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & - plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) - enddo - - sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 - - -!-------------------------------------------------------------------------------------------------- -! required output - c = 0_pInt - plastic_titanmod_postResults = 0.0_pReal - - do o = 1_pInt,plastic_titanmod_Noutput(instance) - select case(plastic_titanmod_outputID(o,instance)) - case (rhoedge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(1_pInt:ns, of) - c = c + ns - case (rhoscrew_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of) - c = c + ns - case (segment_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(3_pInt*ns+nt+1_pInt:4_pInt*ns+nt, of) - c = c + ns - case (segment_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(4_pInt*ns+nt+1_pInt:5_pInt*ns+nt, of) - c = c + ns - case (resistance_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(5_pInt*ns+nt+1_pInt:6_pInt*ns+nt, of) - c = c + ns - case (resistance_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(6_pInt*ns+nt+1_pInt:7_pInt*ns+nt, of) - c = c + ns - case (velocity_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(7*ns+2*nt+1:8*ns+2*nt, of) - c = c + ns - case (velocity_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(8*ns+2*nt+1:9*ns+2*nt, of) - c = c + ns - case (tau_slip_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(9*ns+2*nt+1:10*ns+2*nt, of)) - c = c + ns - case (gdot_slip_edge_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) - c = c + ns - case (gdot_slip_screw_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) - c = c + ns - case (gdot_slip_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) + & - abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) - c = c + ns - case (stressratio_edge_p_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(12*ns+2*nt+1:13*ns+2*nt, of)) - c = c + ns - case (stressratio_screw_p_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(13*ns+2*nt+1:14*ns+2*nt, of)) - c = c + ns - case (shear_system_ID) - plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(2*ns+1:3*ns, of)) - c = c + ns - case (shear_basal_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:2*ns+3, of))) - c = c + 1_pInt - case (shear_prism_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+4:2*ns+6, of))) - c = c + 1_pInt - case (shear_pyra_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+7:2*ns+12, of))) - c = c + 1_pInt - case (shear_pyrca_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+13:2*ns+24, of))) - c = c + 1_pInt - - case (rhoedge_basal_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(1:3, of)) - c = c + 1_pInt - case (rhoedge_prism_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(4:6, of)) - c = c + 1_pInt - case (rhoedge_pyra_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(7:12,of)) - c = c + 1_pInt - case (rhoedge_pyrca_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(13:24, of)) - c = c + 1_pInt - - case (rhoscrew_basal_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+1:ns+3, of)) - c = c + 1_pInt - case (rhoscrew_prism_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+4:ns+6, of)) - c = c + 1_pInt - case (rhoscrew_pyra_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+7:ns+12, of)) - c = c + 1_pInt - case (rhoscrew_pyrca_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+13:ns+24, of)) - c = c + 1_pInt - case (shear_total_ID) - plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:3*ns, of))) - c = c + 1_pInt - case (twin_fraction_ID) - plastic_titanmod_postResults(c+1_pInt:c+nt) = abs(volumefraction_PerTwinSys(1:nt)) - c = c + nt - end select - enddo - -end function plastic_titanmod_postResults - -end module plastic_titanmod diff --git a/code/porosity_none.f90 b/code/porosity_none.f90 deleted file mode 100644 index 69f10a5c6..000000000 --- a/code/porosity_none.f90 +++ /dev/null @@ -1,61 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for constant porosity -!-------------------------------------------------------------------------------------------------- -module porosity_none - - implicit none - private - - public :: & - porosity_none_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine porosity_none_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- porosity_'//POROSITY_none_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (porosity_type(homog) == POROSITY_none_ID) then - NofMyHomog = count(material_homog == homog) - porosityState(homog)%sizeState = 0_pInt - porosityState(homog)%sizePostResults = 0_pInt - allocate(porosityState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) - allocate(porosityState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) - allocate(porosityState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) - - deallocate(porosity(homog)%p) - allocate (porosity(homog)%p(1), source=porosity_initialPhi(homog)) - - endif myhomog - enddo initializeInstances - - -end subroutine porosity_none_init - -end module porosity_none diff --git a/code/porosity_phasefield.f90 b/code/porosity_phasefield.f90 deleted file mode 100644 index dc8b82b76..000000000 --- a/code/porosity_phasefield.f90 +++ /dev/null @@ -1,450 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for phase field modelling of pore nucleation and growth -!> @details phase field model for pore nucleation and growth based on vacancy clustering -!-------------------------------------------------------------------------------------------------- -module porosity_phasefield - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - porosity_phasefield_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - porosity_phasefield_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - porosity_phasefield_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - porosity_phasefield_Noutput !< number of outputs per instance of this porosity - - enum, bind(c) - enumerator :: undefined_ID, & - porosity_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - porosity_phasefield_outputID !< ID of each post result output - - - public :: & - porosity_phasefield_init, & - porosity_phasefield_getFormationEnergy, & - porosity_phasefield_getSurfaceEnergy, & - porosity_phasefield_getSourceAndItsTangent, & - porosity_phasefield_getDiffusion33, & - porosity_phasefield_getMobility, & - porosity_phasefield_putPorosity, & - porosity_phasefield_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine porosity_phasefield_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - porosity_type, & - porosity_typeInstance, & - homogenization_Noutput, & - POROSITY_phasefield_label, & - POROSITY_phasefield_ID, & - material_homog, & - mappingHomogenization, & - porosityState, & - porosityMapping, & - porosity, & - porosity_initialPhi, & - material_partHomogenization, & - material_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- porosity_'//POROSITY_phasefield_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(porosity_type == POROSITY_phasefield_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(porosity_phasefield_sizePostResults(maxNinstance), source=0_pInt) - allocate(porosity_phasefield_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(porosity_phasefield_output (maxval(homogenization_Noutput),maxNinstance)) - porosity_phasefield_output = '' - allocate(porosity_phasefield_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(porosity_phasefield_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (porosity_type(section) == POROSITY_phasefield_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = porosity_typeInstance(section) ! which instance of my porosity is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('porosity') - porosity_phasefield_Noutput(instance) = porosity_phasefield_Noutput(instance) + 1_pInt - porosity_phasefield_outputID(porosity_phasefield_Noutput(instance),instance) = porosity_ID - porosity_phasefield_output(porosity_phasefield_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingHomog - - initializeInstances: do section = 1_pInt, size(porosity_type) - if (porosity_type(section) == POROSITY_phasefield_ID) then - NofMyHomog=count(material_homog==section) - instance = porosity_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,porosity_phasefield_Noutput(instance) - select case(porosity_phasefield_outputID(o,instance)) - case(porosity_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - porosity_phasefield_sizePostResult(o,instance) = mySize - porosity_phasefield_sizePostResults(instance) = porosity_phasefield_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 0_pInt - porosityState(section)%sizeState = sizeState - porosityState(section)%sizePostResults = porosity_phasefield_sizePostResults(instance) - allocate(porosityState(section)%state0 (sizeState,NofMyHomog)) - allocate(porosityState(section)%subState0(sizeState,NofMyHomog)) - allocate(porosityState(section)%state (sizeState,NofMyHomog)) - - nullify(porosityMapping(section)%p) - porosityMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(porosity(section)%p) - allocate(porosity(section)%p(NofMyHomog), source=porosity_initialPhi(section)) - - endif - - enddo initializeInstances -end subroutine porosity_phasefield_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized vacancy formation energy -!-------------------------------------------------------------------------------------------------- -function porosity_phasefield_getFormationEnergy(ip,el) - use lattice, only: & - lattice_vacancyFormationEnergy, & - lattice_vacancyVol - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - porosity_phasefield_getFormationEnergy - integer(pInt) :: & - grain - - porosity_phasefield_getFormationEnergy = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - porosity_phasefield_getFormationEnergy = porosity_phasefield_getFormationEnergy + & - lattice_vacancyFormationEnergy(material_phase(grain,ip,el))/ & - lattice_vacancyVol(material_phase(grain,ip,el)) - enddo - - porosity_phasefield_getFormationEnergy = & - porosity_phasefield_getFormationEnergy/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function porosity_phasefield_getFormationEnergy - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized pore surface energy (normalized by characteristic length) -!-------------------------------------------------------------------------------------------------- -function porosity_phasefield_getSurfaceEnergy(ip,el) - use lattice, only: & - lattice_vacancySurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - porosity_phasefield_getSurfaceEnergy - integer(pInt) :: & - grain - - porosity_phasefield_getSurfaceEnergy = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - porosity_phasefield_getSurfaceEnergy = porosity_phasefield_getSurfaceEnergy + & - lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) - enddo - - porosity_phasefield_getSurfaceEnergy = & - porosity_phasefield_getSurfaceEnergy/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function porosity_phasefield_getSurfaceEnergy - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates homogenized local driving force for pore nucleation and growth -!-------------------------------------------------------------------------------------------------- -subroutine porosity_phasefield_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) - use math, only : & - math_mul33x33, & - math_mul66x6, & - math_Mandel33to6, & - math_transpose33, & - math_I3 - use material, only: & - homogenization_Ngrains, & - material_homog, & - material_phase, & - phase_NstiffnessDegradations, & - phase_stiffnessDegradation, & - vacancyConc, & - vacancyfluxMapping, & - damage, & - damageMapping, & - STIFFNESS_DEGRADATION_damage_ID - use crystallite, only: & - crystallite_Fe - use constitutive, only: & - constitutive_homogenizedC - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - integer(pInt) :: & - phase, & - grain, & - homog, & - mech - real(pReal) :: & - phiDot, dPhiDot_dPhi, Cv, W_e, strain(6), C(6,6) - - homog = material_homog(ip,el) - Cv = vacancyConc(homog)%p(vacancyfluxMapping(homog)%p(ip,el)) - - W_e = 0.0_pReal - do grain = 1, homogenization_Ngrains(homog) - phase = material_phase(grain,ip,el) - strain = math_Mandel33to6(math_mul33x33(math_transpose33(crystallite_Fe(1:3,1:3,grain,ip,el)), & - crystallite_Fe(1:3,1:3,grain,ip,el)) - math_I3)/2.0_pReal - C = constitutive_homogenizedC(grain,ip,el) - do mech = 1_pInt, phase_NstiffnessDegradations(phase) - select case(phase_stiffnessDegradation(mech,phase)) - case (STIFFNESS_DEGRADATION_damage_ID) - C = damage(homog)%p(damageMapping(homog)%p(ip,el))* & - damage(homog)%p(damageMapping(homog)%p(ip,el))* & - C - - end select - enddo - W_e = W_e + sum(abs(strain*math_mul66x6(C,strain))) - enddo - W_e = W_e/homogenization_Ngrains(homog) - - phiDot = 2.0_pReal*(1.0_pReal - phi)*(1.0_pReal - Cv)*(1.0_pReal - Cv) - & - 2.0_pReal*phi*(W_e + Cv*porosity_phasefield_getFormationEnergy(ip,el))/ & - porosity_phasefield_getSurfaceEnergy (ip,el) - dPhiDot_dPhi = - 2.0_pReal*(1.0_pReal - Cv)*(1.0_pReal - Cv) & - - 2.0_pReal*(W_e + Cv*porosity_phasefield_getFormationEnergy(ip,el))/ & - porosity_phasefield_getSurfaceEnergy (ip,el) - -end subroutine porosity_phasefield_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized nonlocal diffusion tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function porosity_phasefield_getDiffusion33(ip,el) - use lattice, only: & - lattice_PorosityDiffusion33 - use material, only: & - homogenization_Ngrains, & - material_phase, & - mappingHomogenization - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - porosity_phasefield_getDiffusion33 - integer(pInt) :: & - homog, & - grain - - homog = mappingHomogenization(2,ip,el) - porosity_phasefield_getDiffusion33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(homog) - porosity_phasefield_getDiffusion33 = porosity_phasefield_getDiffusion33 + & - crystallite_push33ToRef(grain,ip,el,lattice_PorosityDiffusion33(1:3,1:3,material_phase(grain,ip,el))) - enddo - - porosity_phasefield_getDiffusion33 = & - porosity_phasefield_getDiffusion33/ & - homogenization_Ngrains(homog) - -end function porosity_phasefield_getDiffusion33 - -!-------------------------------------------------------------------------------------------------- -!> @brief Returns homogenized phase field mobility -!-------------------------------------------------------------------------------------------------- -real(pReal) function porosity_phasefield_getMobility(ip,el) - use mesh, only: & - mesh_element - use lattice, only: & - lattice_PorosityMobility - use material, only: & - material_phase, & - homogenization_Ngrains - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - integer(pInt) :: & - ipc - - porosity_phasefield_getMobility = 0.0_pReal - - do ipc = 1, homogenization_Ngrains(mesh_element(3,el)) - porosity_phasefield_getMobility = porosity_phasefield_getMobility + lattice_PorosityMobility(material_phase(ipc,ip,el)) - enddo - - porosity_phasefield_getMobility = porosity_phasefield_getMobility/homogenization_Ngrains(mesh_element(3,el)) - -end function porosity_phasefield_getMobility - -!-------------------------------------------------------------------------------------------------- -!> @brief updates porosity with solution from phasefield PDE -!-------------------------------------------------------------------------------------------------- -subroutine porosity_phasefield_putPorosity(phi,ip,el) - use material, only: & - material_homog, & - porosityMapping, & - porosity - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - integer(pInt) :: & - homog, & - offset - - homog = material_homog(ip,el) - offset = porosityMapping(homog)%p(ip,el) - porosity(homog)%p(offset) = phi - -end subroutine porosity_phasefield_putPorosity - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of porosity results -!-------------------------------------------------------------------------------------------------- -function porosity_phasefield_postResults(ip,el) - use material, only: & - mappingHomogenization, & - porosity_typeInstance, & - porosity - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(porosity_phasefield_sizePostResults(porosity_typeInstance(mappingHomogenization(2,ip,el)))) :: & - porosity_phasefield_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - instance = porosity_typeInstance(homog) - - c = 0_pInt - porosity_phasefield_postResults = 0.0_pReal - - do o = 1_pInt,porosity_phasefield_Noutput(instance) - select case(porosity_phasefield_outputID(o,instance)) - - case (porosity_ID) - porosity_phasefield_postResults(c+1_pInt) = porosity(homog)%p(offset) - c = c + 1 - end select - enddo -end function porosity_phasefield_postResults - -end module porosity_phasefield diff --git a/code/prec.f90 b/code/prec.f90 deleted file mode 100644 index e39a32cfa..000000000 --- a/code/prec.f90 +++ /dev/null @@ -1,192 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @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 Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH -!> @brief setting precision for real and int type depending on makros "FLOAT" and "INT" -!> @details setting precision for real and int type and for DAMASK_NaN. Definition is made -!! depending on makros "FLOAT" and "INT" defined during compilation -!! for details on NaN see https://software.intel.com/en-us/forums/topic/294680 -!-------------------------------------------------------------------------------------------------- -module prec - -#if !(defined(__GFORTRAN__) && __GNUC__ < 5) - use, intrinsic :: & ! unfortunately not avialable in gfortran <= 5 - IEEE_arithmetic -#endif - - implicit none - private -#if (FLOAT==4) -#if defined(Spectral) || defined(FEM) - SPECTRAL SOLVER AND OWN FEM DO NOT SUPPORT SINGLE PRECISION, STOPPING COMPILATION -#endif - integer, parameter, public :: pReal = 4 !< floating point single precition (was selected_real_kind(6,37), number with 6 significant digits, up to 1e+-37) -#ifdef __INTEL_COMPILER - real(pReal), parameter, public :: DAMASK_NaN = Z'7F800001' !< quiet NaN for single precision (from http://www.hpc.unimelb.edu.au/doc/f90lrm/dfum_035.html, copy can be found in documentation/Code/Fortran) -#endif -#ifdef __GFORTRAN__ - real(pReal), parameter, public :: DAMASK_NaN = real(Z'7F800001', pReal) !< quiet NaN for single precision (from http://www.hpc.unimelb.edu.au/doc/f90lrm/dfum_035.html, copy can be found in documentation/Code/Fortran) -#endif -#elif (FLOAT==8) - integer, parameter, public :: pReal = 8 !< floating point double precision (was selected_real_kind(15,300), number with 15 significant digits, up to 1e+-300) -#ifdef __INTEL_COMPILER - real(pReal), parameter, public :: DAMASK_NaN = Z'7FF8000000000000' !< quiet NaN for double precision (from http://www.hpc.unimelb.edu.au/doc/f90lrm/dfum_035.html, copy can be found in documentation/Code/Fortran) -#endif -#ifdef __GFORTRAN__ - real(pReal), parameter, public :: DAMASK_NaN = real(Z'7FF8000000000000',pReal) !< quiet NaN for double precision (from http://www.hpc.unimelb.edu.au/doc/f90lrm/dfum_035.html, copy can be found in documentation/Code/Fortran) -#endif -#else - NO SUITABLE PRECISION FOR REAL SELECTED, STOPPING COMPILATION -#endif - -#if (INT==4) - integer, parameter, public :: pInt = 4 !< integer representation 32 bit (was selected_int_kind(9), number with at least up to +- 1e9) -#elif (INT==8) - integer, parameter, public :: pInt = 8 !< integer representation 64 bit (was selected_int_kind(12), number with at least up to +- 1e12) -#else - NO SUITABLE PRECISION FOR INTEGER SELECTED, STOPPING COMPILATION -#endif - - integer, parameter, public :: pLongInt = 8 !< integer representation 64 bit (was selected_int_kind(12), number with at least up to +- 1e12) - real(pReal), parameter, public :: tol_math_check = 1.0e-8_pReal !< tolerance for internal math self-checks (rotation) - - integer(pInt), allocatable, dimension(:) :: realloc_lhs_test - - type, public :: p_vec !< variable length datatype used for storage of state - real(pReal), dimension(:), pointer :: p - end type p_vec - - type, public :: p_intvec - integer(pInt), dimension(:), pointer :: p - end type p_intvec - -!http://stackoverflow.com/questions/3948210/can-i-have-a-pointer-to-an-item-in-an-allocatable-array - type, public :: tState - integer(pInt) :: & - sizeState = 0_pInt , & !< size of state - sizeDotState = 0_pInt, & !< size of dot state, i.e. parts of the state that are integrated - sizeDeltaState = 0_pInt, & !< size of delta state, i.e. parts of the state that have discontinuous rates - sizePostResults = 0_pInt !< size of output data - real(pReal), pointer, dimension(:), contiguous :: & - atolState - real(pReal), pointer, dimension(:,:), contiguous :: & ! a pointer is needed here because we might point to state/doState. However, they will never point to something, but are rather allocated and, hence, contiguous - state, & !< state - dotState, & !< state rate - state0 - real(pReal), allocatable, dimension(:,:) :: & - partionedState0, & - subState0, & - state_backup, & - deltaState, & - previousDotState, & !< state rate of previous xxxx - previousDotState2, & !< state rate two xxxx ago - dotState_backup, & !< backup of state rate - RK4dotState - real(pReal), allocatable, dimension(:,:,:) :: & - RKCK45dotState - end type - - type, extends(tState), public :: tPlasticState - integer(pInt) :: & - nSlip = 0_pInt , & - nTwin = 0_pInt, & - nTrans = 0_pInt - logical :: & - nonlocal = .false. !< absolute tolerance for state integration - real(pReal), pointer, dimension(:,:), contiguous :: & - slipRate, & !< slip rate - accumulatedSlip !< accumulated plastic slip - end type - - type, public :: tSourceState - type(tState), dimension(:), allocatable :: p !< tState for each active source mechanism in a phase - end type - - type, public :: tHomogMapping - integer(pInt), pointer, dimension(:,:) :: p - end type - - type, public :: tPhaseMapping - integer(pInt), pointer, dimension(:,:,:) :: p - end type - -#ifdef FEM - type, public :: tOutputData - integer(pInt) :: & - sizeIpCells = 0_pInt , & - sizeResults = 0_pInt - real(pReal), allocatable, dimension(:,:) :: & - output !< output data - end type -#endif - - public :: & - prec_init, & - prec_isNaN - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief reporting precision and checking if DAMASK_NaN is set correctly -!-------------------------------------------------------------------------------------------------- -subroutine prec_init - use, intrinsic :: & - iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - - implicit none - integer(pInt) :: worldrank = 0_pInt -#ifdef PETSc -#include - PetscErrorCode :: ierr -#endif - external :: & - quit, & - MPI_Comm_rank, & - MPI_Abort - -#ifdef PETSc - call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) -#endif - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- prec init -+>>>' -#include "compilation_info.f90" - write(6,'(a,i3)') ' Bytes for pReal: ',pReal - write(6,'(a,i3)') ' Bytes for pInt: ',pInt - write(6,'(a,i3)') ' Bytes for pLongInt: ',pLongInt - write(6,'(a,e10.3)') ' NaN: ', DAMASK_NaN - write(6,'(a,l3)') ' NaN != NaN: ',DAMASK_NaN /= DAMASK_NaN - write(6,'(a,l3,/)') ' NaN check passed ',prec_isNAN(DAMASK_NaN) - endif mainProcess - - if ((.not. prec_isNaN(DAMASK_NaN)) .or. (DAMASK_NaN == DAMASK_NaN)) call quit(9000) - realloc_lhs_test = [1_pInt,2_pInt] - if (realloc_lhs_test(2)/=2_pInt) call quit(9000) - - -end subroutine prec_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief figures out if a floating point number is NaN -! basically just a small wrapper, because gfortran < 4.9 does not have the IEEE module -!-------------------------------------------------------------------------------------------------- -logical elemental function prec_isNaN(a) - - implicit none - real(pReal), intent(in) :: a - -#if (defined(__GFORTRAN__) && __GNUC__ < 5) - intrinsic :: isNaN - prec_isNaN = isNaN(a) -#else - prec_isNaN = IEEE_is_NaN(a) -#endif -end function prec_isNaN - -end module prec diff --git a/code/quit__genmod.f90 b/code/quit__genmod.f90 deleted file mode 100644 index ef0a49bc0..000000000 --- a/code/quit__genmod.f90 +++ /dev/null @@ -1,8 +0,0 @@ - !COMPILER-GENERATED INTERFACE MODULE: Thu Mar 3 12:28:23 2016 - MODULE QUIT__genmod - INTERFACE - SUBROUTINE QUIT(STOP_ID) - INTEGER(KIND=4), INTENT(IN) :: STOP_ID - END SUBROUTINE QUIT - END INTERFACE - END MODULE QUIT__genmod diff --git a/code/source_damage_anisoBrittle.f90 b/code/source_damage_anisoBrittle.f90 deleted file mode 100644 index a751eefdc..000000000 --- a/code/source_damage_anisoBrittle.f90 +++ /dev/null @@ -1,425 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @brief material subroutine incorporating anisotropic brittle damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_anisoBrittle - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_anisoBrittle_sizePostResults, & !< cumulative size of post results - source_damage_anisoBrittle_offset, & !< which source is my current source mechanism? - source_damage_anisoBrittle_instance !< instance of source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_anisoBrittle_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_anisoBrittle_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_anisoBrittle_Noutput !< number of outputs per instance of this source - - integer(pInt), dimension(:), allocatable, private :: & - source_damage_anisoBrittle_totalNcleavage !< total number of cleavage systems - - integer(pInt), dimension(:,:), allocatable, private :: & - source_damage_anisoBrittle_Ncleavage !< number of cleavage systems per family - - real(pReal), dimension(:), allocatable, private :: & - source_damage_anisoBrittle_aTol, & - source_damage_anisoBrittle_sdot_0, & - source_damage_anisoBrittle_N - - real(pReal), dimension(:,:), allocatable, private :: & - source_damage_anisoBrittle_critDisp, & - source_damage_anisoBrittle_critLoad - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_anisoBrittle_outputID !< ID of each post result output - - - public :: & - source_damage_anisoBrittle_init, & - source_damage_anisoBrittle_dotState, & - source_damage_anisobrittle_getRateAndItsTangent, & - source_damage_anisoBrittle_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoBrittle_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_anisoBrittle_label, & - SOURCE_damage_anisoBrittle_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - use lattice, only: & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoBrittle_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_anisoBrittle_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_anisoBrittle_offset(material_Nphase), source=0_pInt) - allocate(source_damage_anisoBrittle_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_anisoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoBrittle_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_anisoBrittle_ID) & - source_damage_anisoBrittle_offset(phase) = source - enddo - enddo - - allocate(source_damage_anisoBrittle_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_output(maxval(phase_Noutput),maxNinstance)) - source_damage_anisoBrittle_output = '' - allocate(source_damage_anisoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_anisoBrittle_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_totalNcleavage(maxNinstance), source=0_pInt) - allocate(source_damage_anisoBrittle_aTol(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_sdot_0(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoBrittle_N(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_anisoBrittle_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('anisobrittle_drivingforce') - source_damage_anisoBrittle_Noutput(instance) = source_damage_anisoBrittle_Noutput(instance) + 1_pInt - source_damage_anisoBrittle_outputID(source_damage_anisoBrittle_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_anisoBrittle_output(source_damage_anisoBrittle_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('anisobrittle_atol') - source_damage_anisoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisobrittle_sdot0') - source_damage_anisoBrittle_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisobrittle_ratesensitivity') - source_damage_anisoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('ncleavage') ! - Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_CleavageFamilies - source_damage_anisoBrittle_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticaldisplacement') - do j = 1_pInt, Nchunks_CleavageFamilies - source_damage_anisoBrittle_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisobrittle_criticalload') - do j = 1_pInt, Nchunks_CleavageFamilies - source_damage_anisoBrittle_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then - instance = source_damage_anisoBrittle_instance(phase) - source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & - min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested - source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance)) - source_damage_anisoBrittle_totalNcleavage(instance) = sum(source_damage_anisoBrittle_Ncleavage(:,instance)) ! how many cleavage systems altogether - if (source_damage_anisoBrittle_aTol(instance) < 0.0_pReal) & - source_damage_anisoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_anisoBrittle_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoBrittle_LABEL//')') - if (any(source_damage_anisoBrittle_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//SOURCE_damage_anisoBrittle_LABEL//')') - if (any(source_damage_anisoBrittle_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//SOURCE_damage_anisoBrittle_LABEL//')') - if (source_damage_anisoBrittle_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoBrittle_LABEL//')') - endif myPhase - enddo sanityChecks - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_anisoBrittle_instance(phase) - sourceOffset = source_damage_anisoBrittle_offset(phase) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) - select case(source_damage_anisoBrittle_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_anisoBrittle_sizePostResult(o,instance) = mySize - source_damage_anisoBrittle_sizePostResults(instance) = source_damage_anisoBrittle_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoBrittle_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_anisoBrittle_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_anisoBrittle_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoBrittle_dotState(Tstar_v, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState, & - material_homog, & - damage, & - damageMapping - use lattice, only: & - lattice_Scleavage_v, & - lattice_maxNcleavageFamily, & - lattice_NcleavageSystem - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) - integer(pInt) :: & - phase, & - constituent, & - instance, & - sourceOffset, & - damageOffset, & - homog, & - f, i, index_myFamily - real(pReal) :: & - traction_d, traction_t, traction_n, traction_crit - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoBrittle_instance(phase) - sourceOffset = source_damage_anisoBrittle_offset(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal - do f = 1_pInt,lattice_maxNcleavageFamily - index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family - do i = 1_pInt,source_damage_anisoBrittle_Ncleavage(f,instance) ! process each (active) cleavage system in family - traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) - traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) - traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) - - traction_crit = source_damage_anisoBrittle_critLoad(f,instance)* & - damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & - source_damage_anisoBrittle_sdot_0(instance)* & - ((max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & - (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & - (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance))/ & - source_damage_anisoBrittle_critDisp(f,instance) - - enddo - enddo - -end subroutine source_damage_anisoBrittle_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_damage_anisoBrittle_offset(phase) - - localphiDot = 1.0_pReal - & - sourceState(phase)%p(sourceOffset)%state(1,constituent)*phi - - dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_anisobrittle_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_anisoBrittle_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_anisoBrittle_sizePostResults( & - source_damage_anisoBrittle_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_anisoBrittle_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoBrittle_instance(phase) - sourceOffset = source_damage_anisoBrittle_offset(phase) - - c = 0_pInt - source_damage_anisoBrittle_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) - select case(source_damage_anisoBrittle_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_anisoBrittle_postResults(c+1_pInt) = & - sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1_pInt - - end select - enddo -end function source_damage_anisoBrittle_postResults - -end module source_damage_anisoBrittle diff --git a/code/source_damage_anisoDuctile.f90 b/code/source_damage_anisoDuctile.f90 deleted file mode 100644 index 028fd479a..000000000 --- a/code/source_damage_anisoDuctile.f90 +++ /dev/null @@ -1,415 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incorporating anisotropic ductile damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_anisoDuctile - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_anisoDuctile_sizePostResults, & !< cumulative size of post results - source_damage_anisoDuctile_offset, & !< which source is my current damage mechanism? - source_damage_anisoDuctile_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_anisoDuctile_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_anisoDuctile_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_anisoDuctile_Noutput !< number of outputs per instance of this damage - - integer(pInt), dimension(:), allocatable, private :: & - source_damage_anisoDuctile_totalNslip !< total number of slip systems - - integer(pInt), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_Nslip !< number of slip systems per family - - real(pReal), dimension(:), allocatable, private :: & - source_damage_anisoDuctile_aTol - - real(pReal), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_critPlasticStrain - - real(pReal), dimension(:), allocatable, private :: & - source_damage_anisoDuctile_sdot_0, & - source_damage_anisoDuctile_N - - real(pReal), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_critLoad - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_anisoDuctile_outputID !< ID of each post result output - - - public :: & - source_damage_anisoDuctile_init, & - source_damage_anisoDuctile_dotState, & - source_damage_anisoDuctile_getRateAndItsTangent, & - source_damage_anisoDuctile_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoDuctile_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_anisoDuctile_label, & - SOURCE_damage_anisoDuctile_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - use lattice, only: & - lattice_maxNslipFamily, & - lattice_NslipSystem - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoDuctile_LABEL//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_anisoDuctile_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_anisoDuctile_offset(material_Nphase), source=0_pInt) - allocate(source_damage_anisoDuctile_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_anisoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoDuctile_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_anisoDuctile_ID) & - source_damage_anisoDuctile_offset(phase) = source - enddo - enddo - - allocate(source_damage_anisoDuctile_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_damage_anisoDuctile_output(maxval(phase_Noutput),maxNinstance)) - source_damage_anisoDuctile_output = '' - allocate(source_damage_anisoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_anisoDuctile_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoDuctile_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) - allocate(source_damage_anisoDuctile_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_totalNslip(maxNinstance), source=0_pInt) - allocate(source_damage_anisoDuctile_N(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoDuctile_sdot_0(maxNinstance), source=0.0_pReal) - allocate(source_damage_anisoDuctile_aTol(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_anisoDuctile_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('anisoductile_drivingforce') - source_damage_anisoDuctile_Noutput(instance) = source_damage_anisoDuctile_Noutput(instance) + 1_pInt - source_damage_anisoDuctile_outputID(source_damage_anisoDuctile_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_anisoDuctile_output(source_damage_anisoDuctile_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('anisoductile_atol') - source_damage_anisoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('nslip') ! - Nchunks_SlipFamilies = chunkPos(1) - 1_pInt - do j = 1_pInt, Nchunks_SlipFamilies - source_damage_anisoDuctile_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_sdot0') - source_damage_anisoDuctile_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalplasticstrain') - do j = 1_pInt, Nchunks_SlipFamilies - source_damage_anisoDuctile_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - case ('anisoductile_ratesensitivity') - source_damage_anisoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('anisoductile_criticalload') - do j = 1_pInt, Nchunks_SlipFamilies - source_damage_anisoDuctile_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) - enddo - - end select - endif; endif - enddo parsingFile - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, size(phase_source) - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then - instance = source_damage_anisoDuctile_instance(phase) - source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance) = & - min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested - source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance)) - source_damage_anisoDuctile_totalNslip(instance) = sum(source_damage_anisoDuctile_Nslip(:,instance)) - if (source_damage_anisoDuctile_aTol(instance) < 0.0_pReal) & - source_damage_anisoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_anisoDuctile_sdot_0(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoDuctile_LABEL//')') - if (any(source_damage_anisoDuctile_critPlasticStrain(:,instance) < 0.0_pReal)) & - call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//SOURCE_damage_anisoDuctile_LABEL//')') - if (source_damage_anisoDuctile_N(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoDuctile_LABEL//')') - endif myPhase - enddo sanityChecks - - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_anisoDuctile_instance(phase) - sourceOffset = source_damage_anisoDuctile_offset(phase) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) - select case(source_damage_anisoDuctile_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_anisoDuctile_sizePostResult(o,instance) = mySize - source_damage_anisoDuctile_sizePostResults(instance) = source_damage_anisoDuctile_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -!-------------------------------------------------------------------------------------------------- -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoDuctile_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_anisoDuctile_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_anisoDuctile_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoDuctile_dotState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - sourceState, & - material_homog, & - damage, & - damageMapping - use lattice, only: & - lattice_maxNslipFamily - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, & - constituent, & - sourceOffset, & - homog, damageOffset, & - instance, & - index, f, i - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoDuctile_instance(phase) - sourceOffset = source_damage_anisoDuctile_offset(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - index = 1_pInt - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal - do f = 1_pInt,lattice_maxNslipFamily - do i = 1_pInt,source_damage_anisoDuctile_Nslip(f,instance) ! process each (active) slip system in family - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & - plasticState(phase)%slipRate(index,constituent)/ & - ((damage(homog)%p(damageOffset))**source_damage_anisoDuctile_N(instance))/ & - source_damage_anisoDuctile_critPlasticStrain(f,instance) - - index = index + 1_pInt - enddo - enddo - -end subroutine source_damage_anisoDuctile_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_anisoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_damage_anisoDuctile_offset(phase) - - localphiDot = 1.0_pReal - & - sourceState(phase)%p(sourceOffset)%state(1,constituent)* & - phi - - dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_anisoDuctile_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_anisoDuctile_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_anisoDuctile_sizePostResults( & - source_damage_anisoDuctile_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_anisoDuctile_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_anisoDuctile_instance(phase) - sourceOffset = source_damage_anisoDuctile_offset(phase) - - c = 0_pInt - source_damage_anisoDuctile_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) - select case(source_damage_anisoDuctile_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_anisoDuctile_postResults(c+1_pInt) = & - sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1_pInt - - end select - enddo -end function source_damage_anisoDuctile_postResults - -end module source_damage_anisoDuctile diff --git a/code/source_damage_isoBrittle.f90 b/code/source_damage_isoBrittle.f90 deleted file mode 100644 index c063ae86f..000000000 --- a/code/source_damage_isoBrittle.f90 +++ /dev/null @@ -1,383 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine incoprorating isotropic brittle damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_isoBrittle - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_isoBrittle_sizePostResults, & !< cumulative size of post results - source_damage_isoBrittle_offset, & !< which source is my current damage mechanism? - source_damage_isoBrittle_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_isoBrittle_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_isoBrittle_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_isoBrittle_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_damage_isoBrittle_aTol, & - source_damage_isoBrittle_N, & - source_damage_isoBrittle_critStrainEnergy - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_isoBrittle_outputID !< ID of each post result output - - - public :: & - source_damage_isoBrittle_init, & - source_damage_isoBrittle_deltaState, & - source_damage_isoBrittle_getRateAndItsTangent, & - source_damage_isoBrittle_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoBrittle_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_isoBrittle_label, & - SOURCE_damage_isoBrittle_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoBrittle_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_isoBrittle_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_isoBrittle_offset(material_Nphase), source=0_pInt) - allocate(source_damage_isoBrittle_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_isoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoBrittle_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_isoBrittle_ID) & - source_damage_isoBrittle_offset(phase) = source - enddo - enddo - - allocate(source_damage_isoBrittle_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_isoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_damage_isoBrittle_output(maxval(phase_Noutput),maxNinstance)) - source_damage_isoBrittle_output = '' - allocate(source_damage_isoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_isoBrittle_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_isoBrittle_critStrainEnergy(maxNinstance), source=0.0_pReal) - allocate(source_damage_isoBrittle_N(maxNinstance), source=1.0_pReal) - allocate(source_damage_isoBrittle_aTol(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_isoBrittle_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('isobrittle_drivingforce') - source_damage_isoBrittle_Noutput(instance) = source_damage_isoBrittle_Noutput(instance) + 1_pInt - source_damage_isoBrittle_outputID(source_damage_isoBrittle_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_isoBrittle_output(source_damage_isoBrittle_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('isobrittle_criticalstrainenergy') - source_damage_isoBrittle_critStrainEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isobrittle_n') - source_damage_isoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isobrittle_atol') - source_damage_isoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then - instance = source_damage_isoBrittle_instance(phase) - if (source_damage_isoBrittle_aTol(instance) < 0.0_pReal) & - source_damage_isoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_isoBrittle_critStrainEnergy(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='criticalStrainEnergy ('//SOURCE_damage_isoBrittle_LABEL//')') - endif myPhase - enddo sanityChecks - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_isoBrittle_instance(phase) - sourceOffset = source_damage_isoBrittle_offset(phase) -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) - select case(source_damage_isoBrittle_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_isoBrittle_sizePostResult(o,instance) = mySize - source_damage_isoBrittle_sizePostResults(instance) = source_damage_isoBrittle_sizePostResults(instance) + mySize - endif - enddo outputsLoop -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 1_pInt - sizeState = 1_pInt - - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoBrittle_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_isoBrittle_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_isoBrittle_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoBrittle_deltaState(C, Fe, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState, & - material_homog, & - phase_NstiffnessDegradations, & - phase_stiffnessDegradation, & - porosity, & - porosityMapping, & - STIFFNESS_DEGRADATION_porosity_ID - use math, only : & - math_mul33x33, & - math_mul66x6, & - math_Mandel33to6, & - math_transpose33, & - math_I3 - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(3,3) :: & - Fe - real(pReal), intent(in), dimension(6,6) :: & - C - integer(pInt) :: & - phase, constituent, instance, sourceOffset, mech - real(pReal) :: & - strain(6), & - stiffness(6,6), & - strainenergy - - phase = phaseAt(ipc,ip,el) !< phase ID at ipc,ip,el - constituent = phasememberAt(ipc,ip,el) !< state array offset for phase ID at ipc,ip,el - ! ToDo: capability for multiple instances of SAME source within given phase. Needs Ninstance loop from here on! - instance = source_damage_isoBrittle_instance(phase) !< instance of damage_isoBrittle source - sourceOffset = source_damage_isoBrittle_offset(phase) - - stiffness = C - do mech = 1_pInt, phase_NstiffnessDegradations(phase) - select case(phase_stiffnessDegradation(mech,phase)) - case (STIFFNESS_DEGRADATION_porosity_ID) - stiffness = porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & - porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & - stiffness - end select - enddo - strain = 0.5_pReal*math_Mandel33to6(math_mul33x33(math_transpose33(Fe),Fe)-math_I3) - - strainenergy = 2.0_pReal*sum(strain*math_mul66x6(stiffness,strain))/ & - source_damage_isoBrittle_critStrainEnergy(instance) - if (strainenergy > sourceState(phase)%p(sourceOffset)%subState0(1,constituent)) then - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - strainenergy - sourceState(phase)%p(sourceOffset)%state(1,constituent) - else - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - sourceState(phase)%p(sourceOffset)%subState0(1,constituent) - & - sourceState(phase)%p(sourceOffset)%state(1,constituent) - endif - -end subroutine source_damage_isoBrittle_deltaState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoBrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, instance, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoBrittle_instance(phase) - sourceOffset = source_damage_isoBrittle_offset(phase) - - localphiDot = (1.0_pReal - phi)**(source_damage_isoBrittle_N(instance) - 1.0_pReal) - & - phi*sourceState(phase)%p(sourceOffset)%state(1,constituent) - dLocalphiDot_dPhi = - (source_damage_isoBrittle_N(instance) - 1.0_pReal)* & - (1.0_pReal - phi)**max(0.0_pReal,source_damage_isoBrittle_N(instance) - 2.0_pReal) & - - sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_isoBrittle_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_isoBrittle_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_isoBrittle_sizePostResults( & - source_damage_isoBrittle_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_isoBrittle_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoBrittle_instance(phase) - sourceOffset = source_damage_isoBrittle_offset(phase) - - c = 0_pInt - source_damage_isoBrittle_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) - select case(source_damage_isoBrittle_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_isoBrittle_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1 - - end select - enddo -end function source_damage_isoBrittle_postResults - -end module source_damage_isoBrittle diff --git a/code/source_damage_isoDuctile.f90 b/code/source_damage_isoDuctile.f90 deleted file mode 100644 index b0290264c..000000000 --- a/code/source_damage_isoDuctile.f90 +++ /dev/null @@ -1,350 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH -!> @brief material subroutine incoprorating isotropic ductile damage source mechanism -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_damage_isoDuctile - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_damage_isoDuctile_sizePostResults, & !< cumulative size of post results - source_damage_isoDuctile_offset, & !< which source is my current damage mechanism? - source_damage_isoDuctile_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_damage_isoDuctile_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_damage_isoDuctile_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_damage_isoDuctile_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_damage_isoDuctile_aTol, & - source_damage_isoDuctile_critPlasticStrain, & - source_damage_isoDuctile_N - - enum, bind(c) - enumerator :: undefined_ID, & - damage_drivingforce_ID - end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo - - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - source_damage_isoDuctile_outputID !< ID of each post result output - - - public :: & - source_damage_isoDuctile_init, & - source_damage_isoDuctile_dotState, & - source_damage_isoDuctile_getRateAndItsTangent, & - source_damage_isoDuctile_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoDuctile_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_damage_isoDuctile_label, & - SOURCE_damage_isoDuctile_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoDuctile_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_damage_isoDuctile_ID),pInt) - if (maxNinstance == 0_pInt) return - - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_damage_isoDuctile_offset(material_Nphase), source=0_pInt) - allocate(source_damage_isoDuctile_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_damage_isoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoDuctile_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_damage_isoDuctile_ID) & - source_damage_isoDuctile_offset(phase) = source - enddo - enddo - - allocate(source_damage_isoDuctile_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_damage_isoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_damage_isoDuctile_output(maxval(phase_Noutput),maxNinstance)) - source_damage_isoDuctile_output = '' - allocate(source_damage_isoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) - allocate(source_damage_isoDuctile_Noutput(maxNinstance), source=0_pInt) - allocate(source_damage_isoDuctile_critPlasticStrain(maxNinstance), source=0.0_pReal) - allocate(source_damage_isoDuctile_N(maxNinstance), source=0.0_pReal) - allocate(source_damage_isoDuctile_aTol(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - instance = source_damage_isoDuctile_instance(phase) ! which instance of my damage is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('isoductile_drivingforce') - source_damage_isoDuctile_Noutput(instance) = source_damage_isoDuctile_Noutput(instance) + 1_pInt - source_damage_isoDuctile_outputID(source_damage_isoDuctile_Noutput(instance),instance) = damage_drivingforce_ID - source_damage_isoDuctile_output(source_damage_isoDuctile_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('isoductile_criticalplasticstrain') - source_damage_isoDuctile_critPlasticStrain(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isoductile_ratesensitivity') - source_damage_isoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('isoductile_atol') - source_damage_isoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - -!-------------------------------------------------------------------------------------------------- -! sanity checks - sanityChecks: do phase = 1_pInt, material_Nphase - myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then - instance = source_damage_isoDuctile_instance(phase) - if (source_damage_isoDuctile_aTol(instance) < 0.0_pReal) & - source_damage_isoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 - if (source_damage_isoDuctile_critPlasticStrain(instance) <= 0.0_pReal) & - call IO_error(211_pInt,el=instance,ext_msg='critical plastic strain ('//SOURCE_damage_isoDuctile_LABEL//')') - endif myPhase - enddo sanityChecks - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_damage_isoDuctile_instance(phase) - sourceOffset = source_damage_isoDuctile_offset(phase) -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) - select case(source_damage_isoDuctile_outputID(o,instance)) - case(damage_drivingforce_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - source_damage_isoDuctile_sizePostResult(o,instance) = mySize - source_damage_isoDuctile_sizePostResults(instance) = source_damage_isoDuctile_sizePostResults(instance) + mySize - endif - enddo outputsLoop -! Determine size of state array - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoDuctile_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & - source=source_damage_isoDuctile_aTol(instance)) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_damage_isoDuctile_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoDuctile_dotState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - plasticState, & - sourceState, & - material_homog, & - damage, & - damageMapping - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, constituent, instance, homog, sourceOffset, damageOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoDuctile_instance(phase) - sourceOffset = source_damage_isoDuctile_offset(phase) - homog = material_homog(ip,el) - damageOffset = damageMapping(homog)%p(ip,el) - - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & - sum(plasticState(phase)%slipRate(:,constituent))/ & - ((damage(homog)%p(damageOffset))**source_damage_isoDuctile_N(instance))/ & - source_damage_isoDuctile_critPlasticStrain(instance) - -end subroutine source_damage_isoDuctile_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local part of nonlocal damage driving force -!-------------------------------------------------------------------------------------------------- -subroutine source_damage_isoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in) :: & - phi - real(pReal), intent(out) :: & - localphiDot, & - dLocalphiDot_dPhi - integer(pInt) :: & - phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_damage_isoDuctile_offset(phase) - - localphiDot = 1.0_pReal - & - sourceState(phase)%p(sourceOffset)%state(1,constituent)* & - phi - - dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_damage_isoDuctile_getRateAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of local damage results -!-------------------------------------------------------------------------------------------------- -function source_damage_isoDuctile_postResults(ipc,ip,el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), dimension(source_damage_isoDuctile_sizePostResults( & - source_damage_isoDuctile_instance(phaseAt(ipc,ip,el)))) :: & - source_damage_isoDuctile_postResults - - integer(pInt) :: & - instance, phase, constituent, sourceOffset, o, c - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_damage_isoDuctile_instance(phase) - sourceOffset = source_damage_isoDuctile_offset(phase) - - c = 0_pInt - source_damage_isoDuctile_postResults = 0.0_pReal - - do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) - select case(source_damage_isoDuctile_outputID(o,instance)) - case (damage_drivingforce_ID) - source_damage_isoDuctile_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) - c = c + 1 - - end select - enddo -end function source_damage_isoDuctile_postResults - -end module source_damage_isoDuctile diff --git a/code/source_thermal_dissipation.f90 b/code/source_thermal_dissipation.f90 deleted file mode 100644 index 83ad85167..000000000 --- a/code/source_thermal_dissipation.f90 +++ /dev/null @@ -1,220 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for thermal source due to plastic dissipation -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_thermal_dissipation - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_thermal_dissipation_sizePostResults, & !< cumulative size of post results - source_thermal_dissipation_offset, & !< which source is my current thermal dissipation mechanism? - source_thermal_dissipation_instance !< instance of thermal dissipation source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_thermal_dissipation_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_thermal_dissipation_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_thermal_dissipation_Noutput !< number of outputs per instance of this source - - real(pReal), dimension(:), allocatable, private :: & - source_thermal_dissipation_coldworkCoeff - - public :: & - source_thermal_dissipation_init, & - source_thermal_dissipation_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_dissipation_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_thermal_dissipation_label, & - SOURCE_thermal_dissipation_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_dissipation_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_thermal_dissipation_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_thermal_dissipation_offset(material_Nphase), source=0_pInt) - allocate(source_thermal_dissipation_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_thermal_dissipation_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_dissipation_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == SOURCE_thermal_dissipation_ID) & - source_thermal_dissipation_offset(phase) = source - enddo - enddo - - allocate(source_thermal_dissipation_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_thermal_dissipation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_thermal_dissipation_output (maxval(phase_Noutput),maxNinstance)) - source_thermal_dissipation_output = '' - allocate(source_thermal_dissipation_Noutput(maxNinstance), source=0_pInt) - allocate(source_thermal_dissipation_coldworkCoeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_thermal_dissipation_instance(phase) ! which instance of my source is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('dissipation_coldworkcoeff') - source_thermal_dissipation_coldworkCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_thermal_dissipation_instance(phase) - sourceOffset = source_thermal_dissipation_offset(phase) - - sizeDotState = 0_pInt - sizeDeltaState = 0_pInt - sizeState = 0_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_dissipation_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_thermal_dissipation_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_dissipation_getRateAndItsTangent(TDot, dTDOT_dT, Tstar_v, Lp, ipc, ip, el) - use math, only: & - math_Mandel6to33 - use material, only: & - phaseAt, phasememberAt - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(in), dimension(6) :: & - Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) - real(pReal), intent(in), dimension(3,3) :: & - Lp - real(pReal), intent(out) :: & - TDot, & - dTDOT_dT - integer(pInt) :: & - instance, phase, constituent - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_thermal_dissipation_instance(phase) - - TDot = source_thermal_dissipation_coldworkCoeff(instance)* & - sum(abs(math_Mandel6to33(Tstar_v)*Lp)) - dTDOT_dT = 0.0_pReal - -end subroutine source_thermal_dissipation_getRateAndItsTangent - -end module source_thermal_dissipation diff --git a/code/source_thermal_externalheat.f90 b/code/source_thermal_externalheat.f90 deleted file mode 100644 index 257012c06..000000000 --- a/code/source_thermal_externalheat.f90 +++ /dev/null @@ -1,277 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for thermal source due to plastic dissipation -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_thermal_externalheat - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_thermal_externalheat_sizePostResults, & !< cumulative size of post results - source_thermal_externalheat_offset, & !< which source is my current thermal dissipation mechanism? - source_thermal_externalheat_instance !< instance of thermal dissipation source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_thermal_externalheat_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_thermal_externalheat_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_thermal_externalheat_Noutput !< number of outputs per instance of this source - - integer(pInt), dimension(:), allocatable, private :: & - source_thermal_externalheat_nIntervals - - real(pReal), dimension(:,:), allocatable, private :: & - source_thermal_externalheat_time, & - source_thermal_externalheat_rate - - public :: & - source_thermal_externalheat_init, & - source_thermal_externalheat_dotState, & - source_thermal_externalheat_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_externalheat_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_thermal_externalheat_label, & - SOURCE_thermal_externalheat_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase,interval - character(len=65536) :: & - tag = '', & - line = '' - real(pReal), allocatable, dimension(:,:) :: temp_time, temp_rate - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_externalheat_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_thermal_externalheat_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_thermal_externalheat_offset(material_Nphase), source=0_pInt) - allocate(source_thermal_externalheat_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_thermal_externalheat_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_externalheat_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == SOURCE_thermal_externalheat_ID) & - source_thermal_externalheat_offset(phase) = source - enddo - enddo - - allocate(source_thermal_externalheat_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_thermal_externalheat_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_thermal_externalheat_output (maxval(phase_Noutput),maxNinstance)) - source_thermal_externalheat_output = '' - allocate(source_thermal_externalheat_Noutput(maxNinstance), source=0_pInt) - allocate(source_thermal_externalheat_nIntervals(maxNinstance), source=0_pInt) - - allocate(temp_time(maxNinstance,1000), source=0.0_pReal) - allocate(temp_rate(maxNinstance,1000), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_thermal_externalheat_instance(phase) ! which instance of my source is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('externalheat_time') - if (chunkPos(1) <= 2_pInt) & - call IO_error(150_pInt,ext_msg=trim(tag)//' ('//SOURCE_thermal_externalheat_label//')') - source_thermal_externalheat_nIntervals(instance) = chunkPos(1) - 2_pInt - do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt - temp_time(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) - enddo - - case ('externalheat_rate') - do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt - temp_rate(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) - enddo - - end select - endif; endif - enddo parsingFile - - allocate(source_thermal_externalheat_time(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) - allocate(source_thermal_externalheat_rate(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_thermal_externalheat_instance(phase) - sourceOffset = source_thermal_externalheat_offset(phase) - source_thermal_externalheat_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & - temp_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) - source_thermal_externalheat_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & - temp_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) - - sizeDotState = 1_pInt - sizeDeltaState = 0_pInt - sizeState = 1_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_externalheat_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.00001_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_thermal_externalheat_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_externalheat_dotState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, & - constituent, & - sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_thermal_externalheat_offset(phase) - - sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 1.0_pReal - -end subroutine source_thermal_externalheat_dotState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_thermal_externalheat_getRateAndItsTangent(TDot, dTDot_dT, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - TDot, & - dTDot_dT - integer(pInt) :: & - instance, phase, constituent, sourceOffset, interval - real(pReal) :: & - norm_time - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_thermal_externalheat_instance(phase) - sourceOffset = source_thermal_externalheat_offset(phase) - - do interval = 1, source_thermal_externalheat_nIntervals(instance) - norm_time = (sourceState(phase)%p(sourceOffset)%state(1,constituent) - & - source_thermal_externalheat_time(instance,interval)) / & - (source_thermal_externalheat_time(instance,interval+1) - & - source_thermal_externalheat_time(instance,interval)) - if (norm_time >= 0.0_pReal .and. norm_time < 1.0_pReal) & - TDot = source_thermal_externalheat_rate(instance,interval ) * (1.0_pReal - norm_time) + & - source_thermal_externalheat_rate(instance,interval+1) * norm_time - enddo - dTDot_dT = 0.0 - -end subroutine source_thermal_externalheat_getRateAndItsTangent - -end module source_thermal_externalheat diff --git a/code/source_vacancy_irradiation.f90 b/code/source_vacancy_irradiation.f90 deleted file mode 100644 index c4bcfba04..000000000 --- a/code/source_vacancy_irradiation.f90 +++ /dev/null @@ -1,253 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for vacancy generation due to irradiation -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_vacancy_irradiation - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_vacancy_irradiation_sizePostResults, & !< cumulative size of post results - source_vacancy_irradiation_offset, & !< which source is my current damage mechanism? - source_vacancy_irradiation_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_vacancy_irradiation_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_vacancy_irradiation_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_vacancy_irradiation_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_vacancy_irradiation_cascadeProb, & - source_vacancy_irradiation_cascadeVolume - - public :: & - source_vacancy_irradiation_init, & - source_vacancy_irradiation_deltaState, & - source_vacancy_irradiation_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_irradiation_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_vacancy_irradiation_label, & - SOURCE_vacancy_irradiation_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_irradiation_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_vacancy_irradiation_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_vacancy_irradiation_offset(material_Nphase), source=0_pInt) - allocate(source_vacancy_irradiation_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_vacancy_irradiation_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_irradiation_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_vacancy_irradiation_ID) & - source_vacancy_irradiation_offset(phase) = source - enddo - enddo - - allocate(source_vacancy_irradiation_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_vacancy_irradiation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_vacancy_irradiation_output(maxval(phase_Noutput),maxNinstance)) - source_vacancy_irradiation_output = '' - allocate(source_vacancy_irradiation_Noutput(maxNinstance), source=0_pInt) - allocate(source_vacancy_irradiation_cascadeProb(maxNinstance), source=0.0_pReal) - allocate(source_vacancy_irradiation_cascadeVolume(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_vacancy_irradiation_instance(phase) ! which instance of my vacancy is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('irradiation_cascadeprobability') - source_vacancy_irradiation_cascadeProb(instance) = IO_floatValue(line,chunkPos,2_pInt) - - case ('irradiation_cascadevolume') - source_vacancy_irradiation_cascadeVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_vacancy_irradiation_instance(phase) - sourceOffset = source_vacancy_irradiation_offset(phase) - - sizeDotState = 2_pInt - sizeDeltaState = 2_pInt - sizeState = 2_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_irradiation_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_vacancy_irradiation_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_irradiation_deltaState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, constituent, sourceOffset - real(pReal) :: & - randNo - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_vacancy_irradiation_offset(phase) - - call random_number(randNo) - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - randNo - sourceState(phase)%p(sourceOffset)%state(1,constituent) - call random_number(randNo) - sourceState(phase)%p(sourceOffset)%deltaState(2,constituent) = & - randNo - sourceState(phase)%p(sourceOffset)%state(2,constituent) - -end subroutine source_vacancy_irradiation_deltaState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_irradiation_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - CvDot, dCvDot_dCv - integer(pInt) :: & - instance, phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_vacancy_irradiation_instance(phase) - sourceOffset = source_vacancy_irradiation_offset(phase) - - CvDot = 0.0_pReal - dCvDot_dCv = 0.0_pReal - if (sourceState(phase)%p(sourceOffset)%state0(1,constituent) < source_vacancy_irradiation_cascadeProb(instance)) & - CvDot = sourceState(phase)%p(sourceOffset)%state0(2,constituent)*source_vacancy_irradiation_cascadeVolume(instance) - -end subroutine source_vacancy_irradiation_getRateAndItsTangent - -end module source_vacancy_irradiation diff --git a/code/source_vacancy_phenoplasticity.f90 b/code/source_vacancy_phenoplasticity.f90 deleted file mode 100644 index f9e766b2c..000000000 --- a/code/source_vacancy_phenoplasticity.f90 +++ /dev/null @@ -1,215 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for vacancy generation due to plasticity -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_vacancy_phenoplasticity - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_vacancy_phenoplasticity_sizePostResults, & !< cumulative size of post results - source_vacancy_phenoplasticity_offset, & !< which source is my current damage mechanism? - source_vacancy_phenoplasticity_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_vacancy_phenoplasticity_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_vacancy_phenoplasticity_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_vacancy_phenoplasticity_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_vacancy_phenoplasticity_rateCoeff - - public :: & - source_vacancy_phenoplasticity_init, & - source_vacancy_phenoplasticity_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_phenoplasticity_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_vacancy_phenoplasticity_label, & - SOURCE_vacancy_phenoplasticity_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_phenoplasticity_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_vacancy_phenoplasticity_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_vacancy_phenoplasticity_offset(material_Nphase), source=0_pInt) - allocate(source_vacancy_phenoplasticity_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_vacancy_phenoplasticity_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_phenoplasticity_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_vacancy_phenoplasticity_ID) & - source_vacancy_phenoplasticity_offset(phase) = source - enddo - enddo - - allocate(source_vacancy_phenoplasticity_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_vacancy_phenoplasticity_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_vacancy_phenoplasticity_output(maxval(phase_Noutput),maxNinstance)) - source_vacancy_phenoplasticity_output = '' - allocate(source_vacancy_phenoplasticity_Noutput(maxNinstance), source=0_pInt) - allocate(source_vacancy_phenoplasticity_rateCoeff(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_vacancy_phenoplasticity_instance(phase) ! which instance of my vacancy is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('phenoplasticity_ratecoeff') - source_vacancy_phenoplasticity_rateCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_vacancy_phenoplasticity_instance(phase) - sourceOffset = source_vacancy_phenoplasticity_offset(phase) - - sizeDotState = 0_pInt - sizeDeltaState = 0_pInt - sizeState = 0_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_phenoplasticity_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_vacancy_phenoplasticity_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_phenoplasticity_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - plasticState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - CvDot, dCvDot_dCv - integer(pInt) :: & - instance, phase, constituent - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_vacancy_phenoplasticity_instance(phase) - - CvDot = & - source_vacancy_phenoplasticity_rateCoeff(instance)* & - sum(plasticState(phase)%slipRate(:,constituent)) - dCvDot_dCv = 0.0_pReal - -end subroutine source_vacancy_phenoplasticity_getRateAndItsTangent - -end module source_vacancy_phenoplasticity diff --git a/code/source_vacancy_thermalfluc.f90 b/code/source_vacancy_thermalfluc.f90 deleted file mode 100644 index c86406430..000000000 --- a/code/source_vacancy_thermalfluc.f90 +++ /dev/null @@ -1,255 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for vacancy generation due to thermal fluctuations -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module source_vacancy_thermalfluc - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - source_vacancy_thermalfluc_sizePostResults, & !< cumulative size of post results - source_vacancy_thermalfluc_offset, & !< which source is my current damage mechanism? - source_vacancy_thermalfluc_instance !< instance of damage source mechanism - - integer(pInt), dimension(:,:), allocatable, target, public :: & - source_vacancy_thermalfluc_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - source_vacancy_thermalfluc_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - source_vacancy_thermalfluc_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - source_vacancy_thermalfluc_amplitude, & - source_vacancy_thermalfluc_normVacancyEnergy - - public :: & - source_vacancy_thermalfluc_init, & - source_vacancy_thermalfluc_deltaState, & - source_vacancy_thermalfluc_getRateAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_thermalfluc_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use debug, only: & - debug_level,& - debug_constitutive,& - debug_levelBasic - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use lattice, only: & - lattice_vacancyFormationEnergy - use material, only: & - phase_source, & - phase_Nsources, & - phase_Noutput, & - SOURCE_vacancy_thermalfluc_label, & - SOURCE_vacancy_thermalfluc_ID, & - material_Nphase, & - material_phase, & - sourceState, & - MATERIAL_partPhase - use numerics,only: & - analyticJaco, & - worldrank, & - numerics_integrator - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset - integer(pInt) :: sizeState, sizeDotState, sizeDeltaState - integer(pInt) :: NofMyPhase - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_thermalfluc_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(phase_source == SOURCE_vacancy_thermalfluc_ID),pInt) - if (maxNinstance == 0_pInt) return - if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & - write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance - - allocate(source_vacancy_thermalfluc_offset(material_Nphase), source=0_pInt) - allocate(source_vacancy_thermalfluc_instance(material_Nphase), source=0_pInt) - do phase = 1, material_Nphase - source_vacancy_thermalfluc_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_thermalfluc_ID) - do source = 1, phase_Nsources(phase) - if (phase_source(source,phase) == source_vacancy_thermalfluc_ID) & - source_vacancy_thermalfluc_offset(phase) = source - enddo - enddo - - allocate(source_vacancy_thermalfluc_sizePostResults(maxNinstance), source=0_pInt) - allocate(source_vacancy_thermalfluc_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) - allocate(source_vacancy_thermalfluc_output(maxval(phase_Noutput),maxNinstance)) - source_vacancy_thermalfluc_output = '' - allocate(source_vacancy_thermalfluc_Noutput(maxNinstance), source=0_pInt) - allocate(source_vacancy_thermalfluc_amplitude(maxNinstance), source=0.0_pReal) - allocate(source_vacancy_thermalfluc_normVacancyEnergy(maxNinstance), source=0.0_pReal) - - rewind(fileUnit) - phase = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next phase section - phase = phase + 1_pInt ! advance phase section counter - cycle ! skip to next line - endif - - if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = source_vacancy_thermalfluc_instance(phase) ! which instance of my vacancy is present phase - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('thermalfluctuation_amplitude') - source_vacancy_thermalfluc_amplitude(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingFile - - initializeInstances: do phase = 1_pInt, material_Nphase - if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then - NofMyPhase=count(material_phase==phase) - instance = source_vacancy_thermalfluc_instance(phase) - source_vacancy_thermalfluc_normVacancyEnergy(instance) = & - lattice_vacancyFormationEnergy(phase)/1.3806488e-23_pReal - sourceOffset = source_vacancy_thermalfluc_offset(phase) - - sizeDotState = 1_pInt - sizeDeltaState = 1_pInt - sizeState = 1_pInt - sourceState(phase)%p(sourceOffset)%sizeState = sizeState - sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState - sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState - sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_thermalfluc_sizePostResults(instance) - allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) - - allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) - if (.not. analyticJaco) then - allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 1_pInt)) then - allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) - allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) - endif - if (any(numerics_integrator == 4_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) - if (any(numerics_integrator == 5_pInt)) & - allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine source_vacancy_thermalfluc_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates derived quantities from state -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_thermalfluc_deltaState(ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - integer(pInt) :: & - phase, constituent, sourceOffset - real(pReal) :: & - randNo - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - sourceOffset = source_vacancy_thermalfluc_offset(phase) - - call random_number(randNo) - sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & - randNo - 0.5_pReal - sourceState(phase)%p(sourceOffset)%state(1,constituent) - -end subroutine source_vacancy_thermalfluc_deltaState - -!-------------------------------------------------------------------------------------------------- -!> @brief returns local vacancy generation rate -!-------------------------------------------------------------------------------------------------- -subroutine source_vacancy_thermalfluc_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) - use material, only: & - phaseAt, phasememberAt, & - material_homog, & - temperature, & - thermalMapping, & - sourceState - - implicit none - integer(pInt), intent(in) :: & - ipc, & !< grain number - ip, & !< integration point number - el !< element number - real(pReal), intent(out) :: & - CvDot, dCvDot_dCv - integer(pInt) :: & - instance, phase, constituent, sourceOffset - - phase = phaseAt(ipc,ip,el) - constituent = phasememberAt(ipc,ip,el) - instance = source_vacancy_thermalfluc_instance(phase) - sourceOffset = source_vacancy_thermalfluc_offset(phase) - - CvDot = source_vacancy_thermalfluc_amplitude(instance)* & - sourceState(phase)%p(sourceOffset)%state0(2,constituent)* & - exp(-source_vacancy_thermalfluc_normVacancyEnergy(instance)/ & - temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))) - dCvDot_dCv = 0.0_pReal - -end subroutine source_vacancy_thermalfluc_getRateAndItsTangent - -end module source_vacancy_thermalfluc diff --git a/code/spectral_damage.f90 b/code/spectral_damage.f90 deleted file mode 100644 index 0b79d5e5d..000000000 --- a/code/spectral_damage.f90 +++ /dev/null @@ -1,414 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id: spectral_damage.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Shaokang Zhang, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Spectral solver for nonlocal damage -!-------------------------------------------------------------------------------------------------- -module spectral_damage - use prec, only: & - pInt, & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - use numerics, only: & - worldrank, & - worldsize - - implicit none - private -#include - - character (len=*), parameter, public :: & - spectral_damage_label = 'spectraldamage' - -!-------------------------------------------------------------------------------------------------- -! derived types - type(tSolutionParams), private :: params - -!-------------------------------------------------------------------------------------------------- -! PETSc data - SNES, private :: damage_snes - Vec, private :: solution - PetscInt, private :: xstart, xend, ystart, yend, zstart, zend - real(pReal), private, dimension(:,:,:), allocatable :: & - damage_current, & !< field of current damage - damage_lastInc, & !< field of previous damage - damage_stagInc !< field of staggered damage - -!-------------------------------------------------------------------------------------------------- -! reference diffusion tensor, mobility etc. - integer(pInt), private :: totalIter = 0_pInt !< total iteration in current increment - real(pReal), dimension(3,3), private :: D_ref - real(pReal), private :: mobility_ref - character(len=1024), private :: incInfo - - public :: & - spectral_damage_init, & - spectral_damage_solution, & - spectral_damage_forward, & - spectral_damage_destroy - external :: & - VecDestroy, & - DMDestroy, & - DMDACreate3D, & - DMCreateGlobalVector, & - DMDASNESSetFunctionLocal, & - PETScFinalize, & - SNESDestroy, & - SNESGetNumberFunctionEvals, & - SNESGetIterationNumber, & - SNESSolve, & - SNESSetDM, & - SNESGetConvergedReason, & - SNESSetConvergenceTest, & - SNESSetFromOptions, & - SNESCreate, & - MPI_Abort, & - MPI_Bcast, & - MPI_Allreduce - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields and fills them with data, potentially from restart info -!-------------------------------------------------------------------------------------------------- -subroutine spectral_damage_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_intOut, & - IO_read_realFile, & - IO_timeStamp - use spectral_utilities, only: & - wgt - use mesh, only: & - grid, & - grid3 - use damage_nonlocal, only: & - damage_nonlocal_getDiffusion33, & - damage_nonlocal_getMobility - - implicit none - DM :: damage_grid - Vec :: uBound, lBound - PetscErrorCode :: ierr - PetscObject :: dummy - integer(pInt), dimension(:), allocatable :: localK - integer(pInt) :: proc - integer(pInt) :: i, j, k, cell - character(len=100) :: snes_type - - mainProcess: if (worldrank == 0_pInt) then - write(6,'(/,a)') ' <<<+- spectral_damage init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!-------------------------------------------------------------------------------------------------- -! initialize solver specific parts of PETSc - call SNESCreate(PETSC_COMM_WORLD,damage_snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(damage_snes,'damage_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do proc = 1, worldsize - call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & !< cut off stencil at boundary - DMDA_STENCIL_BOX, & !< Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & !< global grid - 1, 1, worldsize, & - 1, 0, & !< #dof (damage phase field), ghost boundary width (domain overlap) - grid(1),grid(2),localK, & !< local grid - damage_grid,ierr) !< handle, error - CHKERRQ(ierr) - call SNESSetDM(damage_snes,damage_grid,ierr); CHKERRQ(ierr) !< connect snes to da - call DMCreateGlobalVector(damage_grid,solution,ierr); CHKERRQ(ierr) !< global solution vector (grid x 1, i.e. every def grad tensor) - call DMDASNESSetFunctionLocal(damage_grid,INSERT_VALUES,spectral_damage_formResidual,dummy,ierr) !< residual vector of same shape as solution vector - CHKERRQ(ierr) - call SNESSetFromOptions(damage_snes,ierr); CHKERRQ(ierr) !< pull it all together with additional cli arguments - call SNESGetType(damage_snes,snes_type,ierr); CHKERRQ(ierr) - if (trim(snes_type) == 'vinewtonrsls' .or. & - trim(snes_type) == 'vinewtonssls') then - call DMGetGlobalVector(damage_grid,lBound,ierr); CHKERRQ(ierr) - call DMGetGlobalVector(damage_grid,uBound,ierr); CHKERRQ(ierr) - call VecSet(lBound,0.0,ierr); CHKERRQ(ierr) - call VecSet(uBound,1.0,ierr); CHKERRQ(ierr) - call SNESVISetVariableBounds(damage_snes,lBound,uBound,ierr) !< variable bounds for variational inequalities like contact mechanics, damage etc. - call DMRestoreGlobalVector(damage_grid,lBound,ierr); CHKERRQ(ierr) - call DMRestoreGlobalVector(damage_grid,uBound,ierr); CHKERRQ(ierr) - endif - -!-------------------------------------------------------------------------------------------------- -! init fields - call DMDAGetCorners(damage_grid,xstart,ystart,zstart,xend,yend,zend,ierr) - CHKERRQ(ierr) - xend = xstart + xend - 1 - yend = ystart + yend - 1 - zend = zstart + zend - 1 - call VecSet(solution,1.0,ierr); CHKERRQ(ierr) - allocate(damage_current(grid(1),grid(2),grid3), source=1.0_pReal) - allocate(damage_lastInc(grid(1),grid(2),grid3), source=1.0_pReal) - allocate(damage_stagInc(grid(1),grid(2),grid3), source=1.0_pReal) - -!-------------------------------------------------------------------------------------------------- -! damage reference diffusion update - cell = 0_pInt - D_ref = 0.0_pReal - mobility_ref = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - D_ref = D_ref + damage_nonlocal_getDiffusion33(1,cell) - mobility_ref = mobility_ref + damage_nonlocal_getMobility(1,cell) - enddo; enddo; enddo - D_ref = D_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - mobility_ref = mobility_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - -end subroutine spectral_damage_init - -!-------------------------------------------------------------------------------------------------- -!> @brief solution for the spectral damage scheme with internal iterations -!-------------------------------------------------------------------------------------------------- -type(tSolutionState) function spectral_damage_solution(guess,timeinc,timeinc_old,loadCaseTime) - use numerics, only: & - itmax, & - err_damage_tolAbs, & - err_damage_tolRel - use spectral_utilities, only: & - tBoundaryCondition, & - Utilities_maskedCompliance, & - Utilities_updateGamma - use mesh, only: & - grid, & - grid3 - use damage_nonlocal, only: & - damage_nonlocal_putNonLocalDamage - - implicit none - -!-------------------------------------------------------------------------------------------------- -! input data for solution - real(pReal), intent(in) :: & - timeinc, & !< increment in time for current solution - timeinc_old, & !< increment in time of last increment - loadCaseTime !< remaining time of current load case - logical, intent(in) :: guess - integer(pInt) :: i, j, k, cell - PetscInt ::position - PetscReal :: minDamage, maxDamage, stagNorm, solnNorm - -!-------------------------------------------------------------------------------------------------- -! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - - spectral_damage_solution%converged =.false. - -!-------------------------------------------------------------------------------------------------- -! set module wide availabe data - params%timeinc = timeinc - params%timeincOld = timeinc_old - - call SNESSolve(damage_snes,PETSC_NULL_OBJECT,solution,ierr); CHKERRQ(ierr) - call SNESGetConvergedReason(damage_snes,reason,ierr); CHKERRQ(ierr) - - if (reason < 1) then - spectral_damage_solution%converged = .false. - spectral_damage_solution%iterationsNeeded = itmax - else - spectral_damage_solution%converged = .true. - spectral_damage_solution%iterationsNeeded = totalIter - endif - stagNorm = maxval(abs(damage_current - damage_stagInc)) - solnNorm = maxval(abs(damage_current)) - call MPI_Allreduce(MPI_IN_PLACE,stagNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) - call MPI_Allreduce(MPI_IN_PLACE,solnNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) - damage_stagInc = damage_current - spectral_damage_solution%stagConverged = stagNorm < err_damage_tolAbs & - .or. stagNorm < err_damage_tolRel*solnNorm - -!-------------------------------------------------------------------------------------------------- -! updating damage state - cell = 0_pInt !< material point = 0 - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt !< material point increase - call damage_nonlocal_putNonLocalDamage(damage_current(i,j,k),1,cell) - enddo; enddo; enddo - - call VecMin(solution,position,minDamage,ierr); CHKERRQ(ierr) - call VecMax(solution,position,maxDamage,ierr); CHKERRQ(ierr) - if (worldrank == 0) then - if (spectral_damage_solution%converged) & - write(6,'(/,a)') ' ... nonlocal damage converged .....................................' - write(6,'(/,a,f8.6,2x,f8.6,2x,f8.6,/)',advance='no') ' Minimum|Maximum|Delta Damage = ',& - minDamage, maxDamage, stagNorm - write(6,'(/,a)') ' ===========================================================================' - flush(6) - endif - -end function spectral_damage_solution - - -!-------------------------------------------------------------------------------------------------- -!> @brief forms the spectral damage residual vector -!-------------------------------------------------------------------------------------------------- -subroutine spectral_damage_formResidual(in,x_scal,f_scal,dummy,ierr) - use numerics, only: & - residualStiffness - use mesh, only: & - grid, & - grid3 - use math, only: & - math_mul33x3 - use spectral_utilities, only: & - scalarField_real, & - vectorField_real, & - utilities_FFTvectorForward, & - utilities_FFTvectorBackward, & - utilities_FFTscalarForward, & - utilities_FFTscalarBackward, & - utilities_fourierGreenConvolution, & - utilities_fourierScalarGradient, & - utilities_fourierVectorDivergence - use damage_nonlocal, only: & - damage_nonlocal_getSourceAndItsTangent,& - damage_nonlocal_getDiffusion33, & - damage_nonlocal_getMobility - - implicit none - DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & - in - PetscScalar, dimension( & - XG_RANGE,YG_RANGE,ZG_RANGE) :: & - x_scal - PetscScalar, dimension( & - X_RANGE,Y_RANGE,Z_RANGE) :: & - f_scal - PetscObject :: dummy - PetscErrorCode :: ierr - integer(pInt) :: i, j, k, cell - real(pReal) :: phiDot, dPhiDot_dPhi, mobility - - damage_current = x_scal -!-------------------------------------------------------------------------------------------------- -! evaluate polarization field - scalarField_real = 0.0_pReal - scalarField_real(1:grid(1),1:grid(2),1:grid3) = damage_current - call utilities_FFTscalarForward() - call utilities_fourierScalarGradient() !< calculate gradient of damage field - call utilities_FFTvectorBackward() - cell = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - vectorField_real(1:3,i,j,k) = math_mul33x3(damage_nonlocal_getDiffusion33(1,cell) - D_ref, & - vectorField_real(1:3,i,j,k)) - enddo; enddo; enddo - call utilities_FFTvectorForward() - call utilities_fourierVectorDivergence() !< calculate damage divergence in fourier field - call utilities_FFTscalarBackward() - cell = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - call damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, damage_current(i,j,k), 1, cell) - mobility = damage_nonlocal_getMobility(1,cell) - scalarField_real(i,j,k) = params%timeinc*scalarField_real(i,j,k) + & - params%timeinc*phiDot + & - mobility*damage_lastInc(i,j,k) - & - mobility*damage_current(i,j,k) + & - mobility_ref*damage_current(i,j,k) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! convolution of damage field with green operator - call utilities_FFTscalarForward() - call utilities_fourierGreenConvolution(D_ref, mobility_ref, params%timeinc) - call utilities_FFTscalarBackward() - where(scalarField_real(1:grid(1),1:grid(2),1:grid3) > damage_lastInc) & - scalarField_real(1:grid(1),1:grid(2),1:grid3) = damage_lastInc - where(scalarField_real(1:grid(1),1:grid(2),1:grid3) < residualStiffness) & - scalarField_real(1:grid(1),1:grid(2),1:grid3) = residualStiffness - -!-------------------------------------------------------------------------------------------------- -! constructing residual - f_scal = scalarField_real(1:grid(1),1:grid(2),1:grid3) - damage_current - -end subroutine spectral_damage_formResidual - -!-------------------------------------------------------------------------------------------------- -!> @brief spectral damage forwarding routine -!-------------------------------------------------------------------------------------------------- -subroutine spectral_damage_forward(guess,timeinc,timeinc_old,loadCaseTime) - use mesh, only: & - grid, & - grid3 - use spectral_utilities, only: & - cutBack, & - wgt - use damage_nonlocal, only: & - damage_nonlocal_putNonLocalDamage, & - damage_nonlocal_getDiffusion33, & - damage_nonlocal_getMobility - - implicit none - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - logical, intent(in) :: guess - PetscErrorCode :: ierr - integer(pInt) :: i, j, k, cell - DM :: dm_local - PetscScalar, dimension(:,:,:), pointer :: x_scal - - if (cutBack) then - damage_current = damage_lastInc - damage_stagInc = damage_lastInc -!-------------------------------------------------------------------------------------------------- -! reverting damage field state - cell = 0_pInt - call SNESGetDM(damage_snes,dm_local,ierr); CHKERRQ(ierr) - call DMDAVecGetArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with - x_scal(xstart:xend,ystart:yend,zstart:zend) = damage_current - call DMDAVecRestoreArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - call damage_nonlocal_putNonLocalDamage(damage_current(i,j,k),1,cell) - enddo; enddo; enddo - else -!-------------------------------------------------------------------------------------------------- -! update rate and forward last inc - damage_lastInc = damage_current - cell = 0_pInt - D_ref = 0.0_pReal - mobility_ref = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - D_ref = D_ref + damage_nonlocal_getDiffusion33(1,cell) - mobility_ref = mobility_ref + damage_nonlocal_getMobility(1,cell) - enddo; enddo; enddo - D_ref = D_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - mobility_ref = mobility_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - endif - - end subroutine spectral_damage_forward - -!-------------------------------------------------------------------------------------------------- -!> @brief destroy routine -!-------------------------------------------------------------------------------------------------- -subroutine spectral_damage_destroy() - - implicit none - PetscErrorCode :: ierr - - call VecDestroy(solution,ierr); CHKERRQ(ierr) - call SNESDestroy(damage_snes,ierr); CHKERRQ(ierr) - -end subroutine spectral_damage_destroy - -end module spectral_damage diff --git a/code/spectral_interface.f90 b/code/spectral_interface.f90 deleted file mode 100644 index b24c5f747..000000000 --- a/code/spectral_interface.f90 +++ /dev/null @@ -1,568 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Interfacing between the spectral solver and the material subroutines provided -!! by DAMASK -!> @details Interfacing between the spectral solver and the material subroutines provided -!> by DAMASK. Interpretating the command line arguments or, in case of called from f2py, -!> the arguments parsed to the init routine to get load case, geometry file, working -!> directory, etc. -!-------------------------------------------------------------------------------------------------- -module DAMASK_interface - use prec, only: & - pInt - - implicit none - private -#ifdef PETSc -#include -#endif - logical, public, protected :: appendToOutFile = .false. !< Append to existing spectralOut file (in case of restart, not in case of regridding) - integer(pInt), public, protected :: spectralRestartInc = 1_pInt !< Increment at which calculation starts - character(len=1024), public, protected :: & - geometryFile = '', & !< parameter given for geometry file - loadCaseFile = '' !< parameter given for load case file - character(len=1024), private :: workingDirectory !< accessed by getSolverWorkingDirectoryName for compatibility reasons - - public :: & - getSolverWorkingDirectoryName, & - getSolverJobName, & - DAMASK_interface_init - private :: & - storeWorkingDirectory, & - getGeometryFile, & - getLoadCaseFile, & - rectifyPath, & - makeRelativePath, & - getPathSep, & - IIO_stringValue, & - IIO_intValue, & - IIO_lc, & - IIO_stringPos - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief initializes the solver by interpreting the command line arguments. Also writes -!! information on computation to screen -!-------------------------------------------------------------------------------------------------- -subroutine DAMASK_interface_init(loadCaseParameterIn,geometryParameterIn) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - - implicit none - character(len=1024), optional, intent(in) :: & - loadCaseParameterIn, & !< if using the f2py variant, the -l argument of DAMASK_spectral.exe - geometryParameterIn !< if using the f2py variant, the -g argument of DAMASK_spectral.exe - character(len=1024) :: & - commandLine, & !< command line call as string - loadCaseArg ='', & !< -l argument given to DAMASK_spectral.exe - geometryArg ='', & !< -g argument given to DAMASK_spectral.exe - workingDirArg ='', & !< -w argument given to DAMASK_spectral.exe - hostName, & !< name of machine on which DAMASK_spectral.exe is execute (might require export HOSTNAME) - userName, & !< name of user calling DAMASK_spectral.exe - tag - integer :: & - i, & - worldrank = 0 - integer, allocatable, dimension(:) :: & - chunkPos - integer, dimension(8) :: & - dateAndTime ! type default integer -#ifdef PETSc - PetscErrorCode :: ierr -#endif - external :: & - quit,& - MPI_Comm_rank,& - PETScInitialize, & - MPI_abort - -!-------------------------------------------------------------------------------------------------- -! PETSc Init -#ifdef PETSc - call PetscInitialize(PETSC_NULL_CHARACTER,ierr) ! according to PETSc manual, that should be the first line in the code - CHKERRQ(ierr) ! this is a macro definition, it is case sensitive - - open(6, encoding='UTF-8') ! modern fortran compilers (gfortran >4.4, ifort >11 support it) - call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) -#endif - mainProcess: if (worldrank == 0) then - call date_and_time(values = dateAndTime) - write(6,'(/,a)') ' <<<+- DAMASK_spectral -+>>>' - write(6,'(/,a)') ' Version: '//DAMASKVERSION - write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& - dateAndTime(2),'/',& - dateAndTime(1) - write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& - dateAndTime(6),':',& - dateAndTime(7) - write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' -#include "compilation_info.f90" - endif mainProcess - - if ( present(loadcaseParameterIn) .and. present(geometryParameterIn)) then ! both mandatory parameters given in function call - geometryArg = geometryParameterIn - loadcaseArg = loadcaseParameterIn - commandLine = 'n/a' - else if ( .not.( present(loadcaseParameterIn) .and. present(geometryParameterIn))) then ! none parameters given in function call, trying to get them from command line - call get_command(commandLine) - chunkPos = IIO_stringPos(commandLine) - do i = 1, chunkPos(1) - tag = IIO_lc(IIO_stringValue(commandLine,chunkPos,i)) ! extract key - select case(tag) - case ('-h','--help') - mainProcess2: if (worldrank == 0) then - write(6,'(a)') ' #######################################################################' - write(6,'(a)') ' DAMASK_spectral:' - write(6,'(a)') ' The spectral method boundary value problem solver for' - write(6,'(a)') ' the Düsseldorf Advanced Material Simulation Kit' - write(6,'(a,/)')' #######################################################################' - write(6,'(a,/)')' Valid command line switches:' - write(6,'(a)') ' --geom (-g, --geometry)' - write(6,'(a)') ' --load (-l, --loadcase)' - write(6,'(a)') ' --workingdir (-w, --wd, --workingdirectory, -d, --directory)' - write(6,'(a)') ' --restart (-r, --rs)' - write(6,'(a)') ' --regrid (--rg)' - write(6,'(a)') ' --help (-h)' - write(6,'(/,a)')' -----------------------------------------------------------------------' - write(6,'(a)') ' Mandatory arguments:' - write(6,'(/,a)')' --geom PathToGeomFile/NameOfGeom.geom' - write(6,'(a)') ' Specifies the location of the geometry definition file,' - write(6,'(a)') ' if no extension is given, .geom will be appended.' - write(6,'(a)') ' "PathToGeomFile" will be the working directory if not specified' - write(6,'(a)') ' via --workingdir.' - write(6,'(a)') ' Make sure the file "material.config" exists in the working' - write(6,'(a)') ' directory.' - write(6,'(a)') ' For further configuration place "numerics.config"' - write(6,'(a)')' and "numerics.config" in that directory.' - write(6,'(/,a)')' --load PathToLoadFile/NameOfLoadFile.load' - write(6,'(a)') ' Specifies the location of the load case definition file,' - write(6,'(a)') ' if no extension is given, .load will be appended.' - write(6,'(/,a)')' -----------------------------------------------------------------------' - write(6,'(a)') ' Optional arguments:' - write(6,'(/,a)')' --workingdirectory PathToWorkingDirectory' - write(6,'(a)') ' Specifies the working directory and overwrites the default' - write(6,'(a)') ' "PathToGeomFile".' - write(6,'(a)') ' Make sure the file "material.config" exists in the working' - write(6,'(a)') ' directory.' - write(6,'(a)') ' For further configuration place "numerics.config"' - write(6,'(a)')' and "numerics.config" in that directory.' - write(6,'(/,a)')' --restart XX' - write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' - write(6,'(a)') ' calculate total increment No. XX.' - write(6,'(a)') ' Appends to existing results file ' - write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' - write(6,'(a)') ' Works only if the restart information for total increment' - write(6,'(a)') ' No. XX-1 is available in the working directory.' - write(6,'(/,a)')' --regrid XX' - write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' - write(6,'(a)') ' calculate total increment No. XX.' - write(6,'(a)') ' Attention: Overwrites existing results file ' - write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' - write(6,'(a)') ' Works only if the restart information for total increment' - write(6,'(a)') ' No. XX-1 is available in the working directory.' - write(6,'(/,a)')' -----------------------------------------------------------------------' - write(6,'(a)') ' Help:' - write(6,'(/,a)')' --help' - write(6,'(a,/)')' Prints this message and exits' - call quit(0_pInt) ! normal Termination - endif mainProcess2 - case ('-l', '--load', '--loadcase') - loadcaseArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) - case ('-g', '--geom', '--geometry') - geometryArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) - case ('-w', '-d', '--wd', '--directory', '--workingdir', '--workingdirectory') - workingDirArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) - case ('-r', '--rs', '--restart') - spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) - appendToOutFile = .true. - case ('--rg', '--regrid') - spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) - appendToOutFile = .false. - end select - enddo - endif - - if (len(trim(loadcaseArg)) == 0 .or. len(trim(geometryArg)) == 0) then - write(6,'(a)') ' Please specify geometry AND load case (-h for help)' - call quit(1_pInt) - endif - - workingDirectory = storeWorkingDirectory(trim(workingDirArg),trim(geometryArg)) - geometryFile = getGeometryFile(geometryArg) - loadCaseFile = getLoadCaseFile(loadCaseArg) - - call get_environment_variable('HOSTNAME',hostName) - call get_environment_variable('USER',userName) - mainProcess3: if (worldrank == 0) then - write(6,'(a,a)') ' Host name: ', trim(hostName) - write(6,'(a,a)') ' User name: ', trim(userName) - write(6,'(a,a)') ' Path separator: ', getPathSep() - write(6,'(a,a)') ' Command line call: ', trim(commandLine) - if (len(trim(workingDirArg))>0) & - write(6,'(a,a)') ' Working dir argument: ', trim(workingDirArg) - write(6,'(a,a)') ' Geometry argument: ', trim(geometryArg) - write(6,'(a,a)') ' Loadcase argument: ', trim(loadcaseArg) - write(6,'(a,a)') ' Working directory: ', trim(getSolverWorkingDirectoryName()) - write(6,'(a,a)') ' Geometry file: ', trim(geometryFile) - write(6,'(a,a)') ' Loadcase file: ', trim(loadCaseFile) - write(6,'(a,a)') ' Solver job name: ', trim(getSolverJobName()) - if (SpectralRestartInc > 1_pInt) & - write(6,'(a,i6.6)') ' Restart at increment: ', spectralRestartInc - write(6,'(a,l1,/)') ' Append to result file: ', appendToOutFile - endif mainProcess3 - -end subroutine DAMASK_interface_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief extract working directory from given argument or from location of geometry file, -!! possibly converting relative arguments to absolut path -!> @todo change working directory with call chdir(storeWorkingDirectory)? -!-------------------------------------------------------------------------------------------------- -character(len=1024) function storeWorkingDirectory(workingDirectoryArg,geometryArg) -#ifdef __INTEL_COMPILER - use IFPORT -#endif - - implicit none - character(len=*), intent(in) :: workingDirectoryArg !< working directory argument - character(len=*), intent(in) :: geometryArg !< geometry argument - character(len=1024) :: cwd - character :: pathSep - logical :: dirExists - external :: quit - integer :: error - - pathSep = getPathSep() - if (len(workingDirectoryArg)>0) then ! got working directory as input - if (workingDirectoryArg(1:1) == pathSep) then ! absolute path given as command line argument - storeWorkingDirectory = workingDirectoryArg - else - error = getcwd(cwd) ! relative path given as command line argument - storeWorkingDirectory = trim(cwd)//pathSep//workingDirectoryArg - endif - if (storeWorkingDirectory(len(trim(storeWorkingDirectory)):len(trim(storeWorkingDirectory))) & ! if path seperator is not given, append it - /= pathSep) storeWorkingDirectory = trim(storeWorkingDirectory)//pathSep -#ifdef __INTEL_COMPILER - inquire(directory = trim(storeWorkingDirectory)//'.', exist=dirExists) -#else - inquire(file = trim(storeWorkingDirectory), exist=dirExists) -#endif - if(.not. dirExists) then ! check if the directory exists - write(6,'(a20,a,a16)') ' working directory "',trim(storeWorkingDirectory),'" does not exist' - call quit(1_pInt) - endif - else ! using path to geometry file as working dir - if (geometryArg(1:1) == pathSep) then ! absolute path given as command line argument - storeWorkingDirectory = geometryArg(1:scan(geometryArg,pathSep,back=.true.)) - else - error = getcwd(cwd) ! relative path given as command line argument - storeWorkingDirectory = trim(cwd)//pathSep//& - geometryArg(1:scan(geometryArg,pathSep,back=.true.)) - endif - endif - storeWorkingDirectory = rectifyPath(storeWorkingDirectory) - -end function storeWorkingDirectory - - -!-------------------------------------------------------------------------------------------------- -!> @brief simply returns the private string workingDir -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getSolverWorkingDirectoryName() - - implicit none - getSolverWorkingDirectoryName = workingDirectory - -end function getSolverWorkingDirectoryName - - -!-------------------------------------------------------------------------------------------------- -!> @brief solver job name (no extension) as combination of geometry and load case name -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getSolverJobName() - - implicit none - integer :: posExt,posSep - character :: pathSep - character(len=1024) :: tempString - - pathSep = getPathSep() - - tempString = geometryFile - posExt = scan(tempString,'.',back=.true.) - posSep = scan(tempString,pathSep,back=.true.) - - getSolverJobName = tempString(posSep+1:posExt-1) - - tempString = loadCaseFile - posExt = scan(tempString,'.',back=.true.) - posSep = scan(tempString,pathSep,back=.true.) - - getSolverJobName = trim(getSolverJobName)//'_'//tempString(posSep+1:posExt-1) - -end function getSolverJobName - - -!-------------------------------------------------------------------------------------------------- -!> @brief basename of geometry file with extension from command line arguments -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getGeometryFile(geometryParameter) -#ifdef __INTEL_COMPILER - use IFPORT -#endif - - implicit none - character(len=1024), intent(in) :: & - geometryParameter - character(len=1024) :: & - cwd - integer :: posExt, posSep - character :: pathSep - integer :: error - - getGeometryFile = geometryParameter - pathSep = getPathSep() - posExt = scan(getGeometryFile,'.',back=.true.) - posSep = scan(getGeometryFile,pathSep,back=.true.) - - if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') ! no extension present - if (scan(getGeometryFile,pathSep) /= 1) then ! relative path given as command line argument - error = getcwd(cwd) - getGeometryFile = rectifyPath(trim(cwd)//pathSep//getGeometryFile) - else - getGeometryFile = rectifyPath(getGeometryFile) - endif - - getGeometryFile = makeRelativePath(getSolverWorkingDirectoryName(), getGeometryFile) - -end function getGeometryFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief relative path of loadcase from command line arguments -!-------------------------------------------------------------------------------------------------- -character(len=1024) function getLoadCaseFile(loadCaseParameter) -#ifdef __INTEL_COMPILER - use IFPORT -#endif - - implicit none - character(len=1024), intent(in) :: & - loadCaseParameter - character(len=1024) :: & - cwd - integer :: posExt, posSep, error - character :: pathSep - - getLoadCaseFile = loadcaseParameter - pathSep = getPathSep() - posExt = scan(getLoadCaseFile,'.',back=.true.) - posSep = scan(getLoadCaseFile,pathSep,back=.true.) - - if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') ! no extension present - if (scan(getLoadCaseFile,pathSep) /= 1) then ! relative path given as command line argument - error = getcwd(cwd) - getLoadCaseFile = rectifyPath(trim(cwd)//pathSep//getLoadCaseFile) - else - getLoadCaseFile = rectifyPath(getLoadCaseFile) - endif - - getLoadCaseFile = makeRelativePath(getSolverWorkingDirectoryName(), getLoadCaseFile) - -end function getLoadCaseFile - - -!-------------------------------------------------------------------------------------------------- -!> @brief remove ../ and /./ from path -!-------------------------------------------------------------------------------------------------- -function rectifyPath(path) - - implicit none - character(len=*) :: path - character(len=len_trim(path)) :: rectifyPath - character :: pathSep - integer :: i,j,k,l ! no pInt - - pathSep = getPathSep() - -!-------------------------------------------------------------------------------------------------- -! remove /./ from path - l = len_trim(path) - rectifyPath = path - do i = l,3,-1 - if (rectifyPath(i-2:i) == pathSep//'.'//pathSep) & - rectifyPath(i-1:l) = rectifyPath(i+1:l)//' ' - enddo - -!-------------------------------------------------------------------------------------------------- -! remove ../ and corresponding directory from rectifyPath - l = len_trim(rectifyPath) - i = index(rectifyPath(i:l),'..'//pathSep) - j = 0 - do while (i > j) - j = scan(rectifyPath(1:i-2),pathSep,back=.true.) - rectifyPath(j+1:l) = rectifyPath(i+3:l)//repeat(' ',2+i-j) - if (rectifyPath(j+1:j+1) == pathSep) then !search for '//' that appear in case of XXX/../../XXX - k = len_trim(rectifyPath) - rectifyPath(j+1:k-1) = rectifyPath(j+2:k) - rectifyPath(k:k) = ' ' - endif - i = j+index(rectifyPath(j+1:l),'..'//pathSep) - enddo - if(len_trim(rectifyPath) == 0) rectifyPath = pathSep - -end function rectifyPath - - -!-------------------------------------------------------------------------------------------------- -!> @brief relative path from absolute a to absolute b -!-------------------------------------------------------------------------------------------------- -character(len=1024) function makeRelativePath(a,b) - - implicit none - character (len=*) :: a,b - character :: pathSep - integer :: i,posLastCommonSlash,remainingSlashes !no pInt - - pathSep = getPathSep() - posLastCommonSlash = 0 - remainingSlashes = 0 - - do i = 1, min(1024,len_trim(a),len_trim(b)) - if (a(i:i) /= b(i:i)) exit - if (a(i:i) == pathSep) posLastCommonSlash = i - enddo - do i = posLastCommonSlash+1,len_trim(a) - if (a(i:i) == pathSep) remainingSlashes = remainingSlashes + 1 - enddo - makeRelativePath = repeat('..'//pathSep,remainingSlashes)//b(posLastCommonSlash+1:len_trim(b)) - -end function makeRelativePath - - -!-------------------------------------------------------------------------------------------------- -!> @brief counting / and \ in $PATH System variable the character occuring more often is assumed -! to be the path separator -!-------------------------------------------------------------------------------------------------- -character function getPathSep() - - implicit none - character(len=2048) :: & - path - integer(pInt) :: & - backslash = 0_pInt, & - slash = 0_pInt - integer :: i - - call get_environment_variable('PATH',path) - do i=1, len(trim(path)) - if (path(i:i)=='/') slash = slash + 1_pInt - if (path(i:i)=='\') backslash = backslash + 1_pInt - enddo - - if (backslash>slash) then - getPathSep = '\' - else - getPathSep = '/' - endif - -end function getPathSep - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_stringValue for documentation -!-------------------------------------------------------------------------------------------------- -pure function IIO_stringValue(string,chunkPos,myChunk) - - implicit none - integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string - integer(pInt), intent(in) :: myChunk !< position number of desired chunk - character(len=1+chunkPos(myChunk*2+1)-chunkPos(myChunk*2)) :: IIO_stringValue - character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - - - valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then - IIO_stringValue = '' - else valuePresent - IIO_stringValue = string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) - endif valuePresent - -end function IIO_stringValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_intValue for documentation -!-------------------------------------------------------------------------------------------------- -integer(pInt) pure function IIO_intValue(string,chunkPos,myChunk) - - implicit none - character(len=*), intent(in) :: string !< raw input with known start and end of each chunk - integer(pInt), intent(in) :: myChunk !< position number of desired sub string - integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string - - - valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then - IIO_intValue = 0_pInt - else valuePresent - read(UNIT=string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)),ERR=100,FMT=*) IIO_intValue - endif valuePresent - return -100 IIO_intValue = huge(1_pInt) - -end function IIO_intValue - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_lc for documentation -!-------------------------------------------------------------------------------------------------- -pure function IIO_lc(string) - - implicit none - character(len=*), intent(in) :: string !< string to convert - character(len=len(string)) :: IIO_lc - - character(26), parameter :: LOWER = 'abcdefghijklmnopqrstuvwxyz' - character(26), parameter :: UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - - integer :: i,n ! no pInt (len returns default integer) - - IIO_lc = string - do i=1,len(string) - n = index(UPPER,IIO_lc(i:i)) - if (n/=0) IIO_lc(i:i) = LOWER(n:n) - enddo - -end function IIO_lc - - -!-------------------------------------------------------------------------------------------------- -!> @brief taken from IO, check IO_stringPos for documentation -!-------------------------------------------------------------------------------------------------- -pure function IIO_stringPos(string) - - implicit none - integer(pInt), dimension(:), allocatable :: IIO_stringPos - character(len=*), intent(in) :: string !< string in which chunks are searched for - - character(len=*), parameter :: SEP=achar(44)//achar(32)//achar(9)//achar(10)//achar(13) ! comma and whitespaces - integer :: left, right ! no pInt (verify and scan return default integer) - - allocate(IIO_stringPos(1), source=0_pInt) - right = 0 - - do while (verify(string(right+1:),SEP)>0) - left = right + verify(string(right+1:),SEP) - right = left + scan(string(left:),SEP) - 2 - if ( string(left:left) == '#' ) exit - IIO_stringPos = [IIO_stringPos,int(left, pInt), int(right, pInt)] - IIO_stringPos(1) = IIO_stringPos(1)+1_pInt - enddo - -end function IIO_stringPos - - -end module diff --git a/code/spectral_mech_AL.f90 b/code/spectral_mech_AL.f90 deleted file mode 100644 index a937dcc86..000000000 --- a/code/spectral_mech_AL.f90 +++ /dev/null @@ -1,715 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief AL scheme solver -!-------------------------------------------------------------------------------------------------- -module spectral_mech_AL - use prec, only: & - pInt, & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - - implicit none - private -#include - - character (len=*), parameter, public :: & - DAMASK_spectral_solverAL_label = 'al' - -!-------------------------------------------------------------------------------------------------- -! derived types - type(tSolutionParams), private :: params - real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! PETSc data - DM, private :: da - SNES, private :: snes - Vec, private :: solution_vec - -!-------------------------------------------------------------------------------------------------- -! common pointwise data - real(pReal), private, dimension(:,:,:,:,:), allocatable :: & - F_lastInc, & !< field of previous compatible deformation gradients - F_lambda_lastInc, & !< field of previous incompatible deformation gradient - Fdot, & !< field of assumed rate of compatible deformation gradient - F_lambdaDot !< field of assumed rate of incopatible deformation gradient - -!-------------------------------------------------------------------------------------------------- -! stress, stiffness and compliance average etc. - real(pReal), private, dimension(3,3) :: & - F_aimDot, & !< assumed rate of average deformation gradient - F_aim = math_I3, & !< current prescribed deformation gradient - F_aim_lastInc = math_I3, & !< previous average deformation gradient - F_av = 0.0_pReal, & !< average incompatible def grad field - P_av = 0.0_pReal, & !< average 1st Piola--Kirchhoff stress - P_avLastEval = 0.0_pReal !< average 1st Piola--Kirchhoff stress last call of CPFEM_general - character(len=1024), private :: incInfo !< time and increment information - real(pReal), private, dimension(3,3,3,3) :: & - C_volAvg = 0.0_pReal, & !< current volume average stiffness - C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness - C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness - S = 0.0_pReal, & !< current compliance (filled up with zeros) - C_scale = 0.0_pReal, & - S_scale = 0.0_pReal - - real(pReal), private :: & - err_BC, & !< deviation from stress BC - err_curl, & !< RMS of curl of F - err_div !< RMS of div of P - logical, private :: ForwardData - integer(pInt), private :: & - totalIter = 0_pInt !< total iteration in current increment - - public :: & - AL_init, & - AL_solution, & - AL_forward, & - AL_destroy - external :: & - VecDestroy, & - DMDestroy, & - DMDACreate3D, & - DMCreateGlobalVector, & - DMDASNESSetFunctionLocal, & - PETScFinalize, & - SNESDestroy, & - SNESGetNumberFunctionEvals, & - SNESGetIterationNumber, & - SNESSolve, & - SNESSetDM, & - SNESGetConvergedReason, & - SNESSetConvergenceTest, & - SNESSetFromOptions, & - SNESCreate, & - MPI_Abort, & - MPI_Bcast, & - MPI_Allreduce - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields and fills them with data, potentially from restart info -!> @todo use sourced allocation, e.g. allocate(Fdot,source = F_lastInc) -!-------------------------------------------------------------------------------------------------- -subroutine AL_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_intOut, & - IO_read_realFile, & - IO_timeStamp - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRestart - use FEsolving, only: & - restartInc - use numerics, only: & - worldrank, & - worldsize - use DAMASK_interface, only: & - getSolverJobName - use spectral_utilities, only: & - Utilities_constitutiveResponse, & - Utilities_updateGamma, & - Utilities_updateIPcoords - use mesh, only: & - grid, & - grid3 - use math, only: & - math_invSym3333 - - implicit none - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal - - PetscErrorCode :: ierr - PetscObject :: dummy - PetscScalar, pointer, dimension(:,:,:,:) :: xx_psc, F, F_lambda - integer(pInt), dimension(:), allocatable :: localK - integer(pInt) :: proc - character(len=1024) :: rankStr - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverAL init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif - -!-------------------------------------------------------------------------------------------------- -! 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_lambda_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - allocate (F_lambdaDot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - -!-------------------------------------------------------------------------------------------------- -! PETSc Init - call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do proc = 1, worldsize - call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary - DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & ! global grid - 1 , 1, worldsize, & - 18, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) - grid(1),grid(2),localK, & ! local grid - da,ierr) ! handle, error - CHKERRQ(ierr) - call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) - call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) - call DMDASNESSetFunctionLocal(da,INSERT_VALUES,AL_formResidual,dummy,ierr) - CHKERRQ(ierr) - call SNESSetConvergenceTest(snes,AL_converged,dummy,PETSC_NULL_FUNCTION,ierr) - CHKERRQ(ierr) - call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) - -!-------------------------------------------------------------------------------------------------- -! init fields - call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! places pointer xx_psc on PETSc data - F => xx_psc(0:8,:,:,:) - F_lambda => xx_psc(9:17,:,:,:) - restart: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading values of increment ', restartInc - 1_pInt, ' from file' - flush(6) - write(rankStr,'(a1,i0)')'_',worldrank - call IO_read_realFile(777,'F'//trim(rankStr), trim(getSolverJobName()),size(F)) - read (777,rec=1) F - close (777) - call IO_read_realFile(777,'F_lastInc'//trim(rankStr), trim(getSolverJobName()),size(F_lastInc)) - read (777,rec=1) F_lastInc - close (777) - call IO_read_realFile(777,'F_lambda'//trim(rankStr),trim(getSolverJobName()),size(F_lambda)) - read (777,rec=1) F_lambda - close (777) - call IO_read_realFile(777,'F_lambda_lastInc'//trim(rankStr),& - trim(getSolverJobName()),size(F_lambda_lastInc)) - read (777,rec=1) F_lambda_lastInc - close (777) - call IO_read_realFile(777,'F_aim', trim(getSolverJobName()),size(F_aim)) - read (777,rec=1) F_aim - close (777) - call IO_read_realFile(777,'F_aim_lastInc', trim(getSolverJobName()),size(F_aim_lastInc)) - read (777,rec=1) F_aim_lastInc - close (777) - call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) - read (777,rec=1) f_aimDot - close (777) - elseif (restartInc == 1_pInt) then restart - F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity - F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) - F_lambda = F - F_lambda_lastInc = F_lastInc - endif restart - - - call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) - call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & - 0.0_pReal,P,C_volAvg,C_minMaxAvg,temp33_Real,.false.,math_I3) - nullify(F) - nullify(F_lambda) - call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! write data back to PETSc - - readRestart: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading more values of increment', restartInc - 1_pInt, 'from file' - flush(6) - call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) - read (777,rec=1) C_volAvg - close (777) - call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) - read (777,rec=1) C_volAvgLastInc - close (777) - call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) - read (777,rec=1) C_minMaxAvg - close (777) - endif readRestart - - call Utilities_updateGamma(C_minMaxAvg,.True.) - C_scale = C_minMaxAvg - S_scale = math_invSym3333(C_minMaxAvg) - -end subroutine AL_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief solution for the AL scheme with internal iterations -!-------------------------------------------------------------------------------------------------- -type(tSolutionState) function & - AL_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) - use IO, only: & - IO_error - use numerics, only: & - update_gamma - use math, only: & - math_invSym3333 - use spectral_utilities, only: & - tBoundaryCondition, & - Utilities_maskedCompliance, & - Utilities_updateGamma - use FEsolving, only: & - restartWrite, & - terminallyIll - - implicit none - -!-------------------------------------------------------------------------------------------------- -! input data for solution - real(pReal), intent(in) :: & - timeinc, & !< increment in time for current solution - timeinc_old, & !< increment in time of last increment - loadCaseTime !< remaining time of current load case - logical, intent(in) :: & - guess - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - character(len=*), intent(in) :: & - incInfoIn - real(pReal), dimension(3,3), intent(in) :: rotation_BC - -!-------------------------------------------------------------------------------------------------- -! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - - incInfo = incInfoIn - -!-------------------------------------------------------------------------------------------------- -! update stiffness (and gamma operator) - S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) - if (update_gamma) then - call Utilities_updateGamma(C_minMaxAvg,restartWrite) - C_scale = C_minMaxAvg - S_scale = math_invSym3333(C_minMaxAvg) - endif - -!-------------------------------------------------------------------------------------------------- -! set module wide availabe data - mask_stress = P_BC%maskFloat - params%P_BC = P_BC%values - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old - -!-------------------------------------------------------------------------------------------------- -! solve BVP - call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) - CHKERRQ(ierr) - -!-------------------------------------------------------------------------------------------------- -! check convergence - call SNESGetConvergedReason(snes,reason,ierr) - CHKERRQ(ierr) - AL_solution%termIll = terminallyIll - terminallyIll = .false. - if (reason == -4) call IO_error(893_pInt) - if (reason < 1) AL_solution%converged = .false. - AL_solution%iterationsNeeded = totalIter - -end function AL_solution - - -!-------------------------------------------------------------------------------------------------- -!> @brief forms the AL residual vector -!-------------------------------------------------------------------------------------------------- -subroutine AL_formResidual(in,x_scal,f_scal,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - polarAlpha, & - polarBeta, & - worldrank - use mesh, only: & - grid3, & - grid - use IO, only: & - IO_intOut - use math, only: & - math_rotate_backward33, & - math_transpose33, & - math_mul3333xx33, & - math_invSym3333, & - math_mul33x33 - use spectral_utilities, only: & - wgt, & - tensorField_real, & - utilities_FFTtensorForward, & - utilities_fourierGammaConvolution, & - utilities_FFTtensorBackward, & - Utilities_constitutiveResponse, & - Utilities_divergenceRMS, & - Utilities_curlRMS - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRotation - use homogenization, only: & - materialpoint_dPdF - use FEsolving, only: & - terminallyIll - - implicit none -!-------------------------------------------------------------------------------------------------- -! strange syntax in the next line because otherwise macros expand beyond 132 character limit - DMDALocalInfo, dimension(& - DMDA_LOCAL_INFO_SIZE) :: & - in - PetscScalar, target, dimension(3,3,2, & - XG_RANGE,YG_RANGE,ZG_RANGE) :: & - x_scal - PetscScalar, target, dimension(3,3,2, & - X_RANGE,Y_RANGE,Z_RANGE) :: & - f_scal - PetscScalar, pointer, dimension(:,:,:,:,:) :: & - F, & - F_lambda, & - residual_F, & - residual_F_lambda - PetscInt :: & - PETScIter, & - nfuncs - PetscObject :: dummy - PetscErrorCode :: ierr - integer(pInt) :: & - i, j, k, e - - F => x_scal(1:3,1:3,1,& - XG_RANGE,YG_RANGE,ZG_RANGE) - F_lambda => x_scal(1:3,1:3,2,& - XG_RANGE,YG_RANGE,ZG_RANGE) - residual_F => f_scal(1:3,1:3,1,& - X_RANGE,Y_RANGE,Z_RANGE) - residual_F_lambda => f_scal(1:3,1:3,2,& - X_RANGE,Y_RANGE,Z_RANGE) - - call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) - call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) - - F_av = sum(sum(sum(F,dim=5),dim=4),dim=3) * wgt - call MPI_Allreduce(MPI_IN_PLACE,F_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - - if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment - newIteration: if(totalIter <= PETScIter) then -!-------------------------------------------------------------------------------------------------- -! report begin of new iteration - totalIter = totalIter + 1_pInt - if (worldrank == 0_pInt) then - write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & - ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax - if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & - math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & - math_transpose33(F_aim) - flush(6) - endif - endif newIteration - -!-------------------------------------------------------------------------------------------------- -! - tensorField_real = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) - tensorField_real(1:3,1:3,i,j,k) = & - polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& - polarAlpha*math_mul33x33(F(1:3,1:3,i,j,k), & - math_mul3333xx33(C_scale,F_lambda(1:3,1:3,i,j,k) - math_I3)) - - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! doing convolution in Fourier space - call utilities_FFTtensorForward() - call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) - call utilities_FFTtensorBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - residual_F_lambda = polarBeta*F - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) - -!-------------------------------------------------------------------------------------------------- -! evaluate constitutive response - P_avLastEval = P_av - call Utilities_constitutiveResponse(F_lastInc,F - residual_F_lambda/polarBeta,params%timeinc, & - residual_F,C_volAvg,C_minMaxAvg,P_av,ForwardData,params%rotation_BC) - call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) - ForwardData = .False. - -!-------------------------------------------------------------------------------------------------- -! calculate divergence - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = residual_F - call utilities_FFTtensorForward() - err_div = Utilities_divergenceRMS() - call utilities_FFTtensorBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - e = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) - e = e + 1_pInt - residual_F(1:3,1:3,i,j,k) = math_mul3333xx33(math_invSym3333(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & - residual_F(1:3,1:3,i,j,k) - & - math_mul33x33(F(1:3,1:3,i,j,k), & - math_mul3333xx33(C_scale,F_lambda(1:3,1:3,i,j,k) - math_I3))) & - + residual_F_lambda(1:3,1:3,i,j,k) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! calculating curl - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F - call utilities_FFTtensorForward() - err_curl = Utilities_curlRMS() - call utilities_FFTtensorBackward() - -end subroutine AL_formResidual - - -!-------------------------------------------------------------------------------------------------- -!> @brief convergence check -!-------------------------------------------------------------------------------------------------- -subroutine AL_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - err_div_tolRel, & - err_div_tolAbs, & - err_curl_tolRel, & - err_curl_tolAbs, & - err_stress_tolAbs, & - err_stress_tolRel, & - worldrank - use math, only: & - math_mul3333xx33 - use FEsolving, only: & - terminallyIll - - implicit none - SNES :: snes_local - PetscInt :: PETScIter - PetscReal :: & - xnorm, & - snorm, & - fnorm - SNESConvergedReason :: reason - PetscObject :: dummy - PetscErrorCode ::ierr - real(pReal) :: & - curlTol, & - divTol, & - BC_tol - -!-------------------------------------------------------------------------------------------------- -! stress BC handling - F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc - err_BC = maxval(abs((-mask_stress+1.0_pReal)*math_mul3333xx33(C_scale,F_aim-F_av) + & - mask_stress *(P_av - params%P_BC))) ! mask = 0.0 for no bc - -!-------------------------------------------------------------------------------------------------- -! error calculation - curlTol = max(maxval(abs(F_aim-math_I3))*err_curl_tolRel,err_curl_tolAbs) - divTol = max(maxval(abs(P_av)) *err_div_tolRel,err_div_tolAbs) - BC_tol = max(maxval(abs(P_av)) *err_stress_tolrel,err_stress_tolabs) - - converged: if ((totalIter >= itmin .and. & - all([ err_div/divTol, & - err_curl/curlTol, & - err_BC/BC_tol ] < 1.0_pReal)) & - .or. terminallyIll) then - reason = 1 - elseif (totalIter >= itmax) then converged - reason = -1 - else converged - reason = 0 - endif converged - -!-------------------------------------------------------------------------------------------------- -! report - if (worldrank == 0_pInt) then - write(6,'(1/,a)') ' ... reporting .............................................................' - write(6,'(/,a,f12.2,a,es8.2,a,es9.2,a)') ' error curl = ', & - err_curl/curlTol,' (',err_curl,' -, tol =',curlTol,')' - write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & - err_div/divTol, ' (',err_div, ' / m, tol =',divTol,')' - write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error BC = ', & - err_BC/BC_tol, ' (',err_BC, ' Pa, tol =',BC_tol,')' - write(6,'(/,a)') ' ===========================================================================' - flush(6) - endif - -end subroutine AL_converged - -!-------------------------------------------------------------------------------------------------- -!> @brief forwarding routine -!-------------------------------------------------------------------------------------------------- -subroutine AL_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) - use math, only: & - math_mul33x33, & - math_mul3333xx33, & - math_transpose33, & - math_rotate_backward33 - use numerics, only: & - worldrank - use mesh, only: & - grid3, & - grid - use spectral_utilities, only: & - Utilities_calculateRate, & - Utilities_forwardField, & - Utilities_updateIPcoords, & - tBoundaryCondition, & - cutBack - use IO, only: & - IO_write_JobRealFile - use FEsolving, only: & - restartWrite - - implicit none - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - real(pReal), dimension(3,3), intent(in) :: rotation_BC - logical, intent(in) :: & - guess - PetscErrorCode :: ierr - PetscScalar, dimension(:,:,:,:), pointer :: xx_psc, F, F_lambda - integer(pInt) :: i, j, k - real(pReal), dimension(3,3) :: F_lambda33 - character(len=1024) :: rankStr - -!-------------------------------------------------------------------------------------------------- -! update coordinates and rate and forward last inc - call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr) - F => xx_psc(0:8,:,:,:) - F_lambda => xx_psc(9:17,:,:,:) - if (restartWrite) then - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' writing converged results for restart' - flush(6) - endif - write(rankStr,'(a1,i0)')'_',worldrank - call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file - write (777,rec=1) F - close (777) - call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file - write (777,rec=1) F_lastInc - close (777) - call IO_write_jobRealFile(777,'F_lambda'//trim(rankStr),size(F_lambda)) ! writing deformation gradient field to file - write (777,rec=1) F_lambda - close (777) - call IO_write_jobRealFile(777,'F_lambda_lastInc'//trim(rankStr),size(F_lambda_lastInc)) ! writing F_lastInc field to file - write (777,rec=1) F_lambda_lastInc - close (777) - if (worldrank == 0_pInt) then - call IO_write_jobRealFile(777,'F_aim',size(F_aim)) - write (777,rec=1) F_aim - close(777) - call IO_write_jobRealFile(777,'F_aim_lastInc',size(F_aim_lastInc)) - write (777,rec=1) F_aim_lastInc - close(777) - call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) - write (777,rec=1) F_aimDot - close(777) - call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) - write (777,rec=1) C_volAvg - close(777) - call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) - write (777,rec=1) C_volAvgLastInc - close(777) - endif - endif - - call utilities_updateIPcoords(F) - - if (cutBack) then - F_aim = F_aim_lastInc - F_lambda = reshape(F_lambda_lastInc,[9,grid(1),grid(2),grid3]) - F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) - C_volAvg = C_volAvgLastInc - else - ForwardData = .True. - C_volAvgLastInc = C_volAvg -!-------------------------------------------------------------------------------------------------- -! calculate rate for aim - if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F - f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) - elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed - f_aimDot = F_BC%maskFloat * F_BC%values - elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed - f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime - endif - if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old - F_aim_lastInc = F_aim - -!-------------------------------------------------------------------------------------------------- -! update coordinates and rate and forward last inc - call utilities_updateIPcoords(F) - Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & - timeinc_old,guess,F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3])) - F_lambdaDot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & - timeinc_old,guess,F_lambda_lastInc,reshape(F_lambda,[3,3,grid(1),grid(2),grid3])) - F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) - F_lambda_lastInc = reshape(F_lambda,[3,3,grid(1),grid(2),grid3]) - endif - - F_aim = F_aim + f_aimDot * timeinc - -!-------------------------------------------------------------------------------------------------- -! update local deformation gradient - F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim - math_rotate_backward33(F_aim,rotation_BC)), & - [9,grid(1),grid(2),grid3]) - F_lambda = reshape(Utilities_forwardField(timeinc,F_lambda_lastInc,F_lambdadot), & - [9,grid(1),grid(2),grid3]) ! does not have any average value as boundary condition - if (.not. guess) then ! large strain forwarding - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) - F_lambda33 = reshape(F_lambda(1:9,i,j,k),[3,3]) - F_lambda33 = math_mul3333xx33(S_scale,math_mul33x33(F_lambda33, & - math_mul3333xx33(C_scale,& - math_mul33x33(math_transpose33(F_lambda33),& - F_lambda33) -math_I3))*0.5_pReal)& - + math_I3 - F_lambda(1:9,i,j,k) = reshape(F_lambda33,[9]) - enddo; enddo; enddo - endif - call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) - -end subroutine AL_forward - -!-------------------------------------------------------------------------------------------------- -!> @brief destroy routine -!-------------------------------------------------------------------------------------------------- -subroutine AL_destroy() - use spectral_utilities, only: & - Utilities_destroy - - implicit none - PetscErrorCode :: ierr - - call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) - call SNESDestroy(snes,ierr); CHKERRQ(ierr) - call DMDestroy(da,ierr); CHKERRQ(ierr) - -end subroutine AL_destroy - -end module spectral_mech_AL diff --git a/code/spectral_mech_Basic.f90 b/code/spectral_mech_Basic.f90 deleted file mode 100644 index a8344fabe..000000000 --- a/code/spectral_mech_Basic.f90 +++ /dev/null @@ -1,569 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Basic scheme PETSc solver -!-------------------------------------------------------------------------------------------------- -module spectral_mech_basic - use prec, only: & - pInt, & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - - implicit none - private -#include - - character (len=*), parameter, public :: & - DAMASK_spectral_SolverBasicPETSC_label = 'basicpetsc' - -!-------------------------------------------------------------------------------------------------- -! derived types - type(tSolutionParams), private :: params - -!-------------------------------------------------------------------------------------------------- -! PETSc data - DM, private :: da - SNES, private :: snes - Vec, private :: solution_vec - -!-------------------------------------------------------------------------------------------------- -! common pointwise data - real(pReal), private, dimension(:,:,:,:,:), allocatable :: F_lastInc, Fdot - -!-------------------------------------------------------------------------------------------------- -! stress, stiffness and compliance average etc. - real(pReal), private, dimension(3,3) :: & - F_aim = math_I3, & - F_aim_lastIter = math_I3, & - F_aim_lastInc = math_I3, & - P_av = 0.0_pReal, & - F_aimDot=0.0_pReal - character(len=1024), private :: incInfo - real(pReal), private, dimension(3,3,3,3) :: & - C_volAvg = 0.0_pReal, & !< current volume average stiffness - C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness - C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness - S = 0.0_pReal !< current compliance (filled up with zeros) - real(pReal), private :: err_stress, err_div - logical, private :: ForwardData - integer(pInt), private :: & - totalIter = 0_pInt !< total iteration in current increment - real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal - - public :: & - basicPETSc_init, & - basicPETSc_solution, & - BasicPETSc_forward, & - basicPETSc_destroy - external :: & - VecDestroy, & - DMDestroy, & - DMDACreate3D, & - DMCreateGlobalVector, & - DMDASNESSetFunctionLocal, & - PETScFinalize, & - SNESDestroy, & - SNESGetNumberFunctionEvals, & - SNESGetIterationNumber, & - SNESSolve, & - SNESSetDM, & - SNESGetConvergedReason, & - SNESSetConvergenceTest, & - SNESSetFromOptions, & - SNESCreate, & - MPI_Abort, & - MPI_Bcast, & - MPI_Allreduce - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields and fills them with data, potentially from restart info -!-------------------------------------------------------------------------------------------------- -subroutine basicPETSc_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_intOut, & - IO_read_realFile, & - IO_timeStamp - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRestart - use FEsolving, only: & - restartInc - use numerics, only: & - worldrank, & - worldsize - use DAMASK_interface, only: & - getSolverJobName - use spectral_utilities, only: & - Utilities_constitutiveResponse, & - Utilities_updateGamma, & - utilities_updateIPcoords, & - wgt - use mesh, only: & - grid, & - grid3 - use math, only: & - math_invSym3333 - - implicit none - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P - PetscScalar, dimension(:,:,:,:), pointer :: F - PetscErrorCode :: ierr - PetscObject :: dummy - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal - integer(pInt), dimension(:), allocatable :: localK - integer(pInt) :: proc - character(len=1024) :: rankStr - - mainProcess: if (worldrank == 0_pInt) then - write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverBasicPETSc init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!-------------------------------------------------------------------------------------------------- -! 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) - -!-------------------------------------------------------------------------------------------------- -! initialize solver specific parts of PETSc - call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do proc = 1, worldsize - call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary - DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & ! global grid - 1, 1, worldsize, & - 9, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) - grid (1),grid (2),localK, & ! local grid - da,ierr) ! handle, error - CHKERRQ(ierr) - call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) - call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) ! global solution vector (grid x 9, i.e. every def grad tensor) - call DMDASNESSetFunctionLocal(da,INSERT_VALUES,BasicPETSC_formResidual,dummy,ierr) ! residual vector of same shape as solution vector - CHKERRQ(ierr) - call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) ! connect snes to da - call SNESSetConvergenceTest(snes,BasicPETSC_converged,dummy,PETSC_NULL_FUNCTION,ierr) ! specify custom convergence check function "_converged" - CHKERRQ(ierr) - call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments - -!-------------------------------------------------------------------------------------------------- -! init fields - call DMDAVecGetArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) ! get the data out of PETSc to work with - - restart: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading values of increment ', restartInc - 1_pInt, ' from file' - flush(6) - write(rankStr,'(a1,i0)')'_',worldrank - call IO_read_realFile(777,'F'//trim(rankStr),trim(getSolverJobName()),size(F)) - read (777,rec=1) F - close (777) - call IO_read_realFile(777,'F_lastInc'//trim(rankStr),trim(getSolverJobName()),size(F_lastInc)) - read (777,rec=1) F_lastInc - close (777) - call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) - read (777,rec=1) f_aimDot - close (777) - F_aim = reshape(sum(sum(sum(F,dim=4),dim=3),dim=2) * wgt, [3,3]) ! average of F - F_aim_lastInc = sum(sum(sum(F_lastInc,dim=5),dim=4),dim=3) * wgt ! average of F_lastInc - elseif (restartInc == 1_pInt) then restart - F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity - F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) - endif restart - - call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) - call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & - 0.0_pReal, & - P, & - C_volAvg,C_minMaxAvg, & ! global average of stiffness and (min+max)/2 - temp33_Real, & - .false., & - math_I3) - - call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) ! write data back to PETSc - - restartRead: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading more values of increment', restartInc - 1_pInt, 'from file' - flush(6) - call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) - read (777,rec=1) C_volAvg - close (777) - call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) - read (777,rec=1) C_volAvgLastInc - close (777) - call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) - read (777,rec=1) C_minMaxAvg - close (777) - endif restartRead - - call Utilities_updateGamma(C_minmaxAvg,.True.) - -end subroutine basicPETSc_init - -!-------------------------------------------------------------------------------------------------- -!> @brief solution for the Basic PETSC scheme with internal iterations -!-------------------------------------------------------------------------------------------------- -type(tSolutionState) function & - basicPETSc_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) - use IO, only: & - IO_error - use numerics, only: & - update_gamma - use spectral_utilities, only: & - tBoundaryCondition, & - Utilities_maskedCompliance, & - Utilities_updateGamma - use FEsolving, only: & - restartWrite, & - terminallyIll - - implicit none - -!-------------------------------------------------------------------------------------------------- -! input data for solution - real(pReal), intent(in) :: & - timeinc, & !< increment in time for current solution - timeinc_old, & !< increment in time of last increment - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - character(len=*), intent(in) :: & - incInfoIn - real(pReal), dimension(3,3), intent(in) :: rotation_BC - logical, intent(in) :: & - guess - -!-------------------------------------------------------------------------------------------------- -! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - incInfo = incInfoIn - -!-------------------------------------------------------------------------------------------------- -! update stiffness (and gamma operator) - S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) - if (update_gamma) call Utilities_updateGamma(C_minmaxAvg,restartWrite) - - -!-------------------------------------------------------------------------------------------------- -! set module wide availabe data - mask_stress = P_BC%maskFloat - params%P_BC = P_BC%values - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old - -!-------------------------------------------------------------------------------------------------- -! solve BVP - call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) - CHKERRQ(ierr) - -!-------------------------------------------------------------------------------------------------- -! check convergence - call SNESGetConvergedReason(snes,reason,ierr) - CHKERRQ(ierr) - basicPETSc_solution%termIll = terminallyIll - terminallyIll = .false. - BasicPETSc_solution%converged =.true. - if (reason == -4) call IO_error(893_pInt) - if (reason < 1) basicPETSC_solution%converged = .false. - basicPETSC_solution%iterationsNeeded = totalIter - -end function BasicPETSc_solution - - -!-------------------------------------------------------------------------------------------------- -!> @brief forms the AL residual vector -!-------------------------------------------------------------------------------------------------- -subroutine BasicPETSC_formResidual(in,x_scal,f_scal,dummy,ierr) - use numerics, only: & - itmax, & - itmin - use numerics, only: & - worldrank - use mesh, only: & - grid, & - grid3 - use math, only: & - math_rotate_backward33, & - math_transpose33, & - math_mul3333xx33 - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRotation - use spectral_utilities, only: & - tensorField_real, & - utilities_FFTtensorForward, & - utilities_FFTtensorBackward, & - utilities_fourierGammaConvolution, & - Utilities_constitutiveResponse, & - Utilities_divergenceRMS - use IO, only: & - IO_intOut - use FEsolving, only: & - terminallyIll - - implicit none - DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & - in - PetscScalar, dimension(3,3, & - XG_RANGE,YG_RANGE,ZG_RANGE) :: & - x_scal - PetscScalar, dimension(3,3, & - X_RANGE,Y_RANGE,Z_RANGE) :: & - f_scal - PetscInt :: & - PETScIter, & - nfuncs - PetscObject :: dummy - PetscErrorCode :: ierr - - call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) - call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) - - if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment - newIteration: if (totalIter <= PETScIter) then -!-------------------------------------------------------------------------------------------------- -! report begin of new iteration - totalIter = totalIter + 1_pInt - if (worldrank == 0_pInt) then - write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & - ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax - if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & - math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & - math_transpose33(F_aim) - flush(6) - endif - endif newIteration - -!-------------------------------------------------------------------------------------------------- -! evaluate constitutive response - call Utilities_constitutiveResponse(F_lastInc,x_scal,params%timeinc, & - f_scal,C_volAvg,C_minmaxAvg,P_av,ForwardData,params%rotation_BC) - call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) - ForwardData = .false. - -!-------------------------------------------------------------------------------------------------- -! stress BC handling - F_aim_lastIter = F_aim - F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc - err_stress = maxval(abs(mask_stress * (P_av - params%P_BC))) ! mask = 0.0 for no bc - -!-------------------------------------------------------------------------------------------------- -! updated deformation gradient using fix point algorithm of basic scheme - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = f_scal - call utilities_FFTtensorForward() - err_div = Utilities_divergenceRMS() - call utilities_fourierGammaConvolution(math_rotate_backward33(F_aim_lastIter-F_aim,params%rotation_BC)) - call utilities_FFTtensorBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - f_scal = tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) - -end subroutine BasicPETSc_formResidual - - -!-------------------------------------------------------------------------------------------------- -!> @brief convergence check -!-------------------------------------------------------------------------------------------------- -subroutine BasicPETSc_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - err_div_tolRel, & - err_div_tolAbs, & - err_stress_tolRel, & - err_stress_tolAbs, & - worldrank - use FEsolving, only: & - terminallyIll - - implicit none - SNES :: snes_local - PetscInt :: PETScIter - PetscReal :: & - xnorm, & - snorm, & - fnorm - SNESConvergedReason :: reason - PetscObject :: dummy - PetscErrorCode :: ierr - real(pReal) :: & - divTol, & - stressTol - - divTol = max(maxval(abs(P_av))*err_div_tolRel,err_div_tolAbs) - stressTol = max(maxval(abs(P_av))*err_stress_tolrel,err_stress_tolabs) - - converged: if ((totalIter >= itmin .and. & - all([ err_div/divTol, & - err_stress/stressTol ] < 1.0_pReal)) & - .or. terminallyIll) then - reason = 1 - elseif (totalIter >= itmax) then converged - reason = -1 - else converged - reason = 0 - endif converged - -!-------------------------------------------------------------------------------------------------- -! report - if (worldrank == 0_pInt) then - write(6,'(1/,a)') ' ... reporting .............................................................' - write(6,'(1/,a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & - err_div/divTol, ' (',err_div,' / m, tol =',divTol,')' - write(6,'(a,f12.2,a,es8.2,a,es9.2,a)') ' error stress BC = ', & - err_stress/stressTol, ' (',err_stress, ' Pa, tol =',stressTol,')' - write(6,'(/,a)') ' ===========================================================================' - flush(6) - endif - -end subroutine BasicPETSc_converged - -!-------------------------------------------------------------------------------------------------- -!> @brief forwarding routine -!-------------------------------------------------------------------------------------------------- -subroutine BasicPETSc_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) - use math, only: & - math_mul33x33 ,& - math_rotate_backward33 - use mesh, only: & - grid, & - grid3 - use spectral_utilities, only: & - Utilities_calculateRate, & - Utilities_forwardField, & - utilities_updateIPcoords, & - tBoundaryCondition, & - cutBack - use IO, only: & - IO_write_JobRealFile - use FEsolving, only: & - restartWrite - use numerics, only: & - worldrank - - implicit none - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - real(pReal), dimension(3,3), intent(in) :: rotation_BC - logical, intent(in) :: & - guess - PetscScalar, pointer :: F(:,:,:,:) - PetscErrorCode :: ierr - character(len=1024) :: rankStr - - call DMDAVecGetArrayF90(da,solution_vec,F,ierr) -!-------------------------------------------------------------------------------------------------- -! restart information for spectral solver - if (restartWrite) then - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' writing converged results for restart' - flush(6) - endif - write(rankStr,'(a1,i0)')'_',worldrank - call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file - write (777,rec=1) F - close (777) - call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file - write (777,rec=1) F_lastInc - close (777) - if (worldrank == 0_pInt) then - call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) - write (777,rec=1) F_aimDot - close(777) - call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) - write (777,rec=1) C_volAvg - close(777) - call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) - write (777,rec=1) C_volAvgLastInc - close(777) - endif - endif - - call utilities_updateIPcoords(F) - - if (cutBack) then - F_aim = F_aim_lastInc - F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) - C_volAvg = C_volAvgLastInc - else - ForwardData = .True. - C_volAvgLastInc = C_volAvg -!-------------------------------------------------------------------------------------------------- -! calculate rate for aim - if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F - f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) - elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed - f_aimDot = F_BC%maskFloat * F_BC%values - elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed - f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime - endif - if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old - F_aim_lastInc = F_aim - -!-------------------------------------------------------------------------------------------------- -! update coordinates and rate and forward last inc - call utilities_updateIPcoords(F) - Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & - timeinc_old,guess,F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3])) - F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) - endif - F_aim = F_aim + f_aimDot * timeinc - -!-------------------------------------------------------------------------------------------------- -! update local deformation gradient - F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim - math_rotate_backward33(F_aim,rotation_BC)),[9,grid(1),grid(2),grid3]) - call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) - -end subroutine BasicPETSc_forward - -!-------------------------------------------------------------------------------------------------- -!> @brief destroy routine -!-------------------------------------------------------------------------------------------------- -subroutine BasicPETSc_destroy() - use spectral_utilities, only: & - Utilities_destroy - - implicit none - PetscErrorCode :: ierr - - call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) - call SNESDestroy(snes,ierr); CHKERRQ(ierr) - call DMDestroy(da,ierr); CHKERRQ(ierr) - -end subroutine BasicPETSc_destroy - -end module spectral_mech_basic diff --git a/code/spectral_mech_Polarisation.f90 b/code/spectral_mech_Polarisation.f90 deleted file mode 100644 index a28eb5adb..000000000 --- a/code/spectral_mech_Polarisation.f90 +++ /dev/null @@ -1,712 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Polarisation scheme solver -!-------------------------------------------------------------------------------------------------- -module spectral_mech_Polarisation - use prec, only: & - pInt, & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - - implicit none - private -#include - - character (len=*), parameter, public :: & - DAMASK_spectral_solverPolarisation_label = 'polarisation' - -!-------------------------------------------------------------------------------------------------- -! derived types - type(tSolutionParams), private :: params - real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal - -!-------------------------------------------------------------------------------------------------- -! PETSc data - DM, private :: da - SNES, private :: snes - Vec, private :: solution_vec - -!-------------------------------------------------------------------------------------------------- -! common pointwise data - real(pReal), private, dimension(:,:,:,:,:), allocatable :: & - F_lastInc, & !< field of previous compatible deformation gradients - F_tau_lastInc, & !< field of previous incompatible deformation gradient - Fdot, & !< field of assumed rate of compatible deformation gradient - F_tauDot !< field of assumed rate of incopatible deformation gradient - -!-------------------------------------------------------------------------------------------------- -! stress, stiffness and compliance average etc. - real(pReal), private, dimension(3,3) :: & - F_aimDot, & !< assumed rate of average deformation gradient - F_aim = math_I3, & !< current prescribed deformation gradient - F_aim_lastInc = math_I3, & !< previous average deformation gradient - F_av = 0.0_pReal, & !< average incompatible def grad field - P_av = 0.0_pReal, & !< average 1st Piola--Kirchhoff stress - P_avLastEval = 0.0_pReal !< average 1st Piola--Kirchhoff stress last call of CPFEM_general - character(len=1024), private :: incInfo !< time and increment information - real(pReal), private, dimension(3,3,3,3) :: & - C_volAvg = 0.0_pReal, & !< current volume average stiffness - C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness - C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness - S = 0.0_pReal, & !< current compliance (filled up with zeros) - C_scale = 0.0_pReal, & - S_scale = 0.0_pReal - - real(pReal), private :: & - err_BC, & !< deviation from stress BC - err_curl, & !< RMS of curl of F - err_div !< RMS of div of P - logical, private :: ForwardData - integer(pInt), private :: & - totalIter = 0_pInt !< total iteration in current increment - - public :: & - Polarisation_init, & - Polarisation_solution, & - Polarisation_forward, & - Polarisation_destroy - external :: & - VecDestroy, & - DMDestroy, & - DMDACreate3D, & - DMCreateGlobalVector, & - DMDASNESSetFunctionLocal, & - PETScFinalize, & - SNESDestroy, & - SNESGetNumberFunctionEvals, & - SNESGetIterationNumber, & - SNESSolve, & - SNESSetDM, & - SNESGetConvergedReason, & - SNESSetConvergenceTest, & - SNESSetFromOptions, & - SNESCreate, & - MPI_Abort, & - MPI_Bcast, & - MPI_Allreduce - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields and fills them with data, potentially from restart info -!> @todo use sourced allocation, e.g. allocate(Fdot,source = F_lastInc) -!-------------------------------------------------------------------------------------------------- -subroutine Polarisation_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_intOut, & - IO_read_realFile, & - IO_timeStamp - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRestart - use FEsolving, only: & - restartInc - use numerics, only: & - worldrank, & - worldsize - use DAMASK_interface, only: & - getSolverJobName - use spectral_utilities, only: & - Utilities_constitutiveResponse, & - Utilities_updateGamma, & - Utilities_updateIPcoords - use mesh, only: & - grid, & - grid3 - use math, only: & - math_invSym3333 - - implicit none - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal - - PetscErrorCode :: ierr - PetscObject :: dummy - PetscScalar, pointer, dimension(:,:,:,:) :: xx_psc, F, F_tau - integer(pInt), dimension(:), allocatable :: localK - integer(pInt) :: proc - character(len=1024) :: rankStr - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverPolarisation init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif - -!-------------------------------------------------------------------------------------------------- -! 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_tau_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - allocate (F_tauDot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - -!-------------------------------------------------------------------------------------------------- -! PETSc Init - call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do proc = 1, worldsize - call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary - DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & ! global grid - 1 , 1, worldsize, & - 18, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) - grid (1),grid (2),localK, & ! local grid - da,ierr) ! handle, error - CHKERRQ(ierr) - call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) - call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) - call DMDASNESSetFunctionLocal(da,INSERT_VALUES,Polarisation_formResidual,dummy,ierr) - CHKERRQ(ierr) - call SNESSetConvergenceTest(snes,Polarisation_converged,dummy,PETSC_NULL_FUNCTION,ierr) - CHKERRQ(ierr) - call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) - -!-------------------------------------------------------------------------------------------------- -! init fields - call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! places pointer xx_psc on PETSc data - F => xx_psc(0:8,:,:,:) - F_tau => xx_psc(9:17,:,:,:) - restart: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading values of increment', restartInc - 1_pInt, 'from file' - flush(6) - write(rankStr,'(a1,i0)')'_',worldrank - call IO_read_realFile(777,'F'//trim(rankStr),trim(getSolverJobName()),size(F)) - read (777,rec=1) F - close (777) - call IO_read_realFile(777,'F_lastInc'//trim(rankStr),trim(getSolverJobName()),size(F_lastInc)) - read (777,rec=1) F_lastInc - close (777) - call IO_read_realFile(777,'F_tau'//trim(rankStr),trim(getSolverJobName()),size(F_tau)) - read (777,rec=1) F_tau - close (777) - call IO_read_realFile(777,'F_tau_lastInc'//trim(rankStr),& - trim(getSolverJobName()),size(F_tau_lastInc)) - read (777,rec=1) F_tau_lastInc - close (777) - call IO_read_realFile(777,'F_aim', trim(getSolverJobName()),size(F_aim)) - read (777,rec=1) F_aim - close (777) - call IO_read_realFile(777,'F_aim_lastInc', trim(getSolverJobName()),size(F_aim_lastInc)) - read (777,rec=1) F_aim_lastInc - close (777) - call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) - read (777,rec=1) f_aimDot - close (777) - elseif (restartInc == 1_pInt) then restart - F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity - F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) - F_tau = 2.0_pReal* F - F_tau_lastInc = 2.0_pReal*F_lastInc - endif restart - - call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) - call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & - 0.0_pReal,P,C_volAvg,C_minMaxAvg,temp33_Real,.false.,math_I3) - nullify(F) - nullify(F_tau) - call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! write data back to PETSc - - readRestart: if (restartInc > 1_pInt) then - if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & - write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & - 'reading more values of increment', restartInc - 1_pInt, 'from file' - flush(6) - call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) - read (777,rec=1) C_volAvg - close (777) - call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) - read (777,rec=1) C_volAvgLastInc - close (777) - call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) - read (777,rec=1) C_minMaxAvg - close (777) - endif readRestart - - call Utilities_updateGamma(C_minMaxAvg,.True.) - C_scale = C_minMaxAvg - S_scale = math_invSym3333(C_minMaxAvg) - -end subroutine Polarisation_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief solution for the Polarisation scheme with internal iterations -!-------------------------------------------------------------------------------------------------- -type(tSolutionState) function & - Polarisation_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) - use IO, only: & - IO_error - use numerics, only: & - update_gamma - use math, only: & - math_invSym3333 - use spectral_utilities, only: & - tBoundaryCondition, & - Utilities_maskedCompliance, & - Utilities_updateGamma - use FEsolving, only: & - restartWrite, & - terminallyIll - - implicit none - -!-------------------------------------------------------------------------------------------------- -! input data for solution - real(pReal), intent(in) :: & - timeinc, & !< increment in time for current solution - timeinc_old, & !< increment in time of last increment - loadCaseTime !< remaining time of current load case - logical, intent(in) :: & - guess - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - character(len=*), intent(in) :: & - incInfoIn - real(pReal), dimension(3,3), intent(in) :: rotation_BC - -!-------------------------------------------------------------------------------------------------- -! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - - incInfo = incInfoIn - -!-------------------------------------------------------------------------------------------------- -! update stiffness (and gamma operator) - S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) - if (update_gamma) then - call Utilities_updateGamma(C_minMaxAvg,restartWrite) - C_scale = C_minMaxAvg - S_scale = math_invSym3333(C_minMaxAvg) - endif - -!-------------------------------------------------------------------------------------------------- -! set module wide availabe data - mask_stress = P_BC%maskFloat - params%P_BC = P_BC%values - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old - -!-------------------------------------------------------------------------------------------------- -! solve BVP - call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) - CHKERRQ(ierr) - -!-------------------------------------------------------------------------------------------------- -! check convergence - call SNESGetConvergedReason(snes,reason,ierr) - CHKERRQ(ierr) - Polarisation_solution%termIll = terminallyIll - terminallyIll = .false. - if (reason == -4) call IO_error(893_pInt) - if (reason < 1) Polarisation_solution%converged = .false. - Polarisation_solution%iterationsNeeded = totalIter - -end function Polarisation_solution - - -!-------------------------------------------------------------------------------------------------- -!> @brief forms the Polarisation residual vector -!-------------------------------------------------------------------------------------------------- -subroutine Polarisation_formResidual(in,x_scal,f_scal,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - polarAlpha, & - polarBeta, & - worldrank - use mesh, only: & - grid3, & - grid - use IO, only: & - IO_intOut - use math, only: & - math_rotate_backward33, & - math_transpose33, & - math_mul3333xx33, & - math_invSym3333, & - math_mul33x33 - use spectral_utilities, only: & - wgt, & - tensorField_real, & - utilities_FFTtensorForward, & - utilities_fourierGammaConvolution, & - utilities_FFTtensorBackward, & - Utilities_constitutiveResponse, & - Utilities_divergenceRMS, & - Utilities_curlRMS - use debug, only: & - debug_level, & - debug_spectral, & - debug_spectralRotation - use homogenization, only: & - materialpoint_dPdF - use FEsolving, only: & - terminallyIll - - implicit none -!-------------------------------------------------------------------------------------------------- -! strange syntax in the next line because otherwise macros expand beyond 132 character limit - DMDALocalInfo, dimension(& - DMDA_LOCAL_INFO_SIZE) :: & - in - PetscScalar, target, dimension(3,3,2, & - XG_RANGE,YG_RANGE,ZG_RANGE) :: & - x_scal - PetscScalar, target, dimension(3,3,2, & - X_RANGE,Y_RANGE,Z_RANGE) :: & - f_scal - PetscScalar, pointer, dimension(:,:,:,:,:) :: & - F, & - F_tau, & - residual_F, & - residual_F_tau - PetscInt :: & - PETScIter, & - nfuncs - PetscObject :: dummy - PetscErrorCode :: ierr - integer(pInt) :: & - i, j, k, e - - F => x_scal(1:3,1:3,1,& - XG_RANGE,YG_RANGE,ZG_RANGE) - F_tau => x_scal(1:3,1:3,2,& - XG_RANGE,YG_RANGE,ZG_RANGE) - residual_F => f_scal(1:3,1:3,1,& - X_RANGE,Y_RANGE,Z_RANGE) - residual_F_tau => f_scal(1:3,1:3,2,& - X_RANGE,Y_RANGE,Z_RANGE) - - call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) - call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) - - F_av = sum(sum(sum(F,dim=5),dim=4),dim=3) * wgt - call MPI_Allreduce(MPI_IN_PLACE,F_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - - if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment - newIteration: if(totalIter <= PETScIter) then -!-------------------------------------------------------------------------------------------------- -! report begin of new iteration - totalIter = totalIter + 1_pInt - if (worldrank == 0_pInt) then - write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & - ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax - if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & - math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) - write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & - math_transpose33(F_aim) - flush(6) - endif - endif newIteration - -!-------------------------------------------------------------------------------------------------- -! - tensorField_real = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) - tensorField_real(1:3,1:3,i,j,k) = & - polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& - polarAlpha*math_mul33x33(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)) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! doing convolution in Fourier space - call utilities_FFTtensorForward() - call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) - call utilities_FFTtensorBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - residual_F_tau = polarBeta*F - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) - -!-------------------------------------------------------------------------------------------------- -! evaluate constitutive response - P_avLastEval = P_av - call Utilities_constitutiveResponse(F_lastInc,F - residual_F_tau/polarBeta,params%timeinc, & - residual_F,C_volAvg,C_minMaxAvg,P_av,ForwardData,params%rotation_BC) - call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) - ForwardData = .False. - -!-------------------------------------------------------------------------------------------------- -! calculate divergence - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = residual_F - call utilities_FFTtensorForward() - err_div = Utilities_divergenceRMS() - call utilities_FFTtensorBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - e = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) - e = e + 1_pInt - residual_F(1:3,1:3,i,j,k) = & - math_mul3333xx33(math_invSym3333(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & - residual_F(1:3,1:3,i,j,k) - math_mul33x33(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) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! calculating curl - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F - call utilities_FFTtensorForward() - err_curl = Utilities_curlRMS() - call utilities_FFTtensorBackward() - -end subroutine Polarisation_formResidual - - -!-------------------------------------------------------------------------------------------------- -!> @brief convergence check -!-------------------------------------------------------------------------------------------------- -subroutine Polarisation_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) - use numerics, only: & - itmax, & - itmin, & - err_div_tolRel, & - err_div_tolAbs, & - err_curl_tolRel, & - err_curl_tolAbs, & - err_stress_tolAbs, & - err_stress_tolRel, & - worldrank - use math, only: & - math_mul3333xx33 - use FEsolving, only: & - terminallyIll - - implicit none - SNES :: snes_local - PetscInt :: PETScIter - PetscReal :: & - xnorm, & - snorm, & - fnorm - SNESConvergedReason :: reason - PetscObject :: dummy - PetscErrorCode ::ierr - real(pReal) :: & - curlTol, & - divTol, & - BC_tol - -!-------------------------------------------------------------------------------------------------- -! stress BC handling - F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc - err_BC = maxval(abs((-mask_stress+1.0_pReal)*math_mul3333xx33(C_scale,F_aim-F_av) + & - mask_stress *(P_av - params%P_BC))) ! mask = 0.0 for no bc - -!-------------------------------------------------------------------------------------------------- -! error calculation - curlTol = max(maxval(abs(F_aim-math_I3))*err_curl_tolRel,err_curl_tolAbs) - divTol = max(maxval(abs(P_av)) *err_div_tolRel,err_div_tolAbs) - BC_tol = max(maxval(abs(P_av)) *err_stress_tolrel,err_stress_tolabs) - - converged: if ((totalIter >= itmin .and. & - all([ err_div/divTol, & - err_curl/curlTol, & - err_BC/BC_tol ] < 1.0_pReal)) & - .or. terminallyIll) then - reason = 1 - elseif (totalIter >= itmax) then converged - reason = -1 - else converged - reason = 0 - endif converged - -!-------------------------------------------------------------------------------------------------- -! report -if (worldrank == 0_pInt) then - write(6,'(1/,a)') ' ... reporting .............................................................' - write(6,'(/,a,f12.2,a,es8.2,a,es9.2,a)') ' error curl = ', & - err_curl/curlTol,' (',err_curl,' -, tol =',curlTol,')' - write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & - err_div/divTol, ' (',err_div, ' / m, tol =',divTol,')' - write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error BC = ', & - err_BC/BC_tol, ' (',err_BC, ' Pa, tol =',BC_tol,')' - write(6,'(/,a)') ' ===========================================================================' - flush(6) -endif - -end subroutine Polarisation_converged - -!-------------------------------------------------------------------------------------------------- -!> @brief forwarding routine -!-------------------------------------------------------------------------------------------------- -subroutine Polarisation_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) - use math, only: & - math_mul33x33, & - math_mul3333xx33, & - math_transpose33, & - math_rotate_backward33 - use numerics, only: & - worldrank - use mesh, only: & - grid3, & - grid - use spectral_utilities, only: & - Utilities_calculateRate, & - Utilities_forwardField, & - Utilities_updateIPcoords, & - tBoundaryCondition, & - cutBack - use IO, only: & - IO_write_JobRealFile - use FEsolving, only: & - restartWrite - - implicit none - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & - P_BC, & - F_BC - real(pReal), dimension(3,3), intent(in) :: rotation_BC - logical, intent(in) :: & - guess - PetscErrorCode :: ierr - PetscScalar, dimension(:,:,:,:), pointer :: xx_psc, F, F_tau - integer(pInt) :: i, j, k - real(pReal), dimension(3,3) :: F_lambda33 - character(len=1024) :: rankStr - -!-------------------------------------------------------------------------------------------------- -! update coordinates and rate and forward last inc - call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr) - F => xx_psc(0:8,:,:,:) - F_tau => xx_psc(9:17,:,:,:) - if (restartWrite) then - if (worldrank == 0_pInt) write(6,'(/,a)') ' writing converged results for restart' - flush(6) - write(rankStr,'(a1,i0)')'_',worldrank - call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file - write (777,rec=1) F - close (777) - call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file - write (777,rec=1) F_lastInc - close (777) - call IO_write_jobRealFile(777,'F_tau'//trim(rankStr),size(F_tau)) ! writing deformation gradient field to file - write (777,rec=1) F_tau - close (777) - call IO_write_jobRealFile(777,'F_tau_lastInc'//trim(rankStr),size(F_tau_lastInc)) ! writing F_lastInc field to file - write (777,rec=1) F_tau_lastInc - close (777) - if (worldrank == 0_pInt) then - call IO_write_jobRealFile(777,'F_aim',size(F_aim)) - write (777,rec=1) F_aim - close(777) - call IO_write_jobRealFile(777,'F_aim_lastInc',size(F_aim_lastInc)) - write (777,rec=1) F_aim_lastInc - close (777) - call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) - write (777,rec=1) F_aimDot - close(777) - call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) - write (777,rec=1) C_volAvg - close(777) - call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) - write (777,rec=1) C_volAvgLastInc - close(777) - endif - endif - call utilities_updateIPcoords(F) - - if (cutBack) then - F_aim = F_aim_lastInc - F_tau= reshape(F_tau_lastInc,[9,grid(1),grid(2),grid3]) - F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) - C_volAvg = C_volAvgLastInc - else - ForwardData = .True. - C_volAvgLastInc = C_volAvg -!-------------------------------------------------------------------------------------------------- -! calculate rate for aim - if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F - f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) - elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed - f_aimDot = F_BC%maskFloat * F_BC%values - elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed - f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime - endif - if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old - F_aim_lastInc = F_aim - -!-------------------------------------------------------------------------------------------------- -! update coordinates and rate and forward last inc - call utilities_updateIPcoords(F) - Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & - timeinc_old,guess,F_lastInc, & - reshape(F,[3,3,grid(1),grid(2),grid3])) - F_tauDot = Utilities_calculateRate(math_rotate_backward33(2.0_pReal*f_aimDot,rotation_BC), & - timeinc_old,guess,F_tau_lastInc, & - reshape(F_tau,[3,3,grid(1),grid(2),grid3])) - F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) - F_tau_lastInc = reshape(F_tau,[3,3,grid(1),grid(2),grid3]) - endif - - F_aim = F_aim + f_aimDot * timeinc - -!-------------------------------------------------------------------------------------------------- -! update local deformation gradient - F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim - math_rotate_backward33(F_aim,rotation_BC)), & - [9,grid(1),grid(2),grid3]) - F_tau = reshape(Utilities_forwardField(timeinc,F_tau_lastInc,F_taudot), & ! does not have any average value as boundary condition - [9,grid(1),grid(2),grid3]) - if (.not. guess) then ! large strain forwarding - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, 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,math_mul33x33(F_lambda33, & - math_mul3333xx33(C_scale,& - math_mul33x33(math_transpose33(F_lambda33),& - F_lambda33) -math_I3))*0.5_pReal)& - + 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,xx_psc,ierr); CHKERRQ(ierr) - -end subroutine Polarisation_forward - -!-------------------------------------------------------------------------------------------------- -!> @brief destroy routine -!-------------------------------------------------------------------------------------------------- -subroutine Polarisation_destroy() - use spectral_utilities, only: & - Utilities_destroy - - implicit none - PetscErrorCode :: ierr - - call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) - call SNESDestroy(snes,ierr); CHKERRQ(ierr) - call DMDestroy(da,ierr); CHKERRQ(ierr) - -end subroutine Polarisation_destroy - -end module spectral_mech_Polarisation diff --git a/code/spectral_thermal.f90 b/code/spectral_thermal.f90 deleted file mode 100644 index 843642394..000000000 --- a/code/spectral_thermal.f90 +++ /dev/null @@ -1,419 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id: spectral_thermal.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Shaokang Zhang, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Spectral solver for thermal conduction -!-------------------------------------------------------------------------------------------------- -module spectral_thermal - use prec, only: & - pInt, & - pReal - use math, only: & - math_I3 - use spectral_utilities, only: & - tSolutionState, & - tSolutionParams - use numerics, only: & - worldrank, & - worldsize - - implicit none - private -#include - - character (len=*), parameter, public :: & - spectral_thermal_label = 'spectralthermal' - -!-------------------------------------------------------------------------------------------------- -! derived types - type(tSolutionParams), private :: params - -!-------------------------------------------------------------------------------------------------- -! PETSc data - SNES, private :: thermal_snes - Vec, private :: solution - PetscInt, private :: xstart, xend, ystart, yend, zstart, zend - real(pReal), private, dimension(:,:,:), allocatable :: & - temperature_current, & !< field of current temperature - temperature_lastInc, & !< field of previous temperature - temperature_stagInc !< field of staggered temperature - -!-------------------------------------------------------------------------------------------------- -! reference diffusion tensor, mobility etc. - integer(pInt), private :: totalIter = 0_pInt !< total iteration in current increment - real(pReal), dimension(3,3), private :: D_ref - real(pReal), private :: mobility_ref - character(len=1024), private :: incInfo - - public :: & - spectral_thermal_init, & - spectral_thermal_solution, & - spectral_thermal_forward, & - spectral_thermal_destroy - external :: & - VecDestroy, & - DMDestroy, & - DMDACreate3D, & - DMCreateGlobalVector, & - DMDASNESSetFunctionLocal, & - PETScFinalize, & - SNESDestroy, & - SNESGetNumberFunctionEvals, & - SNESGetIterationNumber, & - SNESSolve, & - SNESSetDM, & - SNESGetConvergedReason, & - SNESSetConvergenceTest, & - SNESSetFromOptions, & - SNESCreate, & - MPI_Abort, & - MPI_Bcast, & - MPI_Allreduce - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields and fills them with data, potentially from restart info -!-------------------------------------------------------------------------------------------------- -subroutine spectral_thermal_init - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_intOut, & - IO_read_realFile, & - IO_timeStamp - use spectral_utilities, only: & - wgt - use mesh, only: & - grid, & - grid3 - use thermal_conduction, only: & - thermal_conduction_getConductivity33, & - thermal_conduction_getMassDensity, & - thermal_conduction_getSpecificHeat - use material, only: & - mappingHomogenization, & - temperature, & - thermalMapping - - implicit none - integer(pInt), dimension(:), allocatable :: localK - integer(pInt) :: proc - integer(pInt) :: i, j, k, cell - DM :: thermal_grid - PetscScalar, pointer :: x_scal(:,:,:) - PetscErrorCode :: ierr - PetscObject :: dummy - - mainProcess: if (worldrank == 0_pInt) then - write(6,'(/,a)') ' <<<+- spectral_thermal init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!-------------------------------------------------------------------------------------------------- -! initialize solver specific parts of PETSc - call SNESCreate(PETSC_COMM_WORLD,thermal_snes,ierr); CHKERRQ(ierr) - call SNESSetOptionsPrefix(thermal_snes,'thermal_',ierr);CHKERRQ(ierr) - allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 - do proc = 1, worldsize - call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) - enddo - call DMDACreate3d(PETSC_COMM_WORLD, & - DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary - DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point - grid(1),grid(2),grid(3), & ! global grid - 1, 1, worldsize, & - 1, 0, & ! #dof (temperature field), ghost boundary width (domain overlap) - grid (1),grid(2),localK, & ! local grid - thermal_grid,ierr) ! handle, error - CHKERRQ(ierr) - call SNESSetDM(thermal_snes,thermal_grid,ierr); CHKERRQ(ierr) ! connect snes to da - call DMCreateGlobalVector(thermal_grid,solution ,ierr); CHKERRQ(ierr) ! global solution vector (grid x 1, i.e. every def grad tensor) - call DMDASNESSetFunctionLocal(thermal_grid,INSERT_VALUES,spectral_thermal_formResidual,dummy,ierr) ! residual vector of same shape as solution vector - CHKERRQ(ierr) - call SNESSetFromOptions(thermal_snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments - -!-------------------------------------------------------------------------------------------------- -! init fields - call DMDAGetCorners(thermal_grid,xstart,ystart,zstart,xend,yend,zend,ierr) - CHKERRQ(ierr) - xend = xstart + xend - 1 - yend = ystart + yend - 1 - zend = zstart + zend - 1 - allocate(temperature_current(grid(1),grid(2),grid3), source=0.0_pReal) - allocate(temperature_lastInc(grid(1),grid(2),grid3), source=0.0_pReal) - allocate(temperature_stagInc(grid(1),grid(2),grid3), source=0.0_pReal) - cell = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - temperature_current(i,j,k) = temperature(mappingHomogenization(2,1,cell))% & - p(thermalMapping(mappingHomogenization(2,1,cell))%p(1,cell)) - temperature_lastInc(i,j,k) = temperature_current(i,j,k) - temperature_stagInc(i,j,k) = temperature_current(i,j,k) - enddo; enddo; enddo - call DMDAVecGetArrayF90(thermal_grid,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with - x_scal(xstart:xend,ystart:yend,zstart:zend) = temperature_current - call DMDAVecRestoreArrayF90(thermal_grid,solution,x_scal,ierr); CHKERRQ(ierr) - - cell = 0_pInt - D_ref = 0.0_pReal - mobility_ref = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - D_ref = D_ref + thermal_conduction_getConductivity33(1,cell) - mobility_ref = mobility_ref + thermal_conduction_getMassDensity(1,cell)* & - thermal_conduction_getSpecificHeat(1,cell) - enddo; enddo; enddo - D_ref = D_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - mobility_ref = mobility_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - -end subroutine spectral_thermal_init - -!-------------------------------------------------------------------------------------------------- -!> @brief solution for the Basic PETSC scheme with internal iterations -!-------------------------------------------------------------------------------------------------- -type(tSolutionState) function spectral_thermal_solution(guess,timeinc,timeinc_old,loadCaseTime) - use numerics, only: & - itmax, & - err_thermal_tolAbs, & - err_thermal_tolRel - use spectral_utilities, only: & - tBoundaryCondition, & - Utilities_maskedCompliance, & - Utilities_updateGamma - use mesh, only: & - grid, & - grid3 - use thermal_conduction, only: & - thermal_conduction_putTemperatureAndItsRate - - implicit none - -!-------------------------------------------------------------------------------------------------- -! input data for solution - real(pReal), intent(in) :: & - timeinc, & !< increment in time for current solution - timeinc_old, & !< increment in time of last increment - loadCaseTime !< remaining time of current load case - logical, intent(in) :: guess - integer(pInt) :: i, j, k, cell - PetscInt :: position - PetscReal :: minTemperature, maxTemperature, stagNorm, solnNorm - -!-------------------------------------------------------------------------------------------------- -! PETSc Data - PetscErrorCode :: ierr - SNESConvergedReason :: reason - - spectral_thermal_solution%converged =.false. - -!-------------------------------------------------------------------------------------------------- -! set module wide availabe data - params%timeinc = timeinc - params%timeincOld = timeinc_old - - call SNESSolve(thermal_snes,PETSC_NULL_OBJECT,solution,ierr); CHKERRQ(ierr) - call SNESGetConvergedReason(thermal_snes,reason,ierr); CHKERRQ(ierr) - - if (reason < 1) then - spectral_thermal_solution%converged = .false. - spectral_thermal_solution%iterationsNeeded = itmax - else - spectral_thermal_solution%converged = .true. - spectral_thermal_solution%iterationsNeeded = totalIter - endif - stagNorm = maxval(abs(temperature_current - temperature_stagInc)) - solnNorm = maxval(abs(temperature_current)) - call MPI_Allreduce(MPI_IN_PLACE,stagNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) - call MPI_Allreduce(MPI_IN_PLACE,solnNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) - temperature_stagInc = temperature_current - spectral_thermal_solution%stagConverged = stagNorm < err_thermal_tolAbs & - .or. stagNorm < err_thermal_tolRel*solnNorm - -!-------------------------------------------------------------------------------------------------- -! updating thermal state - cell = 0_pInt !< material point = 0 - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt !< material point increase - call thermal_conduction_putTemperatureAndItsRate(temperature_current(i,j,k), & - (temperature_current(i,j,k)-temperature_lastInc(i,j,k))/params%timeinc, & - 1,cell) - enddo; enddo; enddo - - call VecMin(solution,position,minTemperature,ierr); CHKERRQ(ierr) - call VecMax(solution,position,maxTemperature,ierr); CHKERRQ(ierr) - if (worldrank == 0) then - if (spectral_thermal_solution%converged) & - write(6,'(/,a)') ' ... thermal conduction converged ..................................' - write(6,'(/,a,f8.4,2x,f8.4,2x,f8.4,/)',advance='no') ' Minimum|Maximum|Delta Temperature = ',& - minTemperature, maxTemperature, stagNorm - write(6,'(/,a)') ' ===========================================================================' - flush(6) - endif - -end function spectral_thermal_solution - - -!-------------------------------------------------------------------------------------------------- -!> @brief forms the spectral thermal residual vector -!-------------------------------------------------------------------------------------------------- -subroutine spectral_thermal_formResidual(in,x_scal,f_scal,dummy,ierr) - use mesh, only: & - grid, & - grid3 - use math, only: & - math_mul33x3 - use spectral_utilities, only: & - scalarField_real, & - vectorField_real, & - utilities_FFTvectorForward, & - utilities_FFTvectorBackward, & - utilities_FFTscalarForward, & - utilities_FFTscalarBackward, & - utilities_fourierGreenConvolution, & - utilities_fourierScalarGradient, & - utilities_fourierVectorDivergence - use thermal_conduction, only: & - thermal_conduction_getSourceAndItsTangent, & - thermal_conduction_getConductivity33, & - thermal_conduction_getMassDensity, & - thermal_conduction_getSpecificHeat - - implicit none - DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & - in - PetscScalar, dimension( & - XG_RANGE,YG_RANGE,ZG_RANGE) :: & - x_scal - PetscScalar, dimension( & - X_RANGE,Y_RANGE,Z_RANGE) :: & - f_scal - PetscObject :: dummy - PetscErrorCode :: ierr - integer(pInt) :: i, j, k, cell - real(pReal) :: Tdot, dTdot_dT - - temperature_current = x_scal -!-------------------------------------------------------------------------------------------------- -! evaluate polarization field - scalarField_real = 0.0_pReal - scalarField_real(1:grid(1),1:grid(2),1:grid3) = temperature_current - call utilities_FFTscalarForward() - call utilities_fourierScalarGradient() !< calculate gradient of damage field - call utilities_FFTvectorBackward() - cell = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - vectorField_real(1:3,i,j,k) = math_mul33x3(thermal_conduction_getConductivity33(1,cell) - D_ref, & - vectorField_real(1:3,i,j,k)) - enddo; enddo; enddo - call utilities_FFTvectorForward() - call utilities_fourierVectorDivergence() !< calculate damage divergence in fourier field - call utilities_FFTscalarBackward() - cell = 0_pInt - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - call thermal_conduction_getSourceAndItsTangent(Tdot, dTdot_dT, temperature_current(i,j,k), 1, cell) - scalarField_real(i,j,k) = params%timeinc*scalarField_real(i,j,k) + & - params%timeinc*Tdot + & - thermal_conduction_getMassDensity (1,cell)* & - thermal_conduction_getSpecificHeat(1,cell)*(temperature_lastInc(i,j,k) - & - temperature_current(i,j,k)) + & - mobility_ref*temperature_current(i,j,k) - enddo; enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! convolution of damage field with green operator - call utilities_FFTscalarForward() - call utilities_fourierGreenConvolution(D_ref, mobility_ref, params%timeinc) - call utilities_FFTscalarBackward() - -!-------------------------------------------------------------------------------------------------- -! constructing residual - f_scal = temperature_current - scalarField_real(1:grid(1),1:grid(2),1:grid3) - -end subroutine spectral_thermal_formResidual - -!-------------------------------------------------------------------------------------------------- -!> @brief forwarding routine -!-------------------------------------------------------------------------------------------------- -subroutine spectral_thermal_forward(guess,timeinc,timeinc_old,loadCaseTime) - use mesh, only: & - grid, & - grid3 - use spectral_utilities, only: & - cutBack, & - wgt - use thermal_conduction, only: & - thermal_conduction_putTemperatureAndItsRate, & - thermal_conduction_getConductivity33, & - thermal_conduction_getMassDensity, & - thermal_conduction_getSpecificHeat - - implicit none - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - logical, intent(in) :: guess - integer(pInt) :: i, j, k, cell - DM :: dm_local - PetscScalar, pointer :: x_scal(:,:,:) - PetscErrorCode :: ierr - - if (cutBack) then - temperature_current = temperature_lastInc - temperature_stagInc = temperature_lastInc - -!-------------------------------------------------------------------------------------------------- -! reverting thermal field state - cell = 0_pInt !< material point = 0 - call SNESGetDM(thermal_snes,dm_local,ierr); CHKERRQ(ierr) - call DMDAVecGetArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with - x_scal(xstart:xend,ystart:yend,zstart:zend) = temperature_current - call DMDAVecRestoreArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt !< material point increase - call thermal_conduction_putTemperatureAndItsRate(temperature_current(i,j,k), & - (temperature_current(i,j,k) - & - temperature_lastInc(i,j,k))/params%timeinc, & - 1,cell) - enddo; enddo; enddo - else -!-------------------------------------------------------------------------------------------------- -! update rate and forward last inc - temperature_lastInc = temperature_current - cell = 0_pInt - D_ref = 0.0_pReal - mobility_ref = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) - cell = cell + 1_pInt - D_ref = D_ref + thermal_conduction_getConductivity33(1,cell) - mobility_ref = mobility_ref + thermal_conduction_getMassDensity(1,cell)* & - thermal_conduction_getSpecificHeat(1,cell) - enddo; enddo; enddo - D_ref = D_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - mobility_ref = mobility_ref*wgt - call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - endif - - end subroutine spectral_thermal_forward - -!-------------------------------------------------------------------------------------------------- -!> @brief destroy routine -!-------------------------------------------------------------------------------------------------- -subroutine spectral_thermal_destroy() - - implicit none - PetscErrorCode :: ierr - - call VecDestroy(solution,ierr); CHKERRQ(ierr) - call SNESDestroy(thermal_snes,ierr); CHKERRQ(ierr) - -end subroutine spectral_thermal_destroy - -end module spectral_thermal diff --git a/code/spectral_utilities.f90 b/code/spectral_utilities.f90 deleted file mode 100644 index bde088ccb..000000000 --- a/code/spectral_utilities.f90 +++ /dev/null @@ -1,1262 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief Utilities used by the different spectral solver variants -!-------------------------------------------------------------------------------------------------- -module spectral_utilities - use, intrinsic :: iso_c_binding - use prec, only: & - pReal, & - pInt - use math, only: & - math_I3 - - implicit none - private -#include - include 'fftw3-mpi.f03' - - logical, public :: cutBack =.false. !< cut back of BVP solver in case convergence is not achieved or a material point is terminally ill - integer(pInt), public, parameter :: maxPhaseFields = 2_pInt - integer(pInt), public :: nActiveFields = 0_pInt - -!-------------------------------------------------------------------------------------------------- -! field labels information - enum, bind(c) - enumerator :: FIELD_UNDEFINED_ID, & - FIELD_MECH_ID, & - FIELD_THERMAL_ID, & - FIELD_DAMAGE_ID, & - FIELD_VACANCYDIFFUSION_ID - end enum - -!-------------------------------------------------------------------------------------------------- -! grid related information information - real(pReal), public :: wgt !< weighting factor 1/Nelems - -!-------------------------------------------------------------------------------------------------- -! variables storing information for spectral method and FFTW - integer(pInt), public :: grid1Red !< grid(1)/2 - real (C_DOUBLE), public, dimension(:,:,:,:,:), pointer :: tensorField_real !< real representation (some stress or deformation) of field_fourier - complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:,:), pointer :: tensorField_fourier !< field on which the Fourier transform operates - real(C_DOUBLE), public, dimension(:,:,:,:), pointer :: vectorField_real !< vector field real representation for fftw - complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:), pointer :: vectorField_fourier !< vector field fourier representation for fftw - real(C_DOUBLE), public, dimension(:,:,:), pointer :: scalarField_real !< scalar field real representation for fftw - complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:), pointer :: scalarField_fourier !< scalar field fourier representation for fftw - complex(pReal), private, dimension(:,:,:,:,:,:,:), allocatable :: gamma_hat !< gamma operator (field) for spectral method - complex(pReal), private, dimension(:,:,:,:), allocatable :: xi1st !< wave vector field for first derivatives - complex(pReal), private, dimension(:,:,:,:), allocatable :: xi2nd !< wave vector field for second derivatives - real(pReal), private, dimension(3,3,3,3) :: C_ref !< mechanic reference stiffness - real(pReal), protected, public, dimension(3) :: scaledGeomSize !< scaled geometry size for calculation of divergence (Basic, Basic PETSc) - -!-------------------------------------------------------------------------------------------------- -! plans for FFTW - type(C_PTR), private :: & - planTensorForth, & !< FFTW MPI plan P(x) to P(k) - planTensorBack, & !< FFTW MPI plan F(k) to F(x) - planVectorForth, & !< FFTW MPI plan v(x) to v(k) - planVectorBack, & !< FFTW MPI plan v(k) to v(x) - planScalarForth, & !< FFTW MPI plan s(x) to s(k) - planScalarBack !< FFTW MPI plan s(k) to s(x) - -!-------------------------------------------------------------------------------------------------- -! variables controlling debugging - logical, private :: & - debugGeneral, & !< general debugging of spectral solver - debugRotation, & !< also printing out results in lab frame - debugPETSc !< use some in debug defined options for more verbose PETSc solution - -!-------------------------------------------------------------------------------------------------- -! derived types - type, public :: tSolutionState !< return type of solution from spectral solver variants - logical :: converged = .true. - logical :: regrid = .false. - logical :: stagConverged = .true. - logical :: termIll = .false. - integer(pInt) :: iterationsNeeded = 0_pInt - end type tSolutionState - - type, public :: tBoundaryCondition !< set of parameters defining a boundary condition - real(pReal), dimension(3,3) :: values = 0.0_pReal - real(pReal), dimension(3,3) :: maskFloat = 0.0_pReal - logical, dimension(3,3) :: maskLogical = .false. - character(len=64) :: myType = 'None' - end type tBoundaryCondition - - type, public :: tLoadCase - real(pReal), dimension (3,3) :: rotation = math_I3 !< rotation of BC - type(tBoundaryCondition) :: P, & !< stress BC - deformation !< deformation BC (Fdot or L) - real(pReal) :: time = 0.0_pReal !< length of increment - integer(pInt) :: incs = 0_pInt, & !< number of increments - outputfrequency = 1_pInt, & !< frequency of result writes - restartfrequency = 0_pInt, & !< frequency of restart writes - logscale = 0_pInt !< linear/logarithmic time inc flag - logical :: followFormerTrajectory = .true. !< follow trajectory of former loadcase - integer(kind(FIELD_UNDEFINED_ID)), allocatable :: ID(:) - end type tLoadCase - - type, public :: tSolutionParams !< @todo use here the type definition for a full loadcase including mask - real(pReal), dimension(3,3) :: P_BC, rotation_BC - real(pReal) :: timeinc - real(pReal) :: timeincOld - real(pReal) :: density - end type tSolutionParams - - type(tSolutionParams), private :: params - - type, public :: phaseFieldDataBin !< set of parameters defining a phase field - real(pReal) :: diffusion = 0.0_pReal, & !< thermal conductivity - mobility = 0.0_pReal, & !< thermal mobility - phaseField0 = 0.0_pReal !< homogeneous damage field starting condition - logical :: active = .false. - character(len=64) :: label = '' - end type phaseFieldDataBin - - enum, bind(c) - enumerator :: DERIVATIVE_CONTINUOUS_ID, & - DERIVATIVE_CENTRAL_DIFF_ID, & - DERIVATIVE_FWBW_DIFF_ID - end enum - integer(kind(DERIVATIVE_CONTINUOUS_ID)) :: & - spectral_derivative_ID - - public :: & - utilities_init, & - utilities_updateGamma, & - utilities_FFTtensorForward, & - utilities_FFTtensorBackward, & - utilities_FFTvectorForward, & - utilities_FFTvectorBackward, & - utilities_FFTscalarForward, & - utilities_FFTscalarBackward, & - utilities_fourierGammaConvolution, & - utilities_fourierGreenConvolution, & - utilities_divergenceRMS, & - utilities_curlRMS, & - utilities_fourierScalarGradient, & - utilities_fourierVectorDivergence, & - utilities_fourierVectorGradient, & - utilities_fourierTensorDivergence, & - utilities_maskedCompliance, & - utilities_constitutiveResponse, & - utilities_calculateRate, & - utilities_forwardField, & - utilities_destroy, & - utilities_updateIPcoords, & - FIELD_UNDEFINED_ID, & - FIELD_MECH_ID, & - FIELD_THERMAL_ID, & - FIELD_DAMAGE_ID - private :: & - utilities_getFreqDerivative - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, sets debug flags, create plans for FFTW -!> @details Sets the debug levels for general, divergence, restart and FFTW from the biwise coding -!> provided by the debug module to logicals. -!> Allocates all fields used by FFTW and create the corresponding plans depending on the debug -!> level chosen. -!> Initializes FFTW. -!-------------------------------------------------------------------------------------------------- -subroutine utilities_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use IO, only: & - IO_error, & - IO_warning, & - IO_timeStamp, & - IO_open_file - use numerics, only: & - spectral_derivative, & - fftw_planner_flag, & - fftw_timelimit, & - memory_efficient, & - petsc_defaultOptions, & - petsc_options, & - divergence_correction, & - worldrank - use debug, only: & - debug_level, & - debug_SPECTRAL, & - debug_LEVELBASIC, & - debug_SPECTRALDIVERGENCE, & - debug_SPECTRALFFTW, & - debug_SPECTRALPETSC, & - debug_SPECTRALROTATION - use debug, only: & - PETSCDEBUG - use math - use mesh, only: & - grid, & - grid3, & - grid3Offset, & - geomSize - - implicit none - - external :: & - PETScOptionsClear, & - PETScOptionsInsertString, & - MPI_Abort - - PetscErrorCode :: ierr - integer(pInt) :: i, j, k - integer(pInt), dimension(3) :: k_s - type(C_PTR) :: & - tensorField, & !< field containing data for FFTW in real and fourier space (in place) - vectorField, & !< field containing data for FFTW in real space when debugging FFTW (no in place) - scalarField !< field containing data for FFTW in real space when debugging FFTW (no in place) - integer(C_INTPTR_T), dimension(3) :: gridFFTW - integer(C_INTPTR_T) :: alloc_local, local_K, local_K_offset - integer(C_INTPTR_T), parameter :: & - scalarSize = 1_C_INTPTR_T, & - vecSize = 3_C_INTPTR_T, & - tensorSize = 9_C_INTPTR_T - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- spectral_utilities init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - -!-------------------------------------------------------------------------------------------------- -! set debugging parameters - debugGeneral = iand(debug_level(debug_SPECTRAL),debug_LEVELBASIC) /= 0 - debugRotation = iand(debug_level(debug_SPECTRAL),debug_SPECTRALROTATION) /= 0 - debugPETSc = iand(debug_level(debug_SPECTRAL),debug_SPECTRALPETSC) /= 0 - - if(debugPETSc .and. worldrank == 0_pInt) write(6,'(3(/,a),/)') & - ' Initializing PETSc with debug options: ', & - trim(PETScDebug), & - ' add more using the PETSc_Options keyword in numerics.config ' - flush(6) - call PetscOptionsClear(ierr); CHKERRQ(ierr) - if(debugPETSc) call PetscOptionsInsertString(trim(PETSCDEBUG),ierr); CHKERRQ(ierr) - call PetscOptionsInsertString(trim(petsc_defaultOptions),ierr); CHKERRQ(ierr) - call PetscOptionsInsertString(trim(petsc_options),ierr); CHKERRQ(ierr) - - grid1Red = grid(1)/2_pInt + 1_pInt - wgt = 1.0/real(product(grid),pReal) - - if (worldrank == 0) then - write(6,'(a,3(i12 ))') ' grid a b c: ', grid - write(6,'(a,3(es12.5))') ' size x y z: ', geomSize - endif - - select case (spectral_derivative) - case ('continuous') ! default, no weighting - spectral_derivative_ID = DERIVATIVE_CONTINUOUS_ID - case ('central_difference') ! cosine curve with 1 for avg and zero for highest freq - spectral_derivative_ID = DERIVATIVE_CENTRAL_DIFF_ID - case ('fwbw_difference') ! gradient, might need grid scaling as for cosine filter - spectral_derivative_ID = DERIVATIVE_FWBW_DIFF_ID - case default - call IO_error(892_pInt,ext_msg=trim(spectral_derivative)) - end select - -!-------------------------------------------------------------------------------------------------- -! scale dimension to calculate either uncorrected, dimension-independent, or dimension- and -! resolution-independent divergence - if (divergence_correction == 1_pInt) then - do j = 1_pInt, 3_pInt - if (j /= minloc(geomSize,1) .and. j /= maxloc(geomSize,1)) & - scaledGeomSize = geomSize/geomSize(j) - enddo - elseif (divergence_correction == 2_pInt) then - do j = 1_pInt, 3_pInt - if (j /= minloc(geomSize/grid,1) .and. j /= maxloc(geomSize/grid,1)) & - scaledGeomSize = geomSize/geomSize(j)*grid(j) - enddo - else - scaledGeomSize = geomSize - endif - - -!-------------------------------------------------------------------------------------------------- -! MPI allocation - gridFFTW = int(grid,C_INTPTR_T) - alloc_local = fftw_mpi_local_size_3d(gridFFTW(3), gridFFTW(2), gridFFTW(1)/2 +1, & - MPI_COMM_WORLD, local_K, local_K_offset) - allocate (xi1st (3,grid1Red,grid(2),grid3),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies, only half the size for first dimension - allocate (xi2nd (3,grid1Red,grid(2),grid3),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies, only half the size for first dimension - - tensorField = fftw_alloc_complex(tensorSize*alloc_local) - call c_f_pointer(tensorField, tensorField_real, [3_C_INTPTR_T,3_C_INTPTR_T, & - 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real tensor representation - call c_f_pointer(tensorField, tensorField_fourier, [3_C_INTPTR_T,3_C_INTPTR_T, & - gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T , gridFFTW(2),local_K]) ! place a pointer for a fourier tensor representation - - vectorField = fftw_alloc_complex(vecSize*alloc_local) - call c_f_pointer(vectorField, vectorField_real, [3_C_INTPTR_T,& - 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real vector representation - call c_f_pointer(vectorField, vectorField_fourier,[3_C_INTPTR_T,& - gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T, gridFFTW(2),local_K]) ! place a pointer for a fourier vector representation - - scalarField = fftw_alloc_complex(scalarSize*alloc_local) ! allocate data for real representation (no in place transform) - call c_f_pointer(scalarField, scalarField_real, & - [2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1),gridFFTW(2),local_K]) ! place a pointer for a real scalar representation - call c_f_pointer(scalarField, scalarField_fourier, & - [ gridFFTW(1)/2_C_INTPTR_T + 1 ,gridFFTW(2),local_K]) ! place a pointer for a fourier scarlar representation - -!-------------------------------------------------------------------------------------------------- -! tensor MPI fftw plans - planTensorForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order - tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock - tensorField_real, tensorField_fourier, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planTensorForth)) call IO_error(810, ext_msg='planTensorForth') - planTensorBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order - tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock - tensorField_fourier,tensorField_real, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision - if (.not. C_ASSOCIATED(planTensorBack)) call IO_error(810, ext_msg='planTensorBack') - -!-------------------------------------------------------------------------------------------------- -! vector MPI fftw plans - planVectorForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order - vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock - vectorField_real, vectorField_fourier, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planVectorForth)) call IO_error(810, ext_msg='planVectorForth') - planVectorBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order - vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock - vectorField_fourier,vectorField_real, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision - if (.not. C_ASSOCIATED(planVectorBack)) call IO_error(810, ext_msg='planVectorBack') - -!-------------------------------------------------------------------------------------------------- -! scalar MPI fftw plans - planScalarForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order - scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock - scalarField_real, scalarField_fourier, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planScalarForth)) call IO_error(810, ext_msg='planScalarForth') - planScalarBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order, no. of transforms - scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock - scalarField_fourier,scalarField_real, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planScalarBack)) call IO_error(810, ext_msg='planScalarBack') - -!-------------------------------------------------------------------------------------------------- -! general initialization of FFTW (see manual on fftw.org for more details) - if (pReal /= C_DOUBLE .or. pInt /= C_INT) call IO_error(0_pInt,ext_msg='Fortran to C') ! check for correct precision in C - call fftw_set_timelimit(fftw_timelimit) ! set timelimit for plan creation - - if (debugGeneral .and. worldrank == 0_pInt) write(6,'(/,a)') ' FFTW initialized' - flush(6) - -!-------------------------------------------------------------------------------------------------- -! calculation of discrete angular frequencies, ordered as in FFTW (wrap around) - do k = grid3Offset+1_pInt, grid3Offset+grid3 - k_s(3) = k - 1_pInt - if(k > grid(3)/2_pInt + 1_pInt) k_s(3) = k_s(3) - grid(3) ! running from 0,1,...,N/2,N/2+1,-N/2,-N/2+1,...,-1 - do j = 1_pInt, grid(2) - k_s(2) = j - 1_pInt - if(j > grid(2)/2_pInt + 1_pInt) k_s(2) = k_s(2) - grid(2) ! running from 0,1,...,N/2,N/2+1,-N/2,-N/2+1,...,-1 - do i = 1_pInt, grid1Red - k_s(1) = i - 1_pInt ! symmetry, junst running from 0,1,...,N/2,N/2+1 - xi2nd(1:3,i,j,k-grid3Offset) = utilities_getFreqDerivative(k_s) ! if divergence_correction is set, frequencies are calculated on unit length - where(mod(grid,2)==0 .and. [i,j,k] == grid/2+1 .and. & - spectral_derivative_ID == DERIVATIVE_CONTINUOUS_ID) ! for even grids, set the Nyquist Freq component to 0.0 - xi1st(1:3,i,j,k-grid3Offset) = cmplx(0.0_pReal,0.0_pReal,pReal) - elsewhere - xi1st(1:3,i,j,k-grid3Offset) = xi2nd(1:3,i,j,k-grid3Offset) - endwhere - enddo; enddo; enddo - - if(memory_efficient) then ! allocate just single fourth order tensor - allocate (gamma_hat(3,3,3,3,1,1,1), source = cmplx(0.0_pReal,0.0_pReal,pReal)) - else ! precalculation of gamma_hat field - allocate (gamma_hat(3,3,3,3,grid1Red,grid(2),grid3), source = cmplx(0.0_pReal,0.0_pReal,pReal)) - endif - -end subroutine utilities_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief updates references stiffness and potentially precalculated gamma operator -!> @details Sets the current reference stiffness to the stiffness given as an argument. -!> If the gamma operator is precalculated, it is calculated with this stiffness. -!> In case of a on-the-fly calculation, only the reference stiffness is updated. -!> Also writes out the current reference stiffness for restart. -!-------------------------------------------------------------------------------------------------- -subroutine utilities_updateGamma(C,saveReference) - use IO, only: & - IO_write_jobRealFile - use numerics, only: & - memory_efficient, & - worldrank - use mesh, only: & - grid3Offset, & - grid3,& - grid - use math, only: & - math_det33, & - math_invert - - implicit none - real(pReal), intent(in), dimension(3,3,3,3) :: C !< input stiffness to store as reference stiffness - logical , intent(in) :: saveReference !< save reference stiffness to file for restart - complex(pReal), dimension(3,3) :: temp33_complex, xiDyad_cmplx - real(pReal), dimension(6,6) :: matA, matInvA - integer(pInt) :: & - i, j, k, & - l, m, n, o - logical :: ierr - - C_ref = C - if (saveReference) then - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' writing reference stiffness to file' - flush(6) - call IO_write_jobRealFile(777,'C_ref',size(C_ref)) - write (777,rec=1) C_ref - close(777) - endif - endif - - if(.not. memory_efficient) then - gamma_hat = cmplx(0.0_pReal,0.0_pReal,pReal) ! for the singular point and any non invertible A - do k = grid3Offset+1_pInt, grid3Offset+grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid1Red - if (any([i,j,k] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - xiDyad_cmplx(l,m) = conjg(-xi1st(l,i,j,k-grid3Offset))*xi1st(m,i,j,k-grid3Offset) - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_complex(l,m) = sum(C_ref(l,1:3,m,1:3)*xiDyad_cmplx) - matA(1:3,1:3) = real(temp33_complex); matA(4:6,4:6) = real(temp33_complex) - matA(1:3,4:6) = aimag(temp33_complex); matA(4:6,1:3) = -aimag(temp33_complex) - if (abs(math_det33(matA(1:3,1:3))) > 1e-16) then - call math_invert(6_pInt, matA, matInvA, ierr) - temp33_complex = cmplx(matInvA(1:3,1:3),matInvA(1:3,4:6),pReal) - forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, o=1_pInt:3_pInt) & - gamma_hat(l,m,n,o,i,j,k-grid3Offset) = temp33_complex(l,n)* & - conjg(-xi1st(o,i,j,k-grid3Offset))*xi1st(m,i,j,k-grid3Offset) - endif - endif - enddo; enddo; enddo - endif - -end subroutine utilities_updateGamma - -!-------------------------------------------------------------------------------------------------- -!> @brief forward FFT of data in field_real to field_fourier -!> @details Does an unweighted filtered FFT transform from real to complex -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTtensorForward() - implicit none - -!-------------------------------------------------------------------------------------------------- -! doing the tensor FFT - call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) - -end subroutine utilities_FFTtensorForward - - -!-------------------------------------------------------------------------------------------------- -!> @brief backward FFT of data in field_fourier to field_real -!> @details Does an weighted inverse FFT transform from complex to real -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTtensorBackward() - implicit none - - call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real) - tensorField_real = tensorField_real * wgt ! normalize the result by number of elements - -end subroutine utilities_FFTtensorBackward - -!-------------------------------------------------------------------------------------------------- -!> @brief forward FFT of data in scalarField_real to scalarField_fourier -!> @details Does an unweighted filtered FFT transform from real to complex -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTscalarForward() - implicit none - -!-------------------------------------------------------------------------------------------------- -! doing the scalar FFT - call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier) - -end subroutine utilities_FFTscalarForward - - -!-------------------------------------------------------------------------------------------------- -!> @brief backward FFT of data in scalarField_fourier to scalarField_real -!> @details Does an weighted inverse FFT transform from complex to real -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTscalarBackward() - implicit none - - call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) - scalarField_real = scalarField_real * wgt ! normalize the result by number of elements - -end subroutine utilities_FFTscalarBackward - - -!-------------------------------------------------------------------------------------------------- -!> @brief forward FFT of data in field_real to field_fourier with highest freqs. removed -!> @details Does an unweighted filtered FFT transform from real to complex. -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTvectorForward() - implicit none - -!-------------------------------------------------------------------------------------------------- -! doing the vector FFT - call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier) - -end subroutine utilities_FFTvectorForward - - -!-------------------------------------------------------------------------------------------------- -!> @brief backward FFT of data in field_fourier to field_real -!> @details Does an weighted inverse FFT transform from complex to real -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTvectorBackward() - implicit none - - call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) - vectorField_real = vectorField_real * wgt ! normalize the result by number of elements - -end subroutine utilities_FFTvectorBackward - - -!-------------------------------------------------------------------------------------------------- -!> @brief doing convolution gamma_hat * field_real, ensuring that average value = fieldAim -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierGammaConvolution(fieldAim) - use numerics, only: & - memory_efficient - use math, only: & - math_det33, & - math_invert - use numerics, only: & - worldrank - use mesh, only: & - grid3, & - grid, & - grid3Offset - - implicit none - real(pReal), intent(in), dimension(3,3) :: fieldAim !< desired average value of the field after convolution - complex(pReal), dimension(3,3) :: temp33_complex, xiDyad_cmplx - real(pReal) :: matA(6,6), matInvA(6,6) - - integer(pInt) :: & - i, j, k, & - l, m, n, o - logical :: ierr - - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' ... doing gamma convolution ...............................................' - flush(6) - endif - -!-------------------------------------------------------------------------------------------------- -! do the actual spectral method calculation (mechanical equilibrium) - memoryEfficient: if(memory_efficient) then - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid1Red - if (any([i,j,k+grid3Offset] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - xiDyad_cmplx(l,m) = conjg(-xi1st(l,i,j,k))*xi1st(m,i,j,k) - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_complex(l,m) = sum(C_ref(l,1:3,m,1:3)*xiDyad_cmplx) - matA(1:3,1:3) = real(temp33_complex); matA(4:6,4:6) = real(temp33_complex) - matA(1:3,4:6) = aimag(temp33_complex); matA(4:6,1:3) = -aimag(temp33_complex) - if (abs(math_det33(matA(1:3,1:3))) > 1e-16) then - call math_invert(6_pInt, matA, matInvA, ierr) - temp33_complex = cmplx(matInvA(1:3,1:3),matInvA(1:3,4:6),pReal) - forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, o=1_pInt:3_pInt) & - gamma_hat(l,m,n,o,1,1,1) = temp33_complex(l,n)*conjg(-xi1st(o,i,j,k))*xi1st(m,i,j,k) - else - gamma_hat(1:3,1:3,1:3,1:3,1,1,1) = cmplx(0.0_pReal,0.0_pReal,pReal) - endif - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3,1,1,1)*tensorField_fourier(1:3,1:3,i,j,k)) - tensorField_fourier(1:3,1:3,i,j,k) = temp33_Complex - endif - enddo; enddo; enddo - else memoryEfficient - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3,i,j,k) * tensorField_fourier(1:3,1:3,i,j,k)) - tensorField_fourier(1:3,1:3,i,j,k) = temp33_Complex - enddo; enddo; enddo - endif memoryEfficient - - if (grid3Offset == 0_pInt) & - tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim/wgt,0.0_pReal,pReal) - -end subroutine utilities_fourierGammaConvolution - - -!-------------------------------------------------------------------------------------------------- -!> @brief doing convolution DamageGreenOp_hat * field_real -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierGreenConvolution(D_ref, mobility_ref, deltaT) - - use math, only: & - math_mul33x3, & - PI - use mesh, only: & - grid, & - grid3 - - implicit none - real(pReal), dimension(3,3), intent(in) :: D_ref !< desired average value of the field after convolution - real(pReal), intent(in) :: mobility_ref, deltaT !< desired average value of the field after convolution - complex(pReal) :: GreenOp_hat - integer(pInt) :: i, j, k - -!-------------------------------------------------------------------------------------------------- -! do the actual spectral method calculation - do k = 1_pInt, grid3; do j = 1_pInt, grid(2) ;do i = 1_pInt, grid1Red - GreenOp_hat = cmplx(1.0_pReal,0.0_pReal,pReal)/ & - (cmplx(mobility_ref,0.0_pReal,pReal) + & - deltaT*sum(conjg(xi1st(1:3,i,j,k))*matmul(D_ref,xi1st(1:3,i,j,k)))) ! why not use dot_product - scalarField_fourier(i,j,k) = scalarField_fourier(i,j,k)*GreenOp_hat - enddo; enddo; enddo - -end subroutine utilities_fourierGreenConvolution - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate root mean square of divergence of field_fourier -!-------------------------------------------------------------------------------------------------- -real(pReal) function utilities_divergenceRMS() - use numerics, only: & - worldrank - use mesh, only: & - geomSize, & - grid, & - grid3 - - implicit none - integer(pInt) :: i, j, k - PetscErrorCode :: ierr - - external :: & - MPI_Allreduce - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' ... calculating divergence ................................................' - flush(6) - endif - -!-------------------------------------------------------------------------------------------------- -! calculating RMS divergence criterion in Fourier space - utilities_divergenceRMS = 0.0_pReal - do k = 1_pInt, grid3; do j = 1_pInt, grid(2) - do i = 2_pInt, grid1Red -1_pInt ! Has somewhere a conj. complex counterpart. Therefore count it twice. - utilities_divergenceRMS = utilities_divergenceRMS & - + 2.0_pReal*(sum (real(matmul(tensorField_fourier(1:3,1:3,i,j,k),& ! (sqrt(real(a)**2 + aimag(a)**2))**2 = real(a)**2 + aimag(a)**2. do not take square root and square again - conjg(-xi1st(1:3,i,j,k))*geomSize/scaledGeomSize))**2.0_pReal)& ! --> sum squared L_2 norm of vector - +sum(aimag(matmul(tensorField_fourier(1:3,1:3,i,j,k),& - conjg(-xi1st(1:3,i,j,k))*geomSize/scaledGeomSize))**2.0_pReal)) - enddo - utilities_divergenceRMS = utilities_divergenceRMS & ! these two layers (DC and Nyquist) do not have a conjugate complex counterpart (if grid(1) /= 1) - + sum( real(matmul(tensorField_fourier(1:3,1:3,1 ,j,k), & - conjg(-xi1st(1:3,1,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & - + sum(aimag(matmul(tensorField_fourier(1:3,1:3,1 ,j,k), & - conjg(-xi1st(1:3,1,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & - + sum( real(matmul(tensorField_fourier(1:3,1:3,grid1Red,j,k), & - conjg(-xi1st(1:3,grid1Red,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & - + sum(aimag(matmul(tensorField_fourier(1:3,1:3,grid1Red,j,k), & - conjg(-xi1st(1:3,grid1Red,j,k))*geomSize/scaledGeomSize))**2.0_pReal) - enddo; enddo - if(grid(1) == 1_pInt) utilities_divergenceRMS = utilities_divergenceRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 - call MPI_Allreduce(MPI_IN_PLACE,utilities_divergenceRMS,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - utilities_divergenceRMS = sqrt(utilities_divergenceRMS) * wgt ! RMS in real space calculated with Parsevals theorem from Fourier space - - -end function utilities_divergenceRMS - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate max of curl of field_fourier -!-------------------------------------------------------------------------------------------------- -real(pReal) function utilities_curlRMS() - use numerics, only: & - worldrank - use mesh, only: & - geomSize, & - grid, & - grid3 - - implicit none - integer(pInt) :: i, j, k, l - complex(pReal), dimension(3,3) :: curl_fourier - PetscErrorCode :: ierr - - external :: & - MPI_Reduce, & - MPI_Allreduce - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' ... calculating curl ......................................................' - flush(6) - endif - - !-------------------------------------------------------------------------------------------------- -! calculating max curl criterion in Fourier space - utilities_curlRMS = 0.0_pReal - - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); - do i = 2_pInt, grid1Red - 1_pInt - do l = 1_pInt, 3_pInt - curl_fourier(l,1) = (+tensorField_fourier(l,3,i,j,k)*xi1st(2,i,j,k)*geomSize(2)/scaledGeomSize(2) & - -tensorField_fourier(l,2,i,j,k)*xi1st(3,i,j,k)*geomSize(3)/scaledGeomSize(3)) - curl_fourier(l,2) = (+tensorField_fourier(l,1,i,j,k)*xi1st(3,i,j,k)*geomSize(3)/scaledGeomSize(3) & - -tensorField_fourier(l,3,i,j,k)*xi1st(1,i,j,k)*geomSize(1)/scaledGeomSize(1)) - curl_fourier(l,3) = (+tensorField_fourier(l,2,i,j,k)*xi1st(1,i,j,k)*geomSize(1)/scaledGeomSize(1) & - -tensorField_fourier(l,1,i,j,k)*xi1st(2,i,j,k)*geomSize(2)/scaledGeomSize(2)) - enddo - utilities_curlRMS = utilities_curlRMS + & - 2.0_pReal*sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! Has somewhere a conj. complex counterpart. Therefore count it twice. - enddo - do l = 1_pInt, 3_pInt - curl_fourier = (+tensorField_fourier(l,3,1,j,k)*xi1st(2,1,j,k)*geomSize(2)/scaledGeomSize(2) & - -tensorField_fourier(l,2,1,j,k)*xi1st(3,1,j,k)*geomSize(3)/scaledGeomSize(3)) - curl_fourier = (+tensorField_fourier(l,1,1,j,k)*xi1st(3,1,j,k)*geomSize(3)/scaledGeomSize(3) & - -tensorField_fourier(l,3,1,j,k)*xi1st(1,1,j,k)*geomSize(1)/scaledGeomSize(1)) - curl_fourier = (+tensorField_fourier(l,2,1,j,k)*xi1st(1,1,j,k)*geomSize(1)/scaledGeomSize(1) & - -tensorField_fourier(l,1,1,j,k)*xi1st(2,1,j,k)*geomSize(2)/scaledGeomSize(2)) - enddo - utilities_curlRMS = utilities_curlRMS + & - sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! this layer (DC) does not have a conjugate complex counterpart (if grid(1) /= 1) - do l = 1_pInt, 3_pInt - curl_fourier = (+tensorField_fourier(l,3,grid1Red,j,k)*xi1st(2,grid1Red,j,k)*geomSize(2)/scaledGeomSize(2) & - -tensorField_fourier(l,2,grid1Red,j,k)*xi1st(3,grid1Red,j,k)*geomSize(3)/scaledGeomSize(3)) - curl_fourier = (+tensorField_fourier(l,1,grid1Red,j,k)*xi1st(3,grid1Red,j,k)*geomSize(3)/scaledGeomSize(3) & - -tensorField_fourier(l,3,grid1Red,j,k)*xi1st(1,grid1Red,j,k)*geomSize(1)/scaledGeomSize(1)) - curl_fourier = (+tensorField_fourier(l,2,grid1Red,j,k)*xi1st(1,grid1Red,j,k)*geomSize(1)/scaledGeomSize(1) & - -tensorField_fourier(l,1,grid1Red,j,k)*xi1st(2,grid1Red,j,k)*geomSize(2)/scaledGeomSize(2)) - enddo - utilities_curlRMS = utilities_curlRMS + & - sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! this layer (Nyquist) does not have a conjugate complex counterpart (if grid(1) /= 1) - enddo; enddo - - call MPI_Allreduce(MPI_IN_PLACE,utilities_curlRMS,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - utilities_curlRMS = sqrt(utilities_curlRMS) * wgt - if(grid(1) == 1_pInt) utilities_curlRMS = utilities_curlRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 - -end function utilities_curlRMS - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates mask compliance tensor used to adjust F to fullfill stress BC -!-------------------------------------------------------------------------------------------------- -function utilities_maskedCompliance(rot_BC,mask_stress,C) - use prec, only: & - prec_isNaN - use IO, only: & - IO_error - use numerics, only: & - worldrank - use math, only: & - math_Plain3333to99, & - math_plain99to3333, & - math_rotate_forward3333, & - math_rotate_forward33, & - math_invert - - implicit none - real(pReal), dimension(3,3,3,3) :: utilities_maskedCompliance !< masked compliance - real(pReal), intent(in) , dimension(3,3,3,3) :: C !< current average stiffness - real(pReal), intent(in) , dimension(3,3) :: rot_BC !< rotation of load frame - logical, intent(in), dimension(3,3) :: mask_stress !< mask of stress BC - integer(pInt) :: j, k, m, n - logical, dimension(9) :: mask_stressVector - real(pReal), dimension(9,9) :: temp99_Real - integer(pInt) :: size_reduced = 0_pInt - real(pReal), dimension(:,:), allocatable :: & - s_reduced, & !< reduced compliance matrix (depending on number of stress BC) - c_reduced, & !< reduced stiffness (depending on number of stress BC) - sTimesC !< temp variable to check inversion - logical :: errmatinv - character(len=1024):: formatString - - mask_stressVector = reshape(transpose(mask_stress), [9]) - size_reduced = int(count(mask_stressVector), pInt) - if(size_reduced > 0_pInt )then - allocate (c_reduced(size_reduced,size_reduced), source =0.0_pReal) - allocate (s_reduced(size_reduced,size_reduced), source =0.0_pReal) - allocate (sTimesC(size_reduced,size_reduced), source =0.0_pReal) - temp99_Real = math_Plain3333to99(math_rotate_forward3333(C,rot_BC)) - - if(debugGeneral .and. worldrank == 0_pInt) then - write(6,'(/,a)') ' ... updating masked compliance ............................................' - write(6,'(/,a,/,9(9(2x,f12.7,1x)/))',advance='no') ' Stiffness C (load) / GPa =',& - transpose(temp99_Real)/1.e9_pReal - flush(6) - endif - k = 0_pInt ! calculate reduced stiffness - do n = 1_pInt,9_pInt - if(mask_stressVector(n)) then - k = k + 1_pInt - j = 0_pInt - do m = 1_pInt,9_pInt - if(mask_stressVector(m)) then - j = j + 1_pInt - c_reduced(k,j) = temp99_Real(n,m) - endif; enddo; endif; enddo - - call math_invert(size_reduced, c_reduced, s_reduced, errmatinv) ! invert reduced stiffness - if (any(prec_isNaN(s_reduced))) errmatinv = .true. - if(errmatinv) call IO_error(error_ID=400_pInt,ext_msg='utilities_maskedCompliance') - temp99_Real = 0.0_pReal ! fill up compliance with zeros - k = 0_pInt - do n = 1_pInt,9_pInt - if(mask_stressVector(n)) then - k = k + 1_pInt - j = 0_pInt - do m = 1_pInt,9_pInt - if(mask_stressVector(m)) then - j = j + 1_pInt - temp99_Real(n,m) = s_reduced(k,j) - endif; enddo; endif; enddo - -!-------------------------------------------------------------------------------------------------- -! check if inversion was successful - sTimesC = matmul(c_reduced,s_reduced) - do m=1_pInt, size_reduced - do n=1_pInt, size_reduced - if(m==n .and. abs(sTimesC(m,n)) > (1.0_pReal + 10.0e-12_pReal)) errmatinv = .true. ! diagonal elements of S*C should be 1 - if(m/=n .and. abs(sTimesC(m,n)) > (0.0_pReal + 10.0e-12_pReal)) errmatinv = .true. ! off diagonal elements of S*C should be 0 - enddo - enddo - if((debugGeneral .or. errmatinv) .and. (worldrank == 0_pInt)) then ! report - write(formatString, '(I16.16)') size_reduced - formatString = '(/,a,/,'//trim(formatString)//'('//trim(formatString)//'(2x,es9.2,1x)/))' - write(6,trim(formatString),advance='no') ' C * S (load) ', & - transpose(matmul(c_reduced,s_reduced)) - write(6,trim(formatString),advance='no') ' S (load) ', transpose(s_reduced) - endif - if(errmatinv) call IO_error(error_ID=400_pInt,ext_msg='utilities_maskedCompliance') - deallocate(c_reduced) - deallocate(s_reduced) - deallocate(sTimesC) - else - temp99_real = 0.0_pReal - endif - if(debugGeneral .and. worldrank == 0_pInt) & ! report - write(6,'(/,a,/,9(9(2x,f12.7,1x)/),/)',advance='no') ' Masked Compliance (load) * GPa =', & - transpose(temp99_Real*1.e9_pReal) - flush(6) - utilities_maskedCompliance = math_Plain99to3333(temp99_Real) - -end function utilities_maskedCompliance - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate scalar gradient in fourier field -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierScalarGradient() - use mesh, only: & - grid3, & - grid - - implicit none - integer(pInt) :: i, j, k - - vectorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) - forall(k = 1_pInt:grid3, j = 1_pInt:grid(2), i = 1_pInt:grid1Red) & - vectorField_fourier(1:3,i,j,k) = scalarField_fourier(i,j,k)*xi1st(1:3,i,j,k) - -end subroutine utilities_fourierScalarGradient - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate vector divergence in fourier field -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierVectorDivergence() - use mesh, only: & - grid3, & - grid - - implicit none - integer(pInt) :: i, j, k - - scalarField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) - forall(k = 1_pInt:grid3, j = 1_pInt:grid(2), i = 1_pInt:grid1Red) & - scalarField_fourier(i,j,k) = scalarField_fourier(i,j,k) + & - sum(vectorField_fourier(1:3,i,j,k)*conjg(-xi1st(1:3,i,j,k))) - -end subroutine utilities_fourierVectorDivergence - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate vector gradient in fourier field -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierVectorGradient() - use mesh, only: & - grid3, & - grid - - implicit none - integer(pInt) :: i, j, k, m, n - - tensorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red - do m = 1_pInt, 3_pInt; do n = 1_pInt, 3_pInt - tensorField_fourier(m,n,i,j,k) = vectorField_fourier(m,i,j,k)*xi1st(n,i,j,k) - enddo; enddo - enddo; enddo; enddo -end subroutine utilities_fourierVectorGradient - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate tensor divergence in fourier field -!-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierTensorDivergence() - use mesh, only: & - grid3, & - grid - - implicit none - integer(pInt) :: i, j, k, m, n - - vectorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) - do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red - do m = 1_pInt, 3_pInt; do n = 1_pInt, 3_pInt - vectorField_fourier(m,i,j,k) = & - vectorField_fourier(m,i,j,k) + & - tensorField_fourier(m,n,i,j,k)*conjg(-xi1st(n,i,j,k)) - enddo; enddo - enddo; enddo; enddo -end subroutine utilities_fourierTensorDivergence - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates constitutive response -!-------------------------------------------------------------------------------------------------- -subroutine utilities_constitutiveResponse(F_lastInc,F,timeinc, & - P,C_volAvg,C_minmaxAvg,P_av,forwardData,rotation_BC) - use debug, only: & - debug_reset, & - debug_info - use numerics, only: & - worldrank - use math, only: & - math_transpose33, & - math_rotate_forward33, & - math_det33 - use mesh, only: & - grid,& - grid3 - use FEsolving, only: & - restartWrite - use CPFEM2, only: & - CPFEM_general - use homogenization, only: & - materialpoint_F0, & - materialpoint_F, & - materialpoint_P, & - materialpoint_dPdF - - implicit none - real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & - F_lastInc, & !< target deformation gradient - F !< previous deformation gradient - real(pReal), intent(in) :: timeinc !< loading time - logical, intent(in) :: forwardData !< age results - real(pReal), intent(in), dimension(3,3) :: rotation_BC !< rotation of load frame - - real(pReal),intent(out), dimension(3,3,3,3) :: C_volAvg, C_minmaxAvg !< average stiffness - real(pReal),intent(out), dimension(3,3) :: P_av !< average PK stress - real(pReal),intent(out), dimension(3,3,grid(1),grid(2),grid3) :: P !< PK stress - - logical :: & - age - - integer(pInt) :: & - j,k - real(pReal), dimension(3,3,3,3) :: max_dPdF, min_dPdF - real(pReal) :: max_dPdF_norm, min_dPdF_norm, defgradDetMin, defgradDetMax, defgradDet - PetscErrorCode :: ierr - - external :: & - MPI_Reduce, & - MPI_Allreduce - - if (worldrank == 0_pInt) then - write(6,'(/,a)') ' ... evaluating constitutive response ......................................' - flush(6) - endif - age = .False. - - if (forwardData) then ! aging results - age = .True. - materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) - endif - if (cutBack) then ! restore saved variables - age = .False. - endif - - materialpoint_F = reshape(F,[3,3,1,product(grid(1:2))*grid3]) - call debug_reset() - -!-------------------------------------------------------------------------------------------------- -! calculate bounds of det(F) and report - if(debugGeneral) then - defgradDetMax = -huge(1.0_pReal) - defgradDetMin = +huge(1.0_pReal) - do j = 1_pInt, product(grid(1:2))*grid3 - defgradDet = math_det33(materialpoint_F(1:3,1:3,1,j)) - defgradDetMax = max(defgradDetMax,defgradDet) - defgradDetMin = min(defgradDetMin,defgradDet) - end do - call MPI_reduce(MPI_IN_PLACE,defgradDetMax,1,MPI_DOUBLE,MPI_MAX,0,PETSC_COMM_WORLD,ierr) - call MPI_reduce(MPI_IN_PLACE,defgradDetMin,1,MPI_DOUBLE,MPI_MIN,0,PETSC_COMM_WORLD,ierr) - if (worldrank == 0_pInt) then - write(6,'(a,1x,es11.4)') ' max determinant of deformation =', defgradDetMax - write(6,'(a,1x,es11.4)') ' min determinant of deformation =', defgradDetMin - flush(6) - endif - endif - - call CPFEM_general(age,timeinc) - - max_dPdF = 0.0_pReal - max_dPdF_norm = 0.0_pReal - min_dPdF = huge(1.0_pReal) - min_dPdF_norm = huge(1.0_pReal) - do k = 1_pInt, product(grid(1:2))*grid3 - if (max_dPdF_norm < sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal)) then - max_dPdF = materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k) - max_dPdF_norm = sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal) - endif - if (min_dPdF_norm > sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal)) then - min_dPdF = materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k) - min_dPdF_norm = sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal) - endif - end do - - call MPI_Allreduce(MPI_IN_PLACE,max_dPdF,81,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) - call MPI_Allreduce(MPI_IN_PLACE,min_dPdF,81,MPI_DOUBLE,MPI_MIN,PETSC_COMM_WORLD,ierr) - - C_minmaxAvg = 0.5_pReal*(max_dPdF + min_dPdF) - C_volAvg = sum(sum(materialpoint_dPdF,dim=6),dim=5) * wgt - - call MPI_Allreduce(MPI_IN_PLACE,C_volAvg,81,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - - call debug_info() - - restartWrite = .false. ! reset restartWrite status - cutBack = .false. ! reset cutBack status - - P = reshape(materialpoint_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 .and. worldrank == 0_pInt) & - write(6,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress (lab) / MPa =',& - math_transpose33(P_av)*1.e-6_pReal - P_av = math_rotate_forward33(P_av,rotation_BC) - if (worldrank == 0_pInt) then - write(6,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress / MPa =',& - math_transpose33(P_av)*1.e-6_pReal - flush(6) - endif - -end subroutine utilities_constitutiveResponse - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates forward rate, either guessing or just add delta/timeinc -!-------------------------------------------------------------------------------------------------- -pure function utilities_calculateRate(avRate,timeinc_old,guess,field_lastInc,field) - use mesh, only: & - grid3, & - grid - - implicit none - real(pReal), intent(in), dimension(3,3) :: avRate !< homogeneous addon - real(pReal), intent(in) :: & - timeinc_old !< timeinc of last step - logical, intent(in) :: & - guess !< guess along former trajectory - real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & - field_lastInc, & !< data of previous step - field !< data of current step - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: & - utilities_calculateRate - - if (guess) then - utilities_calculateRate = (field-field_lastInc) / timeinc_old - else - utilities_calculateRate = spread(spread(spread(avRate,3,grid(1)),4,grid(2)),5,grid3) - endif - -end function utilities_calculateRate - - -!-------------------------------------------------------------------------------------------------- -!> @brief forwards a field with a pointwise given rate, if aim is given, -!> ensures that the average matches the aim -!-------------------------------------------------------------------------------------------------- -function utilities_forwardField(timeinc,field_lastInc,rate,aim) - use mesh, only: & - grid3, & - grid - - implicit none - real(pReal), intent(in) :: & - timeinc !< timeinc of current step - real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & - field_lastInc, & !< initial field - rate !< rate by which to forward - real(pReal), intent(in), optional, dimension(3,3) :: & - aim !< average field value aim - real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: & - utilities_forwardField - real(pReal), dimension(3,3) :: fieldDiff !< - aim - PetscErrorCode :: ierr - - external :: & - MPI_Allreduce - - utilities_forwardField = field_lastInc + rate*timeinc - if (present(aim)) then !< correct to match average - fieldDiff = sum(sum(sum(utilities_forwardField,dim=5),dim=4),dim=3)*wgt - call MPI_Allreduce(MPI_IN_PLACE,fieldDiff,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - fieldDiff = fieldDiff - aim - utilities_forwardField = utilities_forwardField - & - spread(spread(spread(fieldDiff,3,grid(1)),4,grid(2)),5,grid3) - endif - -end function utilities_forwardField - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates filter for fourier convolution depending on type given in numerics.config -!-------------------------------------------------------------------------------------------------- -pure function utilities_getFreqDerivative(k_s) - use math, only: & - PI - use mesh, only: & - geomSize, & - grid - - implicit none - integer(pInt), intent(in), dimension(3) :: k_s !< indices of frequency - complex(pReal), dimension(3) :: utilities_getFreqDerivative - - select case (spectral_derivative_ID) - case (DERIVATIVE_CONTINUOUS_ID) - utilities_getFreqDerivative = cmplx(0.0_pReal, 2.0_pReal*PI*real(k_s,pReal)/geomSize,pReal) - - case (DERIVATIVE_CENTRAL_DIFF_ID) - utilities_getFreqDerivative = cmplx(0.0_pReal, sin(2.0_pReal*PI*real(k_s,pReal)/real(grid,pReal)), pReal)/ & - cmplx(2.0_pReal*geomSize/real(grid,pReal), 0.0_pReal, pReal) - - case (DERIVATIVE_FWBW_DIFF_ID) - utilities_getFreqDerivative(1) = & - cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) - 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & - cmplx(4.0_pReal*geomSize(1)/real(grid(1),pReal), 0.0_pReal, pReal) - utilities_getFreqDerivative(2) = & - cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) - 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & - cmplx(4.0_pReal*geomSize(2)/real(grid(2),pReal), 0.0_pReal, pReal) - utilities_getFreqDerivative(3) = & - cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) + 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & - cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) - 1.0_pReal, & - sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & - cmplx(4.0_pReal*geomSize(3)/real(grid(3),pReal), 0.0_pReal, pReal) - - end select - -end function utilities_getFreqDerivative - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate coordinates in current configuration for given defgrad field -! using integration in Fourier space. Similar as in mesh.f90, but using data already defined for -! convolution -!-------------------------------------------------------------------------------------------------- -subroutine utilities_updateIPcoords(F) - use math, only: & - math_mul33x3 - use mesh, only: & - grid, & - grid3, & - grid3Offset, & - geomSize, & - mesh_ipCoordinates - implicit none - - real(pReal), dimension(3,3,grid(1),grid(2),grid3), intent(in) :: F - integer(pInt) :: i, j, k, m - real(pReal), dimension(3) :: step, offset_coords - real(pReal), dimension(3,3) :: Favg - PetscErrorCode :: ierr - external & - MPI_Bcast - -!-------------------------------------------------------------------------------------------------- -! integration in Fourier space - tensorField_real = 0.0_pReal - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F - call utilities_FFTtensorForward() - call utilities_fourierTensorDivergence() - - do k = 1_pInt, grid3; do j = 1_pInt, grid(2) ;do i = 1_pInt, grid1Red - if (any(abs(xi1st(1:3,i,j,k)) > tiny(0.0_pReal))) & - vectorField_fourier(1:3,i,j,k) = vectorField_fourier(1:3,i,j,k)/ & - sum(conjg(-xi1st(1:3,i,j,k))*xi1st(1:3,i,j,k)) - enddo; enddo; enddo - call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) - -!-------------------------------------------------------------------------------------------------- -! average F - if (grid3Offset == 0_pInt) Favg = real(tensorField_fourier(1:3,1:3,1,1,1),pReal)*wgt - call MPI_Bcast(Favg,9,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) - -!-------------------------------------------------------------------------------------------------- -! add average to fluctuation and put (0,0,0) on (0,0,0) - step = geomSize/real(grid, pReal) - if (grid3Offset == 0_pInt) offset_coords = vectorField_real(1:3,1,1,1) - call MPI_Bcast(offset_coords,3,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) - offset_coords = math_mul33x3(Favg,step/2.0_pReal) - offset_coords - m = 1_pInt - do k = 1_pInt,grid3; do j = 1_pInt,grid(2); do i = 1_pInt,grid(1) - mesh_ipCoordinates(1:3,1,m) = vectorField_real(1:3,i,j,k) & - + offset_coords & - + math_mul33x3(Favg,step*real([i,j,k+grid3Offset]-1_pInt,pReal)) - m = m+1_pInt - enddo; enddo; enddo - -end subroutine utilities_updateIPcoords - - -!-------------------------------------------------------------------------------------------------- -!> @brief cleans up -!-------------------------------------------------------------------------------------------------- -subroutine utilities_destroy() - implicit none - - call fftw_destroy_plan(planTensorForth) - call fftw_destroy_plan(planTensorBack) - call fftw_destroy_plan(planVectorForth) - call fftw_destroy_plan(planVectorBack) - call fftw_destroy_plan(planScalarForth) - call fftw_destroy_plan(planScalarBack) - -end subroutine utilities_destroy - - -end module spectral_utilities diff --git a/code/thermal_adiabatic.f90 b/code/thermal_adiabatic.f90 deleted file mode 100644 index 7bb8620e7..000000000 --- a/code/thermal_adiabatic.f90 +++ /dev/null @@ -1,422 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for adiabatic temperature evolution -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module thermal_adiabatic - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - thermal_adiabatic_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - thermal_adiabatic_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - thermal_adiabatic_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - thermal_adiabatic_Noutput !< number of outputs per instance of this thermal model - - enum, bind(c) - enumerator :: undefined_ID, & - temperature_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - thermal_adiabatic_outputID !< ID of each post result output - - - public :: & - thermal_adiabatic_init, & - thermal_adiabatic_updateState, & - thermal_adiabatic_getSourceAndItsTangent, & - thermal_adiabatic_getSpecificHeat, & - thermal_adiabatic_getMassDensity, & - thermal_adiabatic_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine thermal_adiabatic_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - thermal_type, & - thermal_typeInstance, & - homogenization_Noutput, & - THERMAL_ADIABATIC_label, & - THERMAL_adiabatic_ID, & - material_homog, & - mappingHomogenization, & - thermalState, & - thermalMapping, & - thermal_initialT, & - temperature, & - temperatureRate, & - material_partHomogenization - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_ADIABATIC_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(thermal_type == THERMAL_adiabatic_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(thermal_adiabatic_sizePostResults(maxNinstance), source=0_pInt) - allocate(thermal_adiabatic_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(thermal_adiabatic_output (maxval(homogenization_Noutput),maxNinstance)) - thermal_adiabatic_output = '' - allocate(thermal_adiabatic_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(thermal_adiabatic_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (thermal_type(section) == THERMAL_adiabatic_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = thermal_typeInstance(section) ! which instance of my thermal is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('temperature') - thermal_adiabatic_Noutput(instance) = thermal_adiabatic_Noutput(instance) + 1_pInt - thermal_adiabatic_outputID(thermal_adiabatic_Noutput(instance),instance) = temperature_ID - thermal_adiabatic_output(thermal_adiabatic_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingFile - - initializeInstances: do section = 1_pInt, size(thermal_type) - if (thermal_type(section) == THERMAL_adiabatic_ID) then - NofMyHomog=count(material_homog==section) - instance = thermal_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,thermal_adiabatic_Noutput(instance) - select case(thermal_adiabatic_outputID(o,instance)) - case(temperature_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - thermal_adiabatic_sizePostResult(o,instance) = mySize - thermal_adiabatic_sizePostResults(instance) = thermal_adiabatic_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 1_pInt - thermalState(section)%sizeState = sizeState - thermalState(section)%sizePostResults = thermal_adiabatic_sizePostResults(instance) - allocate(thermalState(section)%state0 (sizeState,NofMyHomog), source=thermal_initialT(section)) - allocate(thermalState(section)%subState0(sizeState,NofMyHomog), source=thermal_initialT(section)) - allocate(thermalState(section)%state (sizeState,NofMyHomog), source=thermal_initialT(section)) - - nullify(thermalMapping(section)%p) - thermalMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(temperature(section)%p) - temperature(section)%p => thermalState(section)%state(1,:) - deallocate(temperatureRate(section)%p) - allocate (temperatureRate(section)%p(NofMyHomog), source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine thermal_adiabatic_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates adiabatic change in temperature based on local heat generation model -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_updateState(subdt, ip, el) - use numerics, only: & - err_thermal_tolAbs, & - err_thermal_tolRel - use material, only: & - mappingHomogenization, & - thermalState, & - temperature, & - temperatureRate, & - thermalMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - subdt - logical, dimension(2) :: & - thermal_adiabatic_updateState - integer(pInt) :: & - homog, & - offset - real(pReal) :: & - T, Tdot, dTdot_dT - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,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)) & - <= err_thermal_tolAbs & - .or. abs(T - thermalState(homog)%state(1,offset)) & - <= err_thermal_tolRel*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) - use math, only: & - math_Mandel6to33 - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - thermal_typeInstance, & - phase_Nsources, & - phase_source, & - SOURCE_thermal_dissipation_ID, & - SOURCE_thermal_externalheat_ID - use source_thermal_dissipation, only: & - source_thermal_dissipation_getRateAndItsTangent - use source_thermal_externalheat, only: & - source_thermal_externalheat_getRateAndItsTangent - use crystallite, only: & - crystallite_Tstar_v, & - crystallite_Lp - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - T - real(pReal), intent(out) :: & - Tdot, dTdot_dT - real(pReal) :: & - my_Tdot, my_dTdot_dT - integer(pInt) :: & - phase, & - homog, & - offset, & - instance, & - grain, & - source - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - instance = thermal_typeInstance(homog) - - Tdot = 0.0_pReal - dTdot_dT = 0.0_pReal - do grain = 1, homogenization_Ngrains(homog) - phase = phaseAt(grain,ip,el) - do source = 1, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_thermal_dissipation_ID) - call source_thermal_dissipation_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & - crystallite_Tstar_v(1:6,grain,ip,el), & - crystallite_Lp(1:3,1:3,grain,ip,el), & - grain, ip, el) - - case (SOURCE_thermal_externalheat_ID) - call source_thermal_externalheat_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & - grain, ip, el) - - case default - my_Tdot = 0.0_pReal - my_dTdot_dT = 0.0_pReal - end select - Tdot = Tdot + my_Tdot - dTdot_dT = dTdot_dT + my_dTdot_dT - enddo - enddo - - Tdot = Tdot/homogenization_Ngrains(homog) - dTdot_dT = dTdot_dT/homogenization_Ngrains(homog) - -end subroutine thermal_adiabatic_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized specific heat capacity -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_getSpecificHeat(ip,el) - use lattice, only: & - lattice_specificHeat - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - thermal_adiabatic_getSpecificHeat - integer(pInt) :: & - homog, grain - - thermal_adiabatic_getSpecificHeat = 0.0_pReal - - homog = mappingHomogenization(2,ip,el) - - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - thermal_adiabatic_getSpecificHeat = thermal_adiabatic_getSpecificHeat + & - lattice_specificHeat(material_phase(grain,ip,el)) - enddo - - thermal_adiabatic_getSpecificHeat = & - thermal_adiabatic_getSpecificHeat/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function thermal_adiabatic_getSpecificHeat - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized mass density -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_getMassDensity(ip,el) - use lattice, only: & - lattice_massDensity - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - thermal_adiabatic_getMassDensity - integer(pInt) :: & - homog, grain - - thermal_adiabatic_getMassDensity = 0.0_pReal - - homog = mappingHomogenization(2,ip,el) - - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - thermal_adiabatic_getMassDensity = thermal_adiabatic_getMassDensity + & - lattice_massDensity(material_phase(grain,ip,el)) - enddo - - thermal_adiabatic_getMassDensity = & - thermal_adiabatic_getMassDensity/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function thermal_adiabatic_getMassDensity - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of thermal results -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_postResults(ip,el) - use material, only: & - mappingHomogenization, & - thermal_typeInstance, & - thermalMapping, & - temperature - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(thermal_adiabatic_sizePostResults(thermal_typeInstance(mappingHomogenization(2,ip,el)))) :: & - thermal_adiabatic_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = thermalMapping(homog)%p(ip,el) - instance = thermal_typeInstance(homog) - - c = 0_pInt - thermal_adiabatic_postResults = 0.0_pReal - - do o = 1_pInt,thermal_adiabatic_Noutput(instance) - select case(thermal_adiabatic_outputID(o,instance)) - - case (temperature_ID) - thermal_adiabatic_postResults(c+1_pInt) = temperature(homog)%p(offset) - c = c + 1 - end select - enddo -end function thermal_adiabatic_postResults - -end module thermal_adiabatic diff --git a/code/thermal_conduction.f90 b/code/thermal_conduction.f90 deleted file mode 100644 index 2f9b766eb..000000000 --- a/code/thermal_conduction.f90 +++ /dev/null @@ -1,444 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for temperature evolution from heat conduction -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module thermal_conduction - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - thermal_conduction_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - thermal_conduction_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - thermal_conduction_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - thermal_conduction_Noutput !< number of outputs per instance of this damage - - enum, bind(c) - enumerator :: undefined_ID, & - temperature_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - thermal_conduction_outputID !< ID of each post result output - - - public :: & - thermal_conduction_init, & - thermal_conduction_getSourceAndItsTangent, & - thermal_conduction_getConductivity33, & - thermal_conduction_getSpecificHeat, & - thermal_conduction_getMassDensity, & - thermal_conduction_putTemperatureAndItsRate, & - thermal_conduction_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine thermal_conduction_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - thermal_type, & - thermal_typeInstance, & - homogenization_Noutput, & - THERMAL_conduction_label, & - THERMAL_conduction_ID, & - material_homog, & - mappingHomogenization, & - thermalState, & - thermalMapping, & - thermal_initialT, & - temperature, & - temperatureRate, & - material_partHomogenization - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_CONDUCTION_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(thermal_type == THERMAL_conduction_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(thermal_conduction_sizePostResults(maxNinstance), source=0_pInt) - allocate(thermal_conduction_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(thermal_conduction_output (maxval(homogenization_Noutput),maxNinstance)) - thermal_conduction_output = '' - allocate(thermal_conduction_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(thermal_conduction_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (thermal_type(section) == THERMAL_conduction_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = thermal_typeInstance(section) ! which instance of my thermal is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('temperature') - thermal_conduction_Noutput(instance) = thermal_conduction_Noutput(instance) + 1_pInt - thermal_conduction_outputID(thermal_conduction_Noutput(instance),instance) = temperature_ID - thermal_conduction_output(thermal_conduction_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingFile - - initializeInstances: do section = 1_pInt, size(thermal_type) - if (thermal_type(section) == THERMAL_conduction_ID) then - NofMyHomog=count(material_homog==section) - instance = thermal_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,thermal_conduction_Noutput(instance) - select case(thermal_conduction_outputID(o,instance)) - case(temperature_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - thermal_conduction_sizePostResult(o,instance) = mySize - thermal_conduction_sizePostResults(instance) = thermal_conduction_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 0_pInt - thermalState(section)%sizeState = sizeState - thermalState(section)%sizePostResults = thermal_conduction_sizePostResults(instance) - allocate(thermalState(section)%state0 (sizeState,NofMyHomog)) - allocate(thermalState(section)%subState0(sizeState,NofMyHomog)) - allocate(thermalState(section)%state (sizeState,NofMyHomog)) - - nullify(thermalMapping(section)%p) - thermalMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(temperature (section)%p) - allocate (temperature (section)%p(NofMyHomog), source=thermal_initialT(section)) - deallocate(temperatureRate(section)%p) - allocate (temperatureRate(section)%p(NofMyHomog), source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine thermal_conduction_init - -!-------------------------------------------------------------------------------------------------- -!> @brief returns heat generation rate -!-------------------------------------------------------------------------------------------------- -subroutine thermal_conduction_getSourceAndItsTangent(Tdot, dTdot_dT, T, ip, el) - use math, only: & - math_Mandel6to33 - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - thermal_typeInstance, & - phase_Nsources, & - phase_source, & - SOURCE_thermal_dissipation_ID, & - SOURCE_thermal_externalheat_ID - use source_thermal_dissipation, only: & - source_thermal_dissipation_getRateAndItsTangent - use source_thermal_externalheat, only: & - source_thermal_externalheat_getRateAndItsTangent - use crystallite, only: & - crystallite_Tstar_v, & - crystallite_Lp - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - T - real(pReal), intent(out) :: & - Tdot, dTdot_dT - real(pReal) :: & - my_Tdot, my_dTdot_dT - integer(pInt) :: & - phase, & - homog, & - offset, & - instance, & - grain, & - source - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - instance = thermal_typeInstance(homog) - - Tdot = 0.0_pReal - dTdot_dT = 0.0_pReal - do grain = 1, homogenization_Ngrains(homog) - phase = phaseAt(grain,ip,el) - do source = 1, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_thermal_dissipation_ID) - call source_thermal_dissipation_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & - crystallite_Tstar_v(1:6,grain,ip,el), & - crystallite_Lp(1:3,1:3,grain,ip,el), & - grain, ip, el) - - case (SOURCE_thermal_externalheat_ID) - call source_thermal_externalheat_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & - grain, ip, el) - - case default - my_Tdot = 0.0_pReal - my_dTdot_dT = 0.0_pReal - - end select - Tdot = Tdot + my_Tdot - dTdot_dT = dTdot_dT + my_dTdot_dT - enddo - enddo - - Tdot = Tdot/homogenization_Ngrains(homog) - dTdot_dT = dTdot_dT/homogenization_Ngrains(homog) - -end subroutine thermal_conduction_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized thermal conductivity in reference configuration -!-------------------------------------------------------------------------------------------------- -function thermal_conduction_getConductivity33(ip,el) - use lattice, only: & - lattice_thermalConductivity33 - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - thermal_conduction_getConductivity33 - integer(pInt) :: & - homog, & - grain - - homog = mappingHomogenization(2,ip,el) - - thermal_conduction_getConductivity33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - thermal_conduction_getConductivity33 = thermal_conduction_getConductivity33 + & - crystallite_push33ToRef(grain,ip,el,lattice_thermalConductivity33(:,:,material_phase(grain,ip,el))) - enddo - - thermal_conduction_getConductivity33 = & - thermal_conduction_getConductivity33/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function thermal_conduction_getConductivity33 - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized specific heat capacity -!-------------------------------------------------------------------------------------------------- -function thermal_conduction_getSpecificHeat(ip,el) - use lattice, only: & - lattice_specificHeat - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - thermal_conduction_getSpecificHeat - integer(pInt) :: & - homog, grain - - thermal_conduction_getSpecificHeat = 0.0_pReal - - homog = mappingHomogenization(2,ip,el) - - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - thermal_conduction_getSpecificHeat = thermal_conduction_getSpecificHeat + & - lattice_specificHeat(material_phase(grain,ip,el)) - enddo - - thermal_conduction_getSpecificHeat = & - thermal_conduction_getSpecificHeat/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function thermal_conduction_getSpecificHeat - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized mass density -!-------------------------------------------------------------------------------------------------- -function thermal_conduction_getMassDensity(ip,el) - use lattice, only: & - lattice_massDensity - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - thermal_conduction_getMassDensity - integer(pInt) :: & - homog, grain - - thermal_conduction_getMassDensity = 0.0_pReal - - homog = mappingHomogenization(2,ip,el) - - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - thermal_conduction_getMassDensity = thermal_conduction_getMassDensity + & - lattice_massDensity(material_phase(grain,ip,el)) - enddo - - thermal_conduction_getMassDensity = & - thermal_conduction_getMassDensity/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function thermal_conduction_getMassDensity - -!-------------------------------------------------------------------------------------------------- -!> @brief updates thermal state with solution from heat conduction PDE -!-------------------------------------------------------------------------------------------------- -subroutine thermal_conduction_putTemperatureAndItsRate(T,Tdot,ip,el) - use material, only: & - mappingHomogenization, & - temperature, & - temperatureRate, & - thermalMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - T, & - Tdot - integer(pInt) :: & - homog, & - offset - - homog = mappingHomogenization(2,ip,el) - offset = thermalMapping(homog)%p(ip,el) - temperature (homog)%p(offset) = T - temperatureRate(homog)%p(offset) = Tdot - -end subroutine thermal_conduction_putTemperatureAndItsRate - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of thermal results -!-------------------------------------------------------------------------------------------------- -function thermal_conduction_postResults(ip,el) - use material, only: & - mappingHomogenization, & - thermal_typeInstance, & - temperature, & - thermalMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(thermal_conduction_sizePostResults(thermal_typeInstance(mappingHomogenization(2,ip,el)))) :: & - thermal_conduction_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = thermalMapping(homog)%p(ip,el) - instance = thermal_typeInstance(homog) - - c = 0_pInt - thermal_conduction_postResults = 0.0_pReal - - do o = 1_pInt,thermal_conduction_Noutput(instance) - select case(thermal_conduction_outputID(o,instance)) - - case (temperature_ID) - thermal_conduction_postResults(c+1_pInt) = temperature(homog)%p(offset) - c = c + 1 - end select - enddo -end function thermal_conduction_postResults - -end module thermal_conduction diff --git a/code/thermal_isothermal.f90 b/code/thermal_isothermal.f90 deleted file mode 100644 index 8c9d3a782..000000000 --- a/code/thermal_isothermal.f90 +++ /dev/null @@ -1,65 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for isothermal temperature field -!-------------------------------------------------------------------------------------------------- -module thermal_isothermal - - implicit none - private - - public :: & - thermal_isothermal_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine thermal_isothermal_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog, & - sizeState - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_isothermal_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (thermal_type(homog) == THERMAL_isothermal_ID) then - NofMyHomog = count(material_homog == homog) - sizeState = 0_pInt - thermalState(homog)%sizeState = sizeState - thermalState(homog)%sizePostResults = sizeState - allocate(thermalState(homog)%state0 (sizeState,NofMyHomog), source=0.0_pReal) - allocate(thermalState(homog)%subState0(sizeState,NofMyHomog), source=0.0_pReal) - allocate(thermalState(homog)%state (sizeState,NofMyHomog), source=0.0_pReal) - - deallocate(temperature (homog)%p) - allocate (temperature (homog)%p(1), source=thermal_initialT(homog)) - deallocate(temperatureRate(homog)%p) - allocate (temperatureRate(homog)%p(1), source=0.0_pReal) - - endif myhomog - enddo initializeInstances - - -end subroutine thermal_isothermal_init - -end module thermal_isothermal diff --git a/code/vacancyflux_cahnhilliard.f90 b/code/vacancyflux_cahnhilliard.f90 deleted file mode 100644 index 16a380ffc..000000000 --- a/code/vacancyflux_cahnhilliard.f90 +++ /dev/null @@ -1,606 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for conservative transport of vacancy concentration field -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module vacancyflux_cahnhilliard - use prec, only: & - pReal, & - pInt, & - p_vec - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - vacancyflux_cahnhilliard_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - vacancyflux_cahnhilliard_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - vacancyflux_cahnhilliard_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - vacancyflux_cahnhilliard_Noutput !< number of outputs per instance of this damage - - real(pReal), dimension(:), allocatable, private :: & - vacancyflux_cahnhilliard_flucAmplitude - - type(p_vec), dimension(:), allocatable, private :: & - vacancyflux_cahnhilliard_thermalFluc - - real(pReal), parameter, private :: & - kB = 1.3806488e-23_pReal !< Boltzmann constant in J/Kelvin - - enum, bind(c) - enumerator :: undefined_ID, & - vacancyConc_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - vacancyflux_cahnhilliard_outputID !< ID of each post result output - - - public :: & - vacancyflux_cahnhilliard_init, & - vacancyflux_cahnhilliard_getSourceAndItsTangent, & - vacancyflux_cahnhilliard_getMobility33, & - vacancyflux_cahnhilliard_getDiffusion33, & - vacancyflux_cahnhilliard_getChemPotAndItsTangent, & - vacancyflux_cahnhilliard_putVacancyConcAndItsRate, & - vacancyflux_cahnhilliard_postResults - private :: & - vacancyflux_cahnhilliard_getFormationEnergy, & - vacancyflux_cahnhilliard_getEntropicCoeff, & - vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_cahnhilliard_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - vacancyflux_type, & - vacancyflux_typeInstance, & - homogenization_Noutput, & - VACANCYFLUX_cahnhilliard_label, & - VACANCYFLUX_cahnhilliard_ID, & - material_homog, & - mappingHomogenization, & - vacancyfluxState, & - vacancyfluxMapping, & - vacancyConc, & - vacancyConcRate, & - vacancyflux_initialCv, & - material_partHomogenization, & - material_partPhase - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o,offset - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_cahnhilliard_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(vacancyflux_type == VACANCYFLUX_cahnhilliard_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(vacancyflux_cahnhilliard_sizePostResults(maxNinstance), source=0_pInt) - allocate(vacancyflux_cahnhilliard_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(vacancyflux_cahnhilliard_output (maxval(homogenization_Noutput),maxNinstance)) - vacancyflux_cahnhilliard_output = '' - allocate(vacancyflux_cahnhilliard_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(vacancyflux_cahnhilliard_Noutput (maxNinstance), source=0_pInt) - - allocate(vacancyflux_cahnhilliard_flucAmplitude (maxNinstance)) - allocate(vacancyflux_cahnhilliard_thermalFluc (maxNinstance)) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (vacancyflux_type(section) == VACANCYFLUX_cahnhilliard_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = vacancyflux_typeInstance(section) ! which instance of my vacancyflux is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('vacancyconc') - vacancyflux_cahnhilliard_Noutput(instance) = vacancyflux_cahnhilliard_Noutput(instance) + 1_pInt - vacancyflux_cahnhilliard_outputID(vacancyflux_cahnhilliard_Noutput(instance),instance) = vacancyConc_ID - vacancyflux_cahnhilliard_output(vacancyflux_cahnhilliard_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - case ('vacancyflux_flucamplitude') - vacancyflux_cahnhilliard_flucAmplitude(instance) = IO_floatValue(line,chunkPos,2_pInt) - - end select - endif; endif - enddo parsingHomog - - initializeInstances: do section = 1_pInt, size(vacancyflux_type) - if (vacancyflux_type(section) == VACANCYFLUX_cahnhilliard_ID) then - NofMyHomog=count(material_homog==section) - instance = vacancyflux_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,vacancyflux_cahnhilliard_Noutput(instance) - select case(vacancyflux_cahnhilliard_outputID(o,instance)) - case(vacancyConc_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - vacancyflux_cahnhilliard_sizePostResult(o,instance) = mySize - vacancyflux_cahnhilliard_sizePostResults(instance) = vacancyflux_cahnhilliard_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 0_pInt - vacancyfluxState(section)%sizeState = sizeState - vacancyfluxState(section)%sizePostResults = vacancyflux_cahnhilliard_sizePostResults(instance) - allocate(vacancyfluxState(section)%state0 (sizeState,NofMyHomog)) - allocate(vacancyfluxState(section)%subState0(sizeState,NofMyHomog)) - allocate(vacancyfluxState(section)%state (sizeState,NofMyHomog)) - - allocate(vacancyflux_cahnhilliard_thermalFluc(instance)%p(NofMyHomog)) - do offset = 1_pInt, NofMyHomog - call random_number(vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset)) - vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset) = & - 1.0_pReal - & - vacancyflux_cahnhilliard_flucAmplitude(instance)* & - (vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset) - 0.5_pReal) - enddo - - nullify(vacancyfluxMapping(section)%p) - vacancyfluxMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(vacancyConc (section)%p) - allocate (vacancyConc (section)%p(NofMyHomog), source=vacancyflux_initialCv(section)) - deallocate(vacancyConcRate(section)%p) - allocate (vacancyConcRate(section)%p(NofMyHomog), source=0.0_pReal) - - endif - - enddo initializeInstances - -end subroutine vacancyflux_cahnhilliard_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates homogenized vacancy driving forces -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_cahnhilliard_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - phase_source, & - phase_Nsources, & - SOURCE_vacancy_phenoplasticity_ID, & - SOURCE_vacancy_irradiation_ID, & - SOURCE_vacancy_thermalfluc_ID - use source_vacancy_phenoplasticity, only: & - source_vacancy_phenoplasticity_getRateAndItsTangent - use source_vacancy_irradiation, only: & - source_vacancy_irradiation_getRateAndItsTangent - use source_vacancy_thermalfluc, only: & - source_vacancy_thermalfluc_getRateAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Cv - integer(pInt) :: & - phase, & - grain, & - source - real(pReal) :: & - CvDot, dCvDot_dCv, localCvDot, dLocalCvDot_dCv - - CvDot = 0.0_pReal - dCvDot_dCv = 0.0_pReal - do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) - phase = phaseAt(grain,ip,el) - do source = 1_pInt, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_vacancy_phenoplasticity_ID) - call source_vacancy_phenoplasticity_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) - - case (SOURCE_vacancy_irradiation_ID) - call source_vacancy_irradiation_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) - - case (SOURCE_vacancy_thermalfluc_ID) - call source_vacancy_thermalfluc_getRateAndItsTangent(localCvDot, dLocalCvDot_dCv, grain, ip, el) - - end select - CvDot = CvDot + localCvDot - dCvDot_dCv = dCvDot_dCv + dLocalCvDot_dCv - enddo - enddo - - CvDot = CvDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - dCvDot_dCv = dCvDot_dCv/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - -end subroutine vacancyflux_cahnhilliard_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized vacancy mobility tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function vacancyflux_cahnhilliard_getMobility33(ip,el) - use lattice, only: & - lattice_vacancyfluxMobility33 - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - vacancyflux_cahnhilliard_getMobility33 - integer(pInt) :: & - grain - - vacancyflux_cahnhilliard_getMobility33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - vacancyflux_cahnhilliard_getMobility33 = vacancyflux_cahnhilliard_getMobility33 + & - crystallite_push33ToRef(grain,ip,el,lattice_vacancyfluxMobility33(:,:,material_phase(grain,ip,el))) - enddo - - vacancyflux_cahnhilliard_getMobility33 = & - vacancyflux_cahnhilliard_getMobility33/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function vacancyflux_cahnhilliard_getMobility33 - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized vacancy diffusion tensor in reference configuration -!-------------------------------------------------------------------------------------------------- -function vacancyflux_cahnhilliard_getDiffusion33(ip,el) - use lattice, only: & - lattice_vacancyfluxDiffusion33 - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - use crystallite, only: & - crystallite_push33ToRef - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), dimension(3,3) :: & - vacancyflux_cahnhilliard_getDiffusion33 - integer(pInt) :: & - grain - - vacancyflux_cahnhilliard_getDiffusion33 = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - vacancyflux_cahnhilliard_getDiffusion33 = vacancyflux_cahnhilliard_getDiffusion33 + & - crystallite_push33ToRef(grain,ip,el,lattice_vacancyfluxDiffusion33(:,:,material_phase(grain,ip,el))) - enddo - - vacancyflux_cahnhilliard_getDiffusion33 = & - vacancyflux_cahnhilliard_getDiffusion33/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function vacancyflux_cahnhilliard_getDiffusion33 - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized vacancy formation energy -!-------------------------------------------------------------------------------------------------- -real(pReal) function vacancyflux_cahnhilliard_getFormationEnergy(ip,el) - use lattice, only: & - lattice_vacancyFormationEnergy, & - lattice_vacancyVol, & - lattice_vacancySurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_phase - use mesh, only: & - mesh_element - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - integer(pInt) :: & - grain - - vacancyflux_cahnhilliard_getFormationEnergy = 0.0_pReal - do grain = 1, homogenization_Ngrains(mesh_element(3,el)) - vacancyflux_cahnhilliard_getFormationEnergy = vacancyflux_cahnhilliard_getFormationEnergy + & - lattice_vacancyFormationEnergy(material_phase(grain,ip,el))/ & - lattice_vacancyVol(material_phase(grain,ip,el))/ & - lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) - enddo - - vacancyflux_cahnhilliard_getFormationEnergy = & - vacancyflux_cahnhilliard_getFormationEnergy/ & - homogenization_Ngrains(mesh_element(3,el)) - -end function vacancyflux_cahnhilliard_getFormationEnergy - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized vacancy entropy coefficient -!-------------------------------------------------------------------------------------------------- -real(pReal) function vacancyflux_cahnhilliard_getEntropicCoeff(ip,el) - use lattice, only: & - lattice_vacancyVol, & - lattice_vacancySurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_homog, & - material_phase, & - temperature, & - thermalMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - integer(pInt) :: & - grain - - vacancyflux_cahnhilliard_getEntropicCoeff = 0.0_pReal - do grain = 1, homogenization_Ngrains(material_homog(ip,el)) - vacancyflux_cahnhilliard_getEntropicCoeff = vacancyflux_cahnhilliard_getEntropicCoeff + & - kB/ & - lattice_vacancyVol(material_phase(grain,ip,el))/ & - lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) - enddo - - vacancyflux_cahnhilliard_getEntropicCoeff = & - vacancyflux_cahnhilliard_getEntropicCoeff* & - temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))/ & - homogenization_Ngrains(material_homog(ip,el)) - -end function vacancyflux_cahnhilliard_getEntropicCoeff - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized kinematic contribution to chemical potential -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCv, Cv, ip, el) - use lattice, only: & - lattice_vacancySurfaceEnergy - use material, only: & - homogenization_Ngrains, & - material_homog, & - phase_kinematics, & - phase_Nkinematics, & - material_phase, & - KINEMATICS_vacancy_strain_ID - use crystallite, only: & - crystallite_Tstar_v, & - crystallite_Fi0, & - crystallite_Fi - use kinematics_vacancy_strain, only: & - kinematics_vacancy_strain_ChemPotAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Cv - real(pReal), intent(out) :: & - KPot, dKPot_dCv - real(pReal) :: & - my_KPot, my_dKPot_dCv - integer(pInt) :: & - grain, kinematics - - KPot = 0.0_pReal - dKPot_dCv = 0.0_pReal - do grain = 1_pInt,homogenization_Ngrains(material_homog(ip,el)) - do kinematics = 1_pInt, phase_Nkinematics(material_phase(grain,ip,el)) - select case (phase_kinematics(kinematics,material_phase(grain,ip,el))) - case (KINEMATICS_vacancy_strain_ID) - call kinematics_vacancy_strain_ChemPotAndItsTangent(my_KPot, my_dKPot_dCv, & - crystallite_Tstar_v(1:6,grain,ip,el), & - crystallite_Fi0(1:3,1:3,grain,ip,el), & - crystallite_Fi (1:3,1:3,grain,ip,el), & - grain,ip, el) - - case default - my_KPot = 0.0_pReal - my_dKPot_dCv = 0.0_pReal - - end select - KPot = KPot + my_KPot/lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) - dKPot_dCv = dKPot_dCv + my_dKPot_dCv/lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) - enddo - enddo - - KPot = KPot/homogenization_Ngrains(material_homog(ip,el)) - dKPot_dCv = dKPot_dCv/homogenization_Ngrains(material_homog(ip,el)) - -end subroutine vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized chemical potential and its tangent -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_cahnhilliard_getChemPotAndItsTangent(ChemPot,dChemPot_dCv,Cv,ip,el) - use numerics, only: & - vacancyBoundPenalty, & - vacancyPolyOrder - use material, only: & - mappingHomogenization, & - vacancyflux_typeInstance, & - porosity, & - porosityMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Cv - real(pReal), intent(out) :: & - ChemPot, & - dChemPot_dCv - real(pReal) :: & - VoidPhaseFrac, kBT, KPot, dKPot_dCv - integer(pInt) :: & - homog, o - - homog = mappingHomogenization(2,ip,el) - VoidPhaseFrac = porosity(homog)%p(porosityMapping(homog)%p(ip,el)) - kBT = vacancyflux_cahnhilliard_getEntropicCoeff(ip,el) - - ChemPot = vacancyflux_cahnhilliard_getFormationEnergy(ip,el) - dChemPot_dCv = 0.0_pReal - do o = 1_pInt, vacancyPolyOrder - ChemPot = ChemPot + kBT*((2.0_pReal*Cv - 1.0_pReal)**real(2_pInt*o-1_pInt,pReal))/ & - real(2_pInt*o-1_pInt,pReal) - dChemPot_dCv = dChemPot_dCv + 2.0_pReal*kBT*(2.0_pReal*Cv - 1.0_pReal)**real(2_pInt*o-2_pInt,pReal) - enddo - - ChemPot = VoidPhaseFrac*VoidPhaseFrac*ChemPot & - - 2.0_pReal*(1.0_pReal - Cv)*(1.0_pReal - VoidPhaseFrac)*(1.0_pReal - VoidPhaseFrac) - - dChemPot_dCv = VoidPhaseFrac*VoidPhaseFrac*dChemPot_dCv & - + 2.0_pReal*(1.0_pReal - VoidPhaseFrac)*(1.0_pReal - VoidPhaseFrac) - - call vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCv, Cv, ip, el) - ChemPot = ChemPot + KPot - dChemPot_dCv = dChemPot_dCv + dKPot_dCv - - if (Cv < 0.0_pReal) then - ChemPot = ChemPot - 3.0_pReal*vacancyBoundPenalty*Cv*Cv - dChemPot_dCv = dChemPot_dCv - 6.0_pReal*vacancyBoundPenalty*Cv - elseif (Cv > 1.0_pReal) then - ChemPot = ChemPot + 3.0_pReal*vacancyBoundPenalty*(1.0_pReal - Cv)*(1.0_pReal - Cv) - dChemPot_dCv = dChemPot_dCv - 6.0_pReal*vacancyBoundPenalty*(1.0_pReal - Cv) - endif - - ChemPot = ChemPot* & - vacancyflux_cahnhilliard_thermalFluc(vacancyflux_typeInstance(homog))%p(mappingHomogenization(1,ip,el)) - dChemPot_dCv = dChemPot_dCv* & - vacancyflux_cahnhilliard_thermalFluc(vacancyflux_typeInstance(homog))%p(mappingHomogenization(1,ip,el)) - -end subroutine vacancyflux_cahnhilliard_getChemPotAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief updated vacancy concentration and its rate with solution from transport PDE -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_cahnhilliard_putVacancyConcAndItsRate(Cv,Cvdot,ip,el) - use material, only: & - mappingHomogenization, & - vacancyConc, & - vacancyConcRate, & - vacancyfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Cv, & - Cvdot - integer(pInt) :: & - homog, & - offset - - homog = mappingHomogenization(2,ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - vacancyConc (homog)%p(offset) = Cv - vacancyConcRate(homog)%p(offset) = Cvdot - -end subroutine vacancyflux_cahnhilliard_putVacancyConcAndItsRate - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of vacancy transport results -!-------------------------------------------------------------------------------------------------- -function vacancyflux_cahnhilliard_postResults(ip,el) - use material, only: & - mappingHomogenization, & - vacancyflux_typeInstance, & - vacancyConc, & - vacancyfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(vacancyflux_cahnhilliard_sizePostResults(vacancyflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & - vacancyflux_cahnhilliard_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - instance = vacancyflux_typeInstance(homog) - - c = 0_pInt - vacancyflux_cahnhilliard_postResults = 0.0_pReal - - do o = 1_pInt,vacancyflux_cahnhilliard_Noutput(instance) - select case(vacancyflux_cahnhilliard_outputID(o,instance)) - - case (vacancyConc_ID) - vacancyflux_cahnhilliard_postResults(c+1_pInt) = vacancyConc(homog)%p(offset) - c = c + 1 - end select - enddo -end function vacancyflux_cahnhilliard_postResults - -end module vacancyflux_cahnhilliard diff --git a/code/vacancyflux_isochempot.f90 b/code/vacancyflux_isochempot.f90 deleted file mode 100644 index 35db8d159..000000000 --- a/code/vacancyflux_isochempot.f90 +++ /dev/null @@ -1,329 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for locally evolving vacancy concentration -!> @details to be done -!-------------------------------------------------------------------------------------------------- -module vacancyflux_isochempot - use prec, only: & - pReal, & - pInt - - implicit none - private - integer(pInt), dimension(:), allocatable, public, protected :: & - vacancyflux_isochempot_sizePostResults !< cumulative size of post results - - integer(pInt), dimension(:,:), allocatable, target, public :: & - vacancyflux_isochempot_sizePostResult !< size of each post result output - - character(len=64), dimension(:,:), allocatable, target, public :: & - vacancyflux_isochempot_output !< name of each post result output - - integer(pInt), dimension(:), allocatable, target, public :: & - vacancyflux_isochempot_Noutput !< number of outputs per instance of this damage - - enum, bind(c) - enumerator :: undefined_ID, & - vacancyconc_ID - end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & - vacancyflux_isochempot_outputID !< ID of each post result output - - - public :: & - vacancyflux_isochempot_init, & - vacancyflux_isochempot_updateState, & - vacancyflux_isochempot_getSourceAndItsTangent, & - vacancyflux_isochempot_postResults - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_isochempot_init(fileUnit) - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use IO, only: & - IO_read, & - IO_lc, & - IO_getTag, & - IO_isBlank, & - IO_stringPos, & - IO_stringValue, & - IO_floatValue, & - IO_intValue, & - IO_warning, & - IO_error, & - IO_timeStamp, & - IO_EOF - use material, only: & - vacancyflux_type, & - vacancyflux_typeInstance, & - homogenization_Noutput, & - VACANCYFLUX_isochempot_label, & - VACANCYFLUX_isochempot_ID, & - material_homog, & - mappingHomogenization, & - vacancyfluxState, & - vacancyfluxMapping, & - vacancyConc, & - vacancyConcRate, & - vacancyflux_initialCv, & - material_partHomogenization - use numerics,only: & - worldrank - - implicit none - integer(pInt), intent(in) :: fileUnit - - integer(pInt), allocatable, dimension(:) :: chunkPos - integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o - integer(pInt) :: sizeState - integer(pInt) :: NofMyHomog - character(len=65536) :: & - tag = '', & - line = '' - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_isochempot_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - maxNinstance = int(count(vacancyflux_type == VACANCYFLUX_isochempot_ID),pInt) - if (maxNinstance == 0_pInt) return - - allocate(vacancyflux_isochempot_sizePostResults(maxNinstance), source=0_pInt) - allocate(vacancyflux_isochempot_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) - allocate(vacancyflux_isochempot_output (maxval(homogenization_Noutput),maxNinstance)) - vacancyflux_isochempot_output = '' - allocate(vacancyflux_isochempot_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) - allocate(vacancyflux_isochempot_Noutput (maxNinstance), source=0_pInt) - - rewind(fileUnit) - section = 0_pInt - do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to - line = IO_read(fileUnit) - enddo - - parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part - line = IO_read(fileUnit) - if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part - line = IO_read(fileUnit, .true.) ! reset IO_read - exit - endif - if (IO_getTag(line,'[',']') /= '') then ! next homog section - section = section + 1_pInt ! advance homog section counter - cycle ! skip to next line - endif - - if (section > 0_pInt ) then; if (vacancyflux_type(section) == VACANCYFLUX_isochempot_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran - - instance = vacancyflux_typeInstance(section) ! which instance of my vacancyflux is present homog - chunkPos = IO_stringPos(line) - tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key - select case(tag) - case ('(output)') - select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) - case ('vacancyconc') - vacancyflux_isochempot_Noutput(instance) = vacancyflux_isochempot_Noutput(instance) + 1_pInt - vacancyflux_isochempot_outputID(vacancyflux_isochempot_Noutput(instance),instance) = vacancyconc_ID - vacancyflux_isochempot_output(vacancyflux_isochempot_Noutput(instance),instance) = & - IO_lc(IO_stringValue(line,chunkPos,2_pInt)) - end select - - end select - endif; endif - enddo parsingFile - - initializeInstances: do section = 1_pInt, size(vacancyflux_type) - if (vacancyflux_type(section) == VACANCYFLUX_isochempot_ID) then - NofMyHomog=count(material_homog==section) - instance = vacancyflux_typeInstance(section) - -!-------------------------------------------------------------------------------------------------- -! Determine size of postResults array - outputsLoop: do o = 1_pInt,vacancyflux_isochempot_Noutput(instance) - select case(vacancyflux_isochempot_outputID(o,instance)) - case(vacancyconc_ID) - mySize = 1_pInt - end select - - if (mySize > 0_pInt) then ! any meaningful output found - vacancyflux_isochempot_sizePostResult(o,instance) = mySize - vacancyflux_isochempot_sizePostResults(instance) = vacancyflux_isochempot_sizePostResults(instance) + mySize - endif - enddo outputsLoop - -! allocate state arrays - sizeState = 1_pInt - vacancyfluxState(section)%sizeState = sizeState - vacancyfluxState(section)%sizePostResults = vacancyflux_isochempot_sizePostResults(instance) - allocate(vacancyfluxState(section)%state0 (sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) - allocate(vacancyfluxState(section)%subState0(sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) - allocate(vacancyfluxState(section)%state (sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) - - nullify(vacancyfluxMapping(section)%p) - vacancyfluxMapping(section)%p => mappingHomogenization(1,:,:) - deallocate(vacancyConc(section)%p) - vacancyConc(section)%p => vacancyfluxState(section)%state(1,:) - deallocate(vacancyConcRate(section)%p) - allocate(vacancyConcRate(section)%p(NofMyHomog), source=0.0_pReal) - - endif - - enddo initializeInstances -end subroutine vacancyflux_isochempot_init - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates change in vacancy concentration based on local vacancy generation model -!-------------------------------------------------------------------------------------------------- -function vacancyflux_isochempot_updateState(subdt, ip, el) - use numerics, only: & - err_vacancyflux_tolAbs, & - err_vacancyflux_tolRel - use material, only: & - mappingHomogenization, & - vacancyflux_typeInstance, & - vacancyfluxState, & - vacancyConc, & - vacancyConcRate, & - vacancyfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - subdt - logical, dimension(2) :: & - vacancyflux_isochempot_updateState - integer(pInt) :: & - homog, & - offset, & - instance - real(pReal) :: & - Cv, Cvdot, dCvDot_dCv - - homog = mappingHomogenization(2,ip,el) - offset = mappingHomogenization(1,ip,el) - instance = vacancyflux_typeInstance(homog) - - Cv = vacancyfluxState(homog)%subState0(1,offset) - call vacancyflux_isochempot_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) - Cv = Cv + subdt*Cvdot - - vacancyflux_isochempot_updateState = [ abs(Cv - vacancyfluxState(homog)%state(1,offset)) & - <= err_vacancyflux_tolAbs & - .or. abs(Cv - vacancyfluxState(homog)%state(1,offset)) & - <= err_vacancyflux_tolRel*abs(vacancyfluxState(homog)%state(1,offset)), & - .true.] - - vacancyConc (homog)%p(vacancyfluxMapping(homog)%p(ip,el)) = Cv - vacancyConcRate(homog)%p(vacancyfluxMapping(homog)%p(ip,el)) = & - (vacancyfluxState(homog)%state(1,offset) - vacancyfluxState(homog)%subState0(1,offset))/(subdt+tiny(0.0_pReal)) - -end function vacancyflux_isochempot_updateState - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates homogenized vacancy driving forces -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_isochempot_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) - use material, only: & - homogenization_Ngrains, & - mappingHomogenization, & - phaseAt, phasememberAt, & - phase_source, & - phase_Nsources, & - SOURCE_vacancy_phenoplasticity_ID, & - SOURCE_vacancy_irradiation_ID, & - SOURCE_vacancy_thermalfluc_ID - use source_vacancy_phenoplasticity, only: & - source_vacancy_phenoplasticity_getRateAndItsTangent - use source_vacancy_irradiation, only: & - source_vacancy_irradiation_getRateAndItsTangent - use source_vacancy_thermalfluc, only: & - source_vacancy_thermalfluc_getRateAndItsTangent - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - Cv - integer(pInt) :: & - phase, & - grain, & - source - real(pReal) :: & - CvDot, dCvDot_dCv, localCvDot, dLocalCvDot_dCv - - CvDot = 0.0_pReal - dCvDot_dCv = 0.0_pReal - do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) - phase = phaseAt(grain,ip,el) - do source = 1_pInt, phase_Nsources(phase) - select case(phase_source(source,phase)) - case (SOURCE_vacancy_phenoplasticity_ID) - call source_vacancy_phenoplasticity_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) - - case (SOURCE_vacancy_irradiation_ID) - call source_vacancy_irradiation_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) - - case (SOURCE_vacancy_thermalfluc_ID) - call source_vacancy_thermalfluc_getRateAndItsTangent(localCvDot, dLocalCvDot_dCv, grain, ip, el) - - end select - CvDot = CvDot + localCvDot - dCvDot_dCv = dCvDot_dCv + dLocalCvDot_dCv - enddo - enddo - - CvDot = CvDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - dCvDot_dCv = dCvDot_dCv/homogenization_Ngrains(mappingHomogenization(2,ip,el)) - -end subroutine vacancyflux_isochempot_getSourceAndItsTangent - -!-------------------------------------------------------------------------------------------------- -!> @brief return array of vacancy transport results -!-------------------------------------------------------------------------------------------------- -function vacancyflux_isochempot_postResults(ip,el) - use material, only: & - mappingHomogenization, & - vacancyflux_typeInstance, & - vacancyConc, & - vacancyfluxMapping - - implicit none - integer(pInt), intent(in) :: & - ip, & !< integration point - el !< element - real(pReal), dimension(vacancyflux_isochempot_sizePostResults(vacancyflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & - vacancyflux_isochempot_postResults - - integer(pInt) :: & - instance, homog, offset, o, c - - homog = mappingHomogenization(2,ip,el) - offset = vacancyfluxMapping(homog)%p(ip,el) - instance = vacancyflux_typeInstance(homog) - - c = 0_pInt - vacancyflux_isochempot_postResults = 0.0_pReal - - do o = 1_pInt,vacancyflux_isochempot_Noutput(instance) - select case(vacancyflux_isochempot_outputID(o,instance)) - - case (vacancyconc_ID) - vacancyflux_isochempot_postResults(c+1_pInt) = vacancyConc(homog)%p(offset) - c = c + 1 - end select - enddo -end function vacancyflux_isochempot_postResults - -end module vacancyflux_isochempot diff --git a/code/vacancyflux_isoconc.f90 b/code/vacancyflux_isoconc.f90 deleted file mode 100644 index 63cfb1b62..000000000 --- a/code/vacancyflux_isoconc.f90 +++ /dev/null @@ -1,63 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -! $Id$ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for constant vacancy concentration -!-------------------------------------------------------------------------------------------------- -module vacancyflux_isoconc - - implicit none - private - - public :: & - vacancyflux_isoconc_init - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates all neccessary fields, reads information from material configuration file -!-------------------------------------------------------------------------------------------------- -subroutine vacancyflux_isoconc_init() - use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) - use prec, only: & - pReal, & - pInt - use IO, only: & - IO_timeStamp - use material - use numerics, only: & - worldrank - - implicit none - integer(pInt) :: & - homog, & - NofMyHomog - - mainProcess: if (worldrank == 0) then - write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_isoconc_label//' init -+>>>' - write(6,'(a15,a)') ' Current time: ',IO_timeStamp() -#include "compilation_info.f90" - endif mainProcess - - initializeInstances: do homog = 1_pInt, material_Nhomogenization - - myhomog: if (vacancyflux_type(homog) == VACANCYFLUX_isoconc_ID) then - NofMyHomog = count(material_homog == homog) - vacancyfluxState(homog)%sizeState = 0_pInt - vacancyfluxState(homog)%sizePostResults = 0_pInt - allocate(vacancyfluxState(homog)%state0 (0_pInt,NofMyHomog)) - allocate(vacancyfluxState(homog)%subState0(0_pInt,NofMyHomog)) - allocate(vacancyfluxState(homog)%state (0_pInt,NofMyHomog)) - - deallocate(vacancyConc (homog)%p) - allocate (vacancyConc (homog)%p(1), source=vacancyflux_initialCv(homog)) - deallocate(vacancyConcRate(homog)%p) - allocate (vacancyConcRate(homog)%p(1), source=0.0_pReal) - - endif myhomog - enddo initializeInstances - - -end subroutine vacancyflux_isoconc_init - -end module vacancyflux_isoconc From e33594cb448eba2f5d6c5ce89d1593112b49129c Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Fri, 4 Mar 2016 14:43:29 -0500 Subject: [PATCH 037/183] change code folder to src --- src/CMakeLists.txt | 172 + src/CPFEM.f90 | 705 ++++ src/CPFEM2.f90 | 367 ++ src/DAMASK_abaqus_exp.f | 299 ++ src/DAMASK_abaqus_std.f | 342 ++ src/DAMASK_marc.f90 | 426 +++ src/DAMASK_marc2011.f90 | 1 + src/DAMASK_marc2012.f90 | 1 + src/DAMASK_marc2013.1.f90 | 1 + src/DAMASK_marc2013.f90 | 1 + src/DAMASK_marc2014.2.f90 | 1 + src/DAMASK_marc2014.f90 | 1 + src/DAMASK_marc2015.f90 | 1 + src/DAMASK_spectral.f90 | 751 ++++ src/FEsolving.f90 | 171 + src/IO.f90 | 2470 ++++++++++++ src/Makefile | 701 ++++ src/commercialFEM_fileList.f90 | 59 + src/compilation_info.f90 | 13 + src/constitutive.f90 | 1226 ++++++ src/core_quit.f90 | 15 + src/crystallite.f90 | 4228 +++++++++++++++++++++ src/damage_local.f90 | 327 ++ src/damage_none.f90 | 60 + src/damage_nonlocal.f90 | 380 ++ src/damask.core.pyf | 126 + src/damask_hdf5.f90 | 16 + src/debug.f90 | 476 +++ src/homogenization.f90 | 1396 +++++++ src/homogenization_RGC.f90 | 1558 ++++++++ src/homogenization_isostrain.f90 | 317 ++ src/homogenization_none.f90 | 60 + src/hydrogenflux_cahnhilliard.f90 | 513 +++ src/hydrogenflux_isoconc.f90 | 63 + src/kinematics_cleavage_opening.f90 | 303 ++ src/kinematics_hydrogen_strain.f90 | 264 ++ src/kinematics_slipplane_opening.f90 | 323 ++ src/kinematics_thermal_expansion.f90 | 228 ++ src/kinematics_vacancy_strain.f90 | 265 ++ src/lattice.f90 | 2239 +++++++++++ src/libs.f90 | 14 + src/material.f90 | 1615 ++++++++ src/math.f90 | 2678 +++++++++++++ src/mesh.f90 | 4784 ++++++++++++++++++++++++ src/numerics.f90 | 726 ++++ src/plastic_disloUCLA.f90 | 2116 +++++++++++ src/plastic_dislotwin.f90 | 2542 +++++++++++++ src/plastic_isotropic.f90 | 678 ++++ src/plastic_j2.f90 | 579 +++ src/plastic_none.f90 | 109 + src/plastic_nonlocal.f90 | 4031 ++++++++++++++++++++ src/plastic_phenoplus.f90 | 1419 +++++++ src/plastic_phenopowerlaw.f90 | 1226 ++++++ src/plastic_titanmod.f90 | 1913 ++++++++++ src/porosity_none.f90 | 61 + src/porosity_phasefield.f90 | 450 +++ src/prec.f90 | 192 + src/quit__genmod.f90 | 8 + src/source_damage_anisoBrittle.f90 | 425 +++ src/source_damage_anisoDuctile.f90 | 415 ++ src/source_damage_isoBrittle.f90 | 383 ++ src/source_damage_isoDuctile.f90 | 350 ++ src/source_thermal_dissipation.f90 | 220 ++ src/source_thermal_externalheat.f90 | 277 ++ src/source_vacancy_irradiation.f90 | 253 ++ src/source_vacancy_phenoplasticity.f90 | 215 ++ src/source_vacancy_thermalfluc.f90 | 255 ++ src/spectral_damage.f90 | 414 ++ src/spectral_interface.f90 | 568 +++ src/spectral_mech_AL.f90 | 715 ++++ src/spectral_mech_Basic.f90 | 569 +++ src/spectral_mech_Polarisation.f90 | 712 ++++ src/spectral_thermal.f90 | 419 +++ src/spectral_utilities.f90 | 1262 +++++++ src/thermal_adiabatic.f90 | 422 +++ src/thermal_conduction.f90 | 444 +++ src/thermal_isothermal.f90 | 65 + src/vacancyflux_cahnhilliard.f90 | 606 +++ src/vacancyflux_isochempot.f90 | 329 ++ src/vacancyflux_isoconc.f90 | 63 + 80 files changed, 55388 insertions(+) create mode 100644 src/CMakeLists.txt create mode 100644 src/CPFEM.f90 create mode 100644 src/CPFEM2.f90 create mode 100644 src/DAMASK_abaqus_exp.f create mode 100644 src/DAMASK_abaqus_std.f create mode 100644 src/DAMASK_marc.f90 create mode 120000 src/DAMASK_marc2011.f90 create mode 120000 src/DAMASK_marc2012.f90 create mode 120000 src/DAMASK_marc2013.1.f90 create mode 120000 src/DAMASK_marc2013.f90 create mode 120000 src/DAMASK_marc2014.2.f90 create mode 120000 src/DAMASK_marc2014.f90 create mode 120000 src/DAMASK_marc2015.f90 create mode 100644 src/DAMASK_spectral.f90 create mode 100644 src/FEsolving.f90 create mode 100644 src/IO.f90 create mode 100644 src/Makefile create mode 100644 src/commercialFEM_fileList.f90 create mode 100644 src/compilation_info.f90 create mode 100644 src/constitutive.f90 create mode 100644 src/core_quit.f90 create mode 100644 src/crystallite.f90 create mode 100644 src/damage_local.f90 create mode 100644 src/damage_none.f90 create mode 100644 src/damage_nonlocal.f90 create mode 100644 src/damask.core.pyf create mode 100644 src/damask_hdf5.f90 create mode 100644 src/debug.f90 create mode 100644 src/homogenization.f90 create mode 100644 src/homogenization_RGC.f90 create mode 100644 src/homogenization_isostrain.f90 create mode 100644 src/homogenization_none.f90 create mode 100644 src/hydrogenflux_cahnhilliard.f90 create mode 100644 src/hydrogenflux_isoconc.f90 create mode 100644 src/kinematics_cleavage_opening.f90 create mode 100644 src/kinematics_hydrogen_strain.f90 create mode 100644 src/kinematics_slipplane_opening.f90 create mode 100644 src/kinematics_thermal_expansion.f90 create mode 100644 src/kinematics_vacancy_strain.f90 create mode 100644 src/lattice.f90 create mode 100644 src/libs.f90 create mode 100644 src/material.f90 create mode 100644 src/math.f90 create mode 100644 src/mesh.f90 create mode 100644 src/numerics.f90 create mode 100644 src/plastic_disloUCLA.f90 create mode 100644 src/plastic_dislotwin.f90 create mode 100644 src/plastic_isotropic.f90 create mode 100644 src/plastic_j2.f90 create mode 100644 src/plastic_none.f90 create mode 100644 src/plastic_nonlocal.f90 create mode 100644 src/plastic_phenoplus.f90 create mode 100644 src/plastic_phenopowerlaw.f90 create mode 100644 src/plastic_titanmod.f90 create mode 100644 src/porosity_none.f90 create mode 100644 src/porosity_phasefield.f90 create mode 100644 src/prec.f90 create mode 100644 src/quit__genmod.f90 create mode 100644 src/source_damage_anisoBrittle.f90 create mode 100644 src/source_damage_anisoDuctile.f90 create mode 100644 src/source_damage_isoBrittle.f90 create mode 100644 src/source_damage_isoDuctile.f90 create mode 100644 src/source_thermal_dissipation.f90 create mode 100644 src/source_thermal_externalheat.f90 create mode 100644 src/source_vacancy_irradiation.f90 create mode 100644 src/source_vacancy_phenoplasticity.f90 create mode 100644 src/source_vacancy_thermalfluc.f90 create mode 100644 src/spectral_damage.f90 create mode 100644 src/spectral_interface.f90 create mode 100644 src/spectral_mech_AL.f90 create mode 100644 src/spectral_mech_Basic.f90 create mode 100644 src/spectral_mech_Polarisation.f90 create mode 100644 src/spectral_thermal.f90 create mode 100644 src/spectral_utilities.f90 create mode 100644 src/thermal_adiabatic.f90 create mode 100644 src/thermal_conduction.f90 create mode 100644 src/thermal_isothermal.f90 create mode 100644 src/vacancyflux_cahnhilliard.f90 create mode 100644 src/vacancyflux_isochempot.f90 create mode 100644 src/vacancyflux_isoconc.f90 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..c1abf4d4e --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,172 @@ +# The dependency detection in CMake is not functioning for Fortran +# !!! EXPLICIT DEPENDENCY DECLARATION !!! + +add_library(DAMASK_PREC "prec.f90") + +if (SPECTRAL) + add_library(DAMASK_INTERFACE "spectral_interface.f90") +elseif(FEM) + add_library(DAMASK_INTERFACE "DAMASK_FEM_interface.f90") +endif(SPECTRAL) +target_link_libraries(DAMASK_INTERFACE DAMASK_PREC) + +add_library(DAMASK_IO "IO.f90") +target_link_libraries(DAMASK_IO DAMASK_INTERFACE) + +add_library(DAMASK_LIBS "libs.f90") +target_link_libraries(DAMASK_LIBS DAMASK_IO) + +add_library(DAMASK_NUMERICS "numerics.f90") +target_link_libraries(DAMASK_NUMERICS DAMASK_LIBS) + +add_library(DAMASK_DEBUG "debug.f90") +target_link_libraries(DAMASK_DEBUG DAMASK_NUMERICS) + +add_library(DAMASK_FEsolving "FEsolving.f90") +target_link_libraries(DAMASK_FEsolving DAMASK_DEBUG) + +add_library(DAMASK_MATH "math.f90") +target_link_libraries(DAMASK_MATH DAMASK_FEsolving) + +# SPECTRAL solver and FEM solver use different mesh +# source files +if (SPECTRAL) + add_library(DAMASK_MESH "mesh.f90") + target_link_libraries(DAMASK_MESH DAMASK_MATH) +endif(SPECTRAL) +if (FEM) + add_library(DAMASK_FEZoo "FEZoo.f90") + target_link_libraries(DAMASK_FEZoo DAMASK_MATH) + add_library(DAMASK_MESH "meshFEM.f90") + target_link_libraries(DAMASK_MESH DAMASK_FEZoo) +endif(FEM) + + +add_library(DAMASK_MATERIAL "material.f90") +target_link_libraries(DAMASK_MATERIAL DAMASK_MESH) + +add_library(DAMASK_LATTICE "lattice.f90") +target_link_libraries(DAMASK_LATTICE DAMASK_MATERIAL) +add_library(DAMASK_DRIVERS ALIAS DAMASK_LATTICE) + +# For each modular section +add_library (DAMASK_PLASTIC "plastic_dislotwin.f90" + "plastic_disloUCLA.f90" + "plastic_isotropic.f90" + "plastic_j2.f90" + "plastic_phenopowerlaw.f90" + "plastic_titanmod.f90" + "plastic_nonlocal.f90" + "plastic_none.f90" + "plastic_phenoplus.f90") +target_link_libraries(DAMASK_PLASTIC DAMASK_DRIVERS) + +add_library (DAMASK_KINEMATICS "kinematics_cleavage_opening.f90" + "kinematics_slipplane_opening.f90" + "kinematics_thermal_expansion.f90" + "kinematics_vacancy_strain.f90" + "kinematics_hydrogen_strain.f90") +target_link_libraries(DAMASK_KINEMATICS DAMASK_DRIVERS) + +add_library (DAMASK_SOURCE "source_thermal_dissipation.f90" + "source_thermal_externalheat.f90" + "source_damage_isoBrittle.f90" + "source_damage_isoDuctile.f90" + "source_damage_anisoBrittle.f90" + "source_damage_anisoDuctile.f90" + "source_vacancy_phenoplasticity.f90" + "source_vacancy_irradiation.f90" + "source_vacancy_thermalfluc.f90") +target_link_libraries(DAMASK_SOURCE DAMASK_DRIVERS) + +add_library(DAMASK_CONSTITUTIVE "constitutive.f90") +target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_PLASTIC ) +target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_KINEMATICS) +target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_SOURCE ) + +add_library(DAMASK_CRYSTALLITE "crystallite.f90") +target_link_libraries(DAMASK_CRYSTALLITE DAMASK_CONSTITUTIVE) + +add_library(DAMASK_HOMOGENIZATION "homogenization_RGC.f90" + "homogenization_isostrain.f90" + "homogenization_none.f90") +target_link_libraries(DAMASK_HOMOGENIZATION DAMASK_CRYSTALLITE) + +add_library(DAMASK_HYDROGENFLUX "hydrogenflux_isoconc.f90" + "hydrogenflux_cahnhilliard.f90") +target_link_libraries(DAMASK_HYDROGENFLUX DAMASK_CRYSTALLITE) + +add_library(DAMASK_POROSITY "porosity_none.f90" + "porosity_phasefield.f90") +target_link_libraries(DAMASK_POROSITY DAMASK_CRYSTALLITE) + +add_library(DAMASK_VACANCYFLUX "vacancyflux_isoconc.f90" + "vacancyflux_isochempot.f90" + "vacancyflux_cahnhilliard.f90") +target_link_libraries(DAMASK_VACANCYFLUX DAMASK_CRYSTALLITE) + +add_library(DAMASK_DAMAGE "damage_none.f90" + "damage_local.f90" + "damage_nonlocal.f90") +target_link_libraries(DAMASK_DAMAGE DAMASK_CRYSTALLITE) + +add_library(DAMASK_THERMAL "thermal_isothermal.f90" + "thermal_adiabatic.f90" + "thermal_conduction.f90") +target_link_libraries(DAMASK_THERMAL DAMASK_CRYSTALLITE) + +add_library(DAMASK_ENGINE "homogenization.f90") +target_link_libraries(DAMASK_ENGINE DAMASK_THERMAL ) +target_link_libraries(DAMASK_ENGINE DAMASK_DAMAGE ) +target_link_libraries(DAMASK_ENGINE DAMASK_VACANCYFLUX ) +target_link_libraries(DAMASK_ENGINE DAMASK_POROSITY ) +target_link_libraries(DAMASK_ENGINE DAMASK_HYDROGENFLUX ) +target_link_libraries(DAMASK_ENGINE DAMASK_HOMOGENIZATION) + + +if (FEM) + add_library(DAMASK_CPFE "CPFEM.f90") + target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) + + add_library(DAMASK_FEM_UTILITY "FEM_utilities.f90") + target_link_libraries(DAMASK_FEM_UTILITY DAMASK_CPFE) + + add_library(DAMASK_FEM_BASE "FEM_hydrogenflux.f90" + "FEM_porosity.f90" + "FEM_vacancyflux.f90" + "FEM_damage.f90" + "FEM_thermal.f90" + "FEM_mech.f90") + target_link_libraries(DAMASK_FEM_BASE DAMASK_FEM_UTILITY) + + add_library(DAMASK_FEM_DRIVER "DAMASK_FEM_driver.f90") + target_link_libraries(DAMASK_FEM_DRIVER DAMASK_FEM_BASE) + + add_executable(DAMASK_FEM.exe "DAMASK_FEM_driver.f90") + target_link_libraries(DAMASK_FEM.exe DAMASK_FEM_DRIVER) +endif(FEM) + +if (SPECTRAL) + add_library(DAMASK_CPFE "CPFEM2.f90") + target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) + + add_library(DAMASK_SPECTRAL_UTILITY spectral_utilities.f90) + target_link_libraries(DAMASK_SPECTRAL_UTILITY DAMASK_CPFE) + + add_library(DAMASK_SPECTRAL_BASE "spectral_thermal.f90" + "spectral_damage.f90") + target_link_libraries(DAMASK_SPECTRAL_BASE DAMASK_SPECTRAL_UTILITY) + + add_library(DAMASK_SPECTRAL_MECH "spectral_mech_AL.f90" + "spectral_mech_Polarisation.f90" + "spectral_mech_Basic.f90") + target_link_libraries(DAMASK_SPECTRAL_MECH DAMASK_SPECTRAL_UTILITY) + + add_library(DAMASK_EXE "DAMASK_spectral.f90") + target_link_libraries(DAMASK_EXE DAMASK_CPFE ) + target_link_libraries(DAMASK_EXE DAMASK_SPECTRAL_BASE) + target_link_libraries(DAMASK_EXE DAMASK_SPECTRAL_MECH) + + add_executable(DAMASKSpectral.exe "DAMASK_spectral.f90") + target_link_libraries(DAMASKSpectral.exe DAMASK_EXE) +endif(SPECTRAL) \ No newline at end of file diff --git a/src/CPFEM.f90 b/src/CPFEM.f90 new file mode 100644 index 000000000..91c3eaa6f --- /dev/null +++ b/src/CPFEM.f90 @@ -0,0 +1,705 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief CPFEM engine +!-------------------------------------------------------------------------------------------------- +module CPFEM + use prec, only: & + pReal, & + pInt + + implicit none + private +#if defined(Marc4DAMASK) || defined(Abaqus) + real(pReal), parameter, private :: & + CPFEM_odd_stress = 1e15_pReal, & !< return value for stress in case of ping pong dummy cycle + CPFEM_odd_jacobian = 1e50_pReal !< return value for jacobian in case of ping pong dummy cycle + real(pReal), dimension (:,:,:), allocatable, private :: & + CPFEM_cs !< Cauchy stress + real(pReal), dimension (:,:,:,:), allocatable, private :: & + CPFEM_dcsdE !< Cauchy stress tangent + real(pReal), dimension (:,:,:,:), allocatable, private :: & + CPFEM_dcsdE_knownGood !< known good tangent +#endif + integer(pInt), public :: & + cycleCounter = 0_pInt, & !< needs description + theInc = -1_pInt, & !< needs description + lastLovl = 0_pInt, & !< lovl in previous call to marc hypela2 + lastStep = 0_pInt !< kstep in previous call to abaqus umat + real(pReal), public :: & + theTime = 0.0_pReal, & !< needs description + theDelta = 0.0_pReal + logical, public :: & + outdatedFFN1 = .false., & !< needs description + lastIncConverged = .false., & !< needs description + outdatedByNewInc = .false. !< needs description + + logical, public, protected :: & + CPFEM_init_done = .false. !< remember whether init has been done already + logical, private :: & + CPFEM_calc_done = .false. !< remember whether first ip has already calced the results + + integer(pInt), parameter, public :: & + CPFEM_COLLECT = 2_pInt**0_pInt, & + CPFEM_CALCRESULTS = 2_pInt**1_pInt, & + CPFEM_AGERESULTS = 2_pInt**2_pInt, & + CPFEM_BACKUPJACOBIAN = 2_pInt**3_pInt, & + CPFEM_RESTOREJACOBIAN = 2_pInt**4_pInt + + + public :: & + CPFEM_general, & + CPFEM_initAll + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief call (thread safe) all module initializations +!-------------------------------------------------------------------------------------------------- +subroutine CPFEM_initAll(el,ip) + use prec, only: & + prec_init + use numerics, only: & + numerics_init + use debug, only: & + debug_init + use FEsolving, only: & + FE_init + use math, only: & + math_init + use mesh, only: & + mesh_init + use lattice, only: & + lattice_init + use material, only: & + material_init + use constitutive, only: & + constitutive_init + use crystallite, only: & + crystallite_init + use homogenization, only: & + homogenization_init + use IO, only: & + IO_init + use DAMASK_interface +#ifdef FEM + use FEZoo, only: & + FEZoo_init +#endif + + implicit none + integer(pInt), intent(in) :: el, & !< FE el number + ip !< FE integration point number + + !$OMP CRITICAL (init) + if (.not. CPFEM_init_done) then + call DAMASK_interface_init ! Spectral and FEM interface to commandline + call prec_init + call IO_init +#ifdef FEM + call FEZoo_init +#endif + call numerics_init + call debug_init + call math_init + call FE_init + call mesh_init(ip, el) ! pass on coordinates to alter calcMode of first ip + call lattice_init + call material_init + call constitutive_init + call crystallite_init + call homogenization_init + call CPFEM_init + CPFEM_init_done = .true. + endif + !$OMP END CRITICAL (init) + +end subroutine CPFEM_initAll + + +!-------------------------------------------------------------------------------------------------- +!> @brief allocate the arrays defined in module CPFEM and initialize them +!-------------------------------------------------------------------------------------------------- +subroutine CPFEM_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pInt + use IO, only: & + IO_read_realFile,& + IO_read_intFile, & + IO_timeStamp, & + IO_error + use numerics, only: & + worldrank + use debug, only: & + debug_level, & + debug_CPFEM, & + debug_levelBasic, & + debug_levelExtensive + use FEsolving, only: & +#if defined(Marc4DAMASK) || defined(Abaqus) + symmetricSolver, & +#endif + restartRead, & + modelName +#if defined(Marc4DAMASK) || defined(Abaqus) + use mesh, only: & + mesh_NcpElems, & + mesh_maxNips +#endif + use material, only: & + material_phase, & + homogState, & + phase_plasticity, & + plasticState, & + material_Nhomogenization + use crystallite, only: & + crystallite_F0, & + crystallite_Fp0, & + crystallite_Lp0, & + crystallite_Fi0, & + crystallite_Li0, & + crystallite_dPdF0, & + crystallite_Tstar0_v + + implicit none + integer(pInt) :: k,l,m,ph,homog + character(len=1024) :: rankStr + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- CPFEM init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +#if defined(Marc4DAMASK) || defined(Abaqus) + ! initialize stress and jacobian to zero + allocate(CPFEM_cs(6,mesh_maxNips,mesh_NcpElems)) ; CPFEM_cs = 0.0_pReal + allocate(CPFEM_dcsdE(6,6,mesh_maxNips,mesh_NcpElems)) ; CPFEM_dcsdE = 0.0_pReal + allocate(CPFEM_dcsdE_knownGood(6,6,mesh_maxNips,mesh_NcpElems)) ; CPFEM_dcsdE_knownGood = 0.0_pReal +#endif + + ! *** restore the last converged values of each essential variable from the binary file + if (restartRead) then + if (iand(debug_level(debug_CPFEM), debug_levelExtensive) /= 0_pInt) then + write(6,'(a)') '<< CPFEM >> restored state variables of last converged step from binary files' + flush(6) + endif + + write(rankStr,'(a1,i0)')'_',worldrank + + call IO_read_intFile(777,'recordedPhase'//trim(rankStr),modelName,size(material_phase)) + read (777,rec=1) material_phase + close (777) + + call IO_read_realFile(777,'convergedF'//trim(rankStr),modelName,size(crystallite_F0)) + read (777,rec=1) crystallite_F0 + close (777) + + call IO_read_realFile(777,'convergedFp'//trim(rankStr),modelName,size(crystallite_Fp0)) + read (777,rec=1) crystallite_Fp0 + close (777) + + call IO_read_realFile(777,'convergedFi'//trim(rankStr),modelName,size(crystallite_Fi0)) + read (777,rec=1) crystallite_Fi0 + close (777) + + call IO_read_realFile(777,'convergedLp'//trim(rankStr),modelName,size(crystallite_Lp0)) + read (777,rec=1) crystallite_Lp0 + close (777) + + call IO_read_realFile(777,'convergedLi'//trim(rankStr),modelName,size(crystallite_Li0)) + read (777,rec=1) crystallite_Li0 + close (777) + + call IO_read_realFile(777,'convergeddPdF'//trim(rankStr),modelName,size(crystallite_dPdF0)) + read (777,rec=1) crystallite_dPdF0 + close (777) + + call IO_read_realFile(777,'convergedTstar'//trim(rankStr),modelName,size(crystallite_Tstar0_v)) + read (777,rec=1) crystallite_Tstar0_v + close (777) + + call IO_read_realFile(777,'convergedStateConst'//trim(rankStr),modelName) + m = 0_pInt + readPlasticityInstances: do ph = 1_pInt, size(phase_plasticity) + do k = 1_pInt, plasticState(ph)%sizeState + do l = 1, size(plasticState(ph)%state0(1,:)) + m = m+1_pInt + read(777,rec=m) plasticState(ph)%state0(k,l) + enddo; enddo + enddo readPlasticityInstances + close (777) + + call IO_read_realFile(777,'convergedStateHomog'//trim(rankStr),modelName) + m = 0_pInt + readHomogInstances: do homog = 1_pInt, material_Nhomogenization + do k = 1_pInt, homogState(homog)%sizeState + do l = 1, size(homogState(homog)%state0(1,:)) + m = m+1_pInt + read(777,rec=m) homogState(homog)%state0(k,l) + enddo; enddo + enddo readHomogInstances + close (777) + +#if defined(Marc4DAMASK) || defined(Abaqus) + call IO_read_realFile(777,'convergeddcsdE',modelName,size(CPFEM_dcsdE)) + read (777,rec=1) CPFEM_dcsdE + close (777) +#endif + restartRead = .false. + endif +#if defined(Marc4DAMASK) || defined(Abaqus) + if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0) then + write(6,'(a32,1x,6(i8,1x))') 'CPFEM_cs: ', shape(CPFEM_cs) + write(6,'(a32,1x,6(i8,1x))') 'CPFEM_dcsdE: ', shape(CPFEM_dcsdE) + write(6,'(a32,1x,6(i8,1x),/)') 'CPFEM_dcsdE_knownGood: ', shape(CPFEM_dcsdE_knownGood) + write(6,'(a32,l1)') 'symmetricSolver: ', symmetricSolver + endif +#endif + flush(6) + +end subroutine CPFEM_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief perform initialization at first call, update variables and call the actual material model +!-------------------------------------------------------------------------------------------------- +#if defined(Marc4DAMASK) || defined(Abaqus) +subroutine CPFEM_general(mode, parallelExecution, ffn, ffn1, temperature_inp, dt, elFE, ip, cauchyStress, jacobian) +#else +subroutine CPFEM_general(mode, ffn, ffn1, dt, elFE, ip) +#endif + use numerics, only: & + defgradTolerance, & + iJacoStiffness, & + worldrank + use debug, only: & + debug_level, & + debug_CPFEM, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & +#if defined(Marc4DAMASK) || defined(Abaqus) + debug_stressMaxLocation, & + debug_stressMinLocation, & + debug_jacobianMaxLocation, & + debug_jacobianMinLocation, & + debug_stressMax, & + debug_stressMin, & + debug_jacobianMax, & + debug_jacobianMin, & +#endif + debug_e, & + debug_i + use FEsolving, only: & + terminallyIll, & + FEsolving_execElem, & + FEsolving_execIP, & + restartWrite + use math, only: & + math_identity2nd, & + math_mul33x33, & + math_det33, & + math_transpose33, & + math_I3, & + math_Mandel3333to66, & + math_Mandel66to3333, & + math_Mandel33to6, & + math_Mandel6to33 + use mesh, only: & + mesh_FEasCP, & + mesh_NcpElems, & + mesh_maxNips, & + mesh_element + use material, only: & + microstructure_elemhomo, & + plasticState, & + sourceState, & + homogState, & + thermalState, & + damageState, & + vacancyfluxState, & + hydrogenfluxState, & + phaseAt, phasememberAt, & + material_phase, & + phase_plasticity, & + temperature, & + thermalMapping, & + phase_Nsources, & + material_homog, & + material_Nhomogenization + use crystallite, only: & + crystallite_partionedF,& + crystallite_F0, & + crystallite_Fp0, & + crystallite_Fp, & + crystallite_Fi0, & + crystallite_Fi, & + crystallite_Lp0, & + crystallite_Lp, & + crystallite_Li0, & + crystallite_Li, & + crystallite_dPdF0, & + crystallite_dPdF, & + crystallite_Tstar0_v, & + crystallite_Tstar_v + use homogenization, only: & + materialpoint_F, & + materialpoint_F0, & +#if defined(Marc4DAMASK) || defined(Abaqus) + materialpoint_P, & + materialpoint_dPdF, & + materialpoint_results, & + materialpoint_sizeResults, & +#endif + materialpoint_stressAndItsTangent, & + materialpoint_postResults + use IO, only: & + IO_write_jobRealFile, & + IO_warning + use DAMASK_interface + + implicit none + integer(pInt), intent(in) :: elFE, & !< FE element number + ip !< integration point number + real(pReal), intent(in) :: dt !< time increment + real(pReal), dimension (3,3), intent(in) :: ffn, & !< deformation gradient for t=t0 + ffn1 !< deformation gradient for t=t1 + integer(pInt), intent(in) :: mode !< computation mode 1: regular computation plus aging of results +#if defined(Marc4DAMASK) || defined(Abaqus) + real(pReal), intent(in) :: temperature_inp !< temperature + logical, intent(in) :: parallelExecution !< flag indicating parallel computation of requested IPs + real(pReal), dimension(6), intent(out) :: cauchyStress !< stress vector in Mandel notation + real(pReal), dimension(6,6), intent(out) :: jacobian !< jacobian in Mandel notation (Consistent tangent dcs/dE) + + real(pReal) J_inverse, & ! inverse of Jacobian + rnd + real(pReal), dimension (3,3) :: Kirchhoff, & ! Piola-Kirchhoff stress in Matrix notation + cauchyStress33 ! stress vector in Matrix notation + real(pReal), dimension (3,3,3,3) :: H_sym, & + H, & + jacobian3333 ! jacobian in Matrix notation +#else + logical, parameter :: parallelExecution = .true. +#endif + + integer(pInt) elCP, & ! crystal plasticity element number + i, j, k, l, m, n, ph, homog, mySource + logical updateJaco ! flag indicating if JAcobian has to be updated + character(len=1024) :: rankStr + +#if defined(Marc4DAMASK) || defined(Abaqus) + elCP = mesh_FEasCP('elem',elFE) +#else + elCP = elFE +#endif + + if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt & + .and. elCP == debug_e .and. ip == debug_i) then + write(6,'(/,a)') '#############################################' + write(6,'(a1,a22,1x,i8,a13)') '#','element', elCP, '#' + write(6,'(a1,a22,1x,i8,a13)') '#','ip', ip, '#' + write(6,'(a1,a22,1x,f15.7,a6)') '#','theTime', theTime, '#' + write(6,'(a1,a22,1x,f15.7,a6)') '#','theDelta', theDelta, '#' + write(6,'(a1,a22,1x,i8,a13)') '#','theInc', theInc, '#' + write(6,'(a1,a22,1x,i8,a13)') '#','cycleCounter', cycleCounter, '#' + write(6,'(a1,a22,1x,i8,a13)') '#','computationMode',mode, '#' + if (terminallyIll) & + write(6,'(a,/)') '# --- terminallyIll --- #' + write(6,'(a,/)') '#############################################'; flush (6) + endif + + +#if defined(Marc4DAMASK) || defined(Abaqus) + if (iand(mode, CPFEM_BACKUPJACOBIAN) /= 0_pInt) & + CPFEM_dcsde_knownGood = CPFEM_dcsde + if (iand(mode, CPFEM_RESTOREJACOBIAN) /= 0_pInt) & + CPFEM_dcsde = CPFEM_dcsde_knownGood +#endif + + !*** age results and write restart data if requested + if (iand(mode, CPFEM_AGERESULTS) /= 0_pInt) then + crystallite_F0 = crystallite_partionedF ! crystallite deformation (_subF is perturbed...) + crystallite_Fp0 = crystallite_Fp ! crystallite plastic deformation + crystallite_Lp0 = crystallite_Lp ! crystallite plastic velocity + crystallite_Fi0 = crystallite_Fi ! crystallite intermediate deformation + crystallite_Li0 = crystallite_Li ! crystallite intermediate velocity + crystallite_dPdF0 = crystallite_dPdF ! crystallite stiffness + crystallite_Tstar0_v = crystallite_Tstar_v ! crystallite 2nd Piola Kirchhoff stress + + forall ( i = 1:size(plasticState )) plasticState(i)%state0 = plasticState(i)%state ! copy state in this lenghty way because: A component cannot be an array if the encompassing structure is an array + do i = 1, size(sourceState) + do mySource = 1,phase_Nsources(i) + sourceState(i)%p(mySource)%state0 = sourceState(i)%p(mySource)%state ! copy state in this lenghty way because: A component cannot be an array if the encompassing structure is an array + enddo; enddo + if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt) then + write(6,'(a)') '<< CPFEM >> aging states' + if (debug_e <= mesh_NcpElems .and. debug_i <= mesh_maxNips) then + write(6,'(a,1x,i8,1x,i2,1x,i4,/,(12x,6(e20.8,1x)),/)') & + '<< CPFEM >> aged state of elFE ip grain',debug_e, debug_i, 1, & + plasticState(phaseAt(1,debug_i,debug_e))%state(:,phasememberAt(1,debug_i,debug_e)) + endif + endif + + do homog = 1_pInt, material_Nhomogenization + homogState (homog)%state0 = homogState (homog)%state + thermalState (homog)%state0 = thermalState (homog)%state + damageState (homog)%state0 = damageState (homog)%state + vacancyfluxState (homog)%state0 = vacancyfluxState (homog)%state + hydrogenfluxState(homog)%state0 = hydrogenfluxState(homog)%state + enddo + + + ! * dump the last converged values of each essential variable to a binary file + + if (restartWrite) then + if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt) & + write(6,'(a)') '<< CPFEM >> writing state variables of last converged step to binary files' + + write(rankStr,'(a1,i0)')'_',worldrank + + call IO_write_jobRealFile(777,'recordedPhase'//trim(rankStr),size(material_phase)) + write (777,rec=1) material_phase + close (777) + + call IO_write_jobRealFile(777,'convergedF'//trim(rankStr),size(crystallite_F0)) + write (777,rec=1) crystallite_F0 + close (777) + + call IO_write_jobRealFile(777,'convergedFp'//trim(rankStr),size(crystallite_Fp0)) + write (777,rec=1) crystallite_Fp0 + close (777) + + call IO_write_jobRealFile(777,'convergedFi'//trim(rankStr),size(crystallite_Fi0)) + write (777,rec=1) crystallite_Fi0 + close (777) + + call IO_write_jobRealFile(777,'convergedLp'//trim(rankStr),size(crystallite_Lp0)) + write (777,rec=1) crystallite_Lp0 + close (777) + + call IO_write_jobRealFile(777,'convergedLi'//trim(rankStr),size(crystallite_Li0)) + write (777,rec=1) crystallite_Li0 + close (777) + + call IO_write_jobRealFile(777,'convergeddPdF'//trim(rankStr),size(crystallite_dPdF0)) + write (777,rec=1) crystallite_dPdF0 + close (777) + + call IO_write_jobRealFile(777,'convergedTstar'//trim(rankStr),size(crystallite_Tstar0_v)) + write (777,rec=1) crystallite_Tstar0_v + close (777) + + call IO_write_jobRealFile(777,'convergedStateConst'//trim(rankStr)) + m = 0_pInt + writePlasticityInstances: do ph = 1_pInt, size(phase_plasticity) + do k = 1_pInt, plasticState(ph)%sizeState + do l = 1, size(plasticState(ph)%state0(1,:)) + m = m+1_pInt + write(777,rec=m) plasticState(ph)%state0(k,l) + enddo; enddo + enddo writePlasticityInstances + close (777) + + call IO_write_jobRealFile(777,'convergedStateHomog'//trim(rankStr)) + m = 0_pInt + writeHomogInstances: do homog = 1_pInt, material_Nhomogenization + do k = 1_pInt, homogState(homog)%sizeState + do l = 1, size(homogState(homog)%state0(1,:)) + m = m+1_pInt + write(777,rec=m) homogState(homog)%state0(k,l) + enddo; enddo + enddo writeHomogInstances + close (777) + +#if defined(Marc4DAMASK) || defined(Abaqus) + call IO_write_jobRealFile(777,'convergeddcsdE',size(CPFEM_dcsdE)) + write (777,rec=1) CPFEM_dcsdE + close (777) +#endif + + endif + endif ! results aging + + + + !*** collection of FEM input with returning of randomize odd stress and jacobian + !* If no parallel execution is required, there is no need to collect FEM input + + if (.not. parallelExecution) then +#if defined(Marc4DAMASK) || defined(Abaqus) + temperature(material_homog(ip,elCP))%p(thermalMapping(material_homog(ip,elCP))%p(ip,elCP)) = & + temperature_inp +#endif + materialpoint_F0(1:3,1:3,ip,elCP) = ffn + materialpoint_F(1:3,1:3,ip,elCP) = ffn1 + + elseif (iand(mode, CPFEM_COLLECT) /= 0_pInt) then +#if defined(Marc4DAMASK) || defined(Abaqus) + call random_number(rnd) + if (rnd < 0.5_pReal) rnd = rnd - 1.0_pReal + CPFEM_cs(1:6,ip,elCP) = rnd * CPFEM_odd_stress + CPFEM_dcsde(1:6,1:6,ip,elCP) = CPFEM_odd_jacobian * math_identity2nd(6) + temperature(material_homog(ip,elCP))%p(thermalMapping(material_homog(ip,elCP))%p(ip,elCP)) = & + temperature_inp +#endif + materialpoint_F0(1:3,1:3,ip,elCP) = ffn + materialpoint_F(1:3,1:3,ip,elCP) = ffn1 + CPFEM_calc_done = .false. + endif ! collection + + + + !*** calculation of stress and jacobian + + if (iand(mode, CPFEM_CALCRESULTS) /= 0_pInt) then + + !*** deformation gradient outdated or any actual deformation gradient differs more than relevantStrain from the stored one + validCalculation: if (terminallyIll & + .or. outdatedFFN1 & + .or. any(abs(ffn1 - materialpoint_F(1:3,1:3,ip,elCP)) > defgradTolerance)) then + if (any(abs(ffn1 - materialpoint_F(1:3,1:3,ip,elCP)) > defgradTolerance)) then + if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt) then + write(6,'(a,1x,i8,1x,i2)') '<< CPFEM >> OUTDATED at elFE ip',elFE,ip + write(6,'(a,/,3(12x,3(f10.6,1x),/))') '<< CPFEM >> FFN1 old:',& + math_transpose33(materialpoint_F(1:3,1:3,ip,elCP)) + write(6,'(a,/,3(12x,3(f10.6,1x),/))') '<< CPFEM >> FFN1 now:',math_transpose33(ffn1) + endif + outdatedFFN1 = .true. + endif +#if defined(Marc4DAMASK) || defined(Abaqus) + call random_number(rnd) + if (rnd < 0.5_pReal) rnd = rnd - 1.0_pReal + CPFEM_cs(1:6,ip,elCP) = rnd*CPFEM_odd_stress + CPFEM_dcsde(1:6,1:6,ip,elCP) = CPFEM_odd_jacobian*math_identity2nd(6) +#endif + + !*** deformation gradient is not outdated + + else validCalculation + updateJaco = mod(cycleCounter,iJacoStiffness) == 0 + !* no parallel computation, so we use just one single elFE and ip for computation + + if (.not. parallelExecution) then + FEsolving_execElem(1) = elCP + FEsolving_execElem(2) = elCP + if (.not. microstructure_elemhomo(mesh_element(4,elCP)) .or. & ! calculate unless homogeneous + (microstructure_elemhomo(mesh_element(4,elCP)) .and. ip == 1_pInt)) then ! and then only first ip + FEsolving_execIP(1,elCP) = ip + FEsolving_execIP(2,elCP) = ip + if (iand(debug_level(debug_CPFEM), debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i8,1x,i2)') '<< CPFEM >> calculation for elFE ip ',elFE,ip + call materialpoint_stressAndItsTangent(updateJaco, dt) ! calculate stress and its tangent + call materialpoint_postResults() + endif + + !* parallel computation and calulation not yet done + + elseif (.not. CPFEM_calc_done) then + if (iand(debug_level(debug_CPFEM), debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i8,a,i8)') '<< CPFEM >> calculation for elements ',FEsolving_execElem(1),& + ' to ',FEsolving_execElem(2) + call materialpoint_stressAndItsTangent(updateJaco, dt) ! calculate stress and its tangent (parallel execution inside) + call materialpoint_postResults() + CPFEM_calc_done = .true. + endif + + !* map stress and stiffness (or return odd values if terminally ill) +#if defined(Marc4DAMASK) || defined(Abaqus) + terminalIllness: if ( terminallyIll ) then + + call random_number(rnd) + if (rnd < 0.5_pReal) rnd = rnd - 1.0_pReal + CPFEM_cs(1:6,ip,elCP) = rnd * CPFEM_odd_stress + CPFEM_dcsde(1:6,1:6,ip,elCP) = CPFEM_odd_jacobian * math_identity2nd(6) + + else terminalIllness + + if (microstructure_elemhomo(mesh_element(4,elCP)) .and. ip > 1_pInt) then ! me homogenous? --> copy from first ip + materialpoint_P(1:3,1:3,ip,elCP) = materialpoint_P(1:3,1:3,1,elCP) + materialpoint_F(1:3,1:3,ip,elCP) = materialpoint_F(1:3,1:3,1,elCP) + materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,elCP) = materialpoint_dPdF(1:3,1:3,1:3,1:3,1,elCP) + materialpoint_results(1:materialpoint_sizeResults,ip,elCP) = & + materialpoint_results(1:materialpoint_sizeResults,1,elCP) + endif + + ! translate from P to CS + Kirchhoff = math_mul33x33(materialpoint_P(1:3,1:3,ip,elCP), math_transpose33(materialpoint_F(1:3,1:3,ip,elCP))) + J_inverse = 1.0_pReal / math_det33(materialpoint_F(1:3,1:3,ip,elCP)) + CPFEM_cs(1:6,ip,elCP) = math_Mandel33to6(J_inverse * Kirchhoff) + + ! 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) + & + materialpoint_F(j,m,ip,elCP) * & + materialpoint_F(l,n,ip,elCP) * & + materialpoint_dPdF(i,m,k,n,ip,elCP) - & + math_I3(j,l) * materialpoint_F(i,m,ip,elCP) * materialpoint_P(k,m,ip,elCP) + & + 0.5_pReal * (math_I3(i,k) * Kirchhoff(j,l) + math_I3(j,l) * Kirchhoff(i,k) + & + math_I3(i,l) * Kirchhoff(j,k) + math_I3(j,k) * Kirchhoff(i,l)) + enddo; enddo; enddo; enddo; enddo; enddo + + forall(i=1:3, j=1:3,k=1:3,l=1:3) & + H_sym(i,j,k,l) = 0.25_pReal * (H(i,j,k,l) + H(j,i,k,l) + H(i,j,l,k) + H(j,i,l,k)) + + CPFEM_dcsde(1:6,1:6,ip,elCP) = math_Mandel3333to66(J_inverse * H_sym) + + endif terminalIllness +#endif + + endif validCalculation + +#if defined(Marc4DAMASK) || defined(Abaqus) + !* report stress and stiffness + if ((iand(debug_level(debug_CPFEM), debug_levelExtensive) /= 0_pInt) & + .and. ((debug_e == elCP .and. debug_i == ip) & + .or. .not. iand(debug_level(debug_CPFEM), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i8,1x,i2,/,12x,6(f10.3,1x)/)') & + '<< CPFEM >> stress/MPa at elFE ip ', elFE, ip, CPFEM_cs(1:6,ip,elCP)*1.0e-6_pReal + write(6,'(a,i8,1x,i2,/,6(12x,6(f10.3,1x)/))') & + '<< CPFEM >> Jacobian/GPa at elFE ip ', elFE, ip, transpose(CPFEM_dcsdE(1:6,1:6,ip,elCP))*1.0e-9_pReal + flush(6) + endif +#endif + + endif + +#if defined(Marc4DAMASK) || defined(Abaqus) + !*** warn if stiffness close to zero + if (all(abs(CPFEM_dcsdE(1:6,1:6,ip,elCP)) < 1e-10_pReal)) call IO_warning(601,elCP,ip) + + !*** copy to output if using commercial FEM solver + cauchyStress = CPFEM_cs (1:6, ip,elCP) + jacobian = CPFEM_dcsdE(1:6,1:6,ip,elCP) + + + !*** remember extreme values of stress ... + cauchyStress33 = math_Mandel6to33(CPFEM_cs(1:6,ip,elCP)) + if (maxval(cauchyStress33) > debug_stressMax) then + debug_stressMaxLocation = [elCP, ip] + debug_stressMax = maxval(cauchyStress33) + endif + if (minval(cauchyStress33) < debug_stressMin) then + debug_stressMinLocation = [elCP, ip] + debug_stressMin = minval(cauchyStress33) + endif + !*** ... and Jacobian + jacobian3333 = math_Mandel66to3333(CPFEM_dcsdE(1:6,1:6,ip,elCP)) + if (maxval(jacobian3333) > debug_jacobianMax) then + debug_jacobianMaxLocation = [elCP, ip] + debug_jacobianMax = maxval(jacobian3333) + endif + if (minval(jacobian3333) < debug_jacobianMin) then + debug_jacobianMinLocation = [elCP, ip] + debug_jacobianMin = minval(jacobian3333) + endif +#endif + +end subroutine CPFEM_general + +end module CPFEM diff --git a/src/CPFEM2.f90 b/src/CPFEM2.f90 new file mode 100644 index 000000000..ea5691495 --- /dev/null +++ b/src/CPFEM2.f90 @@ -0,0 +1,367 @@ +!-------------------------------------------------------------------------------------------------- +! $Id: CPFEM.f90 4761 2016-01-17 13:29:42Z MPIE\m.diehl $ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief needs a good name and description +!-------------------------------------------------------------------------------------------------- +module CPFEM2 + + implicit none + private + + public :: & + CPFEM_general, & + CPFEM_initAll + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief call (thread safe) all module initializations +!-------------------------------------------------------------------------------------------------- +subroutine CPFEM_initAll(el,ip) + use prec, only: & + pInt + use prec, only: & + prec_init + use numerics, only: & + numerics_init + use debug, only: & + debug_init + use FEsolving, only: & + FE_init + use math, only: & + math_init + use mesh, only: & + mesh_init + use lattice, only: & + lattice_init + use material, only: & + material_init + use constitutive, only: & + constitutive_init + use crystallite, only: & + crystallite_init + use homogenization, only: & + homogenization_init, & +materialpoint_postResults + use IO, only: & + IO_init + use DAMASK_interface +#ifdef FEM + use FEZoo, only: & + FEZoo_init +#endif + + implicit none + integer(pInt), intent(in) :: el, & !< FE el number + ip !< FE integration point number + + call DAMASK_interface_init ! Spectral and FEM interface to commandline + call prec_init + call IO_init +#ifdef FEM + call FEZoo_init +#endif + call numerics_init + call debug_init + call math_init + call FE_init + call mesh_init(ip, el) ! pass on coordinates to alter calcMode of first ip + call lattice_init + call material_init + call constitutive_init + call crystallite_init + call homogenization_init + call materialpoint_postResults + call CPFEM_init + +end subroutine CPFEM_initAll + + +!-------------------------------------------------------------------------------------------------- +!> @brief allocate the arrays defined in module CPFEM and initialize them +!-------------------------------------------------------------------------------------------------- +subroutine CPFEM_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pInt + use IO, only: & + IO_read_realFile,& + IO_read_intFile, & + IO_timeStamp, & + IO_error + use numerics, only: & + worldrank + use debug, only: & + debug_level, & + debug_CPFEM, & + debug_levelBasic, & + debug_levelExtensive + use FEsolving, only: & + restartRead, & + modelName + use material, only: & + material_phase, & + homogState, & + phase_plasticity, & + plasticState, & + material_Nhomogenization + use crystallite, only: & + crystallite_F0, & + crystallite_Fp0, & + crystallite_Lp0, & + crystallite_Fi0, & + crystallite_Li0, & + crystallite_dPdF0, & + crystallite_Tstar0_v + + implicit none + integer(pInt) :: k,l,m,ph,homog + character(len=1024) :: rankStr + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- CPFEM init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + ! *** restore the last converged values of each essential variable from the binary file + if (restartRead) then + if (iand(debug_level(debug_CPFEM), debug_levelExtensive) /= 0_pInt) then + write(6,'(a)') '<< CPFEM >> restored state variables of last converged step from binary files' + flush(6) + endif + + write(rankStr,'(a1,i0)')'_',worldrank + + call IO_read_intFile(777,'recordedPhase'//trim(rankStr),modelName,size(material_phase)) + read (777,rec=1) material_phase + close (777) + + call IO_read_realFile(777,'convergedF'//trim(rankStr),modelName,size(crystallite_F0)) + read (777,rec=1) crystallite_F0 + close (777) + + call IO_read_realFile(777,'convergedFp'//trim(rankStr),modelName,size(crystallite_Fp0)) + read (777,rec=1) crystallite_Fp0 + close (777) + + call IO_read_realFile(777,'convergedFi'//trim(rankStr),modelName,size(crystallite_Fi0)) + read (777,rec=1) crystallite_Fi0 + close (777) + + call IO_read_realFile(777,'convergedLp'//trim(rankStr),modelName,size(crystallite_Lp0)) + read (777,rec=1) crystallite_Lp0 + close (777) + + call IO_read_realFile(777,'convergedLi'//trim(rankStr),modelName,size(crystallite_Li0)) + read (777,rec=1) crystallite_Li0 + close (777) + + call IO_read_realFile(777,'convergeddPdF'//trim(rankStr),modelName,size(crystallite_dPdF0)) + read (777,rec=1) crystallite_dPdF0 + close (777) + + call IO_read_realFile(777,'convergedTstar'//trim(rankStr),modelName,size(crystallite_Tstar0_v)) + read (777,rec=1) crystallite_Tstar0_v + close (777) + + call IO_read_realFile(777,'convergedStateConst'//trim(rankStr),modelName) + m = 0_pInt + readPlasticityInstances: do ph = 1_pInt, size(phase_plasticity) + do k = 1_pInt, plasticState(ph)%sizeState + do l = 1, size(plasticState(ph)%state0(1,:)) + m = m+1_pInt + read(777,rec=m) plasticState(ph)%state0(k,l) + enddo; enddo + enddo readPlasticityInstances + close (777) + + call IO_read_realFile(777,'convergedStateHomog'//trim(rankStr),modelName) + m = 0_pInt + readHomogInstances: do homog = 1_pInt, material_Nhomogenization + do k = 1_pInt, homogState(homog)%sizeState + do l = 1, size(homogState(homog)%state0(1,:)) + m = m+1_pInt + read(777,rec=m) homogState(homog)%state0(k,l) + enddo; enddo + enddo readHomogInstances + close (777) + + restartRead = .false. + endif + flush(6) + +end subroutine CPFEM_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief perform initialization at first call, update variables and call the actual material model +!-------------------------------------------------------------------------------------------------- +subroutine CPFEM_general(age, dt) + use prec, only: & + pReal, & + pInt + use numerics, only: & + worldrank + use debug, only: & + debug_level, & + debug_CPFEM, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective + use FEsolving, only: & + terminallyIll, & + restartWrite + use math, only: & + math_identity2nd, & + math_mul33x33, & + math_det33, & + math_transpose33, & + math_I3, & + math_Mandel3333to66, & + math_Mandel66to3333, & + math_Mandel33to6, & + math_Mandel6to33 + use material, only: & + plasticState, & + sourceState, & + homogState, & + thermalState, & + damageState, & + vacancyfluxState, & + hydrogenfluxState, & + material_phase, & + phase_plasticity, & + phase_Nsources, & + material_Nhomogenization + use crystallite, only: & + crystallite_partionedF,& + crystallite_F0, & + crystallite_Fp0, & + crystallite_Fp, & + crystallite_Fi0, & + crystallite_Fi, & + crystallite_Lp0, & + crystallite_Lp, & + crystallite_Li0, & + crystallite_Li, & + crystallite_dPdF0, & + crystallite_dPdF, & + crystallite_Tstar0_v, & + crystallite_Tstar_v + use homogenization, only: & + materialpoint_F, & + materialpoint_F0, & + materialpoint_stressAndItsTangent, & + materialpoint_postResults + use IO, only: & + IO_write_jobRealFile, & + IO_warning + use DAMASK_interface + + implicit none + real(pReal), intent(in) :: dt !< time increment + logical, intent(in) :: age !< age results + + integer(pInt) :: i, k, l, m, ph, homog, mySource + character(len=1024) :: rankStr + + !*** age results and write restart data if requested + if (age) then + crystallite_F0 = crystallite_partionedF ! crystallite deformation (_subF is perturbed...) + crystallite_Fp0 = crystallite_Fp ! crystallite plastic deformation + crystallite_Lp0 = crystallite_Lp ! crystallite plastic velocity + crystallite_Fi0 = crystallite_Fi ! crystallite intermediate deformation + crystallite_Li0 = crystallite_Li ! crystallite intermediate velocity + crystallite_dPdF0 = crystallite_dPdF ! crystallite stiffness + crystallite_Tstar0_v = crystallite_Tstar_v ! crystallite 2nd Piola Kirchhoff stress + + forall ( i = 1:size(plasticState )) plasticState(i)%state0 = plasticState(i)%state ! copy state in this lenghty way because: A component cannot be an array if the encompassing structure is an array + do i = 1, size(sourceState) + do mySource = 1,phase_Nsources(i) + sourceState(i)%p(mySource)%state0 = sourceState(i)%p(mySource)%state ! copy state in this lenghty way because: A component cannot be an array if the encompassing structure is an array + enddo; enddo + if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt) & + write(6,'(a)') '<< CPFEM >> aging states' + + do homog = 1_pInt, material_Nhomogenization + homogState (homog)%state0 = homogState (homog)%state + thermalState (homog)%state0 = thermalState (homog)%state + damageState (homog)%state0 = damageState (homog)%state + vacancyfluxState (homog)%state0 = vacancyfluxState (homog)%state + hydrogenfluxState(homog)%state0 = hydrogenfluxState(homog)%state + enddo + + + if (restartWrite) then + if (iand(debug_level(debug_CPFEM), debug_levelBasic) /= 0_pInt) & + write(6,'(a)') '<< CPFEM >> writing state variables of last converged step to binary files' + + write(rankStr,'(a1,i0)')'_',worldrank + + call IO_write_jobRealFile(777,'recordedPhase'//trim(rankStr),size(material_phase)) + write (777,rec=1) material_phase + close (777) + + call IO_write_jobRealFile(777,'convergedF'//trim(rankStr),size(crystallite_F0)) + write (777,rec=1) crystallite_F0 + close (777) + + call IO_write_jobRealFile(777,'convergedFp'//trim(rankStr),size(crystallite_Fp0)) + write (777,rec=1) crystallite_Fp0 + close (777) + + call IO_write_jobRealFile(777,'convergedFi'//trim(rankStr),size(crystallite_Fi0)) + write (777,rec=1) crystallite_Fi0 + close (777) + + call IO_write_jobRealFile(777,'convergedLp'//trim(rankStr),size(crystallite_Lp0)) + write (777,rec=1) crystallite_Lp0 + close (777) + + call IO_write_jobRealFile(777,'convergedLi'//trim(rankStr),size(crystallite_Li0)) + write (777,rec=1) crystallite_Li0 + close (777) + + call IO_write_jobRealFile(777,'convergeddPdF'//trim(rankStr),size(crystallite_dPdF0)) + write (777,rec=1) crystallite_dPdF0 + close (777) + + call IO_write_jobRealFile(777,'convergedTstar'//trim(rankStr),size(crystallite_Tstar0_v)) + write (777,rec=1) crystallite_Tstar0_v + close (777) + + call IO_write_jobRealFile(777,'convergedStateConst'//trim(rankStr)) + m = 0_pInt + writePlasticityInstances: do ph = 1_pInt, size(phase_plasticity) + do k = 1_pInt, plasticState(ph)%sizeState + do l = 1, size(plasticState(ph)%state0(1,:)) + m = m+1_pInt + write(777,rec=m) plasticState(ph)%state0(k,l) + enddo; enddo + enddo writePlasticityInstances + close (777) + + call IO_write_jobRealFile(777,'convergedStateHomog'//trim(rankStr)) + m = 0_pInt + writeHomogInstances: do homog = 1_pInt, material_Nhomogenization + do k = 1_pInt, homogState(homog)%sizeState + do l = 1, size(homogState(homog)%state0(1,:)) + m = m+1_pInt + write(777,rec=m) homogState(homog)%state0(k,l) + enddo; enddo + enddo writeHomogInstances + close (777) + + endif + endif + + if (.not. terminallyIll) & + call materialpoint_stressAndItsTangent(.True., dt) + +end subroutine CPFEM_general + +end module CPFEM2 diff --git a/src/DAMASK_abaqus_exp.f b/src/DAMASK_abaqus_exp.f new file mode 100644 index 000000000..eff898e3e --- /dev/null +++ b/src/DAMASK_abaqus_exp.f @@ -0,0 +1,299 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Koen Janssens, Paul Scherrer Institut +!> @author Arun Prakash, Fraunhofer IWM +!> @brief interfaces DAMASK with Abaqus/Explicit +!> @details put the included file abaqus_v6.env in either your home or model directory, +!> it is a minimum Abaqus environment file containing all changes necessary to use the +!> DAMASK subroutine (see Abaqus documentation for more information on the use of abaqus_v6.env) +!-------------------------------------------------------------------------------------------------- + +#ifndef INT +#define INT 4 +#endif + +#ifndef FLOAT +#define FLOAT 8 +#endif + +#define Abaqus + +#include "prec.f90" + +module DAMASK_interface + +implicit none +character(len=4), dimension(2), parameter :: INPUTFILEEXTENSION = ['.pes','.inp'] +character(len=4), parameter :: LOGFILEEXTENSION = '.log' + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief just reporting +!-------------------------------------------------------------------------------------------------- +subroutine DAMASK_interface_init + integer, dimension(8) :: & + dateAndTime ! type default integer + call date_and_time(values = dateAndTime) + write(6,'(/,a)') ' <<<+- DAMASK_abaqus_exp -+>>>' + write(6,'(/,a)') ' Version: '//DAMASKVERSION + write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& + dateAndTime(2),'/',& + dateAndTime(1) + write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& + dateAndTime(6),':',& + dateAndTime(7) + write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' +#include "compilation_info.f90" + +end subroutine DAMASK_interface_init + + + +!-------------------------------------------------------------------------------------------------- +!> @brief using Abaqus/Explicit function to get working directory name +!-------------------------------------------------------------------------------------------------- +character(1024) function getSolverWorkingDirectoryName() + + implicit none + integer :: lenOutDir + + getSolverWorkingDirectoryName='' + call vgetOutDir(getSolverWorkingDirectoryName, lenOutDir) + getSolverWorkingDirectoryName=trim(getSolverWorkingDirectoryName)//'/' + +end function getSolverWorkingDirectoryName + + +!-------------------------------------------------------------------------------------------------- +!> @brief using Abaqus/Explicit function to get solver job name +!-------------------------------------------------------------------------------------------------- +character(1024) function getSolverJobName() + + implicit none + integer :: lenJobName + + getSolverJobName='' + call vGetJobName(getSolverJobName, lenJobName) + +end function getSolverJobName + +end module DAMASK_interface + +#include "commercialFEM_fileList.f90" + +subroutine vumat(nBlock, nDir, nshr, nStateV, nFieldV, nProps, lAnneal, & + stepTime, totalTime, dt, cmName, coordMp, charLength, & + props, density, strainInc, relSpinInc, & + tempOld, stretchOld, defgradOld, fieldOld, & + stressOld, stateOld, enerInternOld, enerInelasOld, & + tempNew, stretchNew, defgradNew, fieldNew, & + stressNew, stateNew, enerInternNew, enerInelasNew) + use prec, only: & + pReal, & + pInt +!$ use numerics, only: & +!$ DAMASK_NumThreadsInt + use FEsolving, only: & + symmetricSolver, & + terminallyIll + use math, only: & + invnrmMandel + use debug, only: & + debug_info, & + debug_reset, & + debug_levelBasic, & + debug_level, & + debug_abaqus + use mesh, only: & + mesh_unitlength, & + mesh_FEasCP, & + mesh_ipCoordinates + use CPFEM, only: & + CPFEM_general, & + CPFEM_init_done, & + CPFEM_initAll, & + CPFEM_CALCRESULTS, & + CPFEM_AGERESULTS, & + cycleCounter, & + theTime, & + outdatedByNewInc, & + outdatedFFN1 + use homogenization, only: & + materialpoint_sizeResults, & + materialpoint_results + + implicit none + integer(pInt), intent(in) :: & + nDir, & !< number of direct components in a symmetric tensor + nshr, & !< number of indirect components in a symmetric tensor + nStateV, & !< number of user-defined state variables that are associated with this material type + nFieldV, & !< number of user-defined external field variables + nprops, & !< user-specified number of user-defined material properties + lAnneal !< indicating whether the routine is being called during an annealing process + integer(pInt), dimension(*), intent(in) :: & + nBlock !< 1: No of Materialpoints in this call, 2: No of Materialpoint (IP) + !< 3: No of layer, 4: No of secPoint, 5+: element numbers + character(len=80), intent(in) :: & + cmname !< uses-specified material name, left justified + real(pReal), dimension(nprops), intent(in) :: & + props !< user-supplied material properties + real(pReal), intent(in) :: & + stepTime, & !< value of time since the step began + totalTime, & !< value of total time + dt !< time increment size + real(pReal), dimension(nblock(1)), intent(in) :: & + density, & !< current density at material points in the midstep configuration + charLength, & !< characteristic element length + enerInternOld, & !< internal energy per unit mass at each material point at the beginning of the increment + enerInelasOld, & !< dissipated inelastic energy per unit mass at each material point at the beginning of the increment + tempOld, & !< temperature at each material point at the beginning of the increment + tempNew !< temperature at each material point at the end of the increment (Temperature calculated in ABAQUS boundary conditions) + real(pReal), dimension(nblock(1),*), intent(in) :: & + coordMp !< material point coordinates + real(pReal), dimension(nblock(1),ndir+nshr), intent(in) :: & + strainInc, & !< strain increment tensor at each material point + stretchOld, & !< stretch tensor U at each material point + stretchNew, & !< stretch tensor U at each material point + stressOld !< stress tensor at each material point + real(pReal), dimension(nblock(1),nshr), intent(in) :: & + relSpinInc !< incremental relative rotation vector + real(pReal), dimension(nblock(1),nstatev), intent(in) :: & + stateOld !< state variables at each material point at the beginning of the increment + real(pReal), dimension(nblock(1),nfieldv), intent(in) :: & + fieldOld, & !< user-defined field variables + fieldNew !< user-defined field variables + real(pReal), dimension(nblock(1),ndir+2*nshr), intent(in) :: & + defgradOld, & + defgradNew + real(pReal), dimension(nblock(1)), intent(out) :: & + enerInternNew, & !< internal energy per unit mass at each material point at the end of the increment + enerInelasNew !< dissipated inelastic energy per unit mass at each material point at the end of the increment + real(pReal), dimension(nblock(1),ndir+nshr), intent(out) :: & + stressNew !< stress tensor at each material point at the end of the increment + real(pReal), dimension(nblock(1),nstatev), intent(out) :: & + stateNew !< state variables at each material point at the end of the increment + + real(pReal), dimension(3) :: coordinates + real(pReal), dimension(3,3) :: defgrd0,defgrd1 + real(pReal), dimension(6) :: stress + real(pReal), dimension(6,6) :: ddsdde + real(pReal) :: temp, timeInc, stresspower + integer(pInt) :: computationMode, n, i, cp_en + +#ifdef _OPENMP + integer :: defaultNumThreadsInt !< default value set by Abaqus + include "omp_lib.h" + + defaultNumThreadsInt = omp_get_num_threads() ! remember number of threads set by Marc + call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution set by DAMASK_NUM_THREADS +#endif + + computationMode = CPFEM_CALCRESULTS ! always calculate + do n = 1,nblock(1) ! loop over vector of IPs + temp = tempOld(n) ! temp is intent(in) + if ( .not. CPFEM_init_done ) then + call CPFEM_initAll(nBlock(4_pInt+n),nBlock(2)) + outdatedByNewInc = .false. + + if (iand(debug_level(debug_abaqus),debug_levelBasic) /= 0) then + write(6,'(i8,1x,i2,1x,a)') nBlock(4_pInt+n),nBlock(2),'first call special case..!'; flush(6) + endif + else if (theTime < totalTime) then ! reached convergence + outdatedByNewInc = .true. + + if (iand(debug_level(debug_abaqus),debug_levelBasic) /= 0) then + write (6,'(i8,1x,i2,1x,a)') nBlock(4_pInt+n),nBlock(2),'lastIncConverged + outdated'; flush(6) + endif + + endif + outdatedFFN1 = .false. + terminallyIll = .false. + cycleCounter = 1_pInt + if ( outdatedByNewInc ) then + outdatedByNewInc = .false. + call debug_info() ! first after new inc reports debugging + call debug_reset() ! resets debugging + computationMode = ior(computationMode, CPFEM_AGERESULTS) ! age results + endif + + theTime = totalTime ! record current starting time + if (iand(debug_level(debug_abaqus),debug_levelBasic) /= 0) then + write(6,'(a,i8,i2,a)') '(',nBlock(4_pInt+n),nBlock(2),')'; flush(6) + write(6,'(a,l1)') 'Aging Results: ', iand(computationMode, CPFEM_AGERESULTS) /= 0_pInt + endif + defgrd0 = 0.0_pReal + defgrd1 = 0.0_pReal + timeInc = dt + + ! ABAQUS explicit: deformation gradient as vector 11, 22, 33, 12, 23, 31, 21, 32, 13 + ! ABAQUS explicit: deformation gradient as vector 11, 22, 33, 12, 21 + + forall (i=1:ndir) + defgrd0(i,i) = defgradOld(n,i) + defgrd1(i,i) = defgradNew(n,i) + end forall + if (nshr == 1) then + defgrd0(1,2) = defgradOld(n,4) + defgrd1(1,2) = defgradNew(n,4) + defgrd0(2,1) = defgradOld(n,5) + defgrd1(2,1) = defgradNew(n,5) + else + defgrd0(1,2) = defgradOld(n,4) + defgrd1(1,2) = defgradNew(n,4) + defgrd0(1,3) = defgradOld(n,9) + defgrd1(1,3) = defgradNew(n,9) + defgrd0(2,1) = defgradOld(n,7) + defgrd1(2,1) = defgradNew(n,7) + defgrd0(2,3) = defgradOld(n,5) + defgrd1(2,3) = defgradNew(n,5) + defgrd0(3,1) = defgradOld(n,6) + defgrd1(3,1) = defgradNew(n,6) + defgrd0(3,2) = defgradOld(n,8) + defgrd1(3,2) = defgradNew(n,8) + + endif + cp_en = mesh_FEasCP('elem',nBlock(4_pInt+n)) + mesh_ipCoordinates(1:3,n,cp_en) = mesh_unitlength * coordMp(n,1:3) + + call CPFEM_general(computationMode,.false.,defgrd0,defgrd1,temp,timeInc,cp_en,nBlock(2),stress,ddsdde) + + ! Mandel: 11, 22, 33, SQRT(2)*12, SQRT(2)*23, SQRT(2)*13 + ! straight: 11, 22, 33, 12, 23, 13 + ! ABAQUS implicit: 11, 22, 33, 12, 13, 23 + ! ABAQUS explicit: 11, 22, 33, 12, 23, 13 + ! ABAQUS explicit: 11, 22, 33, 12 + + stressNew(n,1:ndir+nshr) = stress(1:ndir+nshr)*invnrmMandel(1:ndir+nshr) + stateNew(n,1:min(nstatev,materialpoint_sizeResults)) = & + materialpoint_results(1:min(nstatev,materialpoint_sizeResults),& + nBlock(2),mesh_FEasCP('elem', nBlock(4_pInt+n))) + + stresspower = 0.5_pReal*sum((stressOld(n,1:ndir)+stressNew(n,1:ndir))*straininc(n,1:ndir))+& + sum((stressOld(n,ndir+1:ndir+nshr)+stressNew(n,ndir+1:ndir+nshr))*straininc(n,ndir+1:ndir+nshr)) + enerInternNew(n) = enerInternOld(n) + stresspower / density(n) ! Internal energy per unit mass + enerInelasNew(n) = enerInternNew(n) ! Dissipated inelastic energy per unit mass(Temporary output) + + enddo +!$ call omp_set_num_threads(defaultNumThreadsInt) ! reset number of threads to stored default value + +end subroutine vumat + + +!-------------------------------------------------------------------------------------------------- +!> @brief calls the exit function of Abaqus/Explicit +!-------------------------------------------------------------------------------------------------- +subroutine quit(mpie_error) + use prec, only: & + pInt + + implicit none + integer(pInt) :: mpie_error + + flush(6) + call xplb_exit + +end subroutine quit diff --git a/src/DAMASK_abaqus_std.f b/src/DAMASK_abaqus_std.f new file mode 100644 index 000000000..faec60650 --- /dev/null +++ b/src/DAMASK_abaqus_std.f @@ -0,0 +1,342 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Koen Janssens, Paul Scherrer Institut +!> @author Arun Prakash, Fraunhofer IWM +!> @brief interfaces DAMASK with Abaqus/Standard +!> @details put the included file abaqus_v6.env in either your home or model directory, +!> it is a minimum Abaqus environment file containing all changes necessary to use the +!> DAMASK subroutine (see Abaqus documentation for more information on the use of abaqus_v6.env) +!-------------------------------------------------------------------------------------------------- + +#ifndef INT +#define INT 4 +#endif + +#ifndef FLOAT +#define FLOAT 8 +#endif + +#define Abaqus + +#include "prec.f90" + +module DAMASK_interface + +implicit none +character(len=4), dimension(2), parameter :: INPUTFILEEXTENSION = ['.pes','.inp'] +character(len=4), parameter :: LOGFILEEXTENSION = '.log' + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief just reporting +!-------------------------------------------------------------------------------------------------- +subroutine DAMASK_interface_init + integer, dimension(8) :: & + dateAndTime ! type default integer + call date_and_time(values = dateAndTime) + write(6,'(/,a)') ' <<<+- DAMASK_abaqus_std -+>>>' + write(6,'(/,a)') ' Version: '//DAMASKVERSION + write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& + dateAndTime(2),'/',& + dateAndTime(1) + write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& + dateAndTime(6),':',& + dateAndTime(7) + write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' +#include "compilation_info.f90" + +end subroutine DAMASK_interface_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief using Abaqus/Standard function to get working directory name +!-------------------------------------------------------------------------------------------------- +character(1024) function getSolverWorkingDirectoryName() + + implicit none + integer :: lenOutDir + + getSolverWorkingDirectoryName='' + call getoutdir(getSolverWorkingDirectoryName, lenOutDir) + getSolverWorkingDirectoryName=trim(getSolverWorkingDirectoryName)//'/' + +end function getSolverWorkingDirectoryName + + +!-------------------------------------------------------------------------------------------------- +!> @brief using Abaqus/Standard function to get solver job name +!-------------------------------------------------------------------------------------------------- +character(1024) function getSolverJobName() + + implicit none + integer :: lenJobName + + getSolverJobName='' + call getJobName(getSolverJobName, lenJobName) + +end function getSolverJobName + +end module DAMASK_interface + +#include "commercialFEM_fileList.f90" + +subroutine UMAT(STRESS,STATEV,DDSDDE,SSE,SPD,SCD,& + RPL,DDSDDT,DRPLDE,DRPLDT,STRAN,DSTRAN,& + TIME,DTIME,TEMP,DTEMP,PREDEF,DPRED,CMNAME,NDI,NSHR,NTENS,& + NSTATV,PROPS,NPROPS,COORDS,DROT,PNEWDT,CELENT,& + DFGRD0,DFGRD1,NOEL,NPT,KSLAY,KSPT,KSTEP,KINC) + use prec, only: & + pReal, & + pInt + use numerics, only: & +!$ DAMASK_NumThreadsInt, & + usePingPong + use FEsolving, only: & + calcMode, & + terminallyIll, & + symmetricSolver + use math, only: & + invnrmMandel + use debug, only: & + debug_info, & + debug_reset, & + debug_levelBasic, & + debug_level, & + debug_abaqus + use mesh, only: & + mesh_unitlength, & + mesh_FEasCP, & + mesh_ipCoordinates + use CPFEM, only: & + CPFEM_general, & + CPFEM_init_done, & + CPFEM_initAll, & + CPFEM_CALCRESULTS, & + CPFEM_AGERESULTS, & + CPFEM_COLLECT, & + CPFEM_RESTOREJACOBIAN, & + CPFEM_BACKUPJACOBIAN, & + cycleCounter, & + theInc, & + theTime, & + theDelta, & + lastIncConverged, & + outdatedByNewInc, & + outdatedFFN1, & + lastStep + use homogenization, only: & + materialpoint_sizeResults, & + materialpoint_results + + implicit none + integer(pInt), intent(in) :: & + nDi, & !< Number of direct stress components at this point + nShr, & !< Number of engineering shear stress components at this point + nTens, & !< Size of the stress or strain component array (NDI + NSHR) + nStatV, & !< Number of solution-dependent state variables + nProps, & !< User-defined number of material constants + noEl, & !< element number + nPt,& !< integration point number + kSlay, & !< layer number (shell elements etc.) + kSpt, & !< section point within the current layer + kStep, & !< step number + kInc !< increment number + character(len=80), intent(in) :: & + cmname !< uses-specified material name, left justified + real(pReal), intent(in) :: & + DTIME, & + TEMP, & + DTEMP, & + CELENT + real(pReal), dimension(1), intent(in) :: & + PREDEF, & + DPRED + real(pReal), dimension(2), intent(in) :: & + TIME !< step time/total time at beginning of the current increment + real(pReal), dimension(3), intent(in) :: & + COORDS + real(pReal), dimension(nTens), intent(in) :: & + STRAN, & !< total strains at beginning of the increment + DSTRAN !< strain increments + real(pReal), dimension(nProps), intent(in) :: & + PROPS + real(pReal), dimension(3,3), intent(in) :: & + DROT, & !< rotation increment matrix + DFGRD0, & !< F at beginning of increment + DFGRD1 !< F at end of increment + real(pReal), intent(inout) :: & + PNEWDT, & !< ratio of suggested new time increment + SSE, & !< specific elastic strain engergy + SPD, & !< specific plastic dissipation + SCD, & !< specific creep dissipation + RPL, & !< volumetric heat generation per unit time at the end of the increment + DRPLDT !< varation of RPL with respect to the temperature + real(pReal), dimension(nTens), intent(inout) :: & + STRESS !< stress tensor at the beginning of the increment, needs to be updated + real(pReal), dimension(nStatV), intent(inout) :: & + STATEV !< solution-dependent state variables + real(pReal), dimension(nTens), intent(out) :: & + DDSDDT, & + DRPLDE + real(pReal), dimension(nTens,nTens), intent(out) :: & + DDSDDE !< Jacobian matrix of the constitutive model + + real(pReal) :: temperature ! temp by Abaqus is intent(in) + real(pReal), dimension(6) :: stress_h + real(pReal), dimension(6,6) :: ddsdde_h + integer(pInt) :: computationMode, i, cp_en + logical :: cutBack + +#ifdef _OPENMP + integer :: defaultNumThreadsInt !< default value set by Abaqus + include "omp_lib.h" + defaultNumThreadsInt = omp_get_num_threads() ! remember number of threads set by Marc + call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution set by DAMASK_NUM_THREADS +#endif + + temperature = temp ! temp is intent(in) + DDSDDT = 0.0_pReal + DRPLDE = 0.0_pReal + + if (iand(debug_level(debug_abaqus),debug_levelBasic) /= 0 .and. noel == 1 .and. npt == 1) then + write(6,*) 'el',noel,'ip',npt + write(6,*) 'got kInc as',kInc + write(6,*) 'got dStran',dStran + flush(6) + endif + + if (.not. CPFEM_init_done) call CPFEM_initAll(noel,npt) + + computationMode = 0 + cp_en = mesh_FEasCP('elem',noel) + if (time(2) > theTime .or. kInc /= theInc) then ! reached convergence + terminallyIll = .false. + cycleCounter = -1 ! first calc step increments this to cycle = 0 + if (kInc == 1) then ! >> start of analysis << + lastIncConverged = .false. ! no Jacobian backup + outdatedByNewInc = .false. ! no aging of state + calcMode = .false. ! pretend last step was collection + write (6,'(i8,1x,i2,1x,a)') noel,npt,'<< UMAT >> start of analysis..!';flush(6) + else if (kInc - theInc > 1) then ! >> restart of broken analysis << + lastIncConverged = .false. ! no Jacobian backup + outdatedByNewInc = .false. ! no aging of state + calcMode = .true. ! pretend last step was calculation + write (6,'(i8,1x,i2,1x,a)') noel,npt,'<< UMAT >> restart of analysis..!';flush(6) + else ! >> just the next inc << + lastIncConverged = .true. ! request Jacobian backup + outdatedByNewInc = .true. ! request aging of state + calcMode = .true. ! assure last step was calculation + write (6,'(i8,1x,i2,1x,a)') noel,npt,'<< UMAT >> new increment..!';flush(6) + endif + else if ( dtime < theDelta ) then ! >> cutBack << + lastIncConverged = .false. ! no Jacobian backup + outdatedByNewInc = .false. ! no aging of state + terminallyIll = .false. + cycleCounter = -1 ! first calc step increments this to cycle = 0 + calcMode = .true. ! pretend last step was calculation + write(6,'(i8,1x,i2,1x,a)') noel,npt,'<< UMAT >> cutback detected..!';flush(6) + endif ! convergence treatment end + + + if (usePingPong) then + calcMode(npt,cp_en) = .not. calcMode(npt,cp_en) ! ping pong (calc <--> collect) + if (calcMode(npt,cp_en)) then ! now --- CALC --- + computationMode = CPFEM_CALCRESULTS + if ( lastStep /= kStep ) then ! first after ping pong + call debug_reset() ! resets debugging + outdatedFFN1 = .false. + cycleCounter = cycleCounter + 1_pInt + endif + if(outdatedByNewInc) then + computationMode = ior(computationMode,CPFEM_AGERESULTS) ! calc and age results + outdatedByNewInc = .false. ! reset flag + endif + else ! now --- COLLECT --- + computationMode = CPFEM_COLLECT ! plain collect + if(lastStep /= kStep .and. .not. terminallyIll) & + call debug_info() ! first after ping pong reports (meaningful) debugging + if (lastIncConverged) then + computationMode = ior(computationMode,CPFEM_BACKUPJACOBIAN) ! collect and backup Jacobian after convergence + lastIncConverged = .false. ! reset flag + endif + mesh_ipCoordinates(1:3,npt,cp_en) = mesh_unitlength * COORDS + endif + else ! --- PLAIN MODE --- + computationMode = CPFEM_CALCRESULTS ! always calc + if (lastStep /= kStep) then + if (.not. terminallyIll) & + call debug_info() ! first reports (meaningful) debugging + call debug_reset() ! and resets debugging + outdatedFFN1 = .false. + cycleCounter = cycleCounter + 1_pInt + endif + if (outdatedByNewInc) then + computationMode = ior(computationMode,CPFEM_AGERESULTS) + outdatedByNewInc = .false. ! reset flag + endif + if (lastIncConverged) then + computationMode = ior(computationMode,CPFEM_BACKUPJACOBIAN) ! backup Jacobian after convergence + lastIncConverged = .false. ! reset flag + endif + endif + + + theTime = time(2) ! record current starting time + theDelta = dtime ! record current time increment + theInc = kInc ! record current increment number + lastStep = kStep ! record step number + + if (iand(debug_level(debug_abaqus),debug_levelBasic) /= 0) then + write(6,'(a16,1x,i2,1x,a,i8,a,i8,1x,i5,a)') 'computationMode',computationMode,'(',cp_en,':',noel,npt,')' + flush(6) + endif + + call CPFEM_general(computationMode,usePingPong,dfgrd0,dfgrd1,temperature,dtime,noel,npt,stress_h,ddsdde_h) + +! Mandel: 11, 22, 33, SQRT(2)*12, SQRT(2)*23, SQRT(2)*13 +! straight: 11, 22, 33, 12, 23, 13 +! ABAQUS explicit: 11, 22, 33, 12, 23, 13 +! ABAQUS implicit: 11, 22, 33, 12, 13, 23 +! ABAQUS implicit: 11, 22, 33, 12 + + forall(i=1:ntens) ddsdde(1:ntens,i) = invnrmMandel(i)*ddsdde_h(1:ntens,i)*invnrmMandel(1:ntens) + stress(1:ntens) = stress_h(1:ntens)*invnrmMandel(1:ntens) + if(symmetricSolver) ddsdde(1:ntens,1:ntens) = 0.5_pReal*(ddsdde(1:ntens,1:ntens) + transpose(ddsdde(1:ntens,1:ntens))) + if(ntens == 6) then + stress_h = stress + stress(5) = stress_h(6) + stress(6) = stress_h(5) + ddsdde_h = ddsdde + ddsdde(:,5) = ddsdde_h(:,6) + ddsdde(:,6) = ddsdde_h(:,5) + ddsdde_h = ddsdde + ddsdde(5,:) = ddsdde_h(6,:) + ddsdde(6,:) = ddsdde_h(5,:) + end if + + statev = materialpoint_results(1:min(nstatv,materialpoint_sizeResults),npt,mesh_FEasCP('elem', noel)) + + if ( terminallyIll ) pnewdt = 0.5_pReal ! force cutback directly ? +!$ call omp_set_num_threads(defaultNumThreadsInt) ! reset number of threads to stored default value + +end subroutine UMAT + + +!-------------------------------------------------------------------------------------------------- +!> @brief calls the exit function of Abaqus/Standard +!-------------------------------------------------------------------------------------------------- +subroutine quit(mpie_error) + use prec, only: & + pInt + + implicit none + integer(pInt) :: mpie_error + + flush(6) + call xit + +end subroutine quit diff --git a/src/DAMASK_marc.f90 b/src/DAMASK_marc.f90 new file mode 100644 index 000000000..14dcc5c06 --- /dev/null +++ b/src/DAMASK_marc.f90 @@ -0,0 +1,426 @@ +#define QUOTE(x) #x +#define PASTE(x,y) x ## y + +#ifndef INT +#define INT 4 +#endif + +#ifndef FLOAT +#define FLOAT 8 +#endif + +#include "prec.f90" +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Luc Hantcherli, Max-Planck-Institut für Eisenforschung GmbH +!> @author W.A. Counts +!> @author Denny Tjahjanto, Max-Planck-Institut für Eisenforschung GmbH +!> @author Christoph Kords, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Material subroutine for MSC.Marc +!> @details Usage: +!> @details - choose material as hypela2 +!> @details - set statevariable 2 to index of homogenization +!> @details - set statevariable 3 to index of microstructure +!> @details - make sure the file "material.config" exists in the working directory +!> @details - make sure the file "numerics.config" exists in the working directory +!> @details - use nonsymmetric option for solver (e.g. direct profile or multifrontal sparse, the latter seems to be faster!) +!> @details - in case of ddm (domain decomposition) a SYMMETRIC solver has to be used, i.e uncheck "non-symmetric" +!> @details Marc subroutines used: +!> @details - hypela2 +!> @details - plotv +!> @details - quit +!> @details Marc common blocks included: +!> @details - concom: lovl, inc +!> @details - creeps: timinc +!-------------------------------------------------------------------------------------------------- +module DAMASK_interface + + implicit none + character(len=4), parameter :: InputFileExtension = '.dat' + character(len=4), parameter :: LogFileExtension = '.log' + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief only output of current version +!-------------------------------------------------------------------------------------------------- +subroutine DAMASK_interface_init + + implicit none + integer, dimension(8) :: & + dateAndTime ! type default integer + + call date_and_time(values = dateAndTime) + write(6,'(/,a)') ' <<<+- DAMASK_Marc -+>>>' + write(6,'(/,a)') ' Version: '//DAMASKVERSION + write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& + dateAndTime(2),'/',& + dateAndTime(1) + write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& + dateAndTime(6),':',& + dateAndTime(7) + write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' +#include "compilation_info.f90" + +end subroutine DAMASK_interface_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the current workingDir +!-------------------------------------------------------------------------------------------------- +function getSolverWorkingDirectoryName() + + implicit none + character(1024) getSolverWorkingDirectoryName, inputName + character(len=*), parameter :: pathSep = achar(47)//achar(92) ! forward and backward slash + + getSolverWorkingDirectoryName='' + inputName='' + inquire(5, name=inputName) ! determine inputputfile + getSolverWorkingDirectoryName=inputName(1:scan(inputName,pathSep,back=.true.)) + +end function getSolverWorkingDirectoryName + + +!-------------------------------------------------------------------------------------------------- +!> @brief solver job name (no extension) as combination of geometry and load case name +!-------------------------------------------------------------------------------------------------- +function getSolverJobName() + use prec, only: & + pReal, & + pInt + + implicit none + character(1024) :: getSolverJobName, inputName + character(len=*), parameter :: pathSep = achar(47)//achar(92) ! forward and backward slash + integer(pInt) :: extPos + + getSolverJobName='' + inputName='' + inquire(5, name=inputName) ! determine inputfile + extPos = len_trim(inputName)-4 + getSolverJobName=inputName(scan(inputName,pathSep,back=.true.)+1:extPos) + +end function getSolverJobName + + +end module DAMASK_interface + +#include "commercialFEM_fileList.f90" + +!-------------------------------------------------------------------------------------------------- +!> @brief This is the MSC.Marc user subroutine for defining material behavior +!> @details (1) F,R,U are only available for continuum and membrane elements (not for +!> @details shells and beams). +!> @details +!> @details (2) Use the -> 'Plasticity,3' card(=update+finite+large disp+constant d) +!> @details in the parameter section of input deck (updated Lagrangian formulation). +!> @details +!> @details The following operation obtains U (stretch tensor) at t=n+1 : +!> @details +!> @details call scla(un1,0.d0,itel,itel,1) +!> @details do k=1,3 +!> @details do i=1,3 +!> @details do j=1,3 +!> @details un1(i,j)=un1(i,j)+dsqrt(strechn1(k))*eigvn1(i,k)*eigvn1(j,k) +!> @details enddo +!> @details enddo +!> @details enddo +!-------------------------------------------------------------------------------------------------- +subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, & + dispt,coord,ffn,frotn,strechn,eigvn,ffn1,frotn1, & + strechn1,eigvn1,ncrd,itel,ndeg,ndm,nnode, & + jtype,lclass,ifr,ifu) + use prec, only: & + pReal, & + pInt + use numerics, only: & +!$ DAMASK_NumThreadsInt, & + numerics_unitlength, & + usePingPong + use FEsolving, only: & + calcMode, & + terminallyIll, & + symmetricSolver + use math, only: & + math_transpose33,& + invnrmMandel + use debug, only: & + debug_level, & + debug_LEVELBASIC, & + debug_MARC, & + debug_info, & + debug_reset + use mesh, only: & + mesh_FEasCP, & + mesh_element, & + mesh_node0, & + mesh_node, & + mesh_Ncellnodes, & + mesh_cellnode, & + mesh_build_cellnodes, & + mesh_build_ipCoordinates, & + FE_Nnodes + use CPFEM, only: & + CPFEM_general, & + CPFEM_init_done, & + CPFEM_initAll, & + CPFEM_CALCRESULTS, & + CPFEM_AGERESULTS, & + CPFEM_COLLECT, & + CPFEM_RESTOREJACOBIAN, & + CPFEM_BACKUPJACOBIAN, & + cycleCounter, & + theInc, & + theTime, & + theDelta, & + lastIncConverged, & + outdatedByNewInc, & + outdatedFFN1, & + lastLovl + + implicit none +!$ include "omp_lib.h" ! the openMP function library + integer(pInt), intent(in) :: & ! according to MSC.Marc 2012 Manual D + ngens, & !< size of stress-strain law + nn, & !< integration point number + ndi, & !< number of direct components + nshear, & !< number of shear components + ncrd, & !< number of coordinates + itel, & !< dimension of F and R, either 2 or 3 + ndeg, & !< number of degrees of freedom + ndm, & !< not specified in MSC.Marc 2012 Manual D + nnode, & !< number of nodes per element + jtype, & !< element type + ifr, & !< set to 1 if R has been calculated + ifu !< set to 1 if stretch has been calculated + integer(pInt), dimension(2), intent(in) :: & ! according to MSC.Marc 2012 Manual D + m, & !< (1) user element number, (2) internal element number + matus, & !< (1) user material identification number, (2) internal material identification number + kcus, & !< (1) layer number, (2) internal layer number + lclass !< (1) element class, (2) 0: displacement, 1: low order Herrmann, 2: high order Herrmann + real(pReal), dimension(*), intent(in) :: & ! has dimension(1) according to MSC.Marc 2012 Manual D, but according to example hypela2.f dimension(*) + e, & !< total elastic strain + de, & !< increment of strain + dt !< increment of state variables + real(pReal), dimension(itel), intent(in) :: & ! according to MSC.Marc 2012 Manual D + strechn, & !< square of principal stretch ratios, lambda(i) at t=n + strechn1 !< square of principal stretch ratios, lambda(i) at t=n+1 + real(pReal), dimension(3,3), intent(in) :: & ! has dimension(itel,*) according to MSC.Marc 2012 Manual D, but we alway assume dimension(3,3) + ffn, & !< deformation gradient at t=n + ffn1 !< deformation gradient at t=n+1 + real(pReal), dimension(itel,*), intent(in) :: & ! according to MSC.Marc 2012 Manual D + frotn, & !< rotation tensor at t=n + eigvn, & !< i principal direction components for j eigenvalues at t=n + frotn1, & !< rotation tensor at t=n+1 + eigvn1 !< i principal direction components for j eigenvalues at t=n+1 + real(pReal), dimension(ndeg,*), intent(in) :: & ! according to MSC.Marc 2012 Manual D + disp, & !< incremental displacements + dispt !< displacements at t=n (at assembly, lovl=4) and displacements at t=n+1 (at stress recovery, lovl=6) + real(pReal), dimension(ncrd,*), intent(in) :: & ! according to MSC.Marc 2012 Manual D + coord !< coordinates + real(pReal), dimension(*), intent(inout) :: & ! according to MSC.Marc 2012 Manual D + t !< state variables (comes in at t=n, must be updated to have state variables at t=n+1) + real(pReal), dimension(ndi+nshear), intent(out) :: & ! has dimension(*) according to MSC.Marc 2012 Manual D, but we need to loop over it + s, & !< stress - should be updated by user + g !< change in stress due to temperature effects + real(pReal), dimension(ngens,ngens), intent(out) :: & ! according to MSC.Marc 2012 Manual D, but according to example hypela2.f dimension(ngens,*) + d !< stress-strain law to be formed + +!-------------------------------------------------------------------------------------------------- +! Marc common blocks are in fixed format so they have to be reformated to free format (f90) +! Beware of changes in newer Marc versions + +#include QUOTE(PASTE(../lib/MarcInclude/concom,Marc4DAMASK)) ! concom is needed for inc, lovl +#include QUOTE(PASTE(../lib/MarcInclude/creeps,Marc4DAMASK)) ! creeps is needed for timinc (time increment) + + logical :: cutBack + real(pReal), dimension(6) :: stress + real(pReal), dimension(6,6) :: ddsdde + integer(pInt) :: computationMode, i, cp_en, node, CPnodeID + !$ integer :: defaultNumThreadsInt !< default value set by Marc + + if (iand(debug_level(debug_MARC),debug_LEVELBASIC) /= 0_pInt) then + write(6,'(a,/,i8,i8,i2)') ' MSC.MARC information on shape of element(2), IP:', m, nn + write(6,'(a,2(1i))'), ' Jacobian: ', ngens,ngens + write(6,'(a,1i)'), ' Direct stress: ', ndi + write(6,'(a,1i)'), ' Shear stress: ', nshear + write(6,'(a,1i)'), ' DoF: ', ndeg + write(6,'(a,1i)'), ' Coordinates: ', ncrd + write(6,'(a,1i)'), ' Nodes: ', nnode + write(6,'(a,1i)'), ' Deformation gradient: ', itel + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' Deformation gradient at t=n:', & + math_transpose33(ffn) + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' Deformation gradient at t=n+1:', & + math_transpose33(ffn1) + endif + + !$ defaultNumThreadsInt = omp_get_num_threads() ! remember number of threads set by Marc + + if (.not. CPFEM_init_done) call CPFEM_initAll(m(1),nn) + + !$ call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution set by DAMASK_NUM_THREADS + + computationMode = 0_pInt ! save initialization value, since it does not result in any calculation + if (lovl == 4 ) then ! jacobian requested by marc + if (timinc < theDelta .and. theInc == inc .and. lastLovl /= lovl) & ! first after cutback + computationMode = CPFEM_RESTOREJACOBIAN + elseif (lovl == 6) then ! stress requested by marc + cp_en = mesh_FEasCP('elem',m(1)) + if (cptim > theTime .or. inc /= theInc) then ! reached "convergence" + terminallyIll = .false. + cycleCounter = -1 ! first calc step increments this to cycle = 0 + if (inc == 0) then ! >> start of analysis << + lastIncConverged = .false. ! no Jacobian backup + outdatedByNewInc = .false. ! no aging of state + calcMode = .false. ! pretend last step was collection + lastLovl = lovl ! pretend that this is NOT the first after a lovl change + !$OMP CRITICAL (write2out) + write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> start of analysis..! ',m(1),nn + flush(6) + !$OMP END CRITICAL (write2out) + else if (inc - theInc > 1) then ! >> restart of broken analysis << + lastIncConverged = .false. ! no Jacobian backup + outdatedByNewInc = .false. ! no aging of state + calcMode = .true. ! pretend last step was calculation + !$OMP CRITICAL (write2out) + write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> restart of analysis..! ',m(1),nn + flush(6) + !$OMP END CRITICAL (write2out) + else ! >> just the next inc << + lastIncConverged = .true. ! request Jacobian backup + outdatedByNewInc = .true. ! request aging of state + calcMode = .true. ! assure last step was calculation + !$OMP CRITICAL (write2out) + write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> new increment..! ',m(1),nn + flush(6) + !$OMP END CRITICAL (write2out) + endif + else if ( timinc < theDelta ) then ! >> cutBack << + lastIncConverged = .false. ! no Jacobian backup + outdatedByNewInc = .false. ! no aging of state + terminallyIll = .false. + cycleCounter = -1 ! first calc step increments this to cycle = 0 + calcMode = .true. ! pretend last step was calculation + !$OMP CRITICAL (write2out) + write(6,'(a,i6,1x,i2)') '<< HYPELA2 >> cutback detected..! ',m(1),nn + flush(6) + !$OMP END CRITICAL (write2out) + endif ! convergence treatment end + + + if (usePingPong) then + calcMode(nn,cp_en) = .not. calcMode(nn,cp_en) ! ping pong (calc <--> collect) + if (calcMode(nn,cp_en)) then ! now --- CALC --- + computationMode = CPFEM_CALCRESULTS + if (lastLovl /= lovl) then ! first after ping pong + call debug_reset() ! resets debugging + outdatedFFN1 = .false. + cycleCounter = cycleCounter + 1_pInt + mesh_cellnode = mesh_build_cellnodes(mesh_node,mesh_Ncellnodes) ! update cell node coordinates + call mesh_build_ipCoordinates() ! update ip coordinates + endif + if (outdatedByNewInc) then + computationMode = ior(computationMode,CPFEM_AGERESULTS) ! calc and age results + outdatedByNewInc = .false. ! reset flag + endif + else ! now --- COLLECT --- + computationMode = CPFEM_COLLECT ! plain collect + if (lastLovl /= lovl .and. & .not. terminallyIll) & + call debug_info() ! first after ping pong reports (meaningful) debugging + if (lastIncConverged) then + computationMode = ior(computationMode,CPFEM_BACKUPJACOBIAN) ! collect and backup Jacobian after convergence + lastIncConverged = .false. ! reset flag + endif + do node = 1,FE_Nnodes(mesh_element(2,cp_en)) + CPnodeID = mesh_element(4_pInt+node,cp_en) + mesh_node(1:ndeg,CPnodeID) = mesh_node0(1:ndeg,CPnodeID) + numerics_unitlength * dispt(1:ndeg,node) + enddo + endif + + else ! --- PLAIN MODE --- + computationMode = CPFEM_CALCRESULTS ! always calc + if (lastLovl /= lovl) then + if (.not. terminallyIll) & + call debug_info() ! first reports (meaningful) debugging + call debug_reset() ! and resets debugging + outdatedFFN1 = .false. + cycleCounter = cycleCounter + 1_pInt + mesh_cellnode = mesh_build_cellnodes(mesh_node,mesh_Ncellnodes) ! update cell node coordinates + call mesh_build_ipCoordinates() ! update ip coordinates + endif + if (outdatedByNewInc) then + computationMode = ior(computationMode,CPFEM_AGERESULTS) + outdatedByNewInc = .false. ! reset flag + endif + if (lastIncConverged) then + computationMode = ior(computationMode,CPFEM_BACKUPJACOBIAN) ! backup Jacobian after convergence + lastIncConverged = .false. ! reset flag + endif + endif + + theTime = cptim ! record current starting time + theDelta = timinc ! record current time increment + theInc = inc ! record current increment number + + endif + lastLovl = lovl ! record lovl + + call CPFEM_general(computationMode,usePingPong,ffn,ffn1,t(1),timinc,m(1),nn,stress,ddsdde) + +! Mandel: 11, 22, 33, SQRT(2)*12, SQRT(2)*23, SQRT(2)*13 +! Marc: 11, 22, 33, 12, 23, 13 +! Marc: 11, 22, 33, 12 + + forall(i=1:ngens) d(1:ngens,i) = invnrmMandel(i)*ddsdde(1:ngens,i)*invnrmMandel(1:ngens) + s(1:ndi+nshear) = stress(1:ndi+nshear)*invnrmMandel(1:ndi+nshear) + g = 0.0_pReal + if(symmetricSolver) d = 0.5_pReal*(d+transpose(d)) + + !$ call omp_set_num_threads(defaultNumThreadsInt) ! reset number of threads to stored default value + +end subroutine hypela2 + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets user defined output variables for Marc +!> @details select a variable contour plotting (user subroutine). +!-------------------------------------------------------------------------------------------------- +subroutine plotv(v,s,sp,etot,eplas,ecreep,t,m,nn,layer,ndi,nshear,jpltcd) + use prec, only: & + pReal, & + pInt + use mesh, only: & + mesh_FEasCP + use IO, only: & + IO_error + use homogenization, only: & + materialpoint_results,& + materialpoint_sizeResults + + implicit none + integer(pInt), intent(in) :: & + m, & !< element number + nn, & !< integration point number + layer, & !< layer number + ndi, & !< number of direct stress components + nshear, & !< number of shear stress components + jpltcd !< user variable index + real(pReal), dimension(*), intent(in) :: & + s, & !< stress array + sp, & !< stresses in preferred direction + etot, & !< total strain (generalized) + eplas, & !< total plastic strain + ecreep, & !< total creep strain + t !< current temperature + real(pReal), intent(out) :: & + v !< variable + + if (jpltcd > materialpoint_sizeResults) call IO_error(700_pInt,jpltcd) ! complain about out of bounds error + v = materialpoint_results(jpltcd,nn,mesh_FEasCP('elem', m)) + +end subroutine plotv diff --git a/src/DAMASK_marc2011.f90 b/src/DAMASK_marc2011.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/src/DAMASK_marc2011.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/src/DAMASK_marc2012.f90 b/src/DAMASK_marc2012.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/src/DAMASK_marc2012.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/src/DAMASK_marc2013.1.f90 b/src/DAMASK_marc2013.1.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/src/DAMASK_marc2013.1.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/src/DAMASK_marc2013.f90 b/src/DAMASK_marc2013.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/src/DAMASK_marc2013.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/src/DAMASK_marc2014.2.f90 b/src/DAMASK_marc2014.2.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/src/DAMASK_marc2014.2.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/src/DAMASK_marc2014.f90 b/src/DAMASK_marc2014.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/src/DAMASK_marc2014.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/src/DAMASK_marc2015.f90 b/src/DAMASK_marc2015.f90 new file mode 120000 index 000000000..2c5bec706 --- /dev/null +++ b/src/DAMASK_marc2015.f90 @@ -0,0 +1 @@ +DAMASK_marc.f90 \ No newline at end of file diff --git a/src/DAMASK_spectral.f90 b/src/DAMASK_spectral.f90 new file mode 100644 index 000000000..0d83d1279 --- /dev/null +++ b/src/DAMASK_spectral.f90 @@ -0,0 +1,751 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Driver controlling inner and outer load case looping of the various spectral solvers +!> @details doing cutbacking, forwarding in case of restart, reporting statistics, writing +!> results +!-------------------------------------------------------------------------------------------------- +program DAMASK_spectral + use, intrinsic :: & + iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use prec, only: & + pInt, & + pLongInt, & + pReal, & + tol_math_check + use DAMASK_interface, only: & + DAMASK_interface_init, & + loadCaseFile, & + geometryFile, & + getSolverWorkingDirectoryName, & + getSolverJobName, & + appendToOutFile + use IO, only: & + IO_read, & + IO_isBlank, & + IO_open_file, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_error, & + IO_lc, & + IO_intOut, & + IO_warning, & + IO_timeStamp, & + IO_EOF + use debug, only: & + debug_level, & + debug_spectral, & + debug_levelBasic + use math ! need to include the whole module for FFTW + use mesh, only: & + grid, & + geomSize + use CPFEM2, only: & + CPFEM_initAll + use FEsolving, only: & + restartWrite, & + restartInc + use numerics, only: & + worldrank, & + worldsize, & + stagItMax, & + maxCutBack, & + spectral_solver, & + continueCalculation + use homogenization, only: & + materialpoint_sizeResults, & + materialpoint_results, & + materialpoint_postResults + + + use material, only: & + thermal_type, & + damage_type, & + THERMAL_conduction_ID, & + DAMAGE_nonlocal_ID + use spectral_utilities, only: & + utilities_init, & + utilities_destroy, & + tSolutionState, & + tLoadCase, & + cutBack, & + nActiveFields, & + FIELD_UNDEFINED_ID, & + FIELD_MECH_ID, & + FIELD_THERMAL_ID, & + FIELD_DAMAGE_ID + use spectral_mech_Basic + use spectral_mech_AL + use spectral_mech_Polarisation + use spectral_damage + use spectral_thermal + + + implicit none + +#include + +!-------------------------------------------------------------------------------------------------- +! 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 + integer(pInt), parameter :: FILEUNIT = 234_pInt !< file unit, DAMASK IO does not support newunit feature + integer(pInt), allocatable, dimension(:) :: chunkPos + + integer(pInt) :: & + N_t = 0_pInt, & !< # of time indicators found in load case file + N_n = 0_pInt, & !< # of increment specifiers found in load case file + N_def = 0_pInt !< # of rate of deformation specifiers found in load case file + character(len=65536) :: & + line + +!-------------------------------------------------------------------------------------------------- +! loop variables, convergence etc. + real(pReal), dimension(3,3), parameter :: & + ones = 1.0_pReal, & + zeros = 0.0_pReal + integer(pInt), parameter :: & + subStepFactor = 2_pInt !< for each substep, divide the last time increment by 2.0 + real(pReal) :: & + time = 0.0_pReal, & !< elapsed time + time0 = 0.0_pReal, & !< begin of interval + timeinc = 1.0_pReal, & !< current time interval + timeIncOld = 0.0_pReal, & !< previous time interval + remainingLoadCaseTime = 0.0_pReal !< remaining time of current load case + logical :: & + guess, & !< guess along former trajectory + stagIterate + integer(pInt) :: & + i, j, k, l, field, & + errorID, & + cutBackLevel = 0_pInt, & !< cut back level \f$ t = \frac{t_{inc}}{2^l} \f$ + stepFraction = 0_pInt !< fraction of current time interval + integer(pInt) :: & + currentLoadcase = 0_pInt, & !< current load case + inc, & !< current increment in current load case + totalIncsCounter = 0_pInt, & !< total # of increments + convergedCounter = 0_pInt, & !< # of converged increments + notConvergedCounter = 0_pInt, & !< # of non-converged increments + resUnit = 0_pInt, & !< file unit for results writing + statUnit = 0_pInt, & !< file unit for statistics output + lastRestartWritten = 0_pInt, & !< total increment # at which last restart information was written + stagIter + character(len=6) :: loadcase_string + character(len=1024) :: incInfo !< string parsed to solution with information about current load case + type(tLoadCase), allocatable, dimension(:) :: loadCases !< array of all load cases + type(tSolutionState), allocatable, dimension(:) :: solres + integer(MPI_OFFSET_KIND) :: fileOffset + integer(MPI_OFFSET_KIND), dimension(:), allocatable :: outputSize + integer(pInt), parameter :: maxByteOut = 2147483647-4096 !< limit of one file output write https://trac.mpich.org/projects/mpich/ticket/1742 + integer(pLongInt), dimension(2) :: outputIndex + PetscErrorCode :: ierr + external :: & + quit, & + MPI_file_open, & + MPI_file_close, & + MPI_file_seek, & + MPI_file_get_position, & + MPI_file_write, & + MPI_allreduce + +!-------------------------------------------------------------------------------------------------- +! init DAMASK (all modules) + call CPFEM_initAll(el = 1_pInt, ip = 1_pInt) + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- DAMASK_spectral init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! initialize field solver information + nActiveFields = 1 + if (any(thermal_type == THERMAL_conduction_ID )) nActiveFields = nActiveFields + 1 + if (any(damage_type == DAMAGE_nonlocal_ID )) nActiveFields = nActiveFields + 1 + allocate(solres(nActiveFields)) + +!-------------------------------------------------------------------------------------------------- +! reading basic information from load case file and allocate data structure containing load cases + call IO_open_file(FILEUNIT,trim(loadCaseFile)) + rewind(FILEUNIT) + do + line = IO_read(FILEUNIT) + if (trim(line) == IO_EOF) exit + if (IO_isBlank(line)) cycle ! skip empty lines + chunkPos = IO_stringPos(line) + do i = 1_pInt, chunkPos(1) ! reading compulsory parameters for loadcase + select case (IO_lc(IO_stringValue(line,chunkPos,i))) + case('l','velocitygrad','velgrad','velocitygradient','fdot','dotf','f') + N_def = N_def + 1_pInt + case('t','time','delta') + N_t = N_t + 1_pInt + case('n','incs','increments','steps','logincs','logincrements','logsteps') + N_n = N_n + 1_pInt + end select + enddo ! count all identifiers to allocate memory and do sanity check + enddo + + if ((N_def /= N_n) .or. (N_n /= N_t) .or. N_n < 1_pInt) & ! sanity check + call IO_error(error_ID=837_pInt,ext_msg = trim(loadCaseFile)) ! error message for incomplete loadcase + allocate (loadCases(N_n)) ! array of load cases + loadCases%P%myType='p' + + do i = 1, size(loadCases) + allocate(loadCases(i)%ID(nActiveFields)) + field = 1 + loadCases(i)%ID(field) = FIELD_MECH_ID ! mechanical active by default + if (any(thermal_type == THERMAL_conduction_ID)) then ! thermal field active + field = field + 1 + loadCases(i)%ID(field) = FIELD_THERMAL_ID + endif + if (any(damage_type == DAMAGE_nonlocal_ID)) then ! damage field active + field = field + 1 + loadCases(i)%ID(field) = FIELD_DAMAGE_ID + endif + enddo + +!-------------------------------------------------------------------------------------------------- +! reading the load case and assign values to the allocated data structure + rewind(FILEUNIT) + do + line = IO_read(FILEUNIT) + if (trim(line) == IO_EOF) exit + if (IO_isBlank(line)) cycle ! skip empty lines + currentLoadCase = currentLoadCase + 1_pInt + chunkPos = IO_stringPos(line) + do i = 1_pInt, chunkPos(1) + select case (IO_lc(IO_stringValue(line,chunkPos,i))) + case('fdot','dotf','l','velocitygrad','velgrad','velocitygradient','f') ! assign values for the deformation BC matrix + temp_valueVector = 0.0_pReal + if (IO_lc(IO_stringValue(line,chunkPos,i)) == 'fdot'.or. & ! in case of Fdot, set type to fdot + IO_lc(IO_stringValue(line,chunkPos,i)) == 'dotf') then + loadCases(currentLoadCase)%deformation%myType = 'fdot' + else if (IO_lc(IO_stringValue(line,chunkPos,i)) == 'f') then + loadCases(currentLoadCase)%deformation%myType = 'f' + else + loadCases(currentLoadCase)%deformation%myType = 'l' + endif + do j = 1_pInt, 9_pInt + temp_maskVector(j) = IO_stringValue(line,chunkPos,i+j) /= '*' ! true if not a * + enddo + do j = 1_pInt,9_pInt + if (temp_maskVector(j)) temp_valueVector(j) = IO_floatValue(line,chunkPos,i+j) ! read value where applicable + enddo + loadCases(currentLoadCase)%deformation%maskLogical = & ! logical mask in 3x3 notation + transpose(reshape(temp_maskVector,[ 3,3])) + loadCases(currentLoadCase)%deformation%maskFloat = & ! float (1.0/0.0) mask in 3x3 notation + merge(ones,zeros,loadCases(currentLoadCase)%deformation%maskLogical) + loadCases(currentLoadCase)%deformation%values = math_plain9to33(temp_valueVector) ! values in 3x3 notation + case('p','pk1','piolakirchhoff','stress', 's') + temp_valueVector = 0.0_pReal + do j = 1_pInt, 9_pInt + temp_maskVector(j) = IO_stringValue(line,chunkPos,i+j) /= '*' ! true if not an asterisk + enddo + do j = 1_pInt,9_pInt + if (temp_maskVector(j)) temp_valueVector(j) = IO_floatValue(line,chunkPos,i+j) ! read value where applicable + enddo + loadCases(currentLoadCase)%P%maskLogical = transpose(reshape(temp_maskVector,[ 3,3])) + loadCases(currentLoadCase)%P%maskFloat = merge(ones,zeros,& + loadCases(currentLoadCase)%P%maskLogical) + loadCases(currentLoadCase)%P%values = math_plain9to33(temp_valueVector) + case('t','time','delta') ! increment time + loadCases(currentLoadCase)%time = IO_floatValue(line,chunkPos,i+1_pInt) + case('n','incs','increments','steps') ! number of increments + loadCases(currentLoadCase)%incs = IO_intValue(line,chunkPos,i+1_pInt) + case('logincs','logincrements','logsteps') ! number of increments (switch to log time scaling) + loadCases(currentLoadCase)%incs = IO_intValue(line,chunkPos,i+1_pInt) + loadCases(currentLoadCase)%logscale = 1_pInt + case('freq','frequency','outputfreq') ! frequency of result writings + loadCases(currentLoadCase)%outputfrequency = IO_intValue(line,chunkPos,i+1_pInt) + case('r','restart','restartwrite') ! frequency of writing restart information + loadCases(currentLoadCase)%restartfrequency = & + max(0_pInt,IO_intValue(line,chunkPos,i+1_pInt)) + case('guessreset','dropguessing') + loadCases(currentLoadCase)%followFormerTrajectory = .false. ! do not continue to predict deformation along former trajectory + case('euler') ! rotation of currentLoadCase given in euler angles + temp_valueVector = 0.0_pReal + l = 1_pInt ! assuming values given in degrees + k = 1_pInt ! assuming keyword indicating degree/radians present + select case (IO_lc(IO_stringValue(line,chunkPos,i+1_pInt))) + case('deg','degree') + case('rad','radian') ! don't convert from degree to radian + l = 0_pInt + case default + k = 0_pInt + end select + do j = 1_pInt, 3_pInt + temp_valueVector(j) = IO_floatValue(line,chunkPos,i+k+j) + enddo + if (l == 1_pInt) temp_valueVector(1:3) = temp_valueVector(1:3) * inRad ! convert to rad + loadCases(currentLoadCase)%rotation = math_EulerToR(temp_valueVector(1:3)) ! convert rad Eulers to rotation matrix + case('rotation','rot') ! assign values for the rotation of currentLoadCase matrix + temp_valueVector = 0.0_pReal + do j = 1_pInt, 9_pInt + temp_valueVector(j) = IO_floatValue(line,chunkPos,i+j) + enddo + loadCases(currentLoadCase)%rotation = math_plain9to33(temp_valueVector) + end select + enddo; enddo + close(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! consistency checks and output of load case + loadCases(1)%followFormerTrajectory = .false. ! cannot guess along trajectory for first inc of first currentLoadCase + errorID = 0_pInt + if (worldrank == 0) then + checkLoadcases: do currentLoadCase = 1_pInt, size(loadCases) + write (loadcase_string, '(i6)' ) currentLoadCase + write(6,'(1x,a,i6)') 'load case: ', currentLoadCase + if (.not. loadCases(currentLoadCase)%followFormerTrajectory) & + write(6,'(2x,a)') 'drop guessing along trajectory' + if (loadCases(currentLoadCase)%deformation%myType=='l') then + do j = 1_pInt, 3_pInt + if (any(loadCases(currentLoadCase)%deformation%maskLogical(j,1:3) .eqv. .true.) .and. & + any(loadCases(currentLoadCase)%deformation%maskLogical(j,1:3) .eqv. .false.)) & + errorID = 832_pInt ! each row should be either fully or not at all defined + enddo + write(6,'(2x,a)') 'velocity gradient:' + else if (loadCases(currentLoadCase)%deformation%myType=='f') then + write(6,'(2x,a)') 'deformation gradient at end of load case:' + else + write(6,'(2x,a)') 'deformation gradient rate:' + endif + do i = 1_pInt, 3_pInt; do j = 1_pInt, 3_pInt + if(loadCases(currentLoadCase)%deformation%maskLogical(i,j)) then + write(6,'(2x,f12.7)',advance='no') loadCases(currentLoadCase)%deformation%values(i,j) + else + write(6,'(2x,12a)',advance='no') ' * ' + endif + enddo; write(6,'(/)',advance='no') + enddo + if (any(loadCases(currentLoadCase)%P%maskLogical .eqv. & + loadCases(currentLoadCase)%deformation%maskLogical)) errorID = 831_pInt ! exclusive or masking only + if (any(loadCases(currentLoadCase)%P%maskLogical .and. & + transpose(loadCases(currentLoadCase)%P%maskLogical) .and. & + reshape([ .false.,.true.,.true.,.true.,.false.,.true.,.true.,.true.,.false.],[ 3,3]))) & + errorID = 838_pInt ! no rotation is allowed by stress BC + write(6,'(2x,a)') 'stress / GPa:' + do i = 1_pInt, 3_pInt; do j = 1_pInt, 3_pInt + if(loadCases(currentLoadCase)%deformation%maskLogical(i,j)) then + write(6,'(2x,f12.7)',advance='no') loadCases(currentLoadCase)%P%values(i,j)*1e-9_pReal + else + write(6,'(2x,12a)',advance='no') ' * ' + endif + enddo; write(6,'(/)',advance='no') + enddo + if (any(abs(math_mul33x33(loadCases(currentLoadCase)%rotation, & + math_transpose33(loadCases(currentLoadCase)%rotation))-math_I3) >& + reshape(spread(tol_math_check,1,9),[ 3,3]))& + .or. abs(math_det33(loadCases(currentLoadCase)%rotation)) > & + 1.0_pReal + tol_math_check) errorID = 846_pInt ! given rotation matrix contains strain + if (any(loadCases(currentLoadCase)%rotation /= math_I3)) & + write(6,'(2x,a,/,3(3(3x,f12.7,1x)/))',advance='no') 'rotation of loadframe:',& + math_transpose33(loadCases(currentLoadCase)%rotation) + if (loadCases(currentLoadCase)%time < 0.0_pReal) errorID = 834_pInt ! negative time increment + write(6,'(2x,a,f12.6)') 'time: ', loadCases(currentLoadCase)%time + if (loadCases(currentLoadCase)%incs < 1_pInt) errorID = 835_pInt ! non-positive incs count + write(6,'(2x,a,i5)') 'increments: ', loadCases(currentLoadCase)%incs + if (loadCases(currentLoadCase)%outputfrequency < 1_pInt) errorID = 836_pInt ! non-positive result frequency + write(6,'(2x,a,i5)') 'output frequency: ', & + loadCases(currentLoadCase)%outputfrequency + write(6,'(2x,a,i5,/)') 'restart frequency: ', & + loadCases(currentLoadCase)%restartfrequency + if (errorID > 0_pInt) call IO_error(error_ID = errorID, ext_msg = loadcase_string) ! exit with error message + enddo checkLoadcases + endif + +!-------------------------------------------------------------------------------------------------- +! doing initialization depending on selected solver + call Utilities_init() + do field = 1, nActiveFields + select case (loadCases(1)%ID(field)) + case(FIELD_MECH_ID) + select case (spectral_solver) + case (DAMASK_spectral_SolverBasicPETSc_label) + call basicPETSc_init + case (DAMASK_spectral_SolverAL_label) + if(iand(debug_level(debug_spectral),debug_levelBasic)/= 0 .and. worldrank == 0_pInt) & + call IO_warning(42_pInt, ext_msg='debug Divergence') + call AL_init + + case (DAMASK_spectral_SolverPolarisation_label) + if(iand(debug_level(debug_spectral),debug_levelBasic)/= 0 .and. worldrank == 0_pInt) & + call IO_warning(42_pInt, ext_msg='debug Divergence') + call Polarisation_init + + case default + call IO_error(error_ID = 891, ext_msg = trim(spectral_solver)) + + end select + + case(FIELD_THERMAL_ID) + call spectral_thermal_init + + case(FIELD_DAMAGE_ID) + call spectral_damage_init() + + end select + enddo + +!-------------------------------------------------------------------------------------------------- +! write header of output file + if (worldrank == 0) then + if (.not. appendToOutFile) then ! after restart, append to existing results file + open(newunit=resUnit,file=trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//& + '.spectralOut',form='UNFORMATTED',status='REPLACE') + write(resUnit) 'load:', trim(loadCaseFile) ! ... and write header + write(resUnit) 'workingdir:', trim(getSolverWorkingDirectoryName()) + write(resUnit) 'geometry:', trim(geometryFile) + write(resUnit) 'grid:', grid + write(resUnit) 'size:', geomSize + write(resUnit) 'materialpoint_sizeResults:', materialpoint_sizeResults + write(resUnit) 'loadcases:', size(loadCases) + write(resUnit) 'frequencies:', loadCases%outputfrequency ! one entry per LoadCase + write(resUnit) 'times:', loadCases%time ! one entry per LoadCase + write(resUnit) 'logscales:', loadCases%logscale + write(resUnit) 'increments:', loadCases%incs ! one entry per LoadCase + write(resUnit) 'startingIncrement:', restartInc - 1_pInt ! start with writing out the previous inc + write(resUnit) 'eoh' + close(resUnit) ! end of header + open(newunit=statUnit,file=trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//& + '.sta',form='FORMATTED',status='REPLACE') + write(statUnit,'(a)') 'Increment Time CutbackLevel Converged IterationsNeeded' ! statistics file + if (iand(debug_level(debug_spectral),debug_levelBasic) /= 0) & + write(6,'(/,a)') ' header of result and statistics file written out' + flush(6) + else ! open new files ... + open(newunit=statUnit,file=trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//& + '.sta',form='FORMATTED', position='APPEND', status='OLD') + endif + endif + +!-------------------------------------------------------------------------------------------------- +! prepare MPI parallel out (including opening of file) + allocate(outputSize(worldsize), source = 0_MPI_OFFSET_KIND) + outputSize(worldrank+1) = int(size(materialpoint_results)*pReal,MPI_OFFSET_KIND) + call MPI_allreduce(MPI_IN_PLACE,outputSize,worldsize,MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get total output size over each process + call MPI_file_open(PETSC_COMM_WORLD, & + trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.spectralOut', & + MPI_MODE_WRONLY + MPI_MODE_APPEND, & + MPI_INFO_NULL, & + resUnit, & + ierr) + call MPI_file_get_position(resUnit,fileOffset,ierr) ! get offset from header + fileOffset = fileOffset + sum(outputSize(1:worldrank)) ! offset of my process in file (header + processes before me) + call MPI_file_seek (resUnit,fileOffset,MPI_SEEK_SET,ierr) + + if (.not. appendToOutFile) then ! if not restarting, write 0th increment + do i=1, size(materialpoint_results,3)/(maxByteOut/(materialpoint_sizeResults*pReal))+1 ! slice the output of my process in chunks not exceeding the limit for one output + outputIndex=[(i-1)*((maxByteOut/pReal)/materialpoint_sizeResults)+1, & + min(i*((maxByteOut/pReal)/materialpoint_sizeResults),size(materialpoint_results,3))] + call MPI_file_write(resUnit,reshape(materialpoint_results(:,:,outputIndex(1):outputIndex(2)),& + [(outputIndex(2)-outputIndex(1)+1)*materialpoint_sizeResults]), & + (outputIndex(2)-outputIndex(1)+1)*materialpoint_sizeResults,& + MPI_DOUBLE, MPI_STATUS_IGNORE, ierr) + fileOffset = fileOffset + sum(outputSize) ! forward to current file position + enddo + if (worldrank == 0) & + write(6,'(1/,a)') ' ... writing initial configuration to file ........................' + endif +!-------------------------------------------------------------------------------------------------- +! loopping over loadcases + loadCaseLooping: do currentLoadCase = 1_pInt, size(loadCases) + time0 = time ! currentLoadCase start time + guess = loadCases(currentLoadCase)%followFormerTrajectory ! change of load case? homogeneous guess for the first inc + +!-------------------------------------------------------------------------------------------------- +! loop oper incs defined in input file for current currentLoadCase + incLooping: do inc = 1_pInt, loadCases(currentLoadCase)%incs + totalIncsCounter = totalIncsCounter + 1_pInt + +!-------------------------------------------------------------------------------------------------- +! forwarding time + timeIncOld = timeinc + if (loadCases(currentLoadCase)%logscale == 0_pInt) then ! linear scale + timeinc = loadCases(currentLoadCase)%time/loadCases(currentLoadCase)%incs ! only valid for given linear time scale. will be overwritten later in case loglinear scale is used + else + if (currentLoadCase == 1_pInt) then ! 1st currentLoadCase of logarithmic scale + if (inc == 1_pInt) then ! 1st inc of 1st currentLoadCase of logarithmic scale + timeinc = loadCases(1)%time*(2.0_pReal**real( 1_pInt-loadCases(1)%incs ,pReal)) ! assume 1st inc is equal to 2nd + else ! not-1st inc of 1st currentLoadCase of logarithmic scale + timeinc = loadCases(1)%time*(2.0_pReal**real(inc-1_pInt-loadCases(1)%incs ,pReal)) + endif + else ! not-1st currentLoadCase of logarithmic scale + timeinc = time0 * & + ( (1.0_pReal + loadCases(currentLoadCase)%time/time0 )**(real( inc,pReal)/& + real(loadCases(currentLoadCase)%incs ,pReal))& + -(1.0_pReal + loadCases(currentLoadCase)%time/time0 )**(real( (inc-1_pInt),pReal)/& + real(loadCases(currentLoadCase)%incs ,pReal))) + endif + endif + timeinc = timeinc / 2.0_pReal**real(cutBackLevel,pReal) ! depending on cut back level, decrease time step + + forwarding: if(totalIncsCounter >= restartInc) then + stepFraction = 0_pInt + +!-------------------------------------------------------------------------------------------------- +! loop over sub incs + subIncLooping: do while (stepFraction/subStepFactor**cutBackLevel <1_pInt) + time = time + timeinc ! forward time + stepFraction = stepFraction + 1_pInt + remainingLoadCaseTime = time0 - time + loadCases(currentLoadCase)%time + timeInc + +!-------------------------------------------------------------------------------------------------- +! report begin of new increment + if (worldrank == 0) then + write(6,'(/,a)') ' ###########################################################################' + write(6,'(1x,a,es12.5'//& + ',a,'//IO_intOut(inc)//',a,'//IO_intOut(loadCases(currentLoadCase)%incs)//& + ',a,'//IO_intOut(stepFraction)//',a,'//IO_intOut(subStepFactor**cutBackLevel)//& + ',a,'//IO_intOut(currentLoadCase)//',a,'//IO_intOut(size(loadCases))//')') & + 'Time', time, & + 's: Increment ', inc, '/', loadCases(currentLoadCase)%incs,& + '-', stepFraction, '/', subStepFactor**cutBackLevel,& + ' of load case ', currentLoadCase,'/',size(loadCases) + flush(6) + write(incInfo,'(a,'//IO_intOut(totalIncsCounter)//',a,'//IO_intOut(sum(loadCases%incs))//& + ',a,'//IO_intOut(stepFraction)//',a,'//IO_intOut(subStepFactor**cutBackLevel)//')') & + 'Increment ',totalIncsCounter,'/',sum(loadCases%incs),& + '-',stepFraction, '/', subStepFactor**cutBackLevel + endif + +!-------------------------------------------------------------------------------------------------- +! forward fields + do field = 1, nActiveFields + select case(loadCases(currentLoadCase)%ID(field)) + case(FIELD_MECH_ID) + select case (spectral_solver) + case (DAMASK_spectral_SolverBasicPETSc_label) + call BasicPETSc_forward (& + guess,timeinc,timeIncOld,remainingLoadCaseTime, & + F_BC = loadCases(currentLoadCase)%deformation, & + P_BC = loadCases(currentLoadCase)%P, & + rotation_BC = loadCases(currentLoadCase)%rotation) + case (DAMASK_spectral_SolverAL_label) + call AL_forward (& + guess,timeinc,timeIncOld,remainingLoadCaseTime, & + F_BC = loadCases(currentLoadCase)%deformation, & + P_BC = loadCases(currentLoadCase)%P, & + rotation_BC = loadCases(currentLoadCase)%rotation) + case (DAMASK_spectral_SolverPolarisation_label) + call Polarisation_forward (& + guess,timeinc,timeIncOld,remainingLoadCaseTime, & + F_BC = loadCases(currentLoadCase)%deformation, & + P_BC = loadCases(currentLoadCase)%P, & + rotation_BC = loadCases(currentLoadCase)%rotation) + end select + + case(FIELD_THERMAL_ID) + call spectral_thermal_forward (& + guess,timeinc,timeIncOld,remainingLoadCaseTime) + + case(FIELD_DAMAGE_ID) + call spectral_damage_forward (& + guess,timeinc,timeIncOld,remainingLoadCaseTime) + end select + enddo + +!-------------------------------------------------------------------------------------------------- +! solve fields + stagIter = 0_pInt + stagIterate = .true. + do while (stagIterate) + do field = 1, nActiveFields + select case(loadCases(currentLoadCase)%ID(field)) + case(FIELD_MECH_ID) + select case (spectral_solver) + case (DAMASK_spectral_SolverBasicPETSc_label) + solres(field) = BasicPETSC_solution (& + incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & + P_BC = loadCases(currentLoadCase)%P, & + F_BC = loadCases(currentLoadCase)%deformation, & + rotation_BC = loadCases(currentLoadCase)%rotation) + + case (DAMASK_spectral_SolverAL_label) + solres(field) = AL_solution (& + incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & + P_BC = loadCases(currentLoadCase)%P, & + F_BC = loadCases(currentLoadCase)%deformation, & + rotation_BC = loadCases(currentLoadCase)%rotation) + + case (DAMASK_spectral_SolverPolarisation_label) + solres(field) = Polarisation_solution (& + incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & + P_BC = loadCases(currentLoadCase)%P, & + F_BC = loadCases(currentLoadCase)%deformation, & + rotation_BC = loadCases(currentLoadCase)%rotation) + + end select + + case(FIELD_THERMAL_ID) + solres(field) = spectral_thermal_solution (& + guess,timeinc,timeIncOld,remainingLoadCaseTime) + + case(FIELD_DAMAGE_ID) + solres(field) = spectral_damage_solution (& + guess,timeinc,timeIncOld,remainingLoadCaseTime) + + end select + if(.not. solres(field)%converged) exit ! no solution found + enddo + stagIter = stagIter + 1_pInt + stagIterate = stagIter < stagItMax .and. & + all(solres(:)%converged) .and. & + .not. all(solres(:)%stagConverged) + enddo + +!-------------------------------------------------------------------------------------------------- +! check solution + cutBack = .False. + if(solres(1)%termIll .or. .not. all(solres(:)%converged .and. solres(:)%stagConverged)) then ! no solution found + if (cutBackLevel < maxCutBack) then ! do cut back + if (worldrank == 0) write(6,'(/,a)') ' cut back detected' + cutBack = .True. + stepFraction = (stepFraction - 1_pInt) * subStepFactor ! adjust to new denominator + cutBackLevel = cutBackLevel + 1_pInt + time = time - timeinc ! rewind time + timeinc = timeinc/2.0_pReal + elseif (solres(1)%termIll) then ! material point model cannot find a solution, exit in any casy + call IO_warning(850_pInt) + call quit(-1_pInt*(lastRestartWritten+1_pInt)) ! quit and provide information about last restart inc written (e.g. for regridding) + elseif (continueCalculation == 1_pInt) then + guess = .true. ! accept non converged BVP solution + else ! default behavior, exit if spectral solver does not converge + call IO_warning(850_pInt) + call quit(-1_pInt*(lastRestartWritten+1_pInt)) ! quit and provide information about last restart inc written (e.g. for regridding) + endif + else + guess = .true. ! start guessing after first converged (sub)inc + endif + if (.not. cutBack) then + if (worldrank == 0) then + write(statUnit,*) totalIncsCounter, time, cutBackLevel, & + solres%converged, solres%iterationsNeeded ! write statistics about accepted solution + flush(statUnit) + endif + endif + enddo subIncLooping + cutBackLevel = max(0_pInt, cutBackLevel - 1_pInt) ! try half number of subincs next inc + if(all(solres(:)%converged)) then ! report converged inc + convergedCounter = convergedCounter + 1_pInt + if (worldrank == 0) & + write(6,'(/,a,'//IO_intOut(totalIncsCounter)//',a)') & + ' increment ', totalIncsCounter, ' converged' + else + if (worldrank == 0) & + write(6,'(/,a,'//IO_intOut(totalIncsCounter)//',a)') & ! report non-converged inc + ' increment ', totalIncsCounter, ' NOT converged' + notConvergedCounter = notConvergedCounter + 1_pInt + endif; flush(6) + if (mod(inc,loadCases(currentLoadCase)%outputFrequency) == 0_pInt) then ! at output frequency + if (worldrank == 0) & + write(6,'(1/,a)') ' ... writing results to file ......................................' + call materialpoint_postResults() + call MPI_file_seek (resUnit,fileOffset,MPI_SEEK_SET,ierr) + do i=1, size(materialpoint_results,3)/(maxByteOut/(materialpoint_sizeResults*pReal))+1 ! slice the output of my process in chunks not exceeding the limit for one output + outputIndex=[(i-1)*maxByteOut/pReal/materialpoint_sizeResults+1, & + min(i*maxByteOut/pReal/materialpoint_sizeResults,size(materialpoint_results,3))] + call MPI_file_write(resUnit,reshape(materialpoint_results(:,:,outputIndex(1):outputIndex(2)),& + [(outputIndex(2)-outputIndex(1)+1)*materialpoint_sizeResults]), & + (outputIndex(2)-outputIndex(1)+1)*materialpoint_sizeResults,& + MPI_DOUBLE, MPI_STATUS_IGNORE, ierr) + fileOffset = fileOffset + sum(outputSize) ! forward to current file position + enddo + endif + if( loadCases(currentLoadCase)%restartFrequency > 0_pInt .and. & ! at frequency of writing restart information set restart parameter for FEsolving + mod(inc,loadCases(currentLoadCase)%restartFrequency) == 0_pInt) then ! first call to CPFEM_general will write? + restartWrite = .true. + lastRestartWritten = inc + endif + else forwarding + time = time + timeinc + guess = .true. + endif forwarding + + enddo incLooping + enddo loadCaseLooping + +!-------------------------------------------------------------------------------------------------- +! report summary of whole calculation + if (worldrank == 0) then + write(6,'(/,a)') ' ###########################################################################' + write(6,'(1x,i6.6,a,i6.6,a,f5.1,a)') convergedCounter, ' out of ', & + notConvergedCounter + convergedCounter, ' (', & + real(convergedCounter, pReal)/& + real(notConvergedCounter + convergedCounter,pReal)*100.0_pReal, & + ' %) increments converged!' + endif + call MPI_file_close(resUnit,ierr) + close(statUnit) + + do field = 1, nActiveFields + select case(loadCases(1)%ID(field)) + case(FIELD_MECH_ID) + select case (spectral_solver) + case (DAMASK_spectral_SolverBasicPETSc_label) + call BasicPETSC_destroy() + case (DAMASK_spectral_SolverAL_label) + call AL_destroy() + case (DAMASK_spectral_SolverPolarisation_label) + call Polarisation_destroy() + end select + case(FIELD_THERMAL_ID) + call spectral_thermal_destroy() + case(FIELD_DAMAGE_ID) + call spectral_damage_destroy() + end select + enddo + call utilities_destroy() + + call PetscFinalize(ierr); CHKERRQ(ierr) + + if (notConvergedCounter > 0_pInt) call quit(3_pInt) ! error if some are not converged + call quit(0_pInt) ! no complains ;) + +end program DAMASK_spectral + + +!-------------------------------------------------------------------------------------------------- +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief quit subroutine to mimic behavior of FEM solvers +!> @details exits the Spectral solver and reports time and duration. Exit code 0 signals +!> everything went fine. Exit code 1 signals an error, message according to IO_error. Exit code +!> 2 signals request for regridding, increment of last saved restart information is written to +!> stderr. Exit code 3 signals no severe problems, but some increments did not converge +!-------------------------------------------------------------------------------------------------- +subroutine quit(stop_id) + use prec, only: & + pInt + use numerics, only: & + worldrank + + implicit none + integer(pInt), intent(in) :: stop_id + integer, dimension(8) :: dateAndTime ! type default integer + + if (worldrank == 0_pInt) then + call date_and_time(values = dateAndTime) + write(6,'(/,a)') 'DAMASK terminated on:' + write(6,'(a,2(i2.2,a),i4.4)') 'Date: ',dateAndTime(3),'/',& + dateAndTime(2),'/',& + dateAndTime(1) + write(6,'(a,2(i2.2,a),i2.2)') 'Time: ',dateAndTime(5),':',& + dateAndTime(6),':',& + dateAndTime(7) + endif + + if (stop_id == 0_pInt) stop 0 ! normal termination + if (stop_id < 0_pInt) then ! trigger regridding + if (worldrank == 0_pInt) & + write(0,'(a,i6)') 'restart information available at ', stop_id*(-1_pInt) + stop 2 + endif + if (stop_id == 3_pInt) stop 3 ! not all incs converged + stop 1 ! error (message from IO_error) + +end subroutine quit diff --git a/src/FEsolving.f90 b/src/FEsolving.f90 new file mode 100644 index 000000000..ed11448d7 --- /dev/null +++ b/src/FEsolving.f90 @@ -0,0 +1,171 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief triggering reading in of restart information when doing a restart +!> @todo Descriptions for public variables needed +!-------------------------------------------------------------------------------------------------- +module FEsolving + use prec, only: & + pInt, & + pReal + + implicit none + private + integer(pInt), public :: & + restartInc = 1_pInt !< needs description + + logical, public :: & + symmetricSolver = .false., & !< use a symmetric FEM solver + restartWrite = .false., & !< write current state to enable restart + restartRead = .false., & !< restart information to continue calculation from saved state + terminallyIll = .false. !< at least one material point is terminally ill + + integer(pInt), dimension(:,:), allocatable, public :: & + FEsolving_execIP !< for ping-pong scheme always range to max IP, otherwise one specific IP + + integer(pInt), dimension(2), public :: & + FEsolving_execElem !< for ping-pong scheme always whole range, otherwise one specific element + + character(len=1024), public :: & + modelName !< needs description + + logical, dimension(:,:), allocatable, public :: & + calcMode !< do calculation or simply collect when using ping pong scheme + + public :: FE_init + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief determine whether a symmetric solver is used and whether restart is requested +!> @details restart information is found in input file in case of FEM solvers, in case of spectal +!> solver the information is provided by the interface module +!-------------------------------------------------------------------------------------------------- +subroutine FE_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_FEsolving, & + debug_levelBasic + use IO, only: & + IO_stringPos, & + IO_stringValue, & + IO_intValue, & + IO_lc, & +#if defined(Marc4DAMASK) || defined(Abaqus) + IO_open_inputFile, & + IO_open_logFile, & +#endif + IO_warning, & + IO_timeStamp + use DAMASK_interface + use numerics, only: & + worldrank + + implicit none +#if defined(Marc4DAMASK) || defined(Abaqus) + integer(pInt), parameter :: & + FILEUNIT = 222_pInt + integer(pInt) :: j + character(len=65536) :: tag, line + integer(pInt), allocatable, dimension(:) :: chunkPos +#endif + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- FEsolving init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + modelName = getSolverJobName() +#ifdef Spectral + restartInc = spectralRestartInc + if(restartInc <= 0_pInt) then + call IO_warning(warning_ID=34_pInt) + restartInc = 1_pInt + endif + restartRead = restartInc > 1_pInt ! only read in if "true" restart requested +#elif defined FEM + restartInc = FEMRestartInc + if(restartInc <= 0_pInt) then + call IO_warning(warning_ID=34_pInt) + restartInc = 1_pInt + endif + restartRead = restartInc > 1_pInt +#else + call IO_open_inputFile(FILEUNIT,modelName) + rewind(FILEUNIT) + do + read (FILEUNIT,'(a1024)',END=100) line + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('solver') + read (FILEUNIT,'(a1024)',END=100) line ! next line + chunkPos = IO_stringPos(line) + symmetricSolver = (IO_intValue(line,chunkPos,2_pInt) /= 1_pInt) + case ('restart') + read (FILEUNIT,'(a1024)',END=100) line ! next line + chunkPos = IO_stringPos(line) + restartWrite = iand(IO_intValue(line,chunkPos,1_pInt),1_pInt) > 0_pInt + restartRead = iand(IO_intValue(line,chunkPos,1_pInt),2_pInt) > 0_pInt + case ('*restart') + do j=2_pInt,chunkPos(1) + restartWrite = (IO_lc(IO_StringValue(line,chunkPos,j)) == 'write') .or. restartWrite + restartRead = (IO_lc(IO_StringValue(line,chunkPos,j)) == 'read') .or. restartRead + enddo + if(restartWrite) then + do j=2_pInt,chunkPos(1) + restartWrite = (IO_lc(IO_StringValue(line,chunkPos,j)) /= 'frequency=0') .and. restartWrite + enddo + endif + end select + enddo + 100 close(FILEUNIT) + + if (restartRead) then +#ifdef Marc4DAMASK + call IO_open_logFile(FILEUNIT) + rewind(FILEUNIT) + do + read (FILEUNIT,'(a1024)',END=200) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'restart' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'file' .and. & + IO_lc(IO_stringValue(line,chunkPos,3_pInt)) == 'job' .and. & + IO_lc(IO_stringValue(line,chunkPos,4_pInt)) == 'id' ) & + modelName = IO_StringValue(line,chunkPos,6_pInt) + enddo +#else + call IO_open_inputFile(FILEUNIT,modelName) + rewind(FILEUNIT) + do + read (FILEUNIT,'(a1024)',END=200) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt))=='*heading') then + read (FILEUNIT,'(a1024)',END=200) line + chunkPos = IO_stringPos(line) + modelName = IO_StringValue(line,chunkPos,1_pInt) + endif + enddo +#endif + 200 close(FILEUNIT) + endif + +!-------------------------------------------------------------------------------------------------- +! the following array are allocated by mesh.f90 and need to be deallocated in case of regridding + if (allocated(calcMode)) deallocate(calcMode) + if (allocated(FEsolving_execIP)) deallocate(FEsolving_execIP) +#endif + if (iand(debug_level(debug_FEsolving),debug_levelBasic) /= 0_pInt) then + write(6,'(a21,l1)') ' restart writing: ', restartWrite + write(6,'(a21,l1)') ' restart reading: ', restartRead + if (restartRead) write(6,'(a,/)') ' restart Job: '//trim(modelName) + endif + +end subroutine FE_init + +end module FEsolving diff --git a/src/IO.f90 b/src/IO.f90 new file mode 100644 index 000000000..95ac6fffd --- /dev/null +++ b/src/IO.f90 @@ -0,0 +1,2470 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @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 Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief input/output functions, partly depending on chosen solver +!-------------------------------------------------------------------------------------------------- +module IO +#ifdef HDF + use hdf5, only: & + HID_T +#endif + use prec, only: & + pInt, & + pReal + + implicit none + private + character(len=5), parameter, public :: & + IO_EOF = '#EOF#' !< end of file string +#ifdef HDF + integer(HID_T), public, protected :: tempCoordinates, tempResults + integer(HID_T), private :: resultsFile, tempFile + integer(pInt), private :: currentInc +#endif + + public :: & +#ifdef HDF + HDF5_mappingConstitutive, & + HDF5_mappingHomogenization, & + HDF5_mappingCells, & + HDF5_addGroup ,& + HDF5_forwardResults, & + HDF5_addScalarDataset, & + IO_formatIntToString ,& +#endif + IO_init, & + IO_read, & + IO_checkAndRewind, & + IO_open_file_stat, & + IO_open_jobFile_stat, & + IO_open_file, & + IO_open_jobFile, & + IO_write_jobFile, & + IO_write_jobRealFile, & + IO_write_jobIntFile, & + IO_read_realFile, & + IO_read_intFile, & + IO_hybridIA, & + IO_isBlank, & + IO_getTag, & + IO_countSections, & + IO_countTagInPart, & + IO_spotTagInPart, & + IO_globalTagInPart, & + IO_stringPos, & + IO_stringValue, & + IO_fixedStringValue ,& + IO_floatValue, & + IO_fixedNoEFloatValue, & + IO_intValue, & + IO_fixedIntValue, & + IO_lc, & + IO_skipChunks, & + IO_extractValue, & + IO_countDataLines, & + IO_countContinuousIntValues, & + IO_continuousIntValues, & + IO_error, & + IO_warning, & + IO_intOut, & + IO_timeStamp +#if defined(Marc4DAMASK) || defined(Abaqus) + public :: & + IO_open_inputFile, & + IO_open_logFile +#endif +#ifdef Abaqus + public :: & + IO_abaqus_hasNoPart +#endif + private :: & + IO_fixedFloatValue, & + IO_verifyFloatValue, & + IO_verifyIntValue +#ifdef Abaqus + private :: & + abaqus_assembleInputFile +#endif + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief only outputs revision number +!-------------------------------------------------------------------------------------------------- +subroutine IO_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + + implicit none + integer(pInt) :: worldrank = 0_pInt +#ifdef PETSc +#include + PetscErrorCode :: ierr +#endif + external :: & + MPI_Comm_rank, & + MPI_Abort + +#ifdef PETSc + call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) +#endif + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- IO init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +#ifdef HDF + call HDF5_createJobFile +#endif + +end subroutine IO_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief recursively reads a line from a text file. +!! Recursion is triggered by "{path/to/inputfile}" in a line +!-------------------------------------------------------------------------------------------------- +recursive function IO_read(fileUnit,reset) result(line) + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + logical, intent(in), optional :: reset + + integer(pInt), dimension(10) :: unitOn = 0_pInt ! save the stack of recursive file units + integer(pInt) :: stack = 1_pInt ! current stack position + character(len=8192), dimension(10) :: pathOn = '' + character(len=512) :: path,input + integer(pInt) :: myStat + character(len=65536) :: line + + character(len=*), parameter :: SEP = achar(47)//achar(92) ! forward and backward slash ("/", "\") + +!-------------------------------------------------------------------------------------------------- +! reset case + if(present(reset)) then; if (reset) then ! do not short circuit here + do while (stack > 1_pInt) ! can go back to former file + close(unitOn(stack)) + stack = stack-1_pInt + enddo + return + endif; endif + + +!-------------------------------------------------------------------------------------------------- +! read from file + unitOn(1) = fileUnit + + read(unitOn(stack),'(a65536)',END=100) line + + input = IO_getTag(line,'{','}') + +!-------------------------------------------------------------------------------------------------- +! normal case + if (input == '') return ! regular line +!-------------------------------------------------------------------------------------------------- +! recursion case + if (stack >= 10_pInt) call IO_error(104_pInt,ext_msg=input) ! recursion limit reached + + inquire(UNIT=unitOn(stack),NAME=path) ! path of current file + stack = stack+1_pInt + if(scan(input,SEP) == 1) then ! absolut path given (UNIX only) + pathOn(stack) = input + else + pathOn(stack) = path(1:scan(path,SEP,.true.))//input ! glue include to current file's dir + endif + + open(newunit=unitOn(stack),iostat=myStat,file=pathOn(stack)) ! open included file + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=pathOn(stack)) + + line = IO_read(fileUnit) + + return + +!-------------------------------------------------------------------------------------------------- +! end of file case +100 if (stack > 1_pInt) then ! can go back to former file + close(unitOn(stack)) + stack = stack-1_pInt + line = IO_read(fileUnit) + else ! top-most file reached + line = IO_EOF + endif + +end function IO_read + + +!-------------------------------------------------------------------------------------------------- +!> @brief checks if unit is opened for reading, if true rewinds. Otherwise stops with +!! error message +!-------------------------------------------------------------------------------------------------- +subroutine IO_checkAndRewind(fileUnit) + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + logical :: fileOpened + character(len=15) :: fileRead + + inquire(unit=fileUnit, opened=fileOpened, read=fileRead) + if (.not. fileOpened .or. trim(fileRead)/='YES') call IO_error(102_pInt) + rewind(fileUnit) + +end subroutine IO_checkAndRewind + + +!-------------------------------------------------------------------------------------------------- +!> @brief opens existing file for reading to given unit. Path to file is relative to working +!! directory +!> @details like IO_open_file_stat, but error is handled via call to IO_error and not via return +!! value +!-------------------------------------------------------------------------------------------------- +subroutine IO_open_file(fileUnit,relPath) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + character(len=*), intent(in) :: relPath !< relative path from working directory + + integer(pInt) :: myStat + character(len=1024) :: path + + path = trim(getSolverWorkingDirectoryName())//relPath + open(fileUnit,status='old',iostat=myStat,file=path) + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) + +end subroutine IO_open_file + + +!-------------------------------------------------------------------------------------------------- +!> @brief opens existing file for reading to given unit. Path to file is relative to working +!! directory +!> @details Like IO_open_file, but error is handled via return value and not via call to IO_error +!-------------------------------------------------------------------------------------------------- +logical function IO_open_file_stat(fileUnit,relPath) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + character(len=*), intent(in) :: relPath !< relative path from working directory + + integer(pInt) :: myStat + character(len=1024) :: path + + path = trim(getSolverWorkingDirectoryName())//relPath + open(fileUnit,status='old',iostat=myStat,file=path) + IO_open_file_stat = (myStat == 0_pInt) + +end function IO_open_file_stat + + +!-------------------------------------------------------------------------------------------------- +!> @brief opens existing file for reading to given unit. File is named after solver job name +!! plus given extension and located in current working directory +!> @details like IO_open_jobFile_stat, but error is handled via call to IO_error and not via return +!! value +!-------------------------------------------------------------------------------------------------- +subroutine IO_open_jobFile(fileUnit,ext) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName, & + getSolverJobName + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + character(len=*), intent(in) :: ext !< extension of file + + integer(pInt) :: myStat + character(len=1024) :: path + + path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext + open(fileUnit,status='old',iostat=myStat,file=path) + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) + +end subroutine IO_open_jobFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief opens existing file for reading to given unit. File is named after solver job name +!! plus given extension and located in current working directory +!> @details Like IO_open_jobFile, but error is handled via return value and not via call to +!! IO_error +!-------------------------------------------------------------------------------------------------- +logical function IO_open_jobFile_stat(fileUnit,ext) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName, & + getSolverJobName + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + character(len=*), intent(in) :: ext !< extension of file + + integer(pInt) :: myStat + character(len=1024) :: path + + path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext + open(fileUnit,status='old',iostat=myStat,file=path) + IO_open_jobFile_stat = (myStat == 0_pInt) + +end function IO_open_JobFile_stat + + +#if defined(Marc4DAMASK) || defined(Abaqus) +!-------------------------------------------------------------------------------------------------- +!> @brief opens FEM input file for reading located in current working directory to given unit +!-------------------------------------------------------------------------------------------------- +subroutine IO_open_inputFile(fileUnit,modelName) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName,& + getSolverJobName, & + inputFileExtension + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + character(len=*), intent(in) :: modelName !< model name, in case of restart not solver job name + + integer(pInt) :: myStat + character(len=1024) :: path +#ifdef Abaqus + integer(pInt) :: fileType + + fileType = 1_pInt ! assume .pes + path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension(fileType) ! attempt .pes, if it exists: it should be used + open(fileUnit+1,status='old',iostat=myStat,file=path) + if(myStat /= 0_pInt) then ! if .pes does not work / exist; use conventional extension, i.e.".inp" + fileType = 2_pInt + path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension(fileType) + open(fileUnit+1,status='old',iostat=myStat,file=path) + endif + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) + + path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension(fileType)//'_assembly' + open(fileUnit,iostat=myStat,file=path) + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) + if (.not.abaqus_assembleInputFile(fileUnit,fileUnit+1_pInt)) call IO_error(103_pInt) ! strip comments and concatenate any "include"s + close(fileUnit+1_pInt) +#endif +#ifdef Marc4DAMASK + path = trim(getSolverWorkingDirectoryName())//trim(modelName)//inputFileExtension + open(fileUnit,status='old',iostat=myStat,file=path) + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) +#endif + +end subroutine IO_open_inputFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief opens existing FEM log file for reading to given unit. File is named after solver job +!! name and located in current working directory +!-------------------------------------------------------------------------------------------------- +subroutine IO_open_logFile(fileUnit) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName, & + getSolverJobName, & + LogFileExtension + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + + integer(pInt) :: myStat + character(len=1024) :: path + + path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//LogFileExtension + open(fileUnit,status='old',iostat=myStat,file=path) + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) + +end subroutine IO_open_logFile +#endif + + +!-------------------------------------------------------------------------------------------------- +!> @brief opens ASCII file to given unit for writing. File is named after solver job name plus +!! given extension and located in current working directory +!-------------------------------------------------------------------------------------------------- +subroutine IO_write_jobFile(fileUnit,ext) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName, & + getSolverJobName + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + character(len=*), intent(in) :: ext !< extension of file + + integer(pInt) :: myStat + character(len=1024) :: path + + path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext + open(fileUnit,status='replace',iostat=myStat,file=path) + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) + +end subroutine IO_write_jobFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief opens binary file containing array of pReal numbers to given unit for writing. File is +!! named after solver job name plus given extension and located in current working directory +!-------------------------------------------------------------------------------------------------- +subroutine IO_write_jobRealFile(fileUnit,ext,recMultiplier) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName, & + getSolverJobName + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + character(len=*), intent(in) :: ext !< extension of file + integer(pInt), intent(in), optional :: recMultiplier !< record length (multiple of pReal Numbers, if not given set to one) + + integer(pInt) :: myStat + character(len=1024) :: path + + path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext + if (present(recMultiplier)) then + open(fileUnit,status='replace',form='unformatted',access='direct', & + recl=pReal*recMultiplier,iostat=myStat,file=path) + else + open(fileUnit,status='replace',form='unformatted',access='direct', & + recl=pReal,iostat=myStat,file=path) + endif + + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) + +end subroutine IO_write_jobRealFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief opens binary file containing array of pInt numbers to given unit for writing. File is +!! named after solver job name plus given extension and located in current working directory +!-------------------------------------------------------------------------------------------------- +subroutine IO_write_jobIntFile(fileUnit,ext,recMultiplier) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName, & + getSolverJobName + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + character(len=*), intent(in) :: ext !< extension of file + integer(pInt), intent(in), optional :: recMultiplier !< record length (multiple of pReal Numbers, if not given set to one) + + integer(pInt) :: myStat + character(len=1024) :: path + + path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//ext + if (present(recMultiplier)) then + open(fileUnit,status='replace',form='unformatted',access='direct', & + recl=pInt*recMultiplier,iostat=myStat,file=path) + else + open(fileUnit,status='replace',form='unformatted',access='direct', & + recl=pInt,iostat=myStat,file=path) + endif + + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) + +end subroutine IO_write_jobIntFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief opens binary file containing array of pReal numbers to given unit for reading. File is +!! located in current working directory +!-------------------------------------------------------------------------------------------------- +subroutine IO_read_realFile(fileUnit,ext,modelName,recMultiplier) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + character(len=*), intent(in) :: ext, & !< extension of file + modelName !< model name, in case of restart not solver job name + integer(pInt), intent(in), optional :: recMultiplier !< record length (multiple of pReal Numbers, if not given set to one) + + integer(pInt) :: myStat + character(len=1024) :: path + + path = trim(getSolverWorkingDirectoryName())//trim(modelName)//'.'//ext + if (present(recMultiplier)) then + open(fileUnit,status='old',form='unformatted',access='direct', & + recl=pReal*recMultiplier,iostat=myStat,file=path) + else + open(fileUnit,status='old',form='unformatted',access='direct', & + recl=pReal,iostat=myStat,file=path) + endif + if (myStat /= 0_pInt) call IO_error(100_pInt,el=myStat,ext_msg=path) + +end subroutine IO_read_realFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief opens binary file containing array of pInt numbers to given unit for reading. File is +!! located in current working directory +!-------------------------------------------------------------------------------------------------- +subroutine IO_read_intFile(fileUnit,ext,modelName,recMultiplier) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName + + implicit none + integer(pInt), intent(in) :: fileUnit !< file unit + character(len=*), intent(in) :: ext, & !< extension of file + modelName !< model name, in case of restart not solver job name + integer(pInt), intent(in), optional :: recMultiplier !< record length (multiple of pReal Numbers, if not given set to one) + + integer(pInt) :: myStat + character(len=1024) :: path + + path = trim(getSolverWorkingDirectoryName())//trim(modelName)//'.'//ext + if (present(recMultiplier)) then + open(fileUnit,status='old',form='unformatted',access='direct', & + recl=pInt*recMultiplier,iostat=myStat,file=path) + else + open(fileUnit,status='old',form='unformatted',access='direct', & + recl=pInt,iostat=myStat,file=path) + endif + if (myStat /= 0) call IO_error(100_pInt,ext_msg=path) + +end subroutine IO_read_intFile + + +#ifdef Abaqus +!-------------------------------------------------------------------------------------------------- +!> @brief check if the input file for Abaqus contains part info +!-------------------------------------------------------------------------------------------------- +logical function IO_abaqus_hasNoPart(fileUnit) + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=65536) :: line + + IO_abaqus_hasNoPart = .true. + +610 FORMAT(A65536) + rewind(fileUnit) + do + read(fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + if (IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) then + IO_abaqus_hasNoPart = .false. + exit + endif + enddo + +620 end function IO_abaqus_hasNoPart +#endif + +!-------------------------------------------------------------------------------------------------- +!> @brief hybrid IA sampling of ODFfile +!-------------------------------------------------------------------------------------------------- +function IO_hybridIA(Nast,ODFfileName) + use prec, only: & + tol_math_check + + implicit none + integer(pInt), intent(in) :: Nast !< number of samples? + real(pReal), dimension(3,Nast) :: IO_hybridIA + character(len=*), intent(in) :: ODFfileName !< name of ODF file including total path + +!-------------------------------------------------------------------------------------------------- +! math module is not available + real(pReal), parameter :: PI = 3.14159265358979323846264338327950288419716939937510_pReal + real(pReal), parameter :: INRAD = PI/180.0_pReal + + integer(pInt) :: i,j,bin,NnonZero,Nset,Nreps,reps,phi1,Phi,phi2 + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt), dimension(3) :: steps !< number of steps in phi1, Phi, and phi2 direction + integer(pInt), dimension(4) :: columns !< columns in linearODF file where eulerangles and density are located + integer(pInt), dimension(:), allocatable :: binSet + real(pReal) :: center,sum_dV_V,prob,dg_0,C,lowerC,upperC,rnd + real(pReal), dimension(2,3) :: limits !< starting and end values for eulerangles + real(pReal), dimension(3) :: deltas, & !< angular step size in phi1, Phi, and phi2 direction + eulers !< euler angles when reading from file + real(pReal), dimension(:,:,:), allocatable :: dV_V + character(len=65536) :: line, keyword + integer(pInt) :: headerLength + integer(pInt), parameter :: FILEUNIT = 999_pInt + + IO_hybridIA = 0.0_pReal ! initialize return value for case of error + write(6,'(/,a,/)',advance='no') ' Using linear ODF file: '//trim(ODFfileName) + +!-------------------------------------------------------------------------------------------------- +! parse header of ODF file + call IO_open_file(FILEUNIT,ODFfileName) + headerLength = 0_pInt + line=IO_read(FILEUNIT) + chunkPos = IO_stringPos(line) + keyword = IO_lc(IO_StringValue(line,chunkPos,2_pInt,.true.)) + if (keyword(1:4) == 'head') then + headerLength = IO_intValue(line,chunkPos,1_pInt) + 1_pInt + else + call IO_error(error_ID=156_pInt, ext_msg='no header found') + endif + +!-------------------------------------------------------------------------------------------------- +! figure out columns containing data + do i = 1_pInt, headerLength-1_pInt + line=IO_read(FILEUNIT) + enddo + columns = 0_pInt + chunkPos = IO_stringPos(line) + do i = 1_pInt, chunkPos(1) + select case ( IO_lc(IO_StringValue(line,chunkPos,i,.true.)) ) + case ('phi1') + columns(1) = i + case ('phi') + columns(2) = i + case ('phi2') + columns(3) = i + case ('intensity') + columns(4) = i + end select + enddo + + if (any(columns<1)) call IO_error(error_ID = 156_pInt, ext_msg='could not find expected header') + +!-------------------------------------------------------------------------------------------------- +! determine limits, number of steps and step size + limits(1,1:3) = 721.0_pReal + limits(2,1:3) = -1.0_pReal + steps = 0_pInt + + line=IO_read(FILEUNIT) + do while (trim(line) /= IO_EOF) + chunkPos = IO_stringPos(line) + eulers=[IO_floatValue(line,chunkPos,columns(1)),& + IO_floatValue(line,chunkPos,columns(2)),& + IO_floatValue(line,chunkPos,columns(3))] + steps = steps + merge(1,0,eulers>limits(2,1:3)) + limits(1,1:3) = min(limits(1,1:3),eulers) + limits(2,1:3) = max(limits(2,1:3),eulers) + line=IO_read(FILEUNIT) + enddo + + deltas = (limits(2,1:3)-limits(1,1:3))/real(steps-1_pInt,pReal) + + write(6,'(/,a,/,3(2x,f12.4,1x))',advance='no') ' Starting angles / ° = ',limits(1,1:3) + write(6,'(/,a,/,3(2x,f12.4,1x))',advance='no') ' Ending angles / ° = ',limits(2,1:3) + write(6,'(/,a,/,3(2x,f12.4,1x))',advance='no') ' Angular steps / ° = ',deltas + + if (all(abs(limits(1,1:3)) < tol_math_check)) then + write(6,'(/,a,/)',advance='no') ' assuming vertex centered data' + center = 0.0_pReal ! no need to shift + if (any(mod(int(limits(2,1:3),pInt),90)==0)) & + call IO_error(error_ID = 156_pInt, ext_msg='linear ODF data repeated at right boundary') + else + write(6,'(/,a,/)',advance='no') ' assuming cell centered data' + center = 0.5_pReal ! shift data by half of a bin + endif + + limits = limits*INRAD + deltas = deltas*INRAD + +!-------------------------------------------------------------------------------------------------- +! read in data + allocate(dV_V(steps(3),steps(2),steps(1)),source=0.0_pReal) + sum_dV_V = 0.0_pReal + dg_0 = deltas(1)*deltas(3)*2.0_pReal*sin(deltas(2)/2.0_pReal) + NnonZero = 0_pInt + + call IO_checkAndRewind(FILEUNIT) ! forward + do i = 1_pInt, headerLength + line=IO_read(FILEUNIT) + enddo + + do phi1=1_pInt,steps(1); do Phi=1_pInt,steps(2); do phi2=1_pInt,steps(3) + line=IO_read(FILEUNIT) + chunkPos = IO_stringPos(line) + eulers=[IO_floatValue(line,chunkPos,columns(1)),& ! read in again for consistency check only + IO_floatValue(line,chunkPos,columns(2)),& + IO_floatValue(line,chunkPos,columns(3))]*INRAD + if (any(abs((real([phi1,phi,phi2],pReal) -1.0_pReal + center)*deltas-eulers)>tol_math_check)) & ! check if data is in expected order (phi2 fast) and correct for Fortran starting at 1 + call IO_error(error_ID = 156_pInt, ext_msg='linear ODF data not in expected order') + + prob = IO_floatValue(line,chunkPos,columns(4)) + if (prob > 0.0_pReal) then + NnonZero = NnonZero+1_pInt + sum_dV_V = sum_dV_V+prob + else + prob = 0.0_pReal + endif + dV_V(phi2,Phi,phi1) = prob*dg_0*sin((Phi-1.0_pReal+center)*deltas(2)) + enddo; enddo; enddo + close(FILEUNIT) + dV_V = dV_V/sum_dV_V ! normalize to 1 + +!-------------------------------------------------------------------------------------------------- +! now fix bounds + Nset = max(Nast,NnonZero) ! if less than non-zero voxel count requested, sample at least that much + lowerC = 0.0_pReal + upperC = real(Nset, pReal) + + do while (hybridIA_reps(dV_V,steps,upperC) < Nset) + lowerC = upperC + upperC = upperC*2.0_pReal + enddo + +!-------------------------------------------------------------------------------------------------- +! binary search for best C + do + C = (upperC+lowerC)/2.0_pReal + Nreps = hybridIA_reps(dV_V,steps,C) + if (abs(upperC-lowerC) < upperC*1.0e-14_pReal) then + C = upperC + Nreps = hybridIA_reps(dV_V,steps,C) + exit + elseif (Nreps < Nset) then + lowerC = C + elseif (Nreps > Nset) then + upperC = C + else + exit + endif + enddo + + allocate(binSet(Nreps)) + bin = 0_pInt ! bin counter + i = 1_pInt ! set counter + do phi1=1_pInt,steps(1); do Phi=1_pInt,steps(2) ;do phi2=1_pInt,steps(3) + reps = nint(C*dV_V(phi2,Phi,phi1), pInt) + binSet(i:i+reps-1) = bin + bin = bin+1_pInt ! advance bin + i = i+reps ! advance set + enddo; enddo; enddo + + do i=1_pInt,Nast + if (i < Nast) then + call random_number(rnd) + j = nint(rnd*(Nreps-i)+i+0.5_pReal,pInt) + else + j = i + endif + bin = binSet(j) + IO_hybridIA(1,i) = deltas(1)*(real(mod(bin/(steps(3)*steps(2)),steps(1)),pReal)+center) ! phi1 + IO_hybridIA(2,i) = deltas(2)*(real(mod(bin/ steps(3) ,steps(2)),pReal)+center) ! Phi + IO_hybridIA(3,i) = deltas(3)*(real(mod(bin ,steps(3)),pReal)+center) ! phi2 + binSet(j) = binSet(i) + enddo + + contains + !-------------------------------------------------------------------------------------------------- + !> @brief counts hybrid IA repetitions + !-------------------------------------------------------------------------------------------------- + integer(pInt) pure function hybridIA_reps(dV_V,steps,C) + + implicit none + integer(pInt), intent(in), dimension(3) :: steps !< number of bins in Euler space + real(pReal), intent(in), dimension(steps(3),steps(2),steps(1)) :: dV_V !< needs description + real(pReal), intent(in) :: C !< needs description + + integer(pInt) :: phi1,Phi,phi2 + + hybridIA_reps = 0_pInt + do phi1=1_pInt,steps(1); do Phi =1_pInt,steps(2); do phi2=1_pInt,steps(3) + hybridIA_reps = hybridIA_reps+nint(C*dV_V(phi2,Phi,phi1), pInt) + enddo; enddo; enddo + + end function hybridIA_reps + +end function IO_hybridIA + + +!-------------------------------------------------------------------------------------------------- +!> @brief identifies strings without content +!-------------------------------------------------------------------------------------------------- +logical pure function IO_isBlank(string) + + implicit none + character(len=*), intent(in) :: string !< string to check for content + + character(len=*), parameter :: blankChar = achar(32)//achar(9)//achar(10)//achar(13) ! whitespaces + character(len=*), parameter :: comment = achar(35) ! comment id '#' + + integer :: posNonBlank, posComment ! no pInt + + posNonBlank = verify(string,blankChar) + posComment = scan(string,comment) + IO_isBlank = posNonBlank == 0 .or. posNonBlank == posComment + +end function IO_isBlank + + +!-------------------------------------------------------------------------------------------------- +!> @brief get tagged content of string +!-------------------------------------------------------------------------------------------------- +pure function IO_getTag(string,openChar,closeChar) + + implicit none + character(len=*), intent(in) :: string !< string to check for tag + character(len=len_trim(string)) :: IO_getTag + + character(len=*), intent(in) :: openChar, & !< indicates beginning of tag + closeChar !< indicates end of tag + + character(len=*), parameter :: SEP=achar(32)//achar(9)//achar(10)//achar(13) ! whitespaces + + integer :: left,right ! no pInt + + IO_getTag = '' + left = scan(string,openChar) + right = scan(string,closeChar) + + if (left == verify(string,SEP) .and. right > left) & ! openChar is first and closeChar occurs + IO_getTag = string(left+1:right-1) + +end function IO_getTag + + +!-------------------------------------------------------------------------------------------------- +!> @brief count number of [sections] in for given file handle +!-------------------------------------------------------------------------------------------------- +integer(pInt) function IO_countSections(fileUnit,part) + + implicit none + integer(pInt), intent(in) :: fileUnit !< file handle + character(len=*), intent(in) :: part !< part name in which sections are counted + + character(len=65536) :: line + + line = '' + IO_countSections = 0_pInt + rewind(fileUnit) + + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= part) ! search for part + line = IO_read(fileUnit) + enddo + + do while (trim(line) /= IO_EOF) + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') & ! found [section] identifier + IO_countSections = IO_countSections + 1_pInt + enddo + +end function IO_countSections + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns array of tag counts within for at most N [sections] +!-------------------------------------------------------------------------------------------------- +function IO_countTagInPart(fileUnit,part,tag,Nsections) + + implicit none + integer(pInt), intent(in) :: Nsections !< maximum number of sections in which tag is searched for + integer(pInt), dimension(Nsections) :: IO_countTagInPart + integer(pInt), intent(in) :: fileUnit !< file handle + character(len=*),intent(in) :: part, & !< part in which tag is searched for + tag !< tag to search for + + + integer(pInt), dimension(Nsections) :: counter + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: section + character(len=65536) :: line + + line = '' + counter = 0_pInt + section = 0_pInt + + rewind(fileUnit) + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= part) ! search for part + line = IO_read(fileUnit) + enddo + + do while (trim(line) /= IO_EOF) + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') section = section + 1_pInt ! found [section] identifier + if (section > 0) then + chunkPos = IO_stringPos(line) + if (tag == trim(IO_lc(IO_stringValue(line,chunkPos,1_pInt)))) & ! match + counter(section) = counter(section) + 1_pInt + endif + enddo + + IO_countTagInPart = counter + +end function IO_countTagInPart + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns array of tag presence within for at most N [sections] +!-------------------------------------------------------------------------------------------------- +function IO_spotTagInPart(fileUnit,part,tag,Nsections) + + implicit none + integer(pInt), intent(in) :: Nsections !< maximum number of sections in which tag is searched for + logical, dimension(Nsections) :: IO_spotTagInPart + integer(pInt), intent(in) :: fileUnit !< file handle + character(len=*),intent(in) :: part, & !< part in which tag is searched for + tag !< tag to search for + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: section + character(len=65536) :: line + + IO_spotTagInPart = .false. ! assume to nowhere spot tag + section = 0_pInt + line ='' + + rewind(fileUnit) + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= part) ! search for part + line = IO_read(fileUnit) + enddo + + do while (trim(line) /= IO_EOF) + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') section = section + 1_pInt ! found [section] identifier + if (section > 0_pInt) then + chunkPos = IO_stringPos(line) + if (tag == trim(IO_lc(IO_stringValue(line,chunkPos,1_pInt)))) & ! match + IO_spotTagInPart(section) = .true. + endif + enddo + + end function IO_spotTagInPart + + +!-------------------------------------------------------------------------------------------------- +!> @brief return logical whether tag is present within before any [sections] +!-------------------------------------------------------------------------------------------------- +logical function IO_globalTagInPart(fileUnit,part,tag) + + implicit none + integer(pInt), intent(in) :: fileUnit !< file handle + character(len=*),intent(in) :: part, & !< part in which tag is searched for + tag !< tag to search for + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: section + character(len=65536) :: line + + IO_globalTagInPart = .false. ! assume to nowhere spot tag + section = 0_pInt + line ='' + + rewind(fileUnit) + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= part) ! search for part + line = IO_read(fileUnit) + enddo + + do while (trim(line) /= IO_EOF) + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') section = section + 1_pInt ! found [section] identifier + if (section == 0_pInt) then + chunkPos = IO_stringPos(line) + if (tag == trim(IO_lc(IO_stringValue(line,chunkPos,1_pInt)))) & ! match + IO_globalTagInPart = .true. + endif + enddo + +end function IO_globalTagInPart + + +!-------------------------------------------------------------------------------------------------- +!> @brief locates all space-separated chunks in given string and returns array containing number +!! them and the left/right position to be used by IO_xxxVal +!! Array size is dynamically adjusted to number of chunks found in string +!! IMPORTANT: first element contains number of chunks! +!-------------------------------------------------------------------------------------------------- +pure function IO_stringPos(string) + + implicit none + integer(pInt), dimension(:), allocatable :: IO_stringPos + character(len=*), intent(in) :: string !< string in which chunk positions are searched for + + character(len=*), parameter :: SEP=achar(44)//achar(32)//achar(9)//achar(10)//achar(13) ! comma and whitespaces + integer :: left, right ! no pInt (verify and scan return default integer) + + allocate(IO_stringPos(1), source=0_pInt) + right = 0 + + do while (verify(string(right+1:),SEP)>0) + left = right + verify(string(right+1:),SEP) + right = left + scan(string(left:),SEP) - 2 + if ( string(left:left) == '#' ) exit + IO_stringPos = [IO_stringPos,int(left, pInt), int(right, pInt)] + IO_stringPos(1) = IO_stringPos(1)+1_pInt + enddo + +end function IO_stringPos + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads string value at myChunk from string +!-------------------------------------------------------------------------------------------------- +function IO_stringValue(string,chunkPos,myChunk,silent) + + implicit none + integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + character(len=*), intent(in) :: string !< raw input with known start and end of each chunk + character(len=:), allocatable :: IO_stringValue + + logical, optional,intent(in) :: silent !< switch to trigger verbosity + character(len=16), parameter :: MYNAME = 'IO_stringValue: ' + + logical :: warn + + if (.not. present(silent)) then + warn = .false. + else + warn = silent + endif + + IO_stringValue = '' + valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then + if (warn) call IO_warning(201,el=myChunk,ext_msg=MYNAME//trim(string)) + else valuePresent + IO_stringValue = string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) + endif valuePresent + +end function IO_stringValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads string value at myChunk from fixed format string +!-------------------------------------------------------------------------------------------------- +pure function IO_fixedStringValue (string,ends,myChunk) + + implicit none + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + integer(pInt), dimension(:), intent(in) :: ends !< positions of end of each tag/chunk in given string + character(len=ends(myChunk+1)-ends(myChunk)) :: IO_fixedStringValue + character(len=*), intent(in) :: string !< raw input with known ends of each chunk + + IO_fixedStringValue = string(ends(myChunk)+1:ends(myChunk+1)) + +end function IO_fixedStringValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads float value at myChunk from string +!-------------------------------------------------------------------------------------------------- +real(pReal) function IO_floatValue (string,chunkPos,myChunk) + + implicit none + integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + character(len=*), intent(in) :: string !< raw input with known start and end of each chunk + character(len=15), parameter :: MYNAME = 'IO_floatValue: ' + character(len=17), parameter :: VALIDCHARACTERS = '0123456789eEdD.+-' + + IO_floatValue = 0.0_pReal + + valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then + call IO_warning(201,el=myChunk,ext_msg=MYNAME//trim(string)) + else valuePresent + IO_floatValue = & + IO_verifyFloatValue(trim(adjustl(string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)))),& + VALIDCHARACTERS,MYNAME) + endif valuePresent + +end function IO_floatValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads float value at myChunk from fixed format string +!-------------------------------------------------------------------------------------------------- +real(pReal) function IO_fixedFloatValue (string,ends,myChunk) + + implicit none + character(len=*), intent(in) :: string !< raw input with known ends of each chunk + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + integer(pInt), dimension(:), intent(in) :: ends !< positions of end of each tag/chunk in given string + character(len=20), parameter :: MYNAME = 'IO_fixedFloatValue: ' + character(len=17), parameter :: VALIDCHARACTERS = '0123456789eEdD.+-' + + IO_fixedFloatValue = & + IO_verifyFloatValue(trim(adjustl(string(ends(myChunk)+1_pInt:ends(myChunk+1_pInt)))),& + VALIDCHARACTERS,MYNAME) + +end function IO_fixedFloatValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads float x.y+z value at myChunk from format string +!-------------------------------------------------------------------------------------------------- +real(pReal) function IO_fixedNoEFloatValue (string,ends,myChunk) + + implicit none + character(len=*), intent(in) :: string !< raw input with known ends of each chunk + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + integer(pInt), dimension(:), intent(in) :: ends !< positions of end of each tag/chunk in given string + character(len=22), parameter :: MYNAME = 'IO_fixedNoEFloatValue ' + character(len=13), parameter :: VALIDBASE = '0123456789.+-' + character(len=12), parameter :: VALIDEXP = '0123456789+-' + + real(pReal) :: base + integer(pInt) :: expon + integer :: pos_exp + + pos_exp = scan(string(ends(myChunk)+1:ends(myChunk+1)),'+-',back=.true.) + hasExponent: if (pos_exp > 1) then + base = IO_verifyFloatValue(trim(adjustl(string(ends(myChunk)+1_pInt:ends(myChunk)+pos_exp-1_pInt))),& + VALIDBASE,MYNAME//'(base): ') + expon = IO_verifyIntValue(trim(adjustl(string(ends(myChunk)+pos_exp:ends(myChunk+1_pInt)))),& + VALIDEXP,MYNAME//'(exp): ') + else hasExponent + base = IO_verifyFloatValue(trim(adjustl(string(ends(myChunk)+1_pInt:ends(myChunk+1_pInt)))),& + VALIDBASE,MYNAME//'(base): ') + expon = 0_pInt + endif hasExponent + IO_fixedNoEFloatValue = base*10.0_pReal**real(expon,pReal) + +end function IO_fixedNoEFloatValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads integer value at myChunk from string +!-------------------------------------------------------------------------------------------------- +integer(pInt) function IO_intValue(string,chunkPos,myChunk) + + implicit none + character(len=*), intent(in) :: string !< raw input with known start and end of each chunk + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string + character(len=13), parameter :: MYNAME = 'IO_intValue: ' + character(len=12), parameter :: VALIDCHARACTERS = '0123456789+-' + + IO_intValue = 0_pInt + + valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then + call IO_warning(201,el=myChunk,ext_msg=MYNAME//trim(string)) + else valuePresent + IO_intValue = IO_verifyIntValue(trim(adjustl(string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)))),& + VALIDCHARACTERS,MYNAME) + endif valuePresent + +end function IO_intValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads integer value at myChunk from fixed format string +!-------------------------------------------------------------------------------------------------- +integer(pInt) function IO_fixedIntValue(string,ends,myChunk) + + implicit none + character(len=*), intent(in) :: string !< raw input with known ends of each chunk + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + integer(pInt), dimension(:), intent(in) :: ends !< positions of end of each tag/chunk in given string + character(len=20), parameter :: MYNAME = 'IO_fixedIntValue: ' + character(len=12), parameter :: VALIDCHARACTERS = '0123456789+-' + + IO_fixedIntValue = IO_verifyIntValue(trim(adjustl(string(ends(myChunk)+1_pInt:ends(myChunk+1_pInt)))),& + VALIDCHARACTERS,MYNAME) + +end function IO_fixedIntValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief changes characters in string to lower case +!-------------------------------------------------------------------------------------------------- +pure function IO_lc(string) + + implicit none + character(len=*), intent(in) :: string !< string to convert + character(len=len(string)) :: IO_lc + + character(26), parameter :: LOWER = 'abcdefghijklmnopqrstuvwxyz' + character(26), parameter :: UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + + integer :: i,n ! no pInt (len returns default integer) + + IO_lc = string + do i=1,len(string) + n = index(UPPER,IO_lc(i:i)) + if (n/=0) IO_lc(i:i) = LOWER(n:n) + enddo + +end function IO_lc + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads file to skip (at least) N chunks (may be over multiple lines) +!-------------------------------------------------------------------------------------------------- +subroutine IO_skipChunks(fileUnit,N) + + implicit none + integer(pInt), intent(in) :: fileUnit, & !< file handle + N !< minimum number of chunks to skip + + integer(pInt) :: remainingChunks + character(len=65536) :: line + + line = '' + remainingChunks = N + + do while (trim(line) /= IO_EOF .and. remainingChunks > 0) + line = IO_read(fileUnit) + remainingChunks = remainingChunks - (size(IO_stringPos(line))-1_pInt)/2_pInt + enddo +end subroutine IO_skipChunks + + +!-------------------------------------------------------------------------------------------------- +!> @brief extracts string value from key=value pair and check whether key matches +!-------------------------------------------------------------------------------------------------- +character(len=300) pure function IO_extractValue(pair,key) + + implicit none + character(len=*), intent(in) :: pair, & !< key=value pair + key !< key to be expected + + character(len=*), parameter :: SEP = achar(61) ! '=' + + integer :: myChunk !< position number of desired chunk + + IO_extractValue = '' + + myChunk = scan(pair,SEP) + if (myChunk > 0 .and. pair(:myChunk-1) == key(:myChunk-1)) & + IO_extractValue = pair(myChunk+1:) ! extract value if key matches + +end function IO_extractValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief count lines containig data up to next *keyword +!-------------------------------------------------------------------------------------------------- +integer(pInt) function IO_countDataLines(fileUnit) + + implicit none + integer(pInt), intent(in) :: fileUnit !< file handle + + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=65536) :: line, & + tmp + + IO_countDataLines = 0_pInt + line = '' + + do while (trim(line) /= IO_EOF) + line = IO_read(fileUnit) + chunkPos = IO_stringPos(line) + tmp = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) + if (tmp(1:1) == '*' .and. tmp(2:2) /= '*') then ! found keyword + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + else + if (tmp(2:2) /= '*') IO_countDataLines = IO_countDataLines + 1_pInt + endif + enddo + backspace(fileUnit) + +end function IO_countDataLines + + +!-------------------------------------------------------------------------------------------------- +!> @brief count items in consecutive lines depending on lines +!> @details Marc: ints concatenated by "c" as last char or range of values a "to" b +!> Abaqus: triplet of start,stop,inc +!> Spectral: ints concatenated range of a "to" b, multiple entries with a "of" b +!-------------------------------------------------------------------------------------------------- +integer(pInt) function IO_countContinuousIntValues(fileUnit) + + implicit none + integer(pInt), intent(in) :: fileUnit + +#ifdef Abaqus + integer(pInt) :: l,c +#endif + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=65536) :: line + + IO_countContinuousIntValues = 0_pInt + line = '' + +#ifndef Abaqus + do while (trim(line) /= IO_EOF) + line = IO_read(fileUnit) + chunkPos = IO_stringPos(line) + if (chunkPos(1) < 1_pInt) then ! empty line + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + elseif (IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'to' ) then ! found range indicator + IO_countContinuousIntValues = 1_pInt + IO_intValue(line,chunkPos,3_pInt) & + - IO_intValue(line,chunkPos,1_pInt) + line = IO_read(fileUnit, .true.) ! reset IO_read + exit ! only one single range indicator allowed + else if (IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'of' ) then ! found multiple entries indicator + IO_countContinuousIntValues = IO_intValue(line,chunkPos,1_pInt) + line = IO_read(fileUnit, .true.) ! reset IO_read + exit ! only one single multiplier allowed + else + IO_countContinuousIntValues = IO_countContinuousIntValues+chunkPos(1)-1_pInt ! add line's count when assuming 'c' + if ( IO_lc(IO_stringValue(line,chunkPos,chunkPos(1))) /= 'c' ) then ! line finished, read last value + IO_countContinuousIntValues = IO_countContinuousIntValues+1_pInt + line = IO_read(fileUnit, .true.) ! reset IO_read + exit ! data ended + endif + endif + enddo +#else + c = IO_countDataLines(fileUnit) + do l = 1_pInt,c + backspace(fileUnit) ! ToDo: substitute by rewind? + enddo + + l = 1_pInt + do while (trim(line) /= IO_EOF .and. l <= c) ! ToDo: is this correct + l = l + 1_pInt + line = IO_read(fileUnit) + chunkPos = IO_stringPos(line) + IO_countContinuousIntValues = IO_countContinuousIntValues + 1_pInt + & ! assuming range generation + (IO_intValue(line,chunkPos,2_pInt)-IO_intValue(line,chunkPos,1_pInt))/& + max(1_pInt,IO_intValue(line,chunkPos,3_pInt)) + enddo +#endif + +end function IO_countContinuousIntValues + + +!-------------------------------------------------------------------------------------------------- +!> @brief return integer list corrsponding to items in consecutive lines. +!! First integer in array is counter +!> @details Marc: ints concatenated by "c" as last char, range of a "to" b, or named set +!! Abaqus: triplet of start,stop,inc or named set +!! Spectral: ints concatenated range of a "to" b, multiple entries with a "of" b +!-------------------------------------------------------------------------------------------------- +function IO_continuousIntValues(fileUnit,maxN,lookupName,lookupMap,lookupMaxN) + + implicit none + integer(pInt), intent(in) :: maxN + integer(pInt), dimension(1+maxN) :: IO_continuousIntValues + + integer(pInt), intent(in) :: fileUnit, & + lookupMaxN + integer(pInt), dimension(:,:), intent(in) :: lookupMap + character(len=64), dimension(:), intent(in) :: lookupName + integer(pInt) :: i +#ifdef Abaqus + integer(pInt) :: j,l,c,first,last +#endif + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=65536) line + logical rangeGeneration + + IO_continuousIntValues = 0_pInt + rangeGeneration = .false. + +#ifndef Abaqus + do + read(fileUnit,'(A65536)',end=100) line + chunkPos = IO_stringPos(line) + if (chunkPos(1) < 1_pInt) then ! empty line + exit + elseif (verify(IO_stringValue(line,chunkPos,1_pInt),'0123456789') > 0) then ! a non-int, i.e. set name + do i = 1_pInt, lookupMaxN ! loop over known set names + if (IO_stringValue(line,chunkPos,1_pInt) == lookupName(i)) then ! found matching name + IO_continuousIntValues = lookupMap(:,i) ! return resp. entity list + exit + endif + enddo + exit + else if (chunkPos(1) > 2_pInt .and. IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'to' ) then ! found range indicator + do i = IO_intValue(line,chunkPos,1_pInt),IO_intValue(line,chunkPos,3_pInt) + IO_continuousIntValues(1) = IO_continuousIntValues(1) + 1_pInt + IO_continuousIntValues(1+IO_continuousIntValues(1)) = i + enddo + exit + else if (chunkPos(1) > 2_pInt .and. IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'of' ) then ! found multiple entries indicator + IO_continuousIntValues(1) = IO_intValue(line,chunkPos,1_pInt) + IO_continuousIntValues(2:IO_continuousIntValues(1)+1) = IO_intValue(line,chunkPos,3_pInt) + exit + else + do i = 1_pInt,chunkPos(1)-1_pInt ! interpret up to second to last value + IO_continuousIntValues(1) = IO_continuousIntValues(1) + 1_pInt + IO_continuousIntValues(1+IO_continuousIntValues(1)) = IO_intValue(line,chunkPos,i) + enddo + if ( IO_lc(IO_stringValue(line,chunkPos,chunkPos(1))) /= 'c' ) then ! line finished, read last value + IO_continuousIntValues(1) = IO_continuousIntValues(1) + 1_pInt + IO_continuousIntValues(1+IO_continuousIntValues(1)) = IO_intValue(line,chunkPos,chunkPos(1)) + exit + endif + endif + enddo +#else + c = IO_countDataLines(fileUnit) + do l = 1_pInt,c + backspace(fileUnit) + enddo + +!-------------------------------------------------------------------------------------------------- +! check if the element values in the elset are auto generated + backspace(fileUnit) + read(fileUnit,'(A65536)',end=100) line + chunkPos = IO_stringPos(line) + do i = 1_pInt,chunkPos(1) + if (IO_lc(IO_stringValue(line,chunkPos,i)) == 'generate') rangeGeneration = .true. + enddo + + do l = 1_pInt,c + read(fileUnit,'(A65536)',end=100) line + chunkPos = IO_stringPos(line) + if (verify(IO_stringValue(line,chunkPos,1_pInt),'0123456789') > 0) then ! a non-int, i.e. set names follow on this line + do i = 1_pInt,chunkPos(1) ! loop over set names in line + do j = 1_pInt,lookupMaxN ! look through known set names + if (IO_stringValue(line,chunkPos,i) == lookupName(j)) then ! found matching name + first = 2_pInt + IO_continuousIntValues(1) ! where to start appending data + last = first + lookupMap(1,j) - 1_pInt ! up to where to append data + IO_continuousIntValues(first:last) = lookupMap(2:1+lookupMap(1,j),j) ! add resp. entity list + IO_continuousIntValues(1) = IO_continuousIntValues(1) + lookupMap(1,j) ! count them + endif + enddo + enddo + else if (rangeGeneration) then ! range generation + do i = IO_intValue(line,chunkPos,1_pInt),& + IO_intValue(line,chunkPos,2_pInt),& + max(1_pInt,IO_intValue(line,chunkPos,3_pInt)) + IO_continuousIntValues(1) = IO_continuousIntValues(1) + 1_pInt + IO_continuousIntValues(1+IO_continuousIntValues(1)) = i + enddo + else ! read individual elem nums + do i = 1_pInt,chunkPos(1) + IO_continuousIntValues(1) = IO_continuousIntValues(1) + 1_pInt + IO_continuousIntValues(1+IO_continuousIntValues(1)) = IO_intValue(line,chunkPos,i) + enddo + endif + enddo +#endif + +100 end function IO_continuousIntValues + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns format string for integer values without leading zeros +!-------------------------------------------------------------------------------------------------- +pure function IO_intOut(intToPrint) + + implicit none + character(len=19) :: N_Digits ! maximum digits for 64 bit integer + character(len=40) :: IO_intOut + integer(pInt), intent(in) :: intToPrint + + write(N_Digits, '(I19.19)') 1_pInt + int(log10(real(intToPrint)),pInt) + IO_intOut = 'I'//trim(N_Digits)//'.'//trim(N_Digits) + +end function IO_intOut + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns time stamp +!-------------------------------------------------------------------------------------------------- +function IO_timeStamp() + + implicit none + character(len=10) :: IO_timeStamp + integer(pInt), dimension(8) :: values + + call DATE_AND_TIME(VALUES=values) + write(IO_timeStamp,'(i2.2,a1,i2.2,a1,i2.2)') values(5),':',values(6),':',values(7) + +end function IO_timeStamp + + +!-------------------------------------------------------------------------------------------------- +!> @brief write error statements to standard out and terminate the Marc/spectral run with exit #9xxx +!> in ABAQUS either time step is reduced or execution terminated +!-------------------------------------------------------------------------------------------------- +subroutine IO_error(error_ID,el,ip,g,ext_msg) + + implicit none + integer(pInt), intent(in) :: error_ID + integer(pInt), optional, intent(in) :: el,ip,g + character(len=*), optional, intent(in) :: ext_msg + + external :: quit + character(len=1024) :: msg + character(len=1024) :: formatString + + select case (error_ID) + +!-------------------------------------------------------------------------------------------------- +! internal errors + case (0_pInt) + msg = 'internal check failed:' + +!-------------------------------------------------------------------------------------------------- +! file handling errors + case (100_pInt) + msg = 'could not open file:' + case (101_pInt) + msg = 'write error for file:' + case (102_pInt) + msg = 'could not read file:' + case (103_pInt) + msg = 'could not assemble input files' + case (104_pInt) + msg = '{input} recursion limit reached' + case (105_pInt) + msg = 'unknown output:' + +!-------------------------------------------------------------------------------------------------- +! lattice error messages + case (130_pInt) + msg = 'unknown lattice structure encountered' + case (131_pInt) + msg = 'hex lattice structure with invalid c/a ratio' + case (132_pInt) + msg = 'trans_lattice_structure not possible' + case (133_pInt) + msg = 'transformed hex lattice structure with invalid c/a ratio' + case (135_pInt) + msg = 'zero entry on stiffness diagonal' + case (136_pInt) + msg = 'zero entry on stiffness diagonal for transformed phase' + +!-------------------------------------------------------------------------------------------------- +! material error messages and related messages in mesh + case (150_pInt) + msg = 'index out of bounds' + case (151_pInt) + msg = 'microstructure has no constituents' + case (153_pInt) + msg = 'sum of phase fractions differs from 1' + case (154_pInt) + msg = 'homogenization index out of bounds' + case (155_pInt) + msg = 'microstructure index out of bounds' + case (156_pInt) + msg = 'reading from ODF file' + case (157_pInt) + msg = 'illegal texture transformation specified' + case (160_pInt) + msg = 'no entries in config part' + case (165_pInt) + msg = 'homogenization configuration' + case (170_pInt) + msg = 'no homogenization specified via State Variable 2' + case (180_pInt) + msg = 'no microstructure specified via State Variable 3' + case (190_pInt) + msg = 'unknown element type:' + +!-------------------------------------------------------------------------------------------------- +! plasticity error messages + case (200_pInt) + msg = 'unknown elasticity specified:' + case (201_pInt) + msg = 'unknown plasticity specified:' + + case (210_pInt) + msg = 'unknown material parameter:' + case (211_pInt) + msg = 'material parameter out of bounds:' + +!-------------------------------------------------------------------------------------------------- +! numerics error messages + case (300_pInt) + msg = 'unknown numerics parameter:' + case (301_pInt) + msg = 'numerics parameter out of bounds:' + +!-------------------------------------------------------------------------------------------------- +! math errors + case (400_pInt) + msg = 'matrix inversion error' + case (401_pInt) + msg = 'math_check: quat -> axisAngle -> quat failed' + case (402_pInt) + msg = 'math_check: quat -> R -> quat failed' + case (403_pInt) + msg = 'math_check: quat -> euler -> quat failed' + case (404_pInt) + msg = 'math_check: R -> euler -> R failed' + case (405_pInt) + msg = 'I_TO_HALTON-error: an input base BASE is <= 1' + case (406_pInt) + msg = 'Prime-error: N must be between 0 and PRIME_MAX' + case (407_pInt) + msg = 'Polar decomposition error' + case (409_pInt) + msg = 'math_check: R*v == q*v failed' + case (410_pInt) + msg = 'eigenvalues computation error' + case (450_pInt) + msg = 'unknown symmetry type specified' + +!------------------------------------------------------------------------------------------------- +! homogenization errors + case (500_pInt) + msg = 'unknown homogenization specified' + +!-------------------------------------------------------------------------------------------------- +! user errors + case (600_pInt) + msg = 'Ping-Pong not possible when using non-DAMASK elements' + case (601_pInt) + msg = 'Ping-Pong needed when using non-local plasticity' + case (602_pInt) + msg = 'invalid element/IP/component (grain) selected for debug' + +!------------------------------------------------------------------------------------------------- +! DAMASK_marc errors + case (700_pInt) + msg = 'invalid materialpoint result requested' + +!------------------------------------------------------------------------------------------------- +! errors related to spectral solver + case (809_pInt) + msg = 'initializing FFTW' + case (810_pInt) + msg = 'FFTW plan creation' + case (831_pInt) + msg = 'mask consistency violated in spectral loadcase' + case (832_pInt) + msg = 'ill-defined L (line partly defined) in spectral loadcase' + case (834_pInt) + msg = 'negative time increment in spectral loadcase' + case (835_pInt) + msg = 'non-positive increments in spectral loadcase' + case (836_pInt) + msg = 'non-positive result frequency in spectral loadcase' + case (837_pInt) + msg = 'incomplete loadcase' + case (838_pInt) + msg = 'mixed boundary conditions allow rotation' + case (841_pInt) + msg = 'missing header length info in spectral mesh' + case (842_pInt) + msg = 'homogenization in spectral mesh' + case (843_pInt) + msg = 'grid in spectral mesh' + case (844_pInt) + msg = 'size in spectral mesh' + case (845_pInt) + msg = 'incomplete information in spectral mesh header' + case (846_pInt) + msg = 'not a rotation defined for loadcase rotation' + case (847_pInt) + msg = 'update of gamma operator not possible when pre-calculated' + case (880_pInt) + msg = 'mismatch of microstructure count and a*b*c in geom file' + case (890_pInt) + msg = 'invalid input for regridding' + case (891_pInt) + msg = 'unknown solver type selected' + case (892_pInt) + msg = 'unknown filter type selected' + case (893_pInt) + msg = 'PETSc: SNES_DIVERGED_FNORM_NAN' + +!------------------------------------------------------------------------------------------------- +! error messages related to parsing of Abaqus input file + case (900_pInt) + msg = 'improper definition of nodes in input file (Nnodes < 2)' + case (901_pInt) + msg = 'no elements defined in input file (Nelems = 0)' + case (902_pInt) + msg = 'no element sets defined in input file (No *Elset exists)' + case (903_pInt) + msg = 'no materials defined in input file (Look into section assigments)' + case (904_pInt) + msg = 'no elements could be assigned for Elset: ' + case (905_pInt) + msg = 'error in mesh_abaqus_map_materials' + case (906_pInt) + msg = 'error in mesh_abaqus_count_cpElements' + case (907_pInt) + msg = 'size of mesh_mapFEtoCPelem in mesh_abaqus_map_elements' + case (908_pInt) + msg = 'size of mesh_mapFEtoCPnode in mesh_abaqus_map_nodes' + case (909_pInt) + msg = 'size of mesh_node in mesh_abaqus_build_nodes not equal to mesh_Nnodes' + + +!------------------------------------------------------------------------------------------------- +! general error messages + case (666_pInt) + msg = 'memory leak detected' + case default + msg = 'unknown error number...' + + end select + + !$OMP CRITICAL (write2out) + write(6,'(/,a)') ' +--------------------------------------------------------+' + write(6,'(a)') ' + error +' + write(6,'(a,i3,a)') ' + ',error_ID,' +' + write(6,'(a)') ' + +' + write(formatString,'(a,i6.6,a,i6.6,a)') '(1x,a2,a',max(1,len(trim(msg))),',',& + max(1,60-len(trim(msg))-5),'x,a)' + write(6,formatString) '+ ', trim(msg),'+' + if (present(ext_msg)) then + write(formatString,'(a,i6.6,a,i6.6,a)') '(1x,a2,a',max(1,len(trim(ext_msg))),',',& + max(1,60-len(trim(ext_msg))-5),'x,a)' + write(6,formatString) '+ ', trim(ext_msg),'+' + endif + if (present(el)) then + if (present(ip)) then + if (present(g)) then + write(6,'(a13,1x,i9,1x,a2,1x,i2,1x,a5,1x,i4,18x,a1)') ' + at element',el,'IP',ip,'grain',g,'+' + else + write(6,'(a13,1x,i9,1x,a2,1x,i2,29x,a1)') ' + at element',el,'IP',ip,'+' + endif + else + write(6,'(a13,1x,i9,35x,a1)') ' + at element',el,'+' + endif + elseif (present(ip)) then ! now having the meaning of "instance" + write(6,'(a15,1x,i9,33x,a1)') ' + for instance',ip,'+' + endif + write(6,'(a)') ' +--------------------------------------------------------+' + flush(6) + call quit(9000_pInt+error_ID) + !$OMP END CRITICAL (write2out) + +end subroutine IO_error + + +!-------------------------------------------------------------------------------------------------- +!> @brief writes warning statement to standard out +!-------------------------------------------------------------------------------------------------- +subroutine IO_warning(warning_ID,el,ip,g,ext_msg) + + implicit none + integer(pInt), intent(in) :: warning_ID + integer(pInt), optional, intent(in) :: el,ip,g + character(len=*), optional, intent(in) :: ext_msg + + character(len=1024) :: msg + character(len=1024) :: formatString + + select case (warning_ID) + case (1_pInt) + msg = 'unknown key' + case (34_pInt) + msg = 'invalid restart increment given' + case (35_pInt) + msg = 'could not get $DAMASK_NUM_THREADS' + case (40_pInt) + msg = 'found spectral solver parameter' + case (42_pInt) + msg = 'parameter has no effect' + case (43_pInt) + msg = 'main diagonal of C66 close to zero' + case (47_pInt) + msg = 'no valid parameter for FFTW, using FFTW_PATIENT' + case (50_pInt) + msg = 'not all available slip system families are defined' + case (51_pInt) + msg = 'not all available twin system families are defined' + case (52_pInt) + msg = 'not all available parameters are defined' + case (53_pInt) + msg = 'not all available transformation system families are defined' + case (101_pInt) + msg = 'crystallite debugging off' + case (201_pInt) + msg = 'position not found when parsing line' + case (202_pInt) + msg = 'invalid character in string chunk' + case (203_pInt) + msg = 'interpretation of string chunk failed' + case (600_pInt) + msg = 'crystallite responds elastically' + case (601_pInt) + msg = 'stiffness close to zero' + case (650_pInt) + msg = 'polar decomposition failed' + case (700_pInt) + msg = 'unknown crystal symmetry' + case (850_pInt) + msg = 'max number of cut back exceeded, terminating' + case default + msg = 'unknown warning number' + end select + + !$OMP CRITICAL (write2out) + write(6,'(/,a)') ' +--------------------------------------------------------+' + write(6,'(a)') ' + warning +' + write(6,'(a,i3,a)') ' + ',warning_ID,' +' + write(6,'(a)') ' + +' + write(formatString,'(a,i6.6,a,i6.6,a)') '(1x,a2,a',max(1,len(trim(msg))),',',& + max(1,60-len(trim(msg))-5),'x,a)' + write(6,formatString) '+ ', trim(msg),'+' + if (present(ext_msg)) then + write(formatString,'(a,i6.6,a,i6.6,a)') '(1x,a2,a',max(1,len(trim(ext_msg))),',',& + max(1,60-len(trim(ext_msg))-5),'x,a)' + write(6,formatString) '+ ', trim(ext_msg),'+' + endif + if (present(el)) then + if (present(ip)) then + if (present(g)) then + write(6,'(a13,1x,i9,1x,a2,1x,i2,1x,a5,1x,i4,18x,a1)') ' + at element',el,'IP',ip,'grain',g,'+' + else + write(6,'(a13,1x,i9,1x,a2,1x,i2,29x,a1)') ' + at element',el,'IP',ip,'+' + endif + else + write(6,'(a13,1x,i9,35x,a1)') ' + at element',el,'+' + endif + endif + write(6,'(a)') ' +--------------------------------------------------------+' + flush(6) + !$OMP END CRITICAL (write2out) + +end subroutine IO_warning + + +!-------------------------------------------------------------------------------------------------- +! internal helper functions + +!-------------------------------------------------------------------------------------------------- +!> @brief returns verified integer value in given string +!-------------------------------------------------------------------------------------------------- +integer(pInt) function IO_verifyIntValue (string,validChars,myName) + + implicit none + character(len=*), intent(in) :: string, & !< string for conversion to int value. Must not contain spaces! + validChars, & !< valid characters in string + myName !< name of caller function (for debugging) + integer(pInt) :: readStatus, invalidWhere + !character(len=len(trim(string))) :: trimmed does not work with ifort 14.0.1 + + IO_verifyIntValue = 0_pInt + + invalidWhere = verify(string,validChars) + if (invalidWhere == 0_pInt) then + read(UNIT=string,iostat=readStatus,FMT=*) IO_verifyIntValue ! no offending chars found + if (readStatus /= 0_pInt) & ! error during string to float conversion + call IO_warning(203_pInt,ext_msg=myName//'"'//string//'"') + else + call IO_warning(202_pInt,ext_msg=myName//'"'//string//'"') ! complain about offending characters + read(UNIT=string(1_pInt:invalidWhere-1_pInt),iostat=readStatus,FMT=*) IO_verifyIntValue ! interpret remaining string + if (readStatus /= 0_pInt) & ! error during string to float conversion + call IO_warning(203_pInt,ext_msg=myName//'"'//string(1_pInt:invalidWhere-1_pInt)//'"') + endif + +end function IO_verifyIntValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns verified float value in given string +!-------------------------------------------------------------------------------------------------- +real(pReal) function IO_verifyFloatValue (string,validChars,myName) + + implicit none + character(len=*), intent(in) :: string, & !< string for conversion to int value. Must not contain spaces! + validChars, & !< valid characters in string + myName !< name of caller function (for debugging) + + integer(pInt) :: readStatus, invalidWhere + !character(len=len(trim(string))) :: trimmed does not work with ifort 14.0.1 + + IO_verifyFloatValue = 0.0_pReal + + invalidWhere = verify(string,validChars) + if (invalidWhere == 0_pInt) then + read(UNIT=string,iostat=readStatus,FMT=*) IO_verifyFloatValue ! no offending chars found + if (readStatus /= 0_pInt) & ! error during string to float conversion + call IO_warning(203_pInt,ext_msg=myName//'"'//string//'"') + else + call IO_warning(202_pInt,ext_msg=myName//'"'//string//'"') ! complain about offending characters + read(UNIT=string(1_pInt:invalidWhere-1_pInt),iostat=readStatus,FMT=*) IO_verifyFloatValue ! interpret remaining string + if (readStatus /= 0_pInt) & ! error during string to float conversion + call IO_warning(203_pInt,ext_msg=myName//'"'//string(1_pInt:invalidWhere-1_pInt)//'"') + endif + +end function IO_verifyFloatValue + +#ifdef Abaqus +!-------------------------------------------------------------------------------------------------- +!> @brief create a new input file for abaqus simulations by removing all comment lines and +!> including "include"s +!-------------------------------------------------------------------------------------------------- +recursive function abaqus_assembleInputFile(unit1,unit2) result(createSuccess) + use DAMASK_interface, only: & + getSolverWorkingDirectoryName + + implicit none + integer(pInt), intent(in) :: unit1, & + unit2 + + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=65536) :: line,fname + logical :: createSuccess,fexist + + + do + read(unit2,'(A65536)',END=220) line + chunkPos = IO_stringPos(line) + + if (IO_lc(IO_StringValue(line,chunkPos,1_pInt))=='*include') then + fname = trim(getSolverWorkingDirectoryName())//trim(line(9+scan(line(9:),'='):)) + inquire(file=fname, exist=fexist) + if (.not.(fexist)) then + !$OMP CRITICAL (write2out) + write(6,*)'ERROR: file does not exist error in abaqus_assembleInputFile' + write(6,*)'filename: ', trim(fname) + !$OMP END CRITICAL (write2out) + createSuccess = .false. + return + endif + open(unit2+1,err=200,status='old',file=fname) + if (abaqus_assembleInputFile(unit1,unit2+1_pInt)) then + createSuccess=.true. + close(unit2+1) + else + createSuccess=.false. + return + endif + else if (line(1:2) /= '**' .OR. line(1:8)=='**damask') then + write(unit1,'(A)') trim(line) + endif + enddo + +220 createSuccess = .true. + return + +200 createSuccess =.false. + +end function abaqus_assembleInputFile +#endif + + +#ifdef HDF +!-------------------------------------------------------------------------------------------------- +!> @brief creates and initializes HDF5 output files +!-------------------------------------------------------------------------------------------------- +subroutine HDF5_createJobFile + use hdf5 + use DAMASK_interface, only: & + getSolverWorkingDirectoryName, & + getSolverJobName + + implicit none + integer :: hdferr + integer(SIZE_T) :: typeSize + character(len=1024) :: path + integer(HID_T) :: prp_id + integer(SIZE_T), parameter :: increment = 104857600 ! increase temp file in memory in 100MB steps + + +!-------------------------------------------------------------------------------------------------- +! initialize HDF5 library and check if integer and float type size match + call h5open_f(hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_createJobFile: h5open_f') + call h5tget_size_f(H5T_NATIVE_INTEGER,typeSize, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_createJobFile: h5tget_size_f (int)') + if (int(pInt,SIZE_T)/=typeSize) call IO_error(0_pInt,ext_msg='pInt does not match H5T_NATIVE_INTEGER') + call h5tget_size_f(H5T_NATIVE_DOUBLE,typeSize, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_createJobFile: h5tget_size_f (double)') + if (int(pReal,SIZE_T)/=typeSize) call IO_error(0_pInt,ext_msg='pReal does not match H5T_NATIVE_DOUBLE') + +!-------------------------------------------------------------------------------------------------- +! open file + path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//'DAMASKout' + call h5fcreate_f(path,H5F_ACC_TRUNC_F,resultsFile,hdferr) + if (hdferr < 0) call IO_error(100_pInt,ext_msg=path) + call HDF5_addStringAttribute(resultsFile,'createdBy','$Id$') + +!-------------------------------------------------------------------------------------------------- +! open temp file + path = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'.'//'DAMASKoutTemp' + call h5pcreate_f(H5P_FILE_ACCESS_F, prp_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_createJobFile: h5pcreate_f') + call h5pset_fapl_core_f(prp_id, increment, .false., hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_createJobFile: h5pset_fapl_core_f') + call h5fcreate_f(path,H5F_ACC_TRUNC_F,tempFile,hdferr) + if (hdferr < 0) call IO_error(100_pInt,ext_msg=path) + +!-------------------------------------------------------------------------------------------------- +! create mapping groups in out file + call HDF5_closeGroup(HDF5_addGroup("mapping")) + call HDF5_closeGroup(HDF5_addGroup("results")) + call HDF5_closeGroup(HDF5_addGroup("coordinates")) + +!-------------------------------------------------------------------------------------------------- +! create results group in temp file + tempResults = HDF5_addGroup("results",tempFile) + tempCoordinates = HDF5_addGroup("coordinates",tempFile) + +end subroutine HDF5_createJobFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief creates and initializes HDF5 output file +!-------------------------------------------------------------------------------------------------- +subroutine HDF5_closeJobFile() + use hdf5 + + implicit none + integer :: hdferr + call h5fclose_f(resultsFile,hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_closeJobFile: h5fclose_f') + +end subroutine HDF5_closeJobFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief adds a new group to the results file, or if loc is present at the given location +!-------------------------------------------------------------------------------------------------- +integer(HID_T) function HDF5_addGroup(path,loc) + use hdf5 + + implicit none + character(len=*), intent(in) :: path + integer(HID_T), intent(in),optional :: loc + integer :: hdferr + + if (present(loc)) then + call h5gcreate_f(loc, trim(path), HDF5_addGroup, hdferr) + else + call h5gcreate_f(resultsFile, trim(path), HDF5_addGroup, hdferr) + endif + if (hdferr < 0) call IO_error(1_pInt,ext_msg = 'HDF5_addGroup: h5gcreate_f ('//trim(path)//' )') + +end function HDF5_addGroup + + + +!-------------------------------------------------------------------------------------------------- +!> @brief adds a new group to the results file +!-------------------------------------------------------------------------------------------------- +integer(HID_T) function HDF5_openGroup(path) + use hdf5 + + implicit none + character(len=*), intent(in) :: path + integer :: hdferr + + call h5gopen_f(resultsFile, trim(path), HDF5_openGroup, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg = 'HDF5_openGroup: h5gopen_f ('//trim(path)//' )') + +end function HDF5_openGroup + + +!-------------------------------------------------------------------------------------------------- +!> @brief closes a group +!-------------------------------------------------------------------------------------------------- +subroutine HDF5_closeGroup(ID) + use hdf5 + + implicit none + integer(HID_T), intent(in) :: ID + integer :: hdferr + + call h5gclose_f(ID, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg = 'HDF5_closeGroup: h5gclose_f') + +end subroutine HDF5_closeGroup + + +!-------------------------------------------------------------------------------------------------- +!> @brief adds a new group to the results file +!-------------------------------------------------------------------------------------------------- +subroutine HDF5_addStringAttribute(entity,attrLabel,attrValue) + use hdf5 + + implicit none + integer(HID_T), intent(in) :: entity + character(len=*), intent(in) :: attrLabel, attrValue + integer :: hdferr + integer(HID_T) :: attr_id, space_id, type_id + + call h5screate_f(H5S_SCALAR_F,space_id,hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5screate_f') + call h5tcopy_f(H5T_NATIVE_CHARACTER, type_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5tcopy_f') + call h5tset_size_f(type_id, int(len(trim(attrValue)),HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5tset_size_f') + call h5acreate_f(entity, trim(attrLabel),type_id,space_id,attr_id,hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5acreate_f') + call h5awrite_f(attr_id, type_id, trim(attrValue), int([1],HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5awrite_f') + call h5aclose_f(attr_id,hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5aclose_f') + call h5sclose_f(space_id,hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_addStringAttribute: h5sclose_f') + +end subroutine HDF5_addStringAttribute + + +!-------------------------------------------------------------------------------------------------- +!> @brief adds the unique mapping from spatial position and constituent ID to results +!-------------------------------------------------------------------------------------------------- +subroutine HDF5_mappingConstitutive(mapping) + use hdf5 + + implicit none + integer(pInt), intent(in), dimension(:,:,:) :: mapping + + integer :: hdferr, NmatPoints,Nconstituents + integer(HID_T) :: mapping_id, dtype_id, dset_id, space_id,instance_id,position_id + + Nconstituents=size(mapping,1) + NmatPoints=size(mapping,2) + mapping_ID = HDF5_openGroup("mapping") + +!-------------------------------------------------------------------------------------------------- +! create dataspace + call h5screate_simple_f(2, int([Nconstituents,NmatPoints],HSIZE_T), space_id, hdferr, & + int([Nconstituents,NmatPoints],HSIZE_T)) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive') + +!-------------------------------------------------------------------------------------------------- +! compound type + call h5tcreate_f(H5T_COMPOUND_F, 6_SIZE_T, dtype_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tcreate_f dtype_id') + + call h5tinsert_f(dtype_id, "Constitutive Instance", 0_SIZE_T, H5T_STD_U16LE, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tinsert_f 0') + call h5tinsert_f(dtype_id, "Position in Instance Results", 2_SIZE_T, H5T_STD_U32LE, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tinsert_f 2') + +!-------------------------------------------------------------------------------------------------- +! create Dataset + call h5dcreate_f(mapping_id, "Constitutive", dtype_id, space_id, dset_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive') + +!-------------------------------------------------------------------------------------------------- +! Create memory types (one compound datatype for each member) + call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), instance_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tcreate_f instance_id') + call h5tinsert_f(instance_id, "Constitutive Instance", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tinsert_f instance_id') + + call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), position_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tcreate_f position_id') + call h5tinsert_f(position_id, "Position in Instance Results", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tinsert_f position_id') + +!-------------------------------------------------------------------------------------------------- +! write data by fields in the datatype. Fields order is not important. + call h5dwrite_f(dset_id, position_id, mapping(1:Nconstituents,1:NmatPoints,1), & + int([Nconstituents, NmatPoints],HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5dwrite_f position_id') + + call h5dwrite_f(dset_id, instance_id, mapping(1:Nconstituents,1:NmatPoints,2), & + int([Nconstituents, NmatPoints],HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5dwrite_f instance_id') + +!-------------------------------------------------------------------------------------------------- +!close types, dataspaces + call h5tclose_f(dtype_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tclose_f dtype_id') + call h5tclose_f(position_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tclose_f position_id') + call h5tclose_f(instance_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5tclose_f instance_id') + call h5dclose_f(dset_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5dclose_f') + call h5sclose_f(space_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5sclose_f') + call HDF5_closeGroup(mapping_ID) + +end subroutine HDF5_mappingConstitutive + + +!-------------------------------------------------------------------------------------------------- +!> @brief adds the unique mapping from spatial position and constituent ID to results +!-------------------------------------------------------------------------------------------------- +subroutine HDF5_mappingCrystallite(mapping) + use hdf5 + + implicit none + integer(pInt), intent(in), dimension(:,:,:) :: mapping + + integer :: hdferr, NmatPoints,Nconstituents + integer(HID_T) :: mapping_id, dtype_id, dset_id, space_id,instance_id,position_id + + Nconstituents=size(mapping,1) + NmatPoints=size(mapping,2) + mapping_ID = HDF5_openGroup("mapping") + +!-------------------------------------------------------------------------------------------------- +! create dataspace + call h5screate_simple_f(2, int([Nconstituents,NmatPoints],HSIZE_T), space_id, hdferr, & + int([Nconstituents,NmatPoints],HSIZE_T)) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite') + +!-------------------------------------------------------------------------------------------------- +! compound type + call h5tcreate_f(H5T_COMPOUND_F, 6_SIZE_T, dtype_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tcreate_f dtype_id') + + call h5tinsert_f(dtype_id, "Crystallite Instance", 0_SIZE_T, H5T_STD_U16LE, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tinsert_f 0') + call h5tinsert_f(dtype_id, "Position in Instance Results", 2_SIZE_T, H5T_STD_U32LE, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tinsert_f 2') + +!-------------------------------------------------------------------------------------------------- +! create Dataset + call h5dcreate_f(mapping_id, "Crystallite", dtype_id, space_id, dset_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite') + +!-------------------------------------------------------------------------------------------------- +! Create memory types (one compound datatype for each member) + call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), instance_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tcreate_f instance_id') + call h5tinsert_f(instance_id, "Crystallite Instance", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tinsert_f instance_id') + + call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), position_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tcreate_f position_id') + call h5tinsert_f(position_id, "Position in Instance Results", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tinsert_f position_id') + +!-------------------------------------------------------------------------------------------------- +! write data by fields in the datatype. Fields order is not important. + call h5dwrite_f(dset_id, position_id, mapping(1:Nconstituents,1:NmatPoints,1), & + int([Nconstituents, NmatPoints],HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5dwrite_f position_id') + + call h5dwrite_f(dset_id, instance_id, mapping(1:Nconstituents,1:NmatPoints,2), & + int([Nconstituents, NmatPoints],HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5dwrite_f instance_id') + +!-------------------------------------------------------------------------------------------------- +!close types, dataspaces + call h5tclose_f(dtype_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tclose_f dtype_id') + call h5tclose_f(position_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tclose_f position_id') + call h5tclose_f(instance_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5tclose_f instance_id') + call h5dclose_f(dset_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5dclose_f') + call h5sclose_f(space_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCrystallite: h5sclose_f') + call HDF5_closeGroup(mapping_ID) + +end subroutine HDF5_mappingCrystallite + + +!-------------------------------------------------------------------------------------------------- +!> @brief adds the unique mapping from spatial position to results +!-------------------------------------------------------------------------------------------------- +subroutine HDF5_mappingHomogenization(mapping) + use hdf5 + + implicit none + integer(pInt), intent(in), dimension(:,:) :: mapping + + integer :: hdferr, NmatPoints + integer(HID_T) :: mapping_id, dtype_id, dset_id, space_id,instance_id,position_id,elem_id,ip_id + + NmatPoints=size(mapping,1) + mapping_ID = HDF5_openGroup("mapping") + +!-------------------------------------------------------------------------------------------------- +! create dataspace + call h5screate_simple_f(1, int([NmatPoints],HSIZE_T), space_id, hdferr, & + int([NmatPoints],HSIZE_T)) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization') + +!-------------------------------------------------------------------------------------------------- +! compound type + call h5tcreate_f(H5T_COMPOUND_F, 11_SIZE_T, dtype_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tcreate_f dtype_id') + + call h5tinsert_f(dtype_id, "Homogenization Instance", 0_SIZE_T, H5T_STD_U16LE, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f 0') + call h5tinsert_f(dtype_id, "Position in Instance Results", 2_SIZE_T, H5T_STD_U32LE, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f 2') + call h5tinsert_f(dtype_id, "Element Number", 6_SIZE_T, H5T_STD_U32LE, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f 6') + call h5tinsert_f(dtype_id, "Material Point Number", 10_SIZE_T, H5T_STD_U8LE, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f 10') + +!-------------------------------------------------------------------------------------------------- +! create Dataset + call h5dcreate_f(mapping_id, "Homogenization", dtype_id, space_id, dset_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization') + +!-------------------------------------------------------------------------------------------------- +! Create memory types (one compound datatype for each member) + call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), instance_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tcreate_f instance_id') + call h5tinsert_f(instance_id, "Homogenization Instance", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f instance_id') + + call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), position_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tcreate_f position_id') + call h5tinsert_f(position_id, "Position in Instance Results", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f position_id') + + call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), elem_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tcreate_f elem_id') + call h5tinsert_f(elem_id, "Element Number", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f elem_id') + + call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), ip_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tcreate_f ip_id') + call h5tinsert_f(ip_id, "Material Point Number", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tinsert_f ip_id') + +!-------------------------------------------------------------------------------------------------- +! write data by fields in the datatype. Fields order is not important. + call h5dwrite_f(dset_id, position_id, mapping(1:NmatPoints,1), & + int([NmatPoints],HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5dwrite_f position_id') + + call h5dwrite_f(dset_id, instance_id, mapping(1:NmatPoints,2), & + int([NmatPoints],HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5dwrite_f position_id') + + call h5dwrite_f(dset_id, elem_id, mapping(1:NmatPoints,3), & + int([NmatPoints],HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5dwrite_f elem_id') + + call h5dwrite_f(dset_id, ip_id, mapping(1:NmatPoints,4), & + int([NmatPoints],HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5dwrite_f ip_id') + +!-------------------------------------------------------------------------------------------------- +!close types, dataspaces + call h5tclose_f(dtype_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tclose_f dtype_id') + call h5tclose_f(position_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tclose_f position_id') + call h5tclose_f(instance_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tclose_f instance_id') + call h5tclose_f(ip_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tclose_f ip_id') + call h5tclose_f(elem_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5tclose_f elem_id') + call h5dclose_f(dset_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5dclose_f') + call h5sclose_f(space_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingHomogenization: h5sclose_f') + call HDF5_closeGroup(mapping_ID) + +end subroutine HDF5_mappingHomogenization + + +!-------------------------------------------------------------------------------------------------- +!> @brief adds the unique cell to node mapping +!-------------------------------------------------------------------------------------------------- +subroutine HDF5_mappingCells(mapping) + use hdf5 + + implicit none + integer(pInt), intent(in), dimension(:) :: mapping + + integer :: hdferr, Nnodes + integer(HID_T) :: mapping_id, dset_id, space_id + + Nnodes=size(mapping) + mapping_ID = HDF5_openGroup("mapping") + +!-------------------------------------------------------------------------------------------------- +! create dataspace + call h5screate_simple_f(1, int([Nnodes],HSIZE_T), space_id, hdferr, & + int([Nnodes],HSIZE_T)) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCells: h5screate_simple_f') + +!-------------------------------------------------------------------------------------------------- +! create Dataset + call h5dcreate_f(mapping_id, "Cell",H5T_NATIVE_INTEGER, space_id, dset_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCells') + +!-------------------------------------------------------------------------------------------------- +! write data by fields in the datatype. Fields order is not important. + call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER, mapping, int([Nnodes],HSIZE_T), hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingCells: h5dwrite_f instance_id') + +!-------------------------------------------------------------------------------------------------- +!close types, dataspaces + call h5dclose_f(dset_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5dclose_f') + call h5sclose_f(space_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='IO_mappingConstitutive: h5sclose_f') + call HDF5_closeGroup(mapping_ID) + +end subroutine HDF5_mappingCells + + +!-------------------------------------------------------------------------------------------------- +!> @brief creates a new scalar dataset in the given group location +!-------------------------------------------------------------------------------------------------- +subroutine HDF5_addScalarDataset(group,nnodes,label,SIunit) + use hdf5 + + implicit none + integer(HID_T), intent(in) :: group + integer(pInt), intent(in) :: nnodes + character(len=*), intent(in) :: SIunit,label + + integer :: hdferr + integer(HID_T) :: dset_id, space_id + +!-------------------------------------------------------------------------------------------------- +! create dataspace + call h5screate_simple_f(1, int([Nnodes],HSIZE_T), space_id, hdferr, & + int([Nnodes],HSIZE_T)) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_addScalarDataset: h5screate_simple_f') + +!-------------------------------------------------------------------------------------------------- +! create Dataset + call h5dcreate_f(group, trim(label),H5T_NATIVE_DOUBLE, space_id, dset_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_addScalarDataset: h5dcreate_f') + call HDF5_addStringAttribute(dset_id,'unit',trim(SIunit)) + +!-------------------------------------------------------------------------------------------------- +!close types, dataspaces + call h5dclose_f(dset_id, hdferr) + if (hdferr < 0) call IO_error(1_pInt,ext_msg='HDF5_addScalarDataset: h5dclose_f') + call h5sclose_f(space_id, hdferr) + +end subroutine HDF5_addScalarDataset + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns nicely formatted string of integer value +!-------------------------------------------------------------------------------------------------- +function IO_formatIntToString(myInt) + + implicit none + integer(pInt), intent(in) :: myInt + character(len=1_pInt + int(log10(real(myInt)),pInt)) :: IO_formatIntToString + write(IO_formatIntToString,'('//IO_intOut(myInt)//')') myInt + + end function + + +!-------------------------------------------------------------------------------------------------- +!> @brief copies the current temp results to the actual results file +!-------------------------------------------------------------------------------------------------- +subroutine HDF5_forwardResults + use hdf5 + + implicit none + integer :: hdferr + integer(HID_T) :: new_loc_id + + new_loc_id = HDF5_openGroup("results") + currentInc = currentInc + 1_pInt + call h5ocopy_f(tempFile, 'results', new_loc_id,dst_name=IO_formatIntToString(currentInc), hdferr=hdferr) + if (hdferr < 0_pInt) call IO_error(1_pInt,ext_msg='HDF5_forwardResults: h5ocopy_f') + call HDF5_closeGroup(new_loc_id) + +end subroutine HDF5_forwardResults + + +#endif +end module IO diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 000000000..2a9a3deae --- /dev/null +++ b/src/Makefile @@ -0,0 +1,701 @@ +SHELL = /bin/sh +######################################################################################## +# Makefile to compile the Material subroutine for BVP solution using spectral method +######################################################################################## +# Be sure to remove all files compiled with different options by using "make clean" +######################################################################################## +# OPTIONS = standard (alternative): meaning +#------------------------------------------------------------- +# F90 = ifort (gfortran): compiler type, choose Intel or GNU +# COMPILERNAME = name of the compiler executable (if not the same as the ype), e.g. using mpich-g90 instead of ifort +# PORTABLE = TRUE (FALSE): decision, if executable is optimized for the machine on which it was built. +# OPTIMIZATION = DEFENSIVE (OFF,AGGRESSIVE,ULTRA): Optimization mode: O2, O0, O3 + further options for most files, O3 + further options for all files +# OPENMP = TRUE (FALSE): OpenMP multiprocessor support +# PREFIX = arbitrary prefix (before compilername) +# OPTION = arbitrary option (just before file to compile) +# SUFFIX = arbitrary suffix (after file to compile) +# STANDARD_CHECK = checking for Fortran 2008, compiler dependend +######################################################################################## +# including PETSc files. PETSC_ARCH is loaded from these files. +DAMASKVERSION :=$(shell cat ../VERSION) + +include ${PETSC_DIR}/lib/petsc/conf/variables +include ${PETSC_DIR}/lib/petsc/conf/rules + +INCLUDE_DIRS := $(PETSC_FC_INCLUDES) -DPETSc -I../lib +LIBRARIES := $(PETSC_WITH_EXTERNAL_LIB) +COMPILERNAME ?= $(FC) +LINKERNAME ?= $(FLINKER) + +# +# setting up for HDF5 support (hard link for now) +# 1. Location of HDF5 binaries (with include/ and lib/ underneath) +HDF5 = /mnt/research/CMM/opt/hdf5 +# 2. Location of External Libraries (missing in the 1.8.12 version) +LIBZ = /mnt/research/CMM/opt/hdf5/lib/libz.a +LIBSZ = /mnt/research/CMM/opt/hdf5/lib/libszip.a +# 3. Set libraries for HDF5 (LIBS: shared lib, LIBZ: external lib) +HDFLIBS = -I$(HDF5)/include -L$(HDF5)/lib +HDFLIBZ = -L$(LIBZ) -L$(LIBSZ) + +# MPI compiler wrappers will tell if they are pointing to ifort or gfortran +COMPILEROUT :=$(shell $(FC) -show) +# search in FC or COMPILEROUT for gfortran/ifort if not defined +ifeq ($(strip $(F90)),) + F90 :=$(findstring gfortran,$(FC) $(COMPILEROUT)) +endif +ifeq ($(strip $(F90)),) + F90 :=$(findstring ifort,$(FC) $(COMPILEROUT)) +endif + +OPENMP ?= ON +OPTIMIZATION ?= DEFENSIVE + +ifeq "$(OPTIMIZATION)" "OFF" +OPTI := OFF +MAXOPTI := OFF +endif +ifeq "$(OPTIMIZATION)" "DEFENSIVE" +OPTI := DEFENSIVE +MAXOPTI := DEFENSIVE +endif +ifeq "$(OPTIMIZATION)" "AGGRESSIVE" +OPTI := AGGRESSIVE +MAXOPTI := DEFENSIVE +endif +ifeq "$(OPTIMIZATION)" "ULTRA" +OPTI := AGGRESSIVE +MAXOPTI := AGGRESSIVE +endif + +ifndef OPTI +OPTI := DEFENSIVE +MAXOPTI := DEFENSIVE +endif + +# settings for shared memory multicore support +ifeq "$(OPENMP)" "ON" +OPENMP_FLAG_ifort =-openmp -openmp-report0 -parallel +OPENMP_FLAG_gfortran =-fopenmp +endif + +ifdef STANDARD_CHECK +STANDARD_CHECK_ifort =$(STANDARD_CHECK) +STANDARD_CHECK_gfortran =$(STANDARD_CHECK) +endif + +STANDARD_CHECK_ifort ?=-stand f08 -standard-semantics +STANDARD_CHECK_gfortran ?=-std=f2008ts -pedantic-errors + +#-pedantic: more strict on standard, enables some warnings +# -pedantic-errors: like pedantic, but errors instead of warnings +OPTIMIZATION_OFF_ifort :=-O0 -no-ip +OPTIMIZATION_OFF_gfortran :=-O0 +OPTIMIZATION_DEFENSIVE_ifort :=-O2 +OPTIMIZATION_DEFENSIVE_gfortran :=-O2 +OPTIMIZATION_AGGRESSIVE_ifort :=-ipo -O3 -no-prec-div -fp-model fast=2 -xHost #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost +OPTIMIZATION_AGGRESSIVE_gfortran :=-O3 -ffast-math -funroll-loops -ftree-vectorize + + +LINK_OPTIONS_ifort :=-shared-intel +COMPILE_OPTIONS_ifort :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ + -fpp\ + -ftz\ + -assume byterecl,fpe_summary\ + -diag-disable 5268\ + -warn declarations\ + -warn general\ + -warn usage\ + -warn interfaces\ + -warn ignore_loc\ + -warn alignments\ + -warn unused + +################################################################################################### +#COMPILE SWITCHES +#-shared-intel: Link against shared Intel libraries instead of static ones +#-fpp: preprocessor +#-ftz: flush unterflow to zero, automatically set if O<0,1,2,3> >0 +#-assume byterecl record length is given in bytes (also set by -standard-semantics) +# fpe_summary print list of floating point exceptions occured during execution +#-fimplicit-none: assume "implicit-none" even if not present in source +#-diag-disable: disables warnings, where +# warning ID 5268: the text exceeds right hand column allowed on the line (we have only comments there) +#-warn: enables warnings, where +# declarations: any undeclared names (alternative name: -implicitnone) +# general: warning messages and informational messages are issued by the compiler +# usage: questionable programming practices +# interfaces: checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks +# ignore_loc: %LOC is stripped from an actual argument +# alignments: data that is not naturally aligned +# unused: declared variables that are never used +# stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) +# +################################################################################################### +#MORE OPTIONS FOR DEBUGGING DURING COMPILATION +#-warn: enables warnings, where +# truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) +# uncalled: Determines whether warnings occur when a statement function is never called +# all: +# -name as_is: case sensitive Fortran! + +DEBUG_OPTIONS_ifort :=-g\ + -traceback\ + -gen-interfaces\ + -fp-stack-check\ + -fp-model strict\ + -check bounds,format,output_conversion,pointers,uninit\ + -ftrapuv\ + -fpe-all0\ + -warn errors\ + -warn stderrors\ + -debug-parameters all + +################################################################################################### +#COMPILE SWITCHES FOR RUNTIME DEBUGGING +#-g: Generate symbolic debugging information in the object file +#-traceback: Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. +#-gen-interfaces: Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ +#-fp-stack-check: Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. +#-ftrapuv Trap uninitalized variables +#-check: checks at runtime, where +# bounds: check if an array index is too small (<1) or too large! +# format: Checking for the data type of an item being formatted for output. +# output_conversion: Checking for the fit of data items within a designated format descriptor field. +# pointers: Checking for certain disassociated or uninitialized pointers or unallocated allocatable objects. +# uninit: Checking for uninitialized variables. +#-fpe-all0 capture all floating-point exceptions, sets -ftz automatically +#-warn: enables warnings, where +# errors: warnings are changed to errors +# stderrors: warnings about Fortran standard violations are changed to errors +# information on http://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors/ +################################################################################################### +#MORE OPTIONS FOR RUNTIME DEBUGGING +#-heap-arrays: should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits +#-check: checks at runtime, where +# arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) +# stack: +LINK_OPTIONS_gfortran :=-Wl,-undefined,dynamic_lookup +COMPILE_OPTIONS_gfortran :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ + -xf95-cpp-input\ + -ffree-line-length-132\ + -fimplicit-none\ + -fmodule-private\ + -Wall\ + -Wextra\ + -Wcharacter-truncation\ + -Wunderflow\ + -Wsuggest-attribute=pure\ + -Wsuggest-attribute=noreturn\ + -Wconversion-extra\ + -Wimplicit-procedure\ + -Wno-unused-parameter +#-ffpe-summary=all only for newer gfortran +################################################################################################### +#COMPILE SWITCHES +#-shared +#-Wl,-undefined,dynamic_lookup:ensure to link against dynamic libraries +#-xf95-cpp-input: preprocessor +#-ffree-line-length-132: restrict line length to the standard 132 characters +#-ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) +#-fimplicit-none: assume "implicit-none" even if not present in source +#-fmodule-private: assume "private" even if not present in source +#-Wcharacter-truncation: warn if character expressions (strings) are truncated +#-Wunderflow: produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation +#-Wsuggest-attribute=pure: +#-Wsuggest-attribute=noreturn: +#-Wconversion-extra +#-Wimplicit-procedure +#-Wall: sets the following Fortran options: +# -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. +# -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line +# -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime +# -Wconversion: warn about implicit conversions between different type +# -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. +# -Wc-binding-type: +# -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error +# -Wno-tabs: do not allow tabs in source +# -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic +# -Wline-truncation: +# -Wtarget-lifetime: +# -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter +# -Wunused: a number of unused-xxx warnings +# these are general (non -Fortran options) implied by -Wall +# -Waddress +# -Warray-bounds (only with -O2) +# -Wc++11-compat +# -Wchar-subscripts +# -Wcomment +# -Wformat +# -Wmaybe-uninitialized +# -Wnonnull +# -Wparentheses +# -Wpointer-sign +# -Wreorder +# -Wreturn-type +# -Wsequence-point +# -Wstrict-aliasing +# -Wstrict-overflow=1 +# -Wswitch +# -Wtrigraphs +# -Wuninitialized +# -Wunknown-pragmas +# -Wunused-function +# -Wunused-label +# -Wunused-value +# -Wunused-variable +# -Wvolatile-register-var +#-Wextra: sets the following Fortran options: +# -Wunuses-parameter: +# -Wcompare-reals: +# these are general (non -Fortran options) implied by -Wextra +# -Wclobbered +# -Wempty-body +# -Wignored-qualifiers +# -Wmissing-field-initializers +# -Woverride-init +# -Wsign-compare +# -Wtype-limits +# -Wuninitialized +# -Wunused-but-set-parameter (only with -Wunused or -Wall) +# -Wno-globals + +################################################################################################### +#MORE OPTIONS FOR DEBUGGING DURING COMPILATION +#-Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): +#-Wimplicit-interface: no interfaces for lapack routines +#-Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. +#-Wstrict-overflow: + +DEBUG_OPTIONS_gfortran :=-g\ + -fbacktrace\ + -fdump-core\ + -fcheck=all\ + -ffpe-trap=invalid,zero,overflow + +################################################################################################### +#COMPILE SWITCHES FOR RUNTIME DEBUGGING +#-ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) +# zero,\ +# overflow +#-fcheck=all: sets the following Fortran options: +#array-temps +#bounds +#do +#mem +#pointer +#recursion +################################################################################################### +#MORE OPTIONS FOR RUNTIME DEBUGGING +#-ffpe-trap=precision,\ +# denormal, \ +# underflow + +ifeq "$(DEBUG)" "ON" +COMPILE_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) +LINK_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) +endif +LINK_OPTIONS_$(F90) += $(OPTIMIZATION_$(MAXOPTI)_$(F90)) + +PRECISION_ifort :=-real-size 64 -integer-size 32 -DFLOAT=8 -DINT=4 +#-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) +#-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) +PRECISION_gfortran :=-fdefault-real-8 -fdefault-double-8 -DFLOAT=8 -DINT=4 +#-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set +#-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used +#-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) + +################################################################################################### +COMPILE =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(OPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) +COMPILE_MAXOPTI =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) +################################################################################################### +SOURCE_FILES = \ + source_thermal_dissipation.o source_thermal_externalheat.o \ + source_damage_isoBrittle.o source_damage_isoDuctile.o source_damage_anisoBrittle.o source_damage_anisoDuctile.o \ + source_vacancy_phenoplasticity.o source_vacancy_irradiation.o source_vacancy_thermalfluc.o + +KINEMATICS_FILES = \ + kinematics_cleavage_opening.o kinematics_slipplane_opening.o \ + kinematics_thermal_expansion.o \ + kinematics_vacancy_strain.o kinematics_hydrogen_strain.o + +PLASTIC_FILES = \ + plastic_dislotwin.o plastic_disloUCLA.o plastic_isotropic.o plastic_j2.o \ + plastic_phenopowerlaw.o plastic_titanmod.o plastic_nonlocal.o plastic_none.o \ + plastic_phenoplus.o + +THERMAL_FILES = \ + thermal_isothermal.o thermal_adiabatic.o thermal_conduction.o + +DAMAGE_FILES = \ + damage_none.o damage_local.o damage_nonlocal.o + +VACANCYFLUX_FILES = \ + vacancyflux_isoconc.o vacancyflux_isochempot.o vacancyflux_cahnhilliard.o + +POROSITY_FILES = \ + porosity_none.o porosity_phasefield.o + +HYDROGENFLUX_FILES = \ + hydrogenflux_isoconc.o hydrogenflux_cahnhilliard.o + +HOMOGENIZATION_FILES = \ + homogenization_RGC.o homogenization_isostrain.o homogenization_none.o + +##################### +# Spectral Solver +##################### +DAMASK_spectral.exe: IGNORE := \# +DAMASK_spectral.exe: COMPILE += -DSpectral +DAMASK_spectral.exe: COMPILE_MAXOPTI += -DSpectral +DAMASK_spectral.exe: MESHNAME := mesh.f90 +DAMASK_spectral.exe: INTERFACENAME := spectral_interface.f90 + +DAMASK_spectral.o: IGNORE := \# +DAMASK_spectral.o: COMPILE += -DSpectral +DAMASK_spectral.o: COMPILE_MAXOPTI += -DSpectral +DAMASK_spectral.o: MESHNAME := mesh.f90 +DAMASK_spectral.o: INTERFACENAME := spectral_interface.f90 + + +SPECTRAL_SOLVER_FILES = spectral_mech_AL.o spectral_mech_Basic.o spectral_mech_Polarisation.o \ + spectral_thermal.o spectral_damage.o + +SPECTRAL_FILES = prec.o DAMASK_interface.o IO.o libs.o numerics.o debug.o math.o damask_hdf5.o \ + FEsolving.o mesh.o material.o lattice.o \ + $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ + crystallite.o \ + $(THERMAL_FILES) $(DAMAGE_FILES) $(VACANCYFLUX_FILES) $(HYDROGENFLUX_FILES) $(POROSITY_FILES) \ + $(HOMOGENIZATION_FILES) homogenization.o \ + CPFEM2.o \ + spectral_utilities.o \ + $(SPECTRAL_SOLVER_FILES) + +DAMASK_spectral.exe: DAMASK_spectral.o \ + $(SPECTRAL_FILES) + $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ + -o DAMASK_spectral.exe DAMASK_spectral.o \ + $(SPECTRAL_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) + + +DAMASK_spectral.o: DAMASK_spectral.f90 \ + $(SPECTRAL_SOLVER_FILES) + $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c DAMASK_spectral.f90 $(SUFFIX) + +spectral_mech_AL.o: spectral_mech_AL.f90 \ + spectral_utilities.o + +spectral_mech_Polarisation.o: spectral_mech_Polarisation.f90 \ + spectral_utilities.o + +spectral_mech_Basic.o: spectral_mech_Basic.f90 \ + spectral_utilities.o + +spectral_thermal.o: spectral_thermal.f90 \ + spectral_utilities.o + +spectral_damage.o: spectral_damage.f90 \ + spectral_utilities.o + +spectral_utilities.o: spectral_utilities.f90 \ + CPFEM2.o + +##################### +# FEM Solver +##################### +VPATH := ../private/FEM/code +DAMASK_FEM.exe: COMPILE += -DFEM +DAMASK_FEM.exe: COMPILE_MAXOPTI += -DFEM +DAMASK_FEM.exe: MESHNAME := ../private/FEM/code/meshFEM.f90 +DAMASK_FEM.exe: INTERFACENAME := ../private/FEM/code/DAMASK_FEM_interface.f90 +DAMASK_FEM.exe: INCLUDE_DIRS += -I./ + +FEM_SOLVER_FILES = FEM_mech.o FEM_thermal.o FEM_damage.o FEM_vacancyflux.o FEM_porosity.o FEM_hydrogenflux.o + +FEM_FILES = prec.o DAMASK_interface.o FEZoo.o IO.o libs.o numerics.o debug.o math.o \ + FEsolving.o mesh.o material.o lattice.o \ + $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ + crystallite.o \ + $(THERMAL_FILES) $(DAMAGE_FILES) $(VACANCYFLUX_FILES) $(HYDROGENFLUX_FILES) $(POROSITY_FILES) \ + $(HOMOGENIZATION_FILES) homogenization.o \ + CPFEM.o \ + FEM_utilities.o $(FEM_SOLVER_FILES) + +DAMASK_FEM.exe: DAMASK_FEM_driver.o + $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ + -o DAMASK_FEM.exe DAMASK_FEM_driver.o \ + $(FEM_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) + +DAMASK_FEM_driver.o: DAMASK_FEM_driver.f90 $(FEM_SOLVER_FILES) + $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c ../private/FEM/code/DAMASK_FEM_driver.f90 $(SUFFIX) + +FEM_mech.o: FEM_mech.f90 \ + FEM_utilities.o + +FEM_thermal.o: FEM_thermal.f90 \ + FEM_utilities.o + +FEM_damage.o: FEM_damage.f90 \ + FEM_utilities.o + +FEM_vacancyflux.o: FEM_vacancyflux.f90 \ + FEM_utilities.o + +FEM_porosity.o: FEM_porosity.f90 \ + FEM_utilities.o + +FEM_hydrogenflux.o: FEM_hydrogenflux.f90 \ + FEM_utilities.o + +FEM_utilities.o: FEM_utilities.f90 \ + CPFEM.o + +FEZoo.o: $(wildcard FEZoo.f90) \ + IO.o + $(IGNORE) $(PREFIX) $(COMPILERNAME) $(COMPILE) -c ../private/FEM/code/FEZoo.f90 $(SUFFIX) + touch FEZoo.o + +CPFEM.o: CPFEM.f90 \ + homogenization.o + +CPFEM2.o: CPFEM2.f90 \ + homogenization.o + +homogenization.o: homogenization.f90 \ + $(THERMAL_FILES) \ + $(DAMAGE_FILES) \ + $(VACANCYFLUX_FILES) \ + $(POROSITY_FILES) \ + $(HYDROGENFLUX_FILES) \ + $(HOMOGENIZATION_FILES) + +thermal_isothermal.o: thermal_isothermal.f90 \ + crystallite.o + +thermal_adiabatic.o: thermal_adiabatic.f90 \ + crystallite.o + +thermal_conduction.o: thermal_conduction.f90 \ + crystallite.o + +damage_none.o: damage_none.f90 \ + crystallite.o + +damage_local.o: damage_local.f90 \ + crystallite.o + +damage_nonlocal.o: damage_nonlocal.f90 \ + crystallite.o + +thermal_conduction.o: thermal_conduction.f90 \ + crystallite.o + +vacancyflux_isoconc.o: vacancyflux_isoconc.f90 \ + crystallite.o + +vacancyflux_isochempot.o: vacancyflux_isochempot.f90 \ + crystallite.o + +vacancyflux_cahnhilliard.o: vacancyflux_cahnhilliard.f90 \ + crystallite.o + +porosity_none.o: porosity_none.f90 \ + crystallite.o + +porosity_phasefield.o: porosity_phasefield.f90 \ + crystallite.o + +hydrogenflux_isoconc.o: hydrogenflux_isoconc.f90 \ + crystallite.o + +hydrogenflux_cahnhilliard.o: hydrogenflux_cahnhilliard.f90 \ + crystallite.o + +homogenization_RGC.o: homogenization_RGC.f90 \ + crystallite.o + +homogenization_isostrain.o: homogenization_isostrain.f90 \ + crystallite.o + +homogenization_none.o: homogenization_none.f90 \ + crystallite.o + +crystallite.o: crystallite.f90 \ + constitutive.o + +constitutive.o: constitutive.f90 \ + $(SOURCE_FILES) \ + $(KINEMATICS_FILES) \ + $(PLASTIC_FILES) + +source_thermal_dissipation.o: source_thermal_dissipation.f90 \ + lattice.o + +source_thermal_externalheat.o: source_thermal_externalheat.f90 \ + lattice.o + +source_damage_isoBrittle.o: source_damage_isoBrittle.f90 \ + lattice.o + +source_damage_isoDuctile.o: source_damage_isoDuctile.f90 \ + lattice.o + +source_damage_anisoBrittle.o: source_damage_anisoBrittle.f90 \ + lattice.o + +source_damage_anisoDuctile.o: source_damage_anisoDuctile.f90 \ + lattice.o + +source_vacancy_phenoplasticity.o: source_vacancy_phenoplasticity.f90 \ + lattice.o + +source_vacancy_irradiation.o: source_vacancy_irradiation.f90 \ + lattice.o + +source_vacancy_thermalfluc.o: source_vacancy_thermalfluc.f90 \ + lattice.o + +kinematics_cleavage_opening.o: kinematics_cleavage_opening.f90 \ + lattice.o + +kinematics_slipplane_opening.o: kinematics_slipplane_opening.f90 \ + lattice.o + +kinematics_thermal_expansion.o: kinematics_thermal_expansion.f90 \ + lattice.o + +kinematics_vacancy_strain.o: kinematics_vacancy_strain.f90 \ + lattice.o + +kinematics_hydrogen_strain.o: kinematics_hydrogen_strain.f90 \ + lattice.o + +plastic_nonlocal.o: plastic_nonlocal.f90 \ + lattice.o + +plastic_titanmod.o: plastic_titanmod.f90 \ + lattice.o + +plastic_disloUCLA.o: plastic_disloUCLA.f90 \ + lattice.o + +plastic_dislotwin.o: plastic_dislotwin.f90 \ + lattice.o + +plastic_phenopowerlaw.o: plastic_phenopowerlaw.f90 \ + lattice.o + +plastic_phenoplus.o: plastic_phenoplus.f90 \ + lattice.o + +plastic_isotropic.o: plastic_isotropic.f90 \ + lattice.o + +plastic_j2.o: plastic_j2.f90 \ + lattice.o + +plastic_none.o: plastic_none.f90 \ + lattice.o +ifeq "$(F90)" "gfortran" +lattice.o: lattice.f90 \ + material.o + $(PREFIX) $(COMPILERNAME) $(COMPILE) -ffree-line-length-240 -c lattice.f90 $(SUFFIX) +# long lines for interaction matrix +else +lattice.o: lattice.f90 \ + material.o +endif + +material.o: material.f90 \ + mesh.o + +mesh.o: mesh.f90 \ + $(wildcard meshFEM.f90) \ + FEsolving.o \ + math.o \ + FEZoo.o + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(MESHNAME) -o mesh.o $(SUFFIX) + +FEsolving.o: FEsolving.f90 \ + debug.o + +math.o: math.f90 \ + debug.o + +debug.o: debug.f90 \ + numerics.o + +numerics.o: numerics.f90 \ + libs.o + +libs.o: libs.f90 \ + IO.o + +damask_hdf5.o: damask_hdf5.f90 \ + prec.o \ + IO.o + + $(PREFIX) $(COMPILERNAME) $(HDFLIBS) $(HDFLIBZ) -c damask_hdf5.f90 $(SUFFIX) -lm + +IO.o: IO.f90 \ + DAMASK_interface.o + +ifeq "$(F90)" "gfortran" +DAMASK_interface.o: spectral_interface.f90 \ + $(wildcard DAMASK_FEM_interface.f90) \ + prec.o + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -fall-intrinsics -o DAMASK_interface.o $(SUFFIX) +#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored +# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external +# --> allows the use of 'getcwd' +prec.o: prec.f90 + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 -fno-range-check -fall-intrinsics -fno-fast-math $(SUFFIX) +# fno-range-check: Disable range checking on results of simplification of constant expressions during compilation +# --> allows the definition of DAMASK_NaN +#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored +# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external +# --> allows the use of 'isnan' +#-fno-fast-math: +# --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) +else +DAMASK_interface.o: spectral_interface.f90 \ + $(wildcard DAMASK_FEM_interface.f90) \ + prec.o + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -diag-remark 7410 -stand none -warn nostderrors -o DAMASK_interface.o $(SUFFIX) +# -diag-disable 7410 should disable warning about directory statement in inquire function, but does not work. hence the other 2 statements +prec.o: prec.f90 + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 $(SUFFIX) + +endif + +%.o : %.f90 + $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $< $(SUFFIX) + +.PHONY: tidy +tidy: + @rm -rf *.o + @rm -rf *.mod + @rm -rf *.inst.f90 # for instrumentation + @rm -rf *.pomp.f90 # for instrumentation + @rm -rf *.pp.f90 # for instrumentation + @rm -rf *.pdb # for instrumnentation + @rm -rf *.opari.inc # for instrumnentation + +.PHONY: cleanDAMASK +cleanDAMASK: + @rm -rf *.exe + @rm -rf *.marc + @rm -rf *.o + @rm -rf *.mod + @rm -rf *.inst.f90 # for instrumentation + @rm -rf *.pomp.f90 # for instrumentation + @rm -rf *.pp.f90 # for instrumentation + @rm -rf *.pdb # for instrumentation + @rm -rf *.opari.inc # for instrumentation + +.PHONY: help +help: + F90="$(F90)" + COMPILERNAME="$(COMPILERNAME)" + COMPILEROUT="$(COMPILEROUT)" + diff --git a/src/commercialFEM_fileList.f90 b/src/commercialFEM_fileList.f90 new file mode 100644 index 000000000..8567da5b1 --- /dev/null +++ b/src/commercialFEM_fileList.f90 @@ -0,0 +1,59 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief all DAMASK files without solver +!> @details List of files needed by MSC.Marc, Abaqus/Explicit, and Abaqus/Standard +!-------------------------------------------------------------------------------------------------- +#include "IO.f90" +#include "libs.f90" +#include "numerics.f90" +#include "debug.f90" +#include "math.f90" +#include "FEsolving.f90" +#include "mesh.f90" +#include "material.f90" +#include "lattice.f90" +#include "source_thermal_dissipation.f90" +#include "source_thermal_externalheat.f90" +#include "source_damage_isoBrittle.f90" +#include "source_damage_isoDuctile.f90" +#include "source_damage_anisoBrittle.f90" +#include "source_damage_anisoDuctile.f90" +#include "source_vacancy_phenoplasticity.f90" +#include "source_vacancy_irradiation.f90" +#include "source_vacancy_thermalfluc.f90" +#include "kinematics_cleavage_opening.f90" +#include "kinematics_slipplane_opening.f90" +#include "kinematics_thermal_expansion.f90" +#include "kinematics_vacancy_strain.f90" +#include "kinematics_hydrogen_strain.f90" +#include "plastic_none.f90" +#include "plastic_isotropic.f90" +#include "plastic_j2.f90" +#include "plastic_phenopowerlaw.f90" +#include "plastic_phenoplus.f90" +#include "plastic_titanmod.f90" +#include "plastic_dislotwin.f90" +#include "plastic_disloUCLA.f90" +#include "plastic_nonlocal.f90" +#include "constitutive.f90" +#include "crystallite.f90" +#include "homogenization_none.f90" +#include "homogenization_isostrain.f90" +#include "homogenization_RGC.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 "vacancyflux_isoconc.f90" +#include "vacancyflux_isochempot.f90" +#include "vacancyflux_cahnhilliard.f90" +#include "porosity_none.f90" +#include "porosity_phasefield.f90" +#include "hydrogenflux_isoconc.f90" +#include "hydrogenflux_cahnhilliard.f90" +#include "homogenization.f90" +#include "CPFEM.f90" diff --git a/src/compilation_info.f90 b/src/compilation_info.f90 new file mode 100644 index 000000000..64e6b136c --- /dev/null +++ b/src/compilation_info.f90 @@ -0,0 +1,13 @@ +!############################################################## +!$Id$ +#ifdef __GFORTRAN__ + write(6,*) 'Compiled with ', compiler_version() !not supported by and ifort <= 15 (and old gfortran) + write(6,*) 'With options ', compiler_options() +#endif +#ifdef __INTEL_COMPILER + write(6,'(a,i4.4,a,i8.8)') ' Compiled with Intel fortran version ', __INTEL_COMPILER,& + ', build date ', __INTEL_COMPILER_BUILD_DATE +#endif +write(6,*) 'Compiled on ', __DATE__,' at ',__TIME__ +write(6,*) +flush(6) diff --git a/src/constitutive.f90 b/src/constitutive.f90 new file mode 100644 index 000000000..50c77b481 --- /dev/null +++ b/src/constitutive.f90 @@ -0,0 +1,1226 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief elasticity, plasticity, internal microstructure state +!-------------------------------------------------------------------------------------------------- +module constitutive + use prec, only: & + pInt + + implicit none + private + integer(pInt), public, protected :: & + constitutive_plasticity_maxSizePostResults, & + constitutive_plasticity_maxSizeDotState, & + constitutive_source_maxSizePostResults, & + constitutive_source_maxSizeDotState + + public :: & + constitutive_init, & + constitutive_homogenizedC, & + constitutive_microstructure, & + constitutive_LpAndItsTangent, & + constitutive_LiAndItsTangent, & + constitutive_initialFi, & + constitutive_TandItsTangent, & + constitutive_collectDotState, & + constitutive_collectDeltaState, & + constitutive_postResults + + private :: & + constitutive_hooke_TandItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates arrays pointing to array of the various constitutive modules +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal + use debug, only: & + debug_constitutive, & + debug_levelBasic + use numerics, only: & + worldrank + use IO, only: & + IO_error, & + IO_open_file, & + IO_checkAndRewind, & + IO_open_jobFile_stat, & + IO_write_jobFile, & + IO_write_jobIntFile, & + IO_timeStamp + use mesh, only: & + FE_geomtype + use material, only: & + material_phase, & + material_Nphase, & + material_localFileExt, & + material_configFile, & + phase_name, & + phase_plasticity, & + phase_plasticityInstance, & + phase_Nsources, & + phase_source, & + phase_kinematics, & + ELASTICITY_hooke_ID, & + PLASTICITY_none_ID, & + PLASTICITY_isotropic_ID, & + PLASTICITY_j2_ID, & + PLASTICITY_phenopowerlaw_ID, & + PLASTICITY_phenoplus_ID, & + PLASTICITY_dislotwin_ID, & + PLASTICITY_disloucla_ID, & + PLASTICITY_titanmod_ID, & + PLASTICITY_nonlocal_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, & + SOURCE_vacancy_phenoplasticity_ID, & + SOURCE_vacancy_irradiation_ID, & + SOURCE_vacancy_thermalfluc_ID, & + KINEMATICS_cleavage_opening_ID, & + KINEMATICS_slipplane_opening_ID, & + KINEMATICS_thermal_expansion_ID, & + KINEMATICS_vacancy_strain_ID, & + KINEMATICS_hydrogen_strain_ID, & + ELASTICITY_HOOKE_label, & + PLASTICITY_NONE_label, & + PLASTICITY_ISOTROPIC_label, & + PLASTICITY_J2_label, & + PLASTICITY_PHENOPOWERLAW_label, & + PLASTICITY_PHENOPLUS_label, & + PLASTICITY_DISLOTWIN_label, & + PLASTICITY_DISLOUCLA_label, & + PLASTICITY_TITANMOD_label, & + PLASTICITY_NONLOCAL_label, & + SOURCE_thermal_dissipation_label, & + SOURCE_thermal_externalheat_label, & + SOURCE_damage_isoBrittle_label, & + SOURCE_damage_isoDuctile_label, & + SOURCE_damage_anisoBrittle_label, & + SOURCE_damage_anisoDuctile_label, & + SOURCE_vacancy_phenoplasticity_label, & + SOURCE_vacancy_irradiation_label, & + SOURCE_vacancy_thermalfluc_label, & + plasticState, & + sourceState + + use plastic_none + use plastic_isotropic + use plastic_j2 + use plastic_phenopowerlaw + use plastic_phenoplus + use plastic_dislotwin + use plastic_disloucla + use plastic_titanmod + use plastic_nonlocal + use source_thermal_dissipation + use source_thermal_externalheat + use source_damage_isoBrittle + use source_damage_isoDuctile + use source_damage_anisoBrittle + use source_damage_anisoDuctile + use source_vacancy_phenoplasticity + use source_vacancy_irradiation + use source_vacancy_thermalfluc + use kinematics_cleavage_opening + use kinematics_slipplane_opening + use kinematics_thermal_expansion + use kinematics_vacancy_strain + use kinematics_hydrogen_strain + + implicit none + integer(pInt), parameter :: FILEUNIT = 200_pInt + integer(pInt) :: & + o, & !< counter in output loop + p, & !< counter in phase loop + s, & !< counter in source loop + ins !< instance of plasticity/source + + integer(pInt), dimension(:,:), pointer :: thisSize + integer(pInt), dimension(:) , pointer :: thisNoutput + character(len=64), dimension(:,:), pointer :: thisOutput + character(len=32) :: outputName !< name of output, intermediate fix until HDF5 output is ready + logical :: knownPlasticity, knownSource, nonlocalConstitutionPresent + nonlocalConstitutionPresent = .false. + +!-------------------------------------------------------------------------------------------------- +! open material.config + if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... + call IO_open_file(FILEUNIT,material_configFile) ! ... open material.config file + +!-------------------------------------------------------------------------------------------------- +! parse plasticities from config file + if (any(phase_plasticity == PLASTICITY_NONE_ID)) call plastic_none_init + if (any(phase_plasticity == PLASTICITY_ISOTROPIC_ID)) call plastic_isotropic_init(FILEUNIT) + if (any(phase_plasticity == PLASTICITY_J2_ID)) call plastic_j2_init(FILEUNIT) + if (any(phase_plasticity == PLASTICITY_PHENOPOWERLAW_ID)) call plastic_phenopowerlaw_init(FILEUNIT) + if (any(phase_plasticity == PLASTICITY_PHENOPLUS_ID)) call plastic_phenoplus_init(FILEUNIT) + if (any(phase_plasticity == PLASTICITY_DISLOTWIN_ID)) call plastic_dislotwin_init(FILEUNIT) + if (any(phase_plasticity == PLASTICITY_DISLOUCLA_ID)) call plastic_disloucla_init(FILEUNIT) + if (any(phase_plasticity == PLASTICITY_TITANMOD_ID)) call plastic_titanmod_init(FILEUNIT) + if (any(phase_plasticity == PLASTICITY_NONLOCAL_ID)) then + call plastic_nonlocal_init(FILEUNIT) + call plastic_nonlocal_stateInit() + endif + +!-------------------------------------------------------------------------------------------------- +! parse source mechanisms from config file + call IO_checkAndRewind(FILEUNIT) + if (any(phase_source == SOURCE_thermal_dissipation_ID)) call source_thermal_dissipation_init(FILEUNIT) + if (any(phase_source == SOURCE_thermal_externalheat_ID)) call source_thermal_externalheat_init(FILEUNIT) + if (any(phase_source == SOURCE_damage_isoBrittle_ID)) call source_damage_isoBrittle_init(FILEUNIT) + if (any(phase_source == SOURCE_damage_isoDuctile_ID)) call source_damage_isoDuctile_init(FILEUNIT) + if (any(phase_source == SOURCE_damage_anisoBrittle_ID)) call source_damage_anisoBrittle_init(FILEUNIT) + if (any(phase_source == SOURCE_damage_anisoDuctile_ID)) call source_damage_anisoDuctile_init(FILEUNIT) + if (any(phase_source == SOURCE_vacancy_phenoplasticity_ID)) call source_vacancy_phenoplasticity_init(FILEUNIT) + if (any(phase_source == SOURCE_vacancy_irradiation_ID)) call source_vacancy_irradiation_init(FILEUNIT) + if (any(phase_source == SOURCE_vacancy_thermalfluc_ID)) call source_vacancy_thermalfluc_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse kinematic mechanisms from config file + call IO_checkAndRewind(FILEUNIT) + if (any(phase_kinematics == KINEMATICS_cleavage_opening_ID)) call kinematics_cleavage_opening_init(FILEUNIT) + if (any(phase_kinematics == KINEMATICS_slipplane_opening_ID)) call kinematics_slipplane_opening_init(FILEUNIT) + if (any(phase_kinematics == KINEMATICS_thermal_expansion_ID)) call kinematics_thermal_expansion_init(FILEUNIT) + if (any(phase_kinematics == KINEMATICS_vacancy_strain_ID)) call kinematics_vacancy_strain_init(FILEUNIT) + if (any(phase_kinematics == KINEMATICS_hydrogen_strain_ID)) call kinematics_hydrogen_strain_init(FILEUNIT) + close(FILEUNIT) + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + +!-------------------------------------------------------------------------------------------------- +! write description file for constitutive output + call IO_write_jobFile(FILEUNIT,'outputConstitutive') + PhaseLoop: do p = 1_pInt,material_Nphase + activePhase: if (any(material_phase == p)) then + ins = phase_plasticityInstance(p) + knownPlasticity = .true. ! assume valid + plasticityType: select case(phase_plasticity(p)) + case (PLASTICITY_NONE_ID) plasticityType + outputName = PLASTICITY_NONE_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (PLASTICITY_ISOTROPIC_ID) plasticityType + outputName = PLASTICITY_ISOTROPIC_label + thisNoutput => plastic_isotropic_Noutput + thisOutput => plastic_isotropic_output + thisSize => plastic_isotropic_sizePostResult + case (PLASTICITY_J2_ID) plasticityType + outputName = PLASTICITY_J2_label + thisNoutput => plastic_j2_Noutput + thisOutput => plastic_j2_output + thisSize => plastic_j2_sizePostResult + case (PLASTICITY_PHENOPOWERLAW_ID) plasticityType + outputName = PLASTICITY_PHENOPOWERLAW_label + thisNoutput => plastic_phenopowerlaw_Noutput + thisOutput => plastic_phenopowerlaw_output + thisSize => plastic_phenopowerlaw_sizePostResult + case (PLASTICITY_PHENOPLUS_ID) plasticityType + outputName = PLASTICITY_PHENOPLUS_label + thisNoutput => plastic_phenoplus_Noutput + thisOutput => plastic_phenoplus_output + thisSize => plastic_phenoplus_sizePostResult + case (PLASTICITY_DISLOTWIN_ID) plasticityType + outputName = PLASTICITY_DISLOTWIN_label + thisNoutput => plastic_dislotwin_Noutput + thisOutput => plastic_dislotwin_output + thisSize => plastic_dislotwin_sizePostResult + case (PLASTICITY_DISLOUCLA_ID) plasticityType + outputName = PLASTICITY_DISLOUCLA_label + thisNoutput => plastic_disloucla_Noutput + thisOutput => plastic_disloucla_output + thisSize => plastic_disloucla_sizePostResult + case (PLASTICITY_TITANMOD_ID) plasticityType + outputName = PLASTICITY_TITANMOD_label + thisNoutput => plastic_titanmod_Noutput + thisOutput => plastic_titanmod_output + thisSize => plastic_titanmod_sizePostResult + case (PLASTICITY_NONLOCAL_ID) plasticityType + outputName = PLASTICITY_NONLOCAL_label + thisNoutput => plastic_nonlocal_Noutput + thisOutput => plastic_nonlocal_output + thisSize => plastic_nonlocal_sizePostResult + case default plasticityType + knownPlasticity = .false. + end select plasticityType + write(FILEUNIT,'(/,a,/)') '['//trim(phase_name(p))//']' + if (knownPlasticity) then + + write(FILEUNIT,'(a)') '(plasticity)'//char(9)//trim(outputName) + if (phase_plasticity(p) /= PLASTICITY_NONE_ID) then + OutputPlasticityLoop: do o = 1_pInt,thisNoutput(ins) + write(FILEUNIT,'(a,i4)') trim(thisOutput(o,ins))//char(9),thisSize(o,ins) + enddo OutputPlasticityLoop + endif + endif + SourceLoop: do s = 1_pInt, phase_Nsources(p) + knownSource = .true. ! assume valid + sourceType: select case (phase_source(s,p)) + case (SOURCE_thermal_dissipation_ID) sourceType + ins = source_thermal_dissipation_instance(p) + outputName = SOURCE_thermal_dissipation_label + thisNoutput => source_thermal_dissipation_Noutput + thisOutput => source_thermal_dissipation_output + thisSize => source_thermal_dissipation_sizePostResult + case (SOURCE_thermal_externalheat_ID) sourceType + ins = source_thermal_externalheat_instance(p) + outputName = SOURCE_thermal_externalheat_label + thisNoutput => source_thermal_externalheat_Noutput + thisOutput => source_thermal_externalheat_output + thisSize => source_thermal_externalheat_sizePostResult + case (SOURCE_damage_isoBrittle_ID) sourceType + ins = source_damage_isoBrittle_instance(p) + outputName = SOURCE_damage_isoBrittle_label + thisNoutput => source_damage_isoBrittle_Noutput + thisOutput => source_damage_isoBrittle_output + thisSize => source_damage_isoBrittle_sizePostResult + case (SOURCE_damage_isoDuctile_ID) sourceType + ins = source_damage_isoDuctile_instance(p) + outputName = SOURCE_damage_isoDuctile_label + thisNoutput => source_damage_isoDuctile_Noutput + thisOutput => source_damage_isoDuctile_output + thisSize => source_damage_isoDuctile_sizePostResult + case (SOURCE_damage_anisoBrittle_ID) sourceType + ins = source_damage_anisoBrittle_instance(p) + outputName = SOURCE_damage_anisoBrittle_label + thisNoutput => source_damage_anisoBrittle_Noutput + thisOutput => source_damage_anisoBrittle_output + thisSize => source_damage_anisoBrittle_sizePostResult + case (SOURCE_damage_anisoDuctile_ID) sourceType + ins = source_damage_anisoDuctile_instance(p) + outputName = SOURCE_damage_anisoDuctile_label + thisNoutput => source_damage_anisoDuctile_Noutput + thisOutput => source_damage_anisoDuctile_output + thisSize => source_damage_anisoDuctile_sizePostResult + case (SOURCE_vacancy_phenoplasticity_ID) sourceType + ins = source_vacancy_phenoplasticity_instance(p) + outputName = SOURCE_vacancy_phenoplasticity_label + thisNoutput => source_vacancy_phenoplasticity_Noutput + thisOutput => source_vacancy_phenoplasticity_output + thisSize => source_vacancy_phenoplasticity_sizePostResult + case (SOURCE_vacancy_irradiation_ID) sourceType + ins = source_vacancy_irradiation_instance(p) + outputName = SOURCE_vacancy_irradiation_label + thisNoutput => source_vacancy_irradiation_Noutput + thisOutput => source_vacancy_irradiation_output + thisSize => source_vacancy_irradiation_sizePostResult + case (SOURCE_vacancy_thermalfluc_ID) sourceType + ins = source_vacancy_thermalfluc_instance(p) + outputName = SOURCE_vacancy_thermalfluc_label + thisNoutput => source_vacancy_thermalfluc_Noutput + thisOutput => source_vacancy_thermalfluc_output + thisSize => source_vacancy_thermalfluc_sizePostResult + case default sourceType + knownSource = .false. + end select sourceType + if (knownSource) then + write(FILEUNIT,'(a)') '(source)'//char(9)//trim(outputName) + OutputSourceLoop: do o = 1_pInt,thisNoutput(ins) + write(FILEUNIT,'(a,i4)') trim(thisOutput(o,ins))//char(9),thisSize(o,ins) + enddo OutputSourceLoop + endif + enddo SourceLoop + endif activePhase + enddo PhaseLoop + close(FILEUNIT) + endif mainProcess + + constitutive_plasticity_maxSizeDotState = 0_pInt + constitutive_plasticity_maxSizePostResults = 0_pInt + constitutive_source_maxSizeDotState = 0_pInt + constitutive_source_maxSizePostResults = 0_pInt + + PhaseLoop2:do p = 1_pInt,material_Nphase +!-------------------------------------------------------------------------------------------------- +! partition and inititalize state + plasticState(p)%partionedState0 = plasticState(p)%State0 + plasticState(p)%State = plasticState(p)%State0 + forall(s = 1_pInt:phase_Nsources(p)) + sourceState(p)%p(s)%partionedState0 = sourceState(p)%p(s)%State0 + sourceState(p)%p(s)%State = sourceState(p)%p(s)%State0 + end forall +!-------------------------------------------------------------------------------------------------- +! determine max size of state and output + constitutive_plasticity_maxSizeDotState = max(constitutive_plasticity_maxSizeDotState, & + plasticState(p)%sizeDotState) + constitutive_plasticity_maxSizePostResults = max(constitutive_plasticity_maxSizePostResults, & + plasticState(p)%sizePostResults) + constitutive_source_maxSizeDotState = max(constitutive_source_maxSizeDotState, & + maxval(sourceState(p)%p(:)%sizeDotState)) + constitutive_source_maxSizePostResults = max(constitutive_source_maxSizePostResults, & + maxval(sourceState(p)%p(:)%sizePostResults)) + enddo PhaseLoop2 + + +#ifdef TODO +!-------------------------------------------------------------------------------------------------- +! report + constitutive_maxSizeState = maxval(constitutive_sizeState) + constitutive_plasticity_maxSizeDotState = maxval(constitutive_sizeDotState) + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) then + write(6,'(a32,1x,7(i8,1x))') 'constitutive_state0: ', shape(constitutive_state0) + write(6,'(a32,1x,7(i8,1x))') 'constitutive_partionedState0: ', shape(constitutive_partionedState0) + write(6,'(a32,1x,7(i8,1x))') 'constitutive_subState0: ', shape(constitutive_subState0) + write(6,'(a32,1x,7(i8,1x))') 'constitutive_state: ', shape(constitutive_state) + write(6,'(a32,1x,7(i8,1x))') 'constitutive_aTolState: ', shape(constitutive_aTolState) + write(6,'(a32,1x,7(i8,1x))') 'constitutive_dotState: ', shape(constitutive_dotState) + write(6,'(a32,1x,7(i8,1x))') 'constitutive_deltaState: ', shape(constitutive_deltaState) + write(6,'(a32,1x,7(i8,1x))') 'constitutive_sizeState: ', shape(constitutive_sizeState) + write(6,'(a32,1x,7(i8,1x))') 'constitutive_sizeDotState: ', shape(constitutive_sizeDotState) + write(6,'(a32,1x,7(i8,1x),/)') 'constitutive_sizePostResults: ', shape(constitutive_sizePostResults) + write(6,'(a32,1x,7(i8,1x))') 'maxSizeState: ', constitutive_maxSizeState + write(6,'(a32,1x,7(i8,1x))') 'maxSizeDotState: ', constitutive_plasticity_maxSizeDotState + write(6,'(a32,1x,7(i8,1x))') 'maxSizePostResults: ', constitutive_plasticity_maxSizePostResults + endif + flush(6) +#endif + + +end subroutine constitutive_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenize elasticity matrix +!-------------------------------------------------------------------------------------------------- +function constitutive_homogenizedC(ipc,ip,el) + use prec, only: & + pReal + use material, only: & + phase_plasticity, & + material_phase, & + PLASTICITY_TITANMOD_ID, & + PLASTICITY_DISLOTWIN_ID, & + PLASTICITY_DISLOUCLA_ID + use plastic_titanmod, only: & + plastic_titanmod_homogenizedC + use plastic_dislotwin, only: & + plastic_dislotwin_homogenizedC + use plastic_disloucla, only: & + plastic_disloucla_homogenizedC + use lattice, only: & + lattice_C66 + + implicit none + real(pReal), dimension(6,6) :: constitutive_homogenizedC + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) + case (PLASTICITY_DISLOTWIN_ID) plasticityType + constitutive_homogenizedC = plastic_dislotwin_homogenizedC(ipc,ip,el) + case (PLASTICITY_DISLOUCLA_ID) plasticityType + constitutive_homogenizedC = plastic_disloucla_homogenizedC(ipc,ip,el) + case (PLASTICITY_TITANMOD_ID) plasticityType + constitutive_homogenizedC = plastic_titanmod_homogenizedC (ipc,ip,el) + case default plasticityType + constitutive_homogenizedC = lattice_C66(1:6,1:6,material_phase (ipc,ip,el)) + end select plasticityType + +end function constitutive_homogenizedC + +!-------------------------------------------------------------------------------------------------- +!> @brief calls microstructure function of the different constitutive models +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el) + use prec, only: & + pReal + use material, only: & + phase_plasticity, & + material_phase, & + material_homog, & + temperature, & + thermalMapping, & + PLASTICITY_dislotwin_ID, & + PLASTICITY_disloucla_ID, & + PLASTICITY_titanmod_ID, & + PLASTICITY_nonlocal_ID, & + PLASTICITY_phenoplus_ID + use plastic_titanmod, only: & + plastic_titanmod_microstructure + use plastic_nonlocal, only: & + plastic_nonlocal_microstructure + use plastic_dislotwin, only: & + plastic_dislotwin_microstructure + use plastic_disloucla, only: & + plastic_disloucla_microstructure + use plastic_phenoplus, only: & + plastic_phenoplus_microstructure + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(3,3) :: & + Fe, & !< elastic deformation gradient + Fp !< plastic deformation gradient + integer(pInt) :: & + ho, & !< homogenization + tme !< thermal member position + real(pReal), intent(in), dimension(:,:,:,:) :: & + orientations !< crystal orientations as quaternions + + ho = material_homog(ip,el) + tme = thermalMapping(ho)%p(ip,el) + + plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) + case (PLASTICITY_DISLOTWIN_ID) plasticityType + call plastic_dislotwin_microstructure(temperature(ho)%p(tme),ipc,ip,el) + case (PLASTICITY_DISLOUCLA_ID) plasticityType + call plastic_disloucla_microstructure(temperature(ho)%p(tme),ipc,ip,el) + case (PLASTICITY_TITANMOD_ID) plasticityType + call plastic_titanmod_microstructure (temperature(ho)%p(tme),ipc,ip,el) + case (PLASTICITY_NONLOCAL_ID) plasticityType + call plastic_nonlocal_microstructure (Fe,Fp,ip,el) + case (PLASTICITY_PHENOPLUS_ID) plasticityType + call plastic_phenoplus_microstructure(orientations,ipc,ip,el) + end select plasticityType + +end subroutine constitutive_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_LpAndItsTangent(Lp, dLp_dTstar3333, dLp_dFi3333, Tstar_v, Fi, ipc, ip, el) + use prec, only: & + pReal + use math, only: & + math_mul33x33, & + math_Mandel6to33, & + math_Mandel33to6, & + math_Plain99to3333 + use material, only: & + phase_plasticity, & + material_phase, & + material_homog, & + temperature, & + thermalMapping, & + PLASTICITY_NONE_ID, & + PLASTICITY_ISOTROPIC_ID, & + PLASTICITY_J2_ID, & + PLASTICITY_PHENOPOWERLAW_ID, & + PLASTICITY_PHENOPLUS_ID, & + PLASTICITY_DISLOTWIN_ID, & + PLASTICITY_DISLOUCLA_ID, & + PLASTICITY_TITANMOD_ID, & + PLASTICITY_NONLOCAL_ID + use plastic_isotropic, only: & + plastic_isotropic_LpAndItsTangent + use plastic_j2, only: & + plastic_j2_LpAndItsTangent + use plastic_phenopowerlaw, only: & + plastic_phenopowerlaw_LpAndItsTangent + use plastic_phenoplus, only: & + plastic_phenoplus_LpAndItsTangent + use plastic_dislotwin, only: & + plastic_dislotwin_LpAndItsTangent + use plastic_disloucla, only: & + plastic_disloucla_LpAndItsTangent + use plastic_titanmod, only: & + plastic_titanmod_LpAndItsTangent + use plastic_nonlocal, only: & + plastic_nonlocal_LpAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola-Kirchhoff stress + real(pReal), intent(in), dimension(3,3) :: & + Fi !< intermediate deformation gradient + real(pReal), intent(out), dimension(3,3) :: & + Lp !< plastic velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLp_dTstar3333, & !< derivative of Lp with respect to Tstar (4th-order tensor) + dLp_dFi3333 !< derivative of Lp with respect to Fi (4th-order tensor) + real(pReal), dimension(6) :: & + Mstar_v !< Mandel stress work conjugate with Lp + real(pReal), dimension(9,9) :: & + dLp_dMstar !< derivative of Lp with respect to Mstar (4th-order tensor) + real(pReal), dimension(3,3) :: & + temp_33 + integer(pInt) :: & + ho, & !< homogenization + tme !< thermal member position + integer(pInt) :: & + i, j + + ho = material_homog(ip,el) + tme = thermalMapping(ho)%p(ip,el) + + Mstar_v = math_Mandel33to6(math_mul33x33(math_mul33x33(transpose(Fi),Fi),math_Mandel6to33(Tstar_v))) + + plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) + case (PLASTICITY_NONE_ID) plasticityType + Lp = 0.0_pReal + dLp_dMstar = 0.0_pReal + case (PLASTICITY_ISOTROPIC_ID) plasticityType + call plastic_isotropic_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v,ipc,ip,el) + case (PLASTICITY_J2_ID) plasticityType + call plastic_j2_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v,ipc,ip,el) + case (PLASTICITY_PHENOPOWERLAW_ID) plasticityType + call plastic_phenopowerlaw_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v,ipc,ip,el) + case (PLASTICITY_PHENOPLUS_ID) plasticityType + call plastic_phenoplus_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v,ipc,ip,el) + case (PLASTICITY_NONLOCAL_ID) plasticityType + call plastic_nonlocal_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v, & + temperature(ho)%p(tme),ip,el) + case (PLASTICITY_DISLOTWIN_ID) plasticityType + call plastic_dislotwin_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v, & + temperature(ho)%p(tme),ipc,ip,el) + case (PLASTICITY_DISLOUCLA_ID) plasticityType + call plastic_disloucla_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v, & + temperature(ho)%p(tme), ipc,ip,el) + case (PLASTICITY_TITANMOD_ID) plasticityType + call plastic_titanmod_LpAndItsTangent(Lp,dLp_dMstar,Mstar_v, & + temperature(ho)%p(tme), ipc,ip,el) + end select plasticityType + + dLp_dTstar3333 = math_Plain99to3333(dLp_dMstar) + temp_33 = math_mul33x33(Fi,math_Mandel6to33(Tstar_v)) + forall(i = 1_pInt:3_pInt, j = 1_pInt:3_pInt) & + dLp_dFi3333(i,j,1:3,1:3) = math_mul33x33(temp_33,transpose(dLp_dTstar3333(i,j,1:3,1:3))) + & + math_mul33x33(math_mul33x33(Fi,dLp_dTstar3333(i,j,1:3,1:3)),math_Mandel6to33(Tstar_v)) + + temp_33 = math_mul33x33(transpose(Fi),Fi) + + forall(i = 1_pInt:3_pInt, j = 1_pInt:3_pInt) & + dLp_dTstar3333(i,j,1:3,1:3) = math_mul33x33(temp_33,dLp_dTstar3333(i,j,1:3,1:3)) + +end subroutine constitutive_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_LiAndItsTangent(Li, dLi_dTstar3333, dLi_dFi3333, Tstar_v, Fi, ipc, ip, el) + use prec, only: & + pReal + use math, only: & + math_I3, & + math_inv33, & + math_det33, & + math_mul33x33 + use material, only: & + phase_plasticity, & + material_phase, & + material_homog, & + phaseAt, phasememberAt, & + phase_kinematics, & + phase_Nkinematics, & + PLASTICITY_isotropic_ID, & + KINEMATICS_cleavage_opening_ID, & + KINEMATICS_slipplane_opening_ID, & + KINEMATICS_thermal_expansion_ID, & + KINEMATICS_vacancy_strain_ID, & + KINEMATICS_hydrogen_strain_ID + use plastic_isotropic, only: & + plastic_isotropic_LiAndItsTangent + use kinematics_cleavage_opening, only: & + kinematics_cleavage_opening_LiAndItsTangent + use kinematics_slipplane_opening, only: & + kinematics_slipplane_opening_LiAndItsTangent + use kinematics_thermal_expansion, only: & + kinematics_thermal_expansion_LiAndItsTangent + use kinematics_vacancy_strain, only: & + kinematics_vacancy_strain_LiAndItsTangent + use kinematics_hydrogen_strain, only: & + kinematics_hydrogen_strain_LiAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola-Kirchhoff stress + real(pReal), intent(in), dimension(3,3) :: & + Fi !< intermediate deformation gradient + real(pReal), intent(out), dimension(3,3) :: & + Li !< intermediate velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLi_dTstar3333, & !< derivative of Li with respect to Tstar (4th-order tensor) + dLi_dFi3333 + real(pReal), dimension(3,3) :: & + my_Li !< intermediate velocity gradient + real(pReal), dimension(3,3,3,3) :: & + my_dLi_dTstar + real(pReal), dimension(3,3) :: & + FiInv, & + temp_33 + real(pReal) :: & + detFi + integer(pInt) :: & + k !< counter in kinematics loop + integer(pInt) :: & + i, j + + Li = 0.0_pReal + dLi_dTstar3333 = 0.0_pReal + dLi_dFi3333 = 0.0_pReal + + plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) + case (PLASTICITY_isotropic_ID) plasticityType + call plastic_isotropic_LiAndItsTangent(my_Li, my_dLi_dTstar, Tstar_v, ipc, ip, el) + case default plasticityType + my_Li = 0.0_pReal + my_dLi_dTstar = 0.0_pReal + end select plasticityType + + Li = Li + my_Li + dLi_dTstar3333 = dLi_dTstar3333 + my_dLi_dTstar + + KinematicsLoop: do k = 1_pInt, phase_Nkinematics(material_phase(ipc,ip,el)) + kinematicsType: select case (phase_kinematics(k,material_phase(ipc,ip,el))) + case (KINEMATICS_cleavage_opening_ID) kinematicsType + call kinematics_cleavage_opening_LiAndItsTangent(my_Li, my_dLi_dTstar, Tstar_v, ipc, ip, el) + case (KINEMATICS_slipplane_opening_ID) kinematicsType + call kinematics_slipplane_opening_LiAndItsTangent(my_Li, my_dLi_dTstar, Tstar_v, ipc, ip, el) + case (KINEMATICS_thermal_expansion_ID) kinematicsType + call kinematics_thermal_expansion_LiAndItsTangent(my_Li, my_dLi_dTstar, ipc, ip, el) + case (KINEMATICS_vacancy_strain_ID) kinematicsType + call kinematics_vacancy_strain_LiAndItsTangent(my_Li, my_dLi_dTstar, ipc, ip, el) + case (KINEMATICS_hydrogen_strain_ID) kinematicsType + call kinematics_hydrogen_strain_LiAndItsTangent(my_Li, my_dLi_dTstar, ipc, ip, el) + case default kinematicsType + my_Li = 0.0_pReal + my_dLi_dTstar = 0.0_pReal + end select kinematicsType + Li = Li + my_Li + dLi_dTstar3333 = dLi_dTstar3333 + my_dLi_dTstar + enddo KinematicsLoop + + FiInv = math_inv33(Fi) + detFi = math_det33(Fi) + Li = math_mul33x33(math_mul33x33(Fi,Li),FiInv)*detFi !< push forward to intermediate configuration + temp_33 = math_mul33x33(FiInv,Li) + forall(i = 1_pInt:3_pInt, j = 1_pInt:3_pInt) + dLi_dTstar3333(1:3,1:3,i,j) = math_mul33x33(math_mul33x33(Fi,dLi_dTstar3333(1:3,1:3,i,j)),FiInv)*detFi + dLi_dFi3333 (1:3,1:3,i,j) = dLi_dFi3333(1:3,1:3,i,j) + Li*FiInv(j,i) + dLi_dFi3333 (1:3,i,1:3,j) = dLi_dFi3333(1:3,i,1:3,j) + math_I3*temp_33(j,i) + Li*FiInv(j,i) + end forall + +end subroutine constitutive_LiAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief collects initial intermediate deformation gradient +!-------------------------------------------------------------------------------------------------- +pure function constitutive_initialFi(ipc, ip, el) + use prec, only: & + pReal + use math, only: & + math_I3, & + math_inv33, & + math_mul33x33 + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + material_phase, & + KINEMATICS_thermal_expansion_ID, & + KINEMATICS_vacancy_strain_ID, & + KINEMATICS_hydrogen_strain_ID + use kinematics_thermal_expansion, only: & + kinematics_thermal_expansion_initialStrain + use kinematics_vacancy_strain, only: & + kinematics_vacancy_strain_initialStrain + use kinematics_hydrogen_strain, only: & + kinematics_hydrogen_strain_initialStrain + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(3,3) :: & + constitutive_initialFi !< composite initial intermediate deformation gradient + integer(pInt) :: & + k !< counter in kinematics loop + + constitutive_initialFi = math_I3 + + KinematicsLoop: do k = 1_pInt, phase_Nkinematics(material_phase(ipc,ip,el)) !< Warning: small initial strain assumption + kinematicsType: select case (phase_kinematics(k,material_phase(ipc,ip,el))) + case (KINEMATICS_thermal_expansion_ID) kinematicsType + constitutive_initialFi = & + constitutive_initialFi + kinematics_thermal_expansion_initialStrain(ipc, ip, el) + case (KINEMATICS_vacancy_strain_ID) kinematicsType + constitutive_initialFi = & + constitutive_initialFi + kinematics_vacancy_strain_initialStrain(ipc, ip, el) + case (KINEMATICS_hydrogen_strain_ID) kinematicsType + constitutive_initialFi = & + constitutive_initialFi + kinematics_hydrogen_strain_initialStrain(ipc, ip, el) + end select kinematicsType + enddo KinematicsLoop + +end function constitutive_initialFi + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the 2nd Piola-Kirchhoff stress tensor and its tangent with respect to +!> the elastic deformation gradient depending on the selected elastic law (so far no case switch +!! because only hooke is implemented +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_TandItsTangent(T, dT_dFe, dT_dFi, Fe, Fi, ipc, ip, el) + use prec, only: & + pReal + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(3,3) :: & + Fe, & !< elastic deformation gradient + Fi !< intermediate deformation gradient + real(pReal), intent(out), dimension(3,3) :: & + T !< 2nd Piola-Kirchhoff stress tensor + real(pReal), intent(out), dimension(3,3,3,3) :: & + dT_dFe, & !< derivative of 2nd P-K stress with respect to elastic deformation gradient + dT_dFi !< derivative of 2nd P-K stress with respect to intermediate deformation gradient + + call constitutive_hooke_TandItsTangent(T, dT_dFe, dT_dFi, Fe, Fi, ipc, ip, el) + + +end subroutine constitutive_TandItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the 2nd Piola-Kirchhoff stress tensor and its tangent with respect to +!> the elastic deformation gradient using hookes law +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_hooke_TandItsTangent(T, dT_dFe, dT_dFi, Fe, Fi, ipc, ip, el) + use prec, only: & + pReal + use math, only : & + math_mul3x3, & + math_mul33x33, & + math_mul3333xx33, & + math_Mandel66to3333, & + math_trace33, & + math_I3 + use material, only: & + material_phase, & + material_homog, & + phase_NstiffnessDegradations, & + phase_stiffnessDegradation, & + damage, & + damageMapping, & + porosity, & + porosityMapping, & + STIFFNESS_DEGRADATION_damage_ID, & + STIFFNESS_DEGRADATION_porosity_ID + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(3,3) :: & + Fe, & !< elastic deformation gradient + Fi !< intermediate deformation gradient + real(pReal), intent(out), dimension(3,3) :: & + T !< 2nd Piola-Kirchhoff stress tensor in lattice configuration + real(pReal), intent(out), dimension(3,3,3,3) :: & + dT_dFe, & !< derivative of 2nd P-K stress with respect to elastic deformation gradient + dT_dFi !< derivative of 2nd P-K stress with respect to intermediate deformation gradient + real(pReal), dimension(3,3) :: E + real(pReal), dimension(3,3,3,3) :: C + integer(pInt) :: & + ho, & !< homogenization + d !< counter in degradation loop + integer(pInt) :: & + i, j + + ho = material_homog(ip,el) + + C = math_Mandel66to3333(constitutive_homogenizedC(ipc,ip,el)) + + DegradationLoop: do d = 1_pInt, phase_NstiffnessDegradations(material_phase(ipc,ip,el)) + degradationType: select case(phase_stiffnessDegradation(d,material_phase(ipc,ip,el))) + case (STIFFNESS_DEGRADATION_damage_ID) degradationType + C = C * damage(ho)%p(damageMapping(ho)%p(ip,el))**2_pInt + case (STIFFNESS_DEGRADATION_porosity_ID) degradationType + C = C * porosity(ho)%p(porosityMapping(ho)%p(ip,el))**2_pInt + end select degradationType + enddo DegradationLoop + + E = 0.5_pReal*(math_mul33x33(transpose(Fe),Fe)-math_I3) !< Green-Lagrange strain in unloaded configuration + T = math_mul3333xx33(C,math_mul33x33(math_mul33x33(transpose(Fi),E),Fi)) !< 2PK stress in lattice configuration in work conjugate with GL strain pulled back to lattice configuration + + dT_dFe = 0.0_pReal + forall (i=1_pInt:3_pInt, j=1_pInt:3_pInt) + dT_dFe(i,j,1:3,1:3) = & + math_mul33x33(Fe,math_mul33x33(math_mul33x33(Fi,C(i,j,1:3,1:3)),transpose(Fi))) !< dT_ij/dFe_kl = C_ijmn * Fi_lm * Fi_on * Fe_ko + dT_dFi(i,j,1:3,1:3) = 2.0_pReal*math_mul33x33(math_mul33x33(E,Fi),C(i,j,1:3,1:3)) !< dT_ij/dFi_kl = C_ijln * E_km * Fe_mn + end forall + +end subroutine constitutive_hooke_TandItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_collectDotState(Tstar_v, FeArray, FpArray, subdt, subfracArray,ipc, ip, el) + use prec, only: & + pReal, & + pLongInt + use debug, only: & + debug_cumDotStateCalls, & + debug_cumDotStateTicks, & + debug_level, & + debug_constitutive, & + debug_levelBasic + use mesh, only: & + mesh_NcpElems, & + mesh_maxNips + use material, only: & + phase_plasticity, & + phase_source, & + phase_Nsources, & + material_phase, & + material_homog, & + temperature, & + thermalMapping, & + homogenization_maxNgrains, & + PLASTICITY_none_ID, & + PLASTICITY_isotropic_ID, & + PLASTICITY_j2_ID, & + PLASTICITY_phenopowerlaw_ID, & + PLASTICITY_phenoplus_ID, & + PLASTICITY_dislotwin_ID, & + PLASTICITY_disloucla_ID, & + PLASTICITY_titanmod_ID, & + PLASTICITY_nonlocal_ID, & + SOURCE_damage_isoDuctile_ID, & + SOURCE_damage_anisoBrittle_ID, & + SOURCE_damage_anisoDuctile_ID, & + SOURCE_thermal_externalheat_ID + use plastic_isotropic, only: & + plastic_isotropic_dotState + use plastic_j2, only: & + plastic_j2_dotState + use plastic_phenopowerlaw, only: & + plastic_phenopowerlaw_dotState + use plastic_phenoplus, only: & + plastic_phenoplus_dotState + use plastic_dislotwin, only: & + plastic_dislotwin_dotState + use plastic_disloucla, only: & + plastic_disloucla_dotState + use plastic_titanmod, only: & + plastic_titanmod_dotState + use plastic_nonlocal, only: & + plastic_nonlocal_dotState + use source_damage_isoDuctile, only: & + source_damage_isoDuctile_dotState + use source_damage_anisoBrittle, only: & + source_damage_anisoBrittle_dotState + use source_damage_anisoDuctile, only: & + source_damage_anisoDuctile_dotState + use source_thermal_externalheat, only: & + source_thermal_externalheat_dotState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + subdt !< timestep + real(pReal), intent(in), dimension(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & + subfracArray !< subfraction of timestep + real(pReal), intent(in), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & + FeArray, & !< elastic deformation gradient + FpArray !< plastic deformation gradient + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) + integer(pLongInt) :: & + tick, tock, & + tickrate, & + maxticks + integer(pInt) :: & + ho, & !< homogenization + tme, & !< thermal member position + s !< counter in source loop + + if (iand(debug_level(debug_constitutive), debug_levelBasic) /= 0_pInt) & + call system_clock(count=tick,count_rate=tickrate,count_max=maxticks) + + ho = material_homog( ip,el) + tme = thermalMapping(ho)%p(ip,el) + + plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) + case (PLASTICITY_ISOTROPIC_ID) plasticityType + call plastic_isotropic_dotState (Tstar_v,ipc,ip,el) + case (PLASTICITY_J2_ID) plasticityType + call plastic_j2_dotState (Tstar_v,ipc,ip,el) + case (PLASTICITY_PHENOPOWERLAW_ID) plasticityType + call plastic_phenopowerlaw_dotState(Tstar_v,ipc,ip,el) + case (PLASTICITY_PHENOPLUS_ID) plasticityType + call plastic_phenoplus_dotState (Tstar_v,ipc,ip,el) + case (PLASTICITY_DISLOTWIN_ID) plasticityType + call plastic_dislotwin_dotState (Tstar_v,temperature(ho)%p(tme), & + ipc,ip,el) + case (PLASTICITY_DISLOUCLA_ID) plasticityType + call plastic_disloucla_dotState (Tstar_v,temperature(ho)%p(tme), & + ipc,ip,el) + case (PLASTICITY_TITANMOD_ID) plasticityType + call plastic_titanmod_dotState (Tstar_v,temperature(ho)%p(tme), & + ipc,ip,el) + case (PLASTICITY_NONLOCAL_ID) plasticityType + call plastic_nonlocal_dotState (Tstar_v,FeArray,FpArray,temperature(ho)%p(tme), & + subdt,subfracArray,ip,el) + end select plasticityType + + SourceLoop: do s = 1_pInt, phase_Nsources(material_phase(ipc,ip,el)) + sourceType: select case (phase_source(s,material_phase(ipc,ip,el))) + case (SOURCE_damage_anisoBrittle_ID) sourceType + call source_damage_anisoBrittle_dotState (Tstar_v, ipc, ip, el) + 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( ipc, ip, el) + end select sourceType + enddo SourceLoop + + if (iand(debug_level(debug_constitutive), debug_levelBasic) /= 0_pInt) then + call system_clock(count=tock,count_rate=tickrate,count_max=maxticks) + !$OMP CRITICAL (debugTimingDotState) + debug_cumDotStateCalls = debug_cumDotStateCalls + 1_pInt + debug_cumDotStateTicks = debug_cumDotStateTicks + tock-tick + !$OMP FLUSH (debug_cumDotStateTicks) + if (tock < tick) debug_cumDotStateTicks = debug_cumDotStateTicks + maxticks + !$OMP END CRITICAL (debugTimingDotState) + endif +end subroutine constitutive_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 +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_collectDeltaState(Tstar_v, Fe, ipc, ip, el) + use prec, only: & + pReal, & + pLongInt + use debug, only: & + debug_cumDeltaStateCalls, & + debug_cumDeltaStateTicks, & + debug_level, & + debug_constitutive, & + debug_levelBasic + use material, only: & + phase_plasticity, & + phase_source, & + phase_Nsources, & + material_phase, & + PLASTICITY_NONLOCAL_ID, & + SOURCE_damage_isoBrittle_ID, & + SOURCE_vacancy_irradiation_ID, & + SOURCE_vacancy_thermalfluc_ID + use plastic_nonlocal, only: & + plastic_nonlocal_deltaState + use source_damage_isoBrittle, only: & + source_damage_isoBrittle_deltaState + use source_vacancy_irradiation, only: & + source_vacancy_irradiation_deltaState + use source_vacancy_thermalfluc, only: & + source_vacancy_thermalfluc_deltaState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola-Kirchhoff stress + real(pReal), intent(in), dimension(3,3) :: & + Fe !< elastic deformation gradient + integer(pInt) :: & + s !< counter in source loop + integer(pLongInt) :: & + tick, tock, & + tickrate, & + maxticks + + if (iand(debug_level(debug_constitutive), debug_levelBasic) /= 0_pInt) & + call system_clock(count=tick,count_rate=tickrate,count_max=maxticks) + + if(phase_plasticity(material_phase(ipc,ip,el)) == PLASTICITY_NONLOCAL_ID) & + call plastic_nonlocal_deltaState(Tstar_v,ip,el) + + + SourceLoop: do s = 1_pInt, phase_Nsources(material_phase(ipc,ip,el)) + sourceType: select case (phase_source(s,material_phase(ipc,ip,el))) + case (SOURCE_damage_isoBrittle_ID) sourceType + call source_damage_isoBrittle_deltaState (constitutive_homogenizedC(ipc,ip,el), Fe, & + ipc, ip, el) + case (SOURCE_vacancy_irradiation_ID) sourceType + call source_vacancy_irradiation_deltaState(ipc, ip, el) + case (SOURCE_vacancy_thermalfluc_ID) sourceType + call source_vacancy_thermalfluc_deltaState(ipc, ip, el) + end select sourceType + enddo SourceLoop + + if (iand(debug_level(debug_constitutive), debug_levelBasic) /= 0_pInt) then + call system_clock(count=tock,count_rate=tickrate,count_max=maxticks) + !$OMP CRITICAL (debugTimingDeltaState) + debug_cumDeltaStateCalls = debug_cumDeltaStateCalls + 1_pInt + debug_cumDeltaStateTicks = debug_cumDeltaStateTicks + tock-tick + !$OMP FLUSH (debug_cumDeltaStateTicks) + if (tock < tick) debug_cumDeltaStateTicks = debug_cumDeltaStateTicks + maxticks + !$OMP END CRITICAL (debugTimingDeltaState) + endif + +end subroutine constitutive_collectDeltaState + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns array of constitutive results +!-------------------------------------------------------------------------------------------------- +function constitutive_postResults(Tstar_v, FeArray, ipc, ip, el) + use prec, only: & + pReal + use mesh, only: & + mesh_NcpElems, & + mesh_maxNips + use material, only: & + plasticState, & + sourceState, & + phase_plasticity, & + phase_source, & + phase_Nsources, & + material_phase, & + material_homog, & + temperature, & + thermalMapping, & + homogenization_maxNgrains, & + PLASTICITY_NONE_ID, & + PLASTICITY_ISOTROPIC_ID, & + PLASTICITY_J2_ID, & + PLASTICITY_PHENOPOWERLAW_ID, & + PLASTICITY_PHENOPLUS_ID, & + PLASTICITY_DISLOTWIN_ID, & + PLASTICITY_DISLOUCLA_ID, & + PLASTICITY_TITANMOD_ID, & + PLASTICITY_NONLOCAL_ID, & + SOURCE_damage_isoBrittle_ID, & + SOURCE_damage_isoDuctile_ID, & + SOURCE_damage_anisoBrittle_ID, & + SOURCE_damage_anisoDuctile_ID + use plastic_isotropic, only: & + plastic_isotropic_postResults + use plastic_j2, only: & + plastic_j2_postResults + use plastic_phenopowerlaw, only: & + plastic_phenopowerlaw_postResults + use plastic_phenoplus, only: & + plastic_phenoplus_postResults + use plastic_dislotwin, only: & + plastic_dislotwin_postResults + use plastic_disloucla, only: & + plastic_disloucla_postResults + use plastic_titanmod, only: & + plastic_titanmod_postResults + use plastic_nonlocal, only: & + plastic_nonlocal_postResults + use source_damage_isoBrittle, only: & + source_damage_isoBrittle_postResults + use source_damage_isoDuctile, only: & + source_damage_isoDuctile_postResults + use source_damage_anisoBrittle, only: & + source_damage_anisoBrittle_postResults + use source_damage_anisoDuctile, only: & + source_damage_anisoDuctile_postResults + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(plasticState(material_phase(ipc,ip,el))%sizePostResults + & + sum(sourceState(material_phase(ipc,ip,el))%p(:)%sizePostResults)) :: & + constitutive_postResults + real(pReal), intent(in), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & + FeArray !< elastic deformation gradient + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) + integer(pInt) :: & + startPos, endPos + integer(pInt) :: & + ho, & !< homogenization + tme, & !< thermal member position + s !< counter in source loop + + constitutive_postResults = 0.0_pReal + + ho = material_homog( ip,el) + tme = thermalMapping(ho)%p(ip,el) + + startPos = 1_pInt + endPos = plasticState(material_phase(ipc,ip,el))%sizePostResults + + plasticityType: select case (phase_plasticity(material_phase(ipc,ip,el))) + case (PLASTICITY_TITANMOD_ID) plasticityType + constitutive_postResults(startPos:endPos) = plastic_titanmod_postResults(ipc,ip,el) + case (PLASTICITY_ISOTROPIC_ID) plasticityType + constitutive_postResults(startPos:endPos) = plastic_isotropic_postResults(Tstar_v,ipc,ip,el) + case (PLASTICITY_J2_ID) plasticityType + constitutive_postResults(startPos:endPos) = plastic_j2_postResults(Tstar_v,ipc,ip,el) + case (PLASTICITY_PHENOPOWERLAW_ID) plasticityType + constitutive_postResults(startPos:endPos) = & + plastic_phenopowerlaw_postResults(Tstar_v,ipc,ip,el) + case (PLASTICITY_PHENOPLUS_ID) plasticityType + constitutive_postResults(startPos:endPos) = & + plastic_phenoplus_postResults(Tstar_v,ipc,ip,el) + case (PLASTICITY_DISLOTWIN_ID) plasticityType + constitutive_postResults(startPos:endPos) = & + plastic_dislotwin_postResults(Tstar_v,temperature(ho)%p(tme),ipc,ip,el) + case (PLASTICITY_DISLOUCLA_ID) plasticityType + constitutive_postResults(startPos:endPos) = & + plastic_disloucla_postResults(Tstar_v,temperature(ho)%p(tme),ipc,ip,el) + case (PLASTICITY_NONLOCAL_ID) plasticityType + constitutive_postResults(startPos:endPos) = & + plastic_nonlocal_postResults (Tstar_v,FeArray,ip,el) + end select plasticityType + + SourceLoop: do s = 1_pInt, phase_Nsources(material_phase(ipc,ip,el)) + startPos = endPos + 1_pInt + endPos = endPos + sourceState(material_phase(ipc,ip,el))%p(s)%sizePostResults + sourceType: select case (phase_source(s,material_phase(ipc,ip,el))) + case (SOURCE_damage_isoBrittle_ID) sourceType + constitutive_postResults(startPos:endPos) = source_damage_isoBrittle_postResults(ipc, ip, el) + case (SOURCE_damage_isoDuctile_ID) sourceType + constitutive_postResults(startPos:endPos) = source_damage_isoDuctile_postResults(ipc, ip, el) + case (SOURCE_damage_anisoBrittle_ID) sourceType + constitutive_postResults(startPos:endPos) = source_damage_anisoBrittle_postResults(ipc, ip, el) + case (SOURCE_damage_anisoDuctile_ID) sourceType + constitutive_postResults(startPos:endPos) = source_damage_anisoDuctile_postResults(ipc, ip, el) + end select sourceType + enddo SourceLoop + +end function constitutive_postResults + +end module constitutive diff --git a/src/core_quit.f90 b/src/core_quit.f90 new file mode 100644 index 000000000..8446e77c8 --- /dev/null +++ b/src/core_quit.f90 @@ -0,0 +1,15 @@ +!################################################################################################## +! $Id$ +!################################################################################################## +!******************************************************************** +! quit subroutine to satisfy IO_error for core module +! +!******************************************************************** +subroutine quit(stop_id) + use prec, only: & + pInt + + implicit none + integer(pInt), intent(in) :: stop_id + +end subroutine diff --git a/src/crystallite.f90 b/src/crystallite.f90 new file mode 100644 index 000000000..6ca40ffef --- /dev/null +++ b/src/crystallite.f90 @@ -0,0 +1,4228 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @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, only: & + pReal, & + pInt + + implicit none + + private + character(len=64), dimension(:,:), allocatable, private :: & + crystallite_output !< name of each post result output + integer(pInt), public, protected :: & + crystallite_maxSizePostResults !< description not available + integer(pInt), dimension(:), allocatable, public, protected :: & + crystallite_sizePostResults !< description not available + integer(pInt), dimension(:,:), allocatable, private :: & + crystallite_sizePostResult !< description not available + + real(pReal), dimension(:,:,:), allocatable, public :: & + crystallite_dt !< requested time increment of each grain + real(pReal), dimension(:,:,:), allocatable, private :: & + crystallite_subdt, & !< substepped time increment of each grain + crystallite_subFrac, & !< already calculated fraction of increment + crystallite_subStep !< size of next integration step + real(pReal), dimension(:,:,:,:), allocatable, public :: & + crystallite_Tstar_v, & !< current 2nd Piola-Kirchhoff stress vector (end of converged time step) + crystallite_Tstar0_v, & !< 2nd Piola-Kirchhoff stress vector at start of FE inc + crystallite_partionedTstar0_v !< 2nd Piola-Kirchhoff stress vector at start of homog inc + real(pReal), dimension(:,:,:,:), allocatable, private :: & + crystallite_subTstar0_v, & !< 2nd Piola-Kirchhoff stress vector at start of crystallite inc + crystallite_orientation, & !< orientation as quaternion + crystallite_orientation0, & !< initial orientation as quaternion + crystallite_rotation !< grain rotation away from initial orientation as axis-angle (in degrees) in crystal reference frame + real(pReal), dimension(:,:,:,:,:), allocatable, public :: & + crystallite_Fp, & !< current plastic def grad (end of converged time step) + crystallite_Fp0, & !< plastic def grad at start of FE inc + crystallite_partionedFp0,& !< plastic def grad at start of homog inc + crystallite_Fi, & !< current intermediate def grad (end of converged time step) + crystallite_Fi0, & !< intermediate def grad at start of FE inc + crystallite_partionedFi0,& !< intermediate def grad at start of homog inc + crystallite_F0, & !< def grad at start of FE inc + crystallite_partionedF, & !< def grad to be reached at end of homog inc + crystallite_partionedF0, & !< def grad at start of homog inc + crystallite_Lp, & !< current plastic velocitiy grad (end of converged time step) + crystallite_Lp0, & !< plastic velocitiy grad at start of FE inc + crystallite_partionedLp0,& !< 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_partionedLi0,& !< intermediate velocity grad at start of homog inc + crystallite_Fe, & !< current "elastic" def grad (end of converged time step) + crystallite_P !< 1st Piola-Kirchhoff stress per grain + real(pReal), dimension(:,:,:,:,:), allocatable, private :: & + crystallite_subFe0,& !< "elastic" def grad at start of crystallite inc + crystallite_invFp, & !< inverse of current plastic def grad (end of converged time step) + crystallite_subFp0,& !< plastic def grad at start of crystallite inc + crystallite_invFi, & !< inverse of current intermediate def grad (end of converged time step) + crystallite_subFi0,& !< intermediate def grad at start of crystallite inc + crystallite_subF, & !< def grad to be reached at end of crystallite inc + crystallite_subF0, & !< def grad at start of crystallite inc + crystallite_subLp0,& !< plastic velocity grad at start of crystallite inc + crystallite_subLi0,& !< intermediate velocity grad at start of crystallite inc + crystallite_disorientation !< disorientation between two neighboring ips (only calculated for single grain IPs) + real(pReal), dimension(:,:,:,:,:,:,:), allocatable, public :: & + crystallite_dPdF, & !< current individual dPdF per grain (end of converged time step) + crystallite_dPdF0, & !< individual dPdF per grain at start of FE inc + crystallite_partioneddPdF0 !< individual dPdF per grain at start of homog inc + real(pReal), dimension(:,:,:,:,:,:,:), allocatable, private :: & + crystallite_fallbackdPdF !< dPdF fallback for non-converged grains (elastic prediction) + logical, dimension(:,:,:), allocatable, public :: & + crystallite_requested !< flag to request crystallite calculation + logical, dimension(:,:,:), allocatable, public, protected :: & + crystallite_converged, & !< convergence flag + crystallite_localPlasticity !< indicates this grain to have purely local constitutive law + logical, dimension(:,:,:), allocatable, private :: & + crystallite_todo !< flag to indicate need for further computation + logical, dimension(:,:), allocatable, private :: & + crystallite_clearToWindForward, & !< description not available + crystallite_clearToCutback, & !< description not available + crystallite_syncSubFrac, & !< description not available + crystallite_syncSubFracCompleted, & !< description not available + crystallite_neighborEnforcedCutback !< description not available + + enum, bind(c) + enumerator :: undefined_ID, & + phase_ID, & + texture_ID, & + volume_ID, & + grainrotationx_ID, & + grainrotationy_ID, & + grainrotationz_ID, & + orientation_ID, & + grainrotation_ID, & + eulerangles_ID, & + defgrad_ID, & + fe_ID, & + fp_ID, & + fi_ID, & + lp_ID, & + li_ID, & + e_ID, & + ee_ID, & + p_ID, & + s_ID, & + elasmatrix_ID, & + neighboringip_ID, & + neighboringelement_ID + end enum + integer(kind(undefined_ID)),dimension(:,:), allocatable, private :: & + crystallite_outputID !< ID of each post result output + + public :: & + crystallite_init, & + crystallite_stressAndItsTangent, & + crystallite_orientations, & + crystallite_push33ToRef, & + crystallite_postResults + private :: & + crystallite_integrateStateFPI, & + crystallite_integrateStateEuler, & + crystallite_integrateStateAdaptiveEuler, & + crystallite_integrateStateRK4, & + crystallite_integrateStateRKCK45, & + crystallite_integrateStress, & + crystallite_stateJump + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates and initialize per grain variables +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_info, & + debug_reset, & + debug_level, & + debug_crystallite, & + debug_levelBasic + use numerics, only: & + worldrank, & + usePingPong + use math, only: & + math_I3, & + math_EulerToR, & + math_inv33, & + math_transpose33, & + math_mul33xx33, & + math_mul33x33 + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP + use mesh, only: & + mesh_element, & + mesh_NcpElems, & + mesh_maxNips, & + mesh_maxNipNeighbors + use IO, only: & + IO_read, & + IO_timeStamp, & + IO_open_jobFile_stat, & + IO_open_file, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_write_jobFile, & + IO_error, & + IO_EOF + use material + use constitutive, only: & + constitutive_initialFi, & + constitutive_microstructure ! derived (shortcut) quantities of given state + + implicit none + integer(pInt), parameter :: & + FILEUNIT = 200_pInt + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + c, & !< counter in integration point component loop + i, & !< counter in integration point loop + e, & !< counter in element loop + o, & !< counter in output loop + r, & !< counter in crystallite loop + cMax, & !< maximum number of integration point components + iMax, & !< maximum number of integration points + eMax, & !< maximum number of elements + nMax, & !< maximum number of ip neighbors + myNcomponents, & !< number of components at current IP + section = 0_pInt, & + j, & + p, & + mySize + + character(len=65536) :: & + tag = '', & + line= '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- crystallite init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + cMax = homogenization_maxNgrains + iMax = mesh_maxNips + eMax = mesh_NcpElems + nMax = mesh_maxNipNeighbors + + + allocate(crystallite_Tstar0_v(6,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_partionedTstar0_v(6,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subTstar0_v(6,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_Tstar_v(6,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_P(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_F0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_partionedF0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_partionedF(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subF0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subF(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_Fp0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_partionedFp0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subFp0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_Fp(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_invFp(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_Fi0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_partionedFi0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subFi0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_Fi(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_invFi(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_Fe(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subFe0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_Lp0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_partionedLp0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subLp0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_Lp(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_Li0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_partionedLi0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subLi0(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_Li(3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_dPdF(3,3,3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_dPdF0(3,3,3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_partioneddPdF0(3,3,3,3,cMax,iMax,eMax),source=0.0_pReal) + allocate(crystallite_fallbackdPdF(3,3,3,3,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_dt(cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subdt(cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subFrac(cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_subStep(cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_orientation(4,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_orientation0(4,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_rotation(4,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_disorientation(4,nMax,cMax,iMax,eMax), source=0.0_pReal) + allocate(crystallite_localPlasticity(cMax,iMax,eMax), source=.true.) + allocate(crystallite_requested(cMax,iMax,eMax), source=.false.) + allocate(crystallite_todo(cMax,iMax,eMax), source=.false.) + allocate(crystallite_converged(cMax,iMax,eMax), source=.true.) + allocate(crystallite_clearToWindForward(iMax,eMax), source=.true.) + allocate(crystallite_syncSubFrac(iMax,eMax), source=.false.) + allocate(crystallite_syncSubFracCompleted(iMax,eMax), source=.false.) + allocate(crystallite_clearToCutback(iMax,eMax), source=.true.) + allocate(crystallite_neighborEnforcedCutback(iMax,eMax), source=.false.) + allocate(crystallite_output(maxval(crystallite_Noutput), & + material_Ncrystallite)) ; crystallite_output = '' + allocate(crystallite_outputID(maxval(crystallite_Noutput), & + material_Ncrystallite), source=undefined_ID) + allocate(crystallite_sizePostResults(material_Ncrystallite),source=0_pInt) + allocate(crystallite_sizePostResult(maxval(crystallite_Noutput), & + material_Ncrystallite), source=0_pInt) + + if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... + call IO_open_file(FILEUNIT,material_configFile) ! ...open material.config file + + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partCrystallite) ! wind forward to + line = IO_read(FILEUNIT) + enddo + + do while (trim(line) /= IO_EOF) ! read through sections of crystallite part + line = IO_read(FILEUNIT) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(FILEUNIT, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + o = 0_pInt ! reset output counter + cycle ! skip to next line + endif + if (section > 0_pInt) then + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + o = o + 1_pInt + crystallite_output(o,section) = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + outputName: select case(crystallite_output(o,section)) + case ('phase') outputName + crystallite_outputID(o,section) = phase_ID + case ('texture') outputName + crystallite_outputID(o,section) = texture_ID + case ('volume') outputName + crystallite_outputID(o,section) = volume_ID + case ('grainrotationx') outputName + crystallite_outputID(o,section) = grainrotationx_ID + case ('grainrotationy') outputName + crystallite_outputID(o,section) = grainrotationy_ID + case ('grainrotationz') outputName + crystallite_outputID(o,section) = grainrotationx_ID + case ('orientation') outputName + crystallite_outputID(o,section) = orientation_ID + case ('grainrotation') outputName + crystallite_outputID(o,section) = grainrotation_ID + case ('eulerangles') outputName + crystallite_outputID(o,section) = eulerangles_ID + case ('defgrad','f') outputName + crystallite_outputID(o,section) = defgrad_ID + case ('fe') outputName + crystallite_outputID(o,section) = fe_ID + case ('fp') outputName + crystallite_outputID(o,section) = fp_ID + case ('fi') outputName + crystallite_outputID(o,section) = fi_ID + case ('lp') outputName + crystallite_outputID(o,section) = lp_ID + case ('li') outputName + crystallite_outputID(o,section) = li_ID + case ('e') outputName + crystallite_outputID(o,section) = e_ID + case ('ee') outputName + crystallite_outputID(o,section) = ee_ID + case ('p','firstpiola','1stpiola') outputName + crystallite_outputID(o,section) = p_ID + case ('s','tstar','secondpiola','2ndpiola') outputName + crystallite_outputID(o,section) = s_ID + case ('elasmatrix') outputName + crystallite_outputID(o,section) = elasmatrix_ID + case ('neighboringip') outputName + crystallite_outputID(o,section) = neighboringip_ID + case ('neighboringelement') outputName + crystallite_outputID(o,section) = neighboringelement_ID + case default outputName + call IO_error(105_pInt,ext_msg=IO_stringValue(line,chunkPos,2_pInt)//' (Crystallite)') + end select outputName + end select + endif + enddo + + close(FILEUNIT) + + do r = 1_pInt,material_Ncrystallite + do o = 1_pInt,crystallite_Noutput(r) + select case(crystallite_outputID(o,r)) + case(phase_ID,texture_ID,volume_ID,grainrotationx_ID,grainrotationy_ID,grainrotationz_ID) + mySize = 1_pInt + case(orientation_ID,grainrotation_ID) + mySize = 4_pInt + case(eulerangles_ID) + mySize = 3_pInt + case(defgrad_ID,fe_ID,fp_ID,fi_ID,lp_ID,li_ID,e_ID,ee_ID,p_ID,s_ID) + mySize = 9_pInt + case(elasmatrix_ID) + mySize = 36_pInt + case(neighboringip_ID,neighboringelement_ID) + mySize = mesh_maxNipNeighbors + case default + mySize = 0_pInt + end select + crystallite_sizePostResult(o,r) = mySize + crystallite_sizePostResults(r) = crystallite_sizePostResults(r) + mySize + enddo + enddo + + crystallite_maxSizePostResults = & + maxval(crystallite_sizePostResults(microstructure_crystallite),microstructure_active) + + +!-------------------------------------------------------------------------------------------------- +! write description file for crystallite output + if (worldrank == 0_pInt) then + call IO_write_jobFile(FILEUNIT,'outputCrystallite') + + do r = 1_pInt,material_Ncrystallite + if (any(microstructure_crystallite(mesh_element(4,:)) == r)) then + write(FILEUNIT,'(/,a,/)') '['//trim(crystallite_name(r))//']' + do o = 1_pInt,crystallite_Noutput(r) + write(FILEUNIT,'(a,i4)') trim(crystallite_output(o,r))//char(9),crystallite_sizePostResult(o,r) + enddo + endif + enddo + + close(FILEUNIT) + endif + +!-------------------------------------------------------------------------------------------------- +! initialize +!$OMP PARALLEL DO PRIVATE(myNcomponents) + do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1_pInt:myNcomponents) + crystallite_Fp0(1:3,1:3,c,i,e) = math_EulerToR(material_EulerAngles(1:3,c,i,e)) ! plastic def gradient reflects init orientation + 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_localPlasticity(c,i,e) = phase_localPlasticity(material_phase(c,i,e)) + crystallite_Fe(1:3,1:3,c,i,e) = math_inv33(math_mul33x33(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. + endforall + enddo + !$OMP END PARALLEL DO + + if(any(.not. crystallite_localPlasticity) .and. .not. usePingPong) call IO_error(601_pInt) ! exit if nonlocal but no ping-pong + + crystallite_partionedFp0 = crystallite_Fp0 + crystallite_partionedFi0 = crystallite_Fi0 + crystallite_partionedF0 = crystallite_F0 + crystallite_partionedF = crystallite_F0 + + call crystallite_orientations() + crystallite_orientation0 = crystallite_orientation ! store initial orientations for calculation of grain rotations + + !$OMP PARALLEL DO PRIVATE(myNcomponents) + do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + do c = 1_pInt,myNcomponents + call constitutive_microstructure(crystallite_orientation, & ! pass orientation to constitutive module + crystallite_Fe(1:3,1:3,c,i,e), & + crystallite_Fp(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 + + call crystallite_stressAndItsTangent(.true.) ! request elastic answers + crystallite_fallbackdPdF = crystallite_dPdF ! use initial elastic stiffness as fallback + +!-------------------------------------------------------------------------------------------------- +! debug output + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Fe: ', shape(crystallite_Fe) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Fp: ', shape(crystallite_Fp) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Fi: ', shape(crystallite_Fi) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Lp: ', shape(crystallite_Lp) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Li: ', shape(crystallite_Li) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_F0: ', shape(crystallite_F0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Fp0: ', shape(crystallite_Fp0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Fi0: ', shape(crystallite_Fi0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Lp0: ', shape(crystallite_Lp0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Li0: ', shape(crystallite_Li0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedF: ', shape(crystallite_partionedF) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedF0: ', shape(crystallite_partionedF0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedFp0: ', shape(crystallite_partionedFp0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedFi0: ', shape(crystallite_partionedFi0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedLp0: ', shape(crystallite_partionedLp0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedLi0: ', shape(crystallite_partionedLi0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subF: ', shape(crystallite_subF) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subF0: ', shape(crystallite_subF0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subFe0: ', shape(crystallite_subFe0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subFp0: ', shape(crystallite_subFp0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subFi0: ', shape(crystallite_subFi0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subLp0: ', shape(crystallite_subLp0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subLi0: ', shape(crystallite_subLi0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_P: ', shape(crystallite_P) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Tstar_v: ', shape(crystallite_Tstar_v) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_Tstar0_v: ', shape(crystallite_Tstar0_v) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_partionedTstar0_v: ', shape(crystallite_partionedTstar0_v) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subTstar0_v: ', shape(crystallite_subTstar0_v) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_dPdF: ', shape(crystallite_dPdF) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_dPdF0: ', shape(crystallite_dPdF0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_partioneddPdF0: ', shape(crystallite_partioneddPdF0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_fallbackdPdF: ', shape(crystallite_fallbackdPdF) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_orientation: ', shape(crystallite_orientation) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_orientation0: ', shape(crystallite_orientation0) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_rotation: ', shape(crystallite_rotation) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_disorientation: ', shape(crystallite_disorientation) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_dt: ', shape(crystallite_dt) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subdt: ', shape(crystallite_subdt) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subFrac: ', shape(crystallite_subFrac) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_subStep: ', shape(crystallite_subStep) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_localPlasticity: ', shape(crystallite_localPlasticity) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_requested: ', shape(crystallite_requested) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_todo: ', shape(crystallite_todo) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_converged: ', shape(crystallite_converged) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_sizePostResults: ', shape(crystallite_sizePostResults) + write(6,'(a35,1x,7(i8,1x))') 'crystallite_sizePostResult: ', shape(crystallite_sizePostResult) + write(6,'(/,a35,1x,i10)') 'Number of nonlocal grains: ',count(.not. crystallite_localPlasticity) + flush(6) + endif + + call debug_info + call debug_reset + +end subroutine crystallite_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate stress (P) and tangent (dPdF) for crystallites +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_stressAndItsTangent(updateJaco) + use prec, only: & + tol_math_check + use numerics, only: & + subStepMinCryst, & + subStepSizeCryst, & + stepIncreaseCryst, & + pert_Fg, & + pert_method, & + nCryst, & + numerics_integrator, & + numerics_integrationMode, & + numerics_timeSyncing, & + analyticJaco + use debug, only: & + debug_level, & + debug_crystallite, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_g, & + debug_CrystalliteLoopDistribution + use IO, only: & + IO_warning, & + IO_error + use math, only: & + math_inv33, & + math_identity2nd, & + math_transpose33, & + math_mul33x33, & + math_mul66x6, & + math_Mandel6to33, & + math_Mandel33to6, & + math_Plain3333to99, & + math_Plain99to3333, & + math_I3, & + math_mul3333xx3333, & + math_mul33xx33, & + math_invert, & + math_det33 + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP + use mesh, only: & + mesh_element, & + mesh_NcpElems, & + mesh_maxNips, & + mesh_ipNeighborhood, & + FE_NipNeighbors, & + FE_geomtype, & + FE_cellType + use material, only: & + homogenization_Ngrains, & + plasticState, & + sourceState, & + phase_Nsources, & + phaseAt, phasememberAt, & + homogenization_maxNgrains + use constitutive, only: & + constitutive_TandItsTangent, & + constitutive_LpAndItsTangent, & + constitutive_LiAndItsTangent + + implicit none + logical, intent(in) :: & + updateJaco !< whether to update the Jacobian (stiffness) or not + real(pReal) :: & + myPert, & ! perturbation with correct sign + formerSubStep, & + subFracIntermediate + real(pReal), dimension(3,3) :: & + invFp, & ! inverse of the plastic deformation gradient + Fe_guess, & ! guess for elastic deformation gradient + Tstar ! 2nd Piola-Kirchhoff stress tensor + real(pReal), allocatable, dimension(:,:,:,:,:,:,:) :: & + dPdF_perturbation1, & + dPdF_perturbation2 + real(pReal), allocatable, dimension(:,:,:,:,:) :: & + F_backup, & + Fp_backup, & + InvFp_backup, & + Fi_backup, & + InvFi_backup, & + Fe_backup, & + Lp_backup, & + Li_backup, & + P_backup + real(pReal), allocatable, dimension(:,:,:,:) :: & + Tstar_v_backup + logical, allocatable, dimension(:,:,:) :: & + convergenceFlag_backup + integer(pInt) :: & + 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 + k, & + l, & + n, startIP, endIP, & + neighboring_e, & + neighboring_i, & + o, & + p, & + perturbation , & ! loop counter for forward,backward perturbation mode + myNcomponents, & + mySource + ! local variables used for calculating analytic Jacobian + real(pReal), dimension(3,3) :: temp_33 + real(pReal), dimension(3,3,3,3) :: dSdFe, & + dSdF, & + dSdFi, & + dLidS, & + dLidFi, & + dLpdS, & + dLpdFi, & + dFidS, & + dFpinvdF, & + rhs_3333, & + lhs_3333, & + temp_3333 + real(pReal), dimension(9,9):: temp_99 + logical :: error + + + if (iand(debug_level(debug_crystallite),debug_levelSelective) /= 0_pInt & + .and. FEsolving_execElem(1) <= debug_e & + .and. debug_e <= FEsolving_execElem(2)) then + write(6,'(/,a,i8,1x,a,i8,a,1x,i2,1x,i3)') '<< CRYST >> boundary values at el ip ipc ', & + debug_e,'(',mesh_element(1,debug_e), ')',debug_i, debug_g + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> F ', & + math_transpose33(crystallite_partionedF(1:3,1:3,debug_g,debug_i,debug_e)) + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> F0 ', & + math_transpose33(crystallite_partionedF0(1:3,1:3,debug_g,debug_i,debug_e)) + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Fp0', & + math_transpose33(crystallite_partionedFp0(1:3,1:3,debug_g,debug_i,debug_e)) + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Fi0', & + math_transpose33(crystallite_partionedFi0(1:3,1:3,debug_g,debug_i,debug_e)) + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Lp0', & + math_transpose33(crystallite_partionedLp0(1:3,1:3,debug_g,debug_i,debug_e)) + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Li0', & + math_transpose33(crystallite_partionedLi0(1:3,1:3,debug_g,debug_i,debug_e)) + endif + +!-------------------------------------------------------------------------------------------------- +! initialize to starting condition + crystallite_subStep = 0.0_pReal + + !$OMP PARALLEL DO PRIVATE(myNcomponents) + elementLooping1: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do c = 1_pInt,myNcomponents + if (crystallite_requested(c,i,e)) then + plasticState (phaseAt(c,i,e))%subState0( :,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%partionedState0(:,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%subState0( :,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%partionedState0(:,phasememberAt(c,i,e)) + enddo + crystallite_subFp0(1:3,1:3,c,i,e) = crystallite_partionedFp0(1:3,1:3,c,i,e) ! ...plastic def grad + crystallite_subLp0(1:3,1:3,c,i,e) = crystallite_partionedLp0(1:3,1:3,c,i,e) ! ...plastic velocity grad + crystallite_subFi0(1:3,1:3,c,i,e) = crystallite_partionedFi0(1:3,1:3,c,i,e) ! ...intermediate def grad + crystallite_subLi0(1:3,1:3,c,i,e) = crystallite_partionedLi0(1:3,1:3,c,i,e) ! ...intermediate velocity grad + crystallite_dPdF0(1:3,1:3,1:3,1:3,c,i,e) = crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,c,i,e) ! ...stiffness + crystallite_subF0(1:3,1:3,c,i,e) = crystallite_partionedF0(1:3,1:3,c,i,e) ! ...def grad + crystallite_subTstar0_v(1:6,c,i,e) = crystallite_partionedTstar0_v(1:6,c,i,e) !...2nd PK stress + crystallite_subFe0(1:3,1:3,c,i,e) = math_mul33x33(math_mul33x33(crystallite_subF0(1:3,1:3,c,i,e), & + math_inv33(crystallite_subFp0(1:3,1:3,c,i,e))), & + math_inv33(crystallite_subFi0(1:3,1:3,c,i,e)))! only needed later on for stiffness calculation + crystallite_subFrac(c,i,e) = 0.0_pReal + crystallite_subStep(c,i,e) = 1.0_pReal/subStepSizeCryst + crystallite_todo(c,i,e) = .true. + crystallite_converged(c,i,e) = .false. ! pretend failed step of twice the required size + endif + enddo; enddo + enddo elementLooping1 + !$OMP END PARALLEL DO + + singleRun: if (FEsolving_execELem(1) == FEsolving_execElem(2) .and. & + FEsolving_execIP(1,FEsolving_execELem(1))==FEsolving_execIP(2,FEsolving_execELem(1))) then + startIP = FEsolving_execIP(1,FEsolving_execELem(1)) + endIP = startIP + else singleRun + startIP = 1_pInt + endIP = mesh_maxNips + endif singleRun + + NiterationCrystallite = 0_pInt + numerics_integrationMode = 1_pInt + cutbackLooping: do while (any(crystallite_todo(:,startIP:endIP,FEsolving_execELem(1):FEsolving_execElem(2)))) + + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i6)') '<< CRYST >> crystallite iteration ',NiterationCrystallite + + timeSyncing1: if (any(.not. crystallite_localPlasticity) .and. numerics_timeSyncing) then + + ! Time synchronization can only be used for nonlocal calculations, and only there it makes sense. + ! The idea is that in nonlocal calculations often the vast majority of the ips + ! converges in one iteration whereas a small fraction of ips has to do a lot of cutbacks. + ! Hence, we try to minimize the computational effort by just doing a lot of cutbacks + ! in the vicinity of the "bad" ips and leave the easily converged volume more or less as it is. + ! However, some synchronization of the time step has to be done at the border between "bad" ips + ! and the ones that immediately converged. + + if (any(crystallite_syncSubFrac)) then + + ! Just did a time synchronization. + ! If all synchronizers converged, then do nothing else than winding them forward. + ! If any of the synchronizers did not converge, something went completely wrong + ! and its not clear how to fix this, so all nonlocals become terminally ill. + + if (any(crystallite_syncSubFrac .and. .not. crystallite_converged(1,:,:))) then + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) then + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if (crystallite_syncSubFrac(i,e) .and. .not. crystallite_converged(1,i,e)) & + write(6,'(a,i8,1x,i2)') '<< CRYST >> time synchronization: failed at el,ip ',e,i + enddo + enddo + endif + crystallite_syncSubFrac = .false. + where(.not. crystallite_localPlasticity) + crystallite_substep = 0.0_pReal + crystallite_todo = .false. + endwhere + else + !$OMP PARALLEL DO + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + crystallite_clearToWindForward(i,e) = crystallite_localPlasticity(1,i,e) .or. crystallite_syncSubFrac(i,e) + crystallite_clearToCutback(i,e) = crystallite_localPlasticity(1,i,e) + enddo + enddo + !$OMP END PARALLEL DO + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i6)') '<< CRYST >> time synchronization: wind forward' + endif + + elseif (any(crystallite_syncSubFracCompleted)) then + + ! Just completed a time synchronization. + ! Make sure that the ips that synchronized their time step start non-converged + + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if (crystallite_syncSubFracCompleted(i,e)) crystallite_converged(1,i,e) = .false. + crystallite_syncSubFracCompleted(i,e) = .false. + crystallite_clearToWindForward(i,e) = crystallite_localPlasticity(1,i,e) + crystallite_clearToCutback(i,e) = crystallite_localPlasticity(1,i,e) .or. .not. crystallite_converged(1,i,e) + enddo + enddo + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i6)') '<< CRYST >> time synchronization: done, proceed with cutback' + else + + ! Normal calculation. + ! If all converged and are at the end of the time increment, then just do a final wind forward. + ! If all converged, but not all reached the end of the time increment, then we only wind + ! those forward that are still on their way, all others have to wait. + ! If some did not converge and all are still at the start of the time increment, + ! then all non-convergers force their converged neighbors to also do a cutback. + ! In case that some ips have already wound forward to an intermediate time (subfrac), + ! then all those ips that converged in the first iteration, but now have a non-converged neighbor + ! have to synchronize their time step to the same intermediate time. If such a synchronization + ! takes place, all other ips have to wait and only the synchronizers do a cutback. In the next + ! iteration those will do a wind forward while all others still wait. + + !$OMP PARALLEL DO + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + crystallite_clearToWindForward(i,e) = crystallite_localPlasticity(1,i,e) + crystallite_clearToCutback(i,e) = crystallite_localPlasticity(1,i,e) + enddo + enddo + !$OMP END PARALLEL DO + if (all(crystallite_localPlasticity .or. crystallite_converged)) then + if (all(crystallite_localPlasticity .or. crystallite_subStep + crystallite_subFrac >= 1.0_pReal)) then + crystallite_clearToWindForward = .true. ! final wind forward + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i6)') '<< CRYST >> final wind forward' + else + !$OMP PARALLEL DO + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + crystallite_clearToWindForward(i,e) = crystallite_localPlasticity(1,i,e) .or. crystallite_subStep(1,i,e) < 1.0_pReal + enddo + enddo + !$OMP END PARALLEL DO + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i6)') '<< CRYST >> wind forward' + endif + else + subFracIntermediate = maxval(crystallite_subFrac, mask=.not.crystallite_localPlasticity) + if (abs(subFracIntermediate) > tiny(0.0_pReal)) then + crystallite_neighborEnforcedCutback = .false. ! look for ips that require a cutback because of a nonconverged neighbor + !$OMP PARALLEL + !$OMP DO PRIVATE(neighboring_e,neighboring_i) + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if (.not. crystallite_localPlasticity(1,i,e) .and. crystallite_converged(1,i,e)) then + do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) + neighboring_e = mesh_ipNeighborhood(1,n,i,e) + neighboring_i = mesh_ipNeighborhood(2,n,i,e) + if (neighboring_e > 0_pInt .and. neighboring_i > 0_pInt) then + if (.not. crystallite_localPlasticity(1,neighboring_i,neighboring_e) & + .and. .not. crystallite_converged(1,neighboring_i,neighboring_e)) then + crystallite_neighborEnforcedCutback(i,e) = .true. +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & + write(6,'(a12,i5,1x,i2,a,i5,1x,i2)') '<< CRYST >> ', neighboring_e,neighboring_i, & + ' enforced cutback at ',e,i +#endif + exit + endif + endif + enddo + endif + enddo + enddo + !$OMP END DO + !$OMP DO + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if(crystallite_neighborEnforcedCutback(i,e)) crystallite_converged(1,i,e) = .false. + enddo + enddo + !$OMP END DO + !$OMP END PARALLEL + else + crystallite_syncSubFrac = .false. ! look for ips that have to do a time synchronization because of a nonconverged neighbor + !$OMP PARALLEL + !$OMP DO PRIVATE(neighboring_e,neighboring_i) + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if (.not. crystallite_localPlasticity(1,i,e) .and. abs(crystallite_subFrac(1,i,e)) > tiny(0.0_pReal)) then + do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) + neighboring_e = mesh_ipNeighborhood(1,n,i,e) + neighboring_i = mesh_ipNeighborhood(2,n,i,e) + if (neighboring_e > 0_pInt .and. neighboring_i > 0_pInt) then + if (.not. crystallite_localPlasticity(1,neighboring_i,neighboring_e) & + .and. .not. crystallite_converged(1,neighboring_i,neighboring_e)) then + crystallite_syncSubFrac(i,e) = .true. +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & + write(6,'(a12,i5,1x,i2,a,i5,1x,i2)') '<< CRYST >> ',neighboring_e,neighboring_i, & + ' enforced time synchronization at ',e,i +#endif + exit + endif + endif + enddo + endif + enddo + enddo + !$OMP END DO + !$OMP DO + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if(crystallite_syncSubFrac(i,e)) crystallite_converged(1,i,e) = .false. + enddo + enddo + !$OMP END DO + !$OMP END PARALLEL + endif + where(.not. crystallite_localPlasticity .and. crystallite_subStep < 1.0_pReal) & + crystallite_converged = .false. + if (any(crystallite_syncSubFrac)) then ! have to do syncing now, so all wait except for the synchronizers which do a cutback + !$OMP PARALLEL DO + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + crystallite_clearToWindForward(i,e) = crystallite_localPlasticity(1,i,e) + crystallite_clearToCutback(i,e) = crystallite_localPlasticity(1,i,e) .or. crystallite_syncSubFrac(i,e) + enddo + enddo + !$OMP END PARALLEL DO + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i6)') '<< CRYST >> time synchronization: cutback' + else + !$OMP PARALLEL DO + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if(.not. crystallite_converged(1,i,e)) crystallite_clearToCutback(i,e) = .true. + enddo + enddo + !$OMP END PARALLEL DO + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i6)') '<< CRYST >> cutback' + endif + endif + endif + + ! Make sure that all cutbackers start with the same substep + + where(.not. crystallite_localPlasticity .and. .not. crystallite_converged) & + crystallite_subStep = minval(crystallite_subStep, mask=.not. crystallite_localPlasticity & + .and. .not. crystallite_converged) + + ! Those that do neither wind forward nor cutback are not to do + + !$OMP PARALLEL DO + elementLooping2: do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if(.not. crystallite_clearToWindForward(i,e) .and. .not. crystallite_clearToCutback(i,e)) & + crystallite_todo(1,i,e) = .false. + enddo + enddo elementLooping2 + !$OMP END PARALLEL DO + + endif timeSyncing1 + + !$OMP PARALLEL DO PRIVATE(myNcomponents,formerSubStep) + elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) ! iterate over IPs of this element to be processed + do c = 1,myNcomponents + ! --- wind forward --- + + if (crystallite_converged(c,i,e) .and. crystallite_clearToWindForward(i,e)) then + formerSubStep = crystallite_subStep(c,i,e) + crystallite_subFrac(c,i,e) = crystallite_subFrac(c,i,e) + crystallite_subStep(c,i,e) + !$OMP FLUSH(crystallite_subFrac) + crystallite_subStep(c,i,e) = min(1.0_pReal - crystallite_subFrac(c,i,e), & + stepIncreaseCryst * crystallite_subStep(c,i,e)) + !$OMP FLUSH(crystallite_subStep) + if (crystallite_subStep(c,i,e) > 0.0_pReal) then + crystallite_subF0(1:3,1:3,c,i,e) = crystallite_subF(1:3,1:3,c,i,e) ! ...def grad + !$OMP FLUSH(crystallite_subF0) + crystallite_subLp0(1:3,1:3,c,i,e) = crystallite_Lp(1:3,1:3,c,i,e) ! ...plastic velocity gradient + crystallite_subLi0(1:3,1:3,c,i,e) = crystallite_Li(1:3,1:3,c,i,e) ! ...intermediate velocity gradient + crystallite_subFp0(1:3,1:3,c,i,e) = crystallite_Fp(1:3,1:3,c,i,e) ! ...plastic def grad + crystallite_subFi0(1:3,1:3,c,i,e) = crystallite_Fi(1:3,1:3,c,i,e) ! ...intermediate def grad + crystallite_subFe0(1:3,1:3,c,i,e) = math_mul33x33(math_mul33x33(crystallite_subF (1:3,1:3,c,i,e), & + crystallite_invFp(1:3,1:3,c,i,e)), & + crystallite_invFi(1:3,1:3,c,i,e)) ! only needed later on for stiffness calculation + !if abbrevation, make c and p private in omp + plasticState (phaseAt(c,i,e))%subState0(:,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%subState0(:,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) + enddo + crystallite_subTstar0_v(1:6,c,i,e) = crystallite_Tstar_v(1:6,c,i,e) ! ...2nd PK stress + if (crystallite_syncSubFrac(i,e)) then ! if we just did a synchronization of states, then we wind forward without any further time integration + crystallite_syncSubFracCompleted(i,e) = .true. + crystallite_syncSubFrac(i,e) = .false. + crystallite_todo(c,i,e) = .false. + else + crystallite_todo(c,i,e) = .true. + endif + !$OMP FLUSH(crystallite_todo) +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite),debug_levelBasic) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i .and. c == debug_g) & + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) & + write(6,'(a,f12.8,a,f12.8,a,i8,1x,i2,1x,i3,/)') '<< CRYST >> winding forward from ', & + crystallite_subFrac(c,i,e)-formerSubStep,' to current crystallite_subfrac ', & + crystallite_subFrac(c,i,e),' in crystallite_stressAndItsTangent at el ip ipc ',e,i,c +#endif + else ! this crystallite just converged for the entire timestep + crystallite_todo(c,i,e) = .false. ! so done here + !$OMP FLUSH(crystallite_todo) + if (iand(debug_level(debug_crystallite),debug_levelBasic) /= 0_pInt & + .and. formerSubStep > 0.0_pReal) then + !$OMP CRITICAL (distributionCrystallite) + debug_CrystalliteLoopDistribution(min(nCryst+1_pInt,NiterationCrystallite)) = & + debug_CrystalliteLoopDistribution(min(nCryst+1_pInt,NiterationCrystallite)) + 1_pInt + !$OMP END CRITICAL (distributionCrystallite) + endif + endif + + ! --- cutback --- + + elseif (.not. crystallite_converged(c,i,e) .and. crystallite_clearToCutback(i,e)) then + if (crystallite_syncSubFrac(i,e)) then ! synchronize time + crystallite_subStep(c,i,e) = subFracIntermediate + else + crystallite_subStep(c,i,e) = subStepSizeCryst * crystallite_subStep(c,i,e) ! cut step in half and restore... + endif + !$OMP FLUSH(crystallite_subStep) + crystallite_Fp(1:3,1:3,c,i,e) = crystallite_subFp0(1:3,1:3,c,i,e) ! ...plastic def grad + !$OMP FLUSH(crystallite_Fp) + crystallite_invFp(1:3,1:3,c,i,e) = math_inv33(crystallite_Fp(1:3,1:3,c,i,e)) + !$OMP FLUSH(crystallite_invFp) + crystallite_Fi(1:3,1:3,c,i,e) = crystallite_subFi0(1:3,1:3,c,i,e) ! ...intermediate def grad + !$OMP FLUSH(crystallite_Fi) + crystallite_invFi(1:3,1:3,c,i,e) = math_inv33(crystallite_Fi(1:3,1:3,c,i,e)) + !$OMP FLUSH(crystallite_invFi) + crystallite_Lp(1:3,1:3,c,i,e) = crystallite_subLp0(1:3,1:3,c,i,e) ! ...plastic velocity grad + crystallite_Li(1:3,1:3,c,i,e) = crystallite_subLi0(1:3,1:3,c,i,e) ! ...intermediate velocity grad + plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%subState0(:,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%subState0(:,phasememberAt(c,i,e)) + enddo + crystallite_Tstar_v(1:6,c,i,e) = crystallite_subTstar0_v(1:6,c,i,e) ! ...2nd PK stress + + ! cant restore dotState here, since not yet calculated in first cutback after initialization + crystallite_todo(c,i,e) = crystallite_subStep(c,i,e) > subStepMinCryst ! still on track or already done (beyond repair) + !$OMP FLUSH(crystallite_todo) +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite),debug_levelBasic) /= 0_pInt) then + if (crystallite_todo(c,i,e)) then + write(6,'(a,f12.8,a,i8,1x,i2,1x,i3,/)') '<< CRYST >> cutback step in crystallite_stressAndItsTangent & + &with new crystallite_subStep: ',& + crystallite_subStep(c,i,e),' at el ip ipc ',e,i,c + else + write(6,'(a,i8,1x,i2,1x,i3,/)') '<< CRYST >> reached minimum step size & + &in crystallite_stressAndItsTangent at el ip ipc ',e,i,c + endif + endif +#endif + endif + + ! --- prepare for integration --- + + if (crystallite_todo(c,i,e) .and. (crystallite_clearToWindForward(i,e) .or. crystallite_clearToCutback(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_partionedF(1:3,1:3,c,i,e) & + - crystallite_partionedF0(1:3,1:3,c,i,e)) + !$OMP FLUSH(crystallite_subF) + crystallite_Fe(1:3,1:3,c,i,e) = math_mul33x33(math_mul33x33(crystallite_subF (1:3,1:3,c,i,e), & + crystallite_invFp(1:3,1:3,c,i,e)), & + crystallite_invFi(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. ! start out non-converged + endif + + enddo ! grains + enddo ! IPs + enddo elementLooping3 + !$OMP END PARALLEL DO + + timeSyncing2: if(numerics_timeSyncing) then + if (any(.not. crystallite_localPlasticity .and. .not. crystallite_todo .and. .not. crystallite_converged & + .and. crystallite_subStep <= subStepMinCryst)) then ! no way of rescuing a nonlocal ip that violated the lower time step limit, ... + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) then + elementLooping4: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + do c = 1,myNcomponents + if (.not. crystallite_localPlasticity(c,i,e) .and. .not. crystallite_todo(c,i,e) & + .and. .not. crystallite_converged(c,i,e) .and. crystallite_subStep(c,i,e) <= subStepMinCryst) & + write(6,'(a,i8,1x,i2,1x,i3)') '<< CRYST >> nonlocal violated minimum subStep at el ip ipc ',e,i,c + enddo + enddo + enddo elementLooping4 + endif + where(.not. crystallite_localPlasticity) + crystallite_todo = .false. ! ... so let all nonlocal ips die peacefully + crystallite_subStep = 0.0_pReal + endwhere + endif + endif timeSyncing2 + + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt) then + write(6,'(/,a,e12.5)') '<< CRYST >> min(subStep) ',minval(crystallite_subStep) + write(6,'(a,e12.5)') '<< CRYST >> max(subStep) ',maxval(crystallite_subStep) + write(6,'(a,e12.5)') '<< CRYST >> min(subFrac) ',minval(crystallite_subFrac) + write(6,'(a,e12.5,/)') '<< CRYST >> max(subFrac) ',maxval(crystallite_subFrac) + flush(6) + endif + + ! --- integrate --- requires fully defined state array (basic + dependent state) + + if (any(crystallite_todo)) then + select case(numerics_integrator(numerics_integrationMode)) + case(1_pInt) + call crystallite_integrateStateFPI() + case(2_pInt) + call crystallite_integrateStateEuler() + case(3_pInt) + call crystallite_integrateStateAdaptiveEuler() + case(4_pInt) + call crystallite_integrateStateRK4() + case(5_pInt) + call crystallite_integrateStateRKCK45() + end select + endif + + where(.not. crystallite_converged .and. crystallite_subStep > subStepMinCryst) & ! do not try non-converged & fully cutbacked any further + crystallite_todo = .true. + + NiterationCrystallite = NiterationCrystallite + 1_pInt + + enddo cutbackLooping + + +! --+>> CHECK FOR NON-CONVERGED CRYSTALLITES <<+-- + + elementLooping5: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) ! iterate over IPs of this element to be processed + do c = 1,myNcomponents + if (.not. crystallite_converged(c,i,e)) then ! respond fully elastically (might be not required due to becoming terminally ill anyway) + if(iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) & + write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3,/)') '<< CRYST >> no convergence: respond fully elastic at el (elFE) ip ipc ', & + e,'(',mesh_element(1,e),')',i,c + invFp = math_inv33(crystallite_partionedFp0(1:3,1:3,c,i,e)) + Fe_guess = math_mul33x33(math_mul33x33(crystallite_partionedF(1:3,1:3,c,i,e), invFp), & + math_inv33(crystallite_partionedFi0(1:3,1:3,c,i,e))) + call constitutive_TandItsTangent(Tstar,dSdFe,dSdFi,Fe_guess,crystallite_partionedFi0(1:3,1:3,c,i,e),c,i,e) + crystallite_P(1:3,1:3,c,i,e) = math_mul33x33(math_mul33x33(crystallite_partionedF(1:3,1:3,c,i,e), invFp), & + math_mul33x33(Tstar,transpose(invFp))) + endif + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i .and. c == debug_g) & + .or. .not. iand(debug_level(debug_crystallite),debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i8,1x,i2,1x,i3)') '<< CRYST >> central solution of cryst_StressAndTangent at el ip ipc ',e,i,c + write(6,'(/,a,/,3(12x,3(f12.4,1x)/))') '<< CRYST >> P / MPa', & + math_transpose33(crystallite_P(1:3,1:3,c,i,e))*1.0e-6_pReal + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Fp', & + math_transpose33(crystallite_Fp(1:3,1:3,c,i,e)) + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< CRYST >> Fi', & + math_transpose33(crystallite_Fi(1:3,1:3,c,i,e)) + write(6,'(a,/,3(12x,3(f14.9,1x)/),/)') '<< CRYST >> Lp', & + math_transpose33(crystallite_Lp(1:3,1:3,c,i,e)) + write(6,'(a,/,3(12x,3(f14.9,1x)/),/)') '<< CRYST >> Li', & + math_transpose33(crystallite_Li(1:3,1:3,c,i,e)) + flush(6) + endif + enddo + enddo + enddo elementLooping5 + + +! --+>> STIFFNESS CALCULATION <<+-- + + computeJacobian: if(updateJaco) then + jacobianMethod: if (analyticJaco) then + + ! --- ANALYTIC JACOBIAN --- + + !$OMP PARALLEL DO PRIVATE(dSdF,dSdFe,dSdFi,dLpdS,dLpdFi,dFpinvdF,dLidS,dLidFi,dFidS,& + !$OMP rhs_3333,lhs_3333,temp_99,temp_33,temp_3333,myNcomponents,error) + elementLooping6: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) ! iterate over IPs of this element to be processed + do c = 1_pInt,myNcomponents + call constitutive_TandItsTangent(temp_33,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 law to calculate elastic stress tangent + + call constitutive_LiAndItsTangent(temp_33,dLidS,dLidFi,crystallite_Tstar_v(1:6,c,i,e), & + crystallite_Fi(1:3,1:3,c,i,e), & + c,i,e) ! call constitutive law to calculate Li tangent in lattice configuration + if (sum(abs(dLidS)) < tol_math_check) then + dFidS = 0.0_pReal + else + temp_33 = math_inv33(crystallite_subFi0(1:3,1:3,c,i,e)) + lhs_3333 = 0.0_pReal; rhs_3333 = 0.0_pReal + do o=1_pInt,3_pInt; do p=1_pInt,3_pInt + lhs_3333(1:3,1:3,o,p) = lhs_3333(1:3,1:3,o,p) + & + crystallite_subdt(c,i,e)*math_mul33x33(temp_33,dLidFi(1:3,1:3,o,p)) + lhs_3333(1:3,o,1:3,p) = lhs_3333(1:3,o,1:3,p) + & + crystallite_invFi(1:3,1:3,c,i,e)*crystallite_invFi(p,o,c,i,e) + rhs_3333(1:3,1:3,o,p) = rhs_3333(1:3,1:3,o,p) - & + crystallite_subdt(c,i,e)*math_mul33x33(temp_33,dLidS(1:3,1:3,o,p)) + enddo; enddo + call math_invert(9_pInt,math_Plain3333to99(lhs_3333),temp_99,error) + if (error) then + call IO_warning(warning_ID=600_pInt,el=e,ip=i,g=c, & + ext_msg='inversion error in analytic tangent calculation') + dFidS = 0.0_pReal + else + dFidS = math_mul3333xx3333(math_Plain99to3333(temp_99),rhs_3333) + endif + dLidS = math_mul3333xx3333(dLidFi,dFidS) + dLidS + endif + + call constitutive_LpAndItsTangent(temp_33,dLpdS,dLpdFi,crystallite_Tstar_v(1:6,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 + + temp_33 = math_transpose33(math_mul33x33(crystallite_invFp(1:3,1:3,c,i,e), & + crystallite_invFi(1:3,1:3,c,i,e))) + rhs_3333 = 0.0_pReal + forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & + rhs_3333(p,o,1:3,1:3) = math_mul33x33(dSdFe(p,o,1:3,1:3),temp_33) + + temp_3333 = 0.0_pReal + temp_33 = math_mul33x33(crystallite_subF(1:3,1:3,c,i,e), & + math_inv33(crystallite_subFp0(1:3,1:3,c,i,e))) + forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & + temp_3333(1:3,1:3,p,o) = math_mul33x33(math_mul33x33(temp_33,dLpdS(1:3,1:3,p,o)), & + crystallite_invFi(1:3,1:3,c,i,e)) + + temp_33 = math_mul33x33(math_mul33x33(crystallite_subF(1:3,1:3,c,i,e), & + crystallite_invFp(1:3,1:3,c,i,e)), & + math_inv33(crystallite_subFi0(1:3,1:3,c,i,e))) + forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & + temp_3333(1:3,1:3,p,o) = temp_3333(1:3,1:3,p,o) + math_mul33x33(temp_33,dLidS(1:3,1:3,p,o)) + + lhs_3333 = crystallite_subdt(c,i,e)*math_mul3333xx3333(dSdFe,temp_3333) + & + math_mul3333xx3333(dSdFi,dFidS) + + call math_invert(9_pInt,math_identity2nd(9_pInt)+math_Plain3333to99(lhs_3333),temp_99,error) + if (error) then + call IO_warning(warning_ID=600_pInt,el=e,ip=i,g=c, & + ext_msg='inversion error in analytic tangent calculation') + dSdF = rhs_3333 + else + dSdF = math_mul3333xx3333(math_Plain99to3333(temp_99),rhs_3333) + endif + + dFpinvdF = 0.0_pReal + temp_3333 = math_mul3333xx3333(dLpdS,dSdF) + forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & + dFpinvdF(1:3,1:3,p,o) = -crystallite_subdt(c,i,e)* & + math_mul33x33(math_inv33(crystallite_subFp0(1:3,1:3,c,i,e)), & + math_mul33x33(temp_3333(1:3,1:3,p,o), & + crystallite_invFi(1:3,1:3,c,i,e))) + + crystallite_dPdF(1:3,1:3,1:3,1:3,c,i,e) = 0.0_pReal + temp_33 = math_mul33x33(crystallite_invFp(1:3,1:3,c,i,e), & + math_mul33x33(math_Mandel6to33(crystallite_Tstar_v(1:6,c,i,e)), & + math_transpose33(crystallite_invFp(1:3,1:3,c,i,e)))) + forall(p=1_pInt:3_pInt) & + crystallite_dPdF(p,1:3,p,1:3,c,i,e) = math_transpose33(temp_33) + + temp_33 = math_mul33x33(math_Mandel6to33(crystallite_Tstar_v(1:6,c,i,e)), & + math_transpose33(crystallite_invFp(1:3,1:3,c,i,e))) + forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & + crystallite_dPdF(1:3,1:3,p,o,c,i,e) = crystallite_dPdF(1:3,1:3,p,o,c,i,e) + & + math_mul33x33(math_mul33x33(crystallite_subF(1:3,1:3,c,i,e),dFpinvdF(1:3,1:3,p,o)),temp_33) + + temp_33 = math_mul33x33(crystallite_subF(1:3,1:3,c,i,e), & + crystallite_invFp(1:3,1:3,c,i,e)) + forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & + crystallite_dPdF(1:3,1:3,p,o,c,i,e) = crystallite_dPdF(1:3,1:3,p,o,c,i,e) + & + math_mul33x33(math_mul33x33(temp_33,dSdF(1:3,1:3,p,o)), & + math_transpose33(crystallite_invFp(1:3,1:3,c,i,e))) + + temp_33 = math_mul33x33(math_mul33x33(crystallite_subF(1:3,1:3,c,i,e), & + crystallite_invFp(1:3,1:3,c,i,e)), & + math_Mandel6to33(crystallite_Tstar_v(1:6,c,i,e))) + forall(p=1_pInt:3_pInt, o=1_pInt:3_pInt) & + crystallite_dPdF(1:3,1:3,p,o,c,i,e) = crystallite_dPdF(1:3,1:3,p,o,c,i,e) + & + math_mul33x33(temp_33,math_transpose33(dFpinvdF(1:3,1:3,p,o))) + + enddo; enddo + enddo elementLooping6 + !$OMP END PARALLEL DO + + else jacobianMethod + + ! --- STANDARD (PERTURBATION METHOD) FOR JACOBIAN --- + + numerics_integrationMode = 2_pInt + + ! --- BACKUP --- + allocate(dPdF_perturbation1(3,3,3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(dPdF_perturbation2(3,3,3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(F_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(Fp_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(InvFp_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(Fi_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(InvFi_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(Fe_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(Lp_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(Li_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(P_backup (3,3, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(Tstar_v_backup (6, homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = 0.0_pReal) + allocate(convergenceFlag_backup (homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source = .false.) + + !$OMP PARALLEL DO PRIVATE(myNcomponents) + elementLooping7: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do c = 1,myNcomponents + + plasticState (phaseAt(c,i,e))%state_backup(:,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%state_backup(:,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) + enddo + + plasticState (phaseAt(c,i,e))%dotState_backup(:,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%dotState( :,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%dotState_backup(:,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%dotState( :,phasememberAt(c,i,e)) + enddo + + F_backup(1:3,1:3,c,i,e) = crystallite_subF(1:3,1:3,c,i,e) ! ... and kinematics + Fp_backup(1:3,1:3,c,i,e) = crystallite_Fp(1:3,1:3,c,i,e) + InvFp_backup(1:3,1:3,c,i,e) = crystallite_invFp(1:3,1:3,c,i,e) + Fi_backup(1:3,1:3,c,i,e) = crystallite_Fi(1:3,1:3,c,i,e) + InvFi_backup(1:3,1:3,c,i,e) = crystallite_invFi(1:3,1:3,c,i,e) + Fe_backup(1:3,1:3,c,i,e) = crystallite_Fe(1:3,1:3,c,i,e) + Lp_backup(1:3,1:3,c,i,e) = crystallite_Lp(1:3,1:3,c,i,e) + Li_backup(1:3,1:3,c,i,e) = crystallite_Li(1:3,1:3,c,i,e) + Tstar_v_backup(1:6,c,i,e) = crystallite_Tstar_v(1:6,c,i,e) + P_backup(1:3,1:3,c,i,e) = crystallite_P(1:3,1:3,c,i,e) + convergenceFlag_backup(c,i,e) = crystallite_converged(c,i,e) + enddo; enddo + enddo elementLooping7 + !$END PARALLEL DO + ! --- CALCULATE STATE AND STRESS FOR PERTURBATION --- + + dPdF_perturbation1 = crystallite_dPdF0 ! initialize stiffness with known good values from last increment + dPdF_perturbation2 = crystallite_dPdF0 ! initialize stiffness with known good values from last increment + pertubationLoop: do perturbation = 1,2 ! forward and backward perturbation + if (iand(pert_method,perturbation) > 0_pInt) then ! mask for desired direction + myPert = -pert_Fg * (-1.0_pReal)**perturbation ! set perturbation step + do k = 1,3; do l = 1,3 ! ...alter individual components + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i .and. c == debug_g) & + .or. .not. iand(debug_level(debug_crystallite),debug_levelSelective) /= 0_pInt)) & + write(6,'(a,2(1x,i1),1x,a,/)') '<< CRYST >> [[[[[[ Stiffness perturbation',k,l,']]]]]]' + ! --- INITIALIZE UNPERTURBED STATE --- + + select case(numerics_integrator(numerics_integrationMode)) + case(1_pInt) +!why not OMP? ! Fix-point method: restore to last converged state at end of subinc, since this is probably closest to perturbed state + do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do c = 1,myNcomponents + + plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%state_backup(:,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%state_backup(:,phasememberAt(c,i,e)) + enddo + + plasticState (phaseAt(c,i,e))%dotState( :,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%dotState_backup(:,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%dotState( :,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%dotState_backup(:,phasememberAt(c,i,e)) + enddo + + crystallite_Fp(1:3,1:3,c,i,e) = Fp_backup(1:3,1:3,c,i,e) + crystallite_invFp(1:3,1:3,c,i,e) = InvFp_backup(1:3,1:3,c,i,e) + crystallite_Fi(1:3,1:3,c,i,e) = Fi_backup(1:3,1:3,c,i,e) + crystallite_invFi(1:3,1:3,c,i,e) = InvFi_backup(1:3,1:3,c,i,e) + crystallite_Fe(1:3,1:3,c,i,e) = Fe_backup(1:3,1:3,c,i,e) + crystallite_Lp(1:3,1:3,c,i,e) = Lp_backup(1:3,1:3,c,i,e) + crystallite_Li(1:3,1:3,c,i,e) = Li_backup(1:3,1:3,c,i,e) + crystallite_Tstar_v(1:6,c,i,e) = Tstar_v_backup(1:6,c,i,e) + enddo; enddo + enddo + case(2_pInt,3_pInt) ! explicit Euler methods: nothing to restore (except for F), since we are only doing a stress integration step + case(4_pInt,5_pInt) +!why not OMP? ! explicit Runge-Kutta methods: restore to start of subinc, since we are doing a full integration of state and stress + do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do c = 1,myNcomponents + + plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%subState0(:,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%subState0(:,phasememberAt(c,i,e)) + enddo + + plasticState (phaseAt(c,i,e))%dotState( :,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%dotState_backup(:,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%dotState( :,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%dotState_backup(:,phasememberAt(c,i,e)) + enddo + + 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_Fe(1:3,1:3,c,i,e) = crystallite_subFe0(1:3,1:3,c,i,e) + crystallite_Lp(1:3,1:3,c,i,e) = crystallite_subLp0(1:3,1:3,c,i,e) + crystallite_Li(1:3,1:3,c,i,e) = crystallite_subLi0(1:3,1:3,c,i,e) + crystallite_Tstar_v(1:6,c,i,e) = crystallite_subTstar0_v(1:6,c,i,e) + enddo; enddo + enddo + end select + + ! --- PERTURB EITHER FORWARD OR BACKWARD --- +!why not OMP? + do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + do c = 1,myNcomponents + crystallite_subF(1:3,1:3,c,i,e) = F_backup(1:3,1:3,c,i,e) + crystallite_subF(k,l,c,i,e) = crystallite_subF(k,l,c,i,e) + myPert + crystallite_todo(c,i,e) = crystallite_requested(c,i,e) & + .and. convergenceFlag_backup(c,i,e) + if (crystallite_todo(c,i,e)) crystallite_converged(c,i,e) = .false. ! start out non-converged + enddo; enddo; enddo + + + select case(numerics_integrator(numerics_integrationMode)) + case(1_pInt) + call crystallite_integrateStateFPI() + case(2_pInt) + call crystallite_integrateStateEuler() + case(3_pInt) + call crystallite_integrateStateAdaptiveEuler() + case(4_pInt) + call crystallite_integrateStateRK4() + case(5_pInt) + call crystallite_integrateStateRKCK45() + end select + !why not OMP? + elementLooping8: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + select case(perturbation) + case(1_pInt) + forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & + crystallite_requested(c,i,e) .and. crystallite_converged(c,i,e)) & ! converged state warrants stiffness update + dPdF_perturbation1(1:3,1:3,k,l,c,i,e) = & + (crystallite_P(1:3,1:3,c,i,e) - P_backup(1:3,1:3,c,i,e)) / myPert ! tangent dP_ij/dFg_kl + case(2_pInt) + forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & + crystallite_requested(c,i,e) .and. crystallite_converged(c,i,e)) & ! converged state warrants stiffness update + dPdF_perturbation2(1:3,1:3,k,l,c,i,e) = & + (crystallite_P(1:3,1:3,c,i,e) - P_backup(1:3,1:3,c,i,e)) / myPert ! tangent dP_ij/dFg_kl + end select + enddo elementLooping8 + + enddo; enddo ! k,l component perturbation loop + + endif + enddo pertubationLoop + + ! --- STIFFNESS ACCORDING TO PERTURBATION METHOD AND CONVERGENCE --- + + elementLooping9: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + select case(pert_method) + case(1_pInt) + forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & + crystallite_requested(c,i,e) .and. convergenceFlag_backup(c,i,e)) & ! perturbation mode 1: central solution converged + crystallite_dPdF(1:3,1:3,1:3,1:3,c,i,e) = dPdF_perturbation1(1:3,1:3,1:3,1:3,c,i,e) + case(2_pInt) + forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & + crystallite_requested(c,i,e) .and. convergenceFlag_backup(c,i,e)) & ! perturbation mode 2: central solution converged + crystallite_dPdF(1:3,1:3,1:3,1:3,c,i,e) = dPdF_perturbation2(1:3,1:3,1:3,1:3,c,i,e) + case(3_pInt) + forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & + crystallite_requested(c,i,e) .and. convergenceFlag_backup(c,i,e)) & ! perturbation mode 3: central solution converged + crystallite_dPdF(1:3,1:3,1:3,1:3,c,i,e) = 0.5_pReal* ( dPdF_perturbation1(1:3,1:3,1:3,1:3,c,i,e) & + + dPdF_perturbation2(1:3,1:3,1:3,1:3,c,i,e)) + end select + forall (i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), c = 1:myNcomponents, & + crystallite_requested(c,i,e) .and. .not. convergenceFlag_backup(c,i,e)) & ! for any pertubation mode: if central solution did not converge... + crystallite_dPdF(1:3,1:3,1:3,1:3,c,i,e) = crystallite_fallbackdPdF(1:3,1:3,1:3,1:3,c,i,e) ! ...use (elastic) fallback + enddo elementLooping9 + + ! --- RESTORE --- +!why not OMP? + elementLooping10: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNcomponents = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do c = 1,myNcomponents + + plasticState (phaseAt(c,i,e))%state( :,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%state_backup(:,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%state( :,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%state_backup(:,phasememberAt(c,i,e)) + enddo + + plasticState (phaseAt(c,i,e))%dotState( :,phasememberAt(c,i,e)) = & + plasticState (phaseAt(c,i,e))%dotState_backup(:,phasememberAt(c,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(c,i,e)) + sourceState(phaseAt(c,i,e))%p(mySource)%dotState( :,phasememberAt(c,i,e)) = & + sourceState(phaseAt(c,i,e))%p(mySource)%dotState_backup(:,phasememberAt(c,i,e)) + enddo + + crystallite_subF(1:3,1:3,c,i,e) = F_backup(1:3,1:3,c,i,e) + crystallite_Fp(1:3,1:3,c,i,e) = Fp_backup(1:3,1:3,c,i,e) + crystallite_invFp(1:3,1:3,c,i,e) = InvFp_backup(1:3,1:3,c,i,e) + crystallite_Fi(1:3,1:3,c,i,e) = Fi_backup(1:3,1:3,c,i,e) + crystallite_invFi(1:3,1:3,c,i,e) = InvFi_backup(1:3,1:3,c,i,e) + crystallite_Fe(1:3,1:3,c,i,e) = Fe_backup(1:3,1:3,c,i,e) + crystallite_Lp(1:3,1:3,c,i,e) = Lp_backup(1:3,1:3,c,i,e) + crystallite_Li(1:3,1:3,c,i,e) = Li_backup(1:3,1:3,c,i,e) + crystallite_Tstar_v(1:6,c,i,e) = Tstar_v_backup(1:6,c,i,e) + crystallite_P(1:3,1:3,c,i,e) = P_backup(1:3,1:3,c,i,e) + crystallite_converged(c,i,e) = convergenceFlag_backup(c,i,e) + enddo; enddo + enddo elementLooping10 + + deallocate(dPdF_perturbation1) + deallocate(dPdF_perturbation2) + deallocate(F_backup ) + deallocate(Fp_backup ) + deallocate(InvFp_backup ) + deallocate(Fi_backup ) + deallocate(InvFi_backup ) + deallocate(Fe_backup ) + deallocate(Lp_backup ) + deallocate(Li_backup ) + deallocate(P_backup ) + deallocate(Tstar_v_backup ) + deallocate(convergenceFlag_backup) + + endif jacobianMethod + endif computeJacobian +!why not OMP? + +end subroutine crystallite_stressAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief integrate stress, state with 4th order explicit Runge Kutta method +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_integrateStateRK4() + use prec, only: & + prec_isNaN + use numerics, only: & + numerics_integrationMode + use debug, only: & + debug_level, & + debug_crystallite, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_g, & + debug_StateLoopDistribution + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP + use mesh, only: & + mesh_element, & + mesh_NcpElems + use material, only: & + homogenization_Ngrains, & + plasticState, & + sourceState, & + phase_Nsources, & + material_Nphase, & + phaseAt, phasememberAt + use constitutive, only: & + constitutive_collectDotState, & + constitutive_microstructure + + implicit none + real(pReal), dimension(4), parameter :: & + TIMESTEPFRACTION = [0.5_pReal, 0.5_pReal, 1.0_pReal, 1.0_pReal] ! factor giving the fraction of the original timestep used for Runge Kutta Integration + real(pReal), dimension(4), parameter :: & + WEIGHT = [1.0_pReal, 2.0_pReal, 2.0_pReal, 1.0_pReal/6.0_pReal] ! weight of slope used for Runge Kutta integration (final weight divided by 6) + + integer(pInt) :: e, & ! element index in element loop + i, & ! integration point index in ip loop + g, & ! grain index in grain loop + p, & ! phase loop + c, & + n, & + mySource, & + mySizePlasticDotState, & + mySizeSourceDotState + integer(pInt), dimension(2) :: eIter ! bounds for element iteration + integer(pInt), dimension(2,mesh_NcpElems) :: iIter, & ! bounds for ip iteration + gIter ! bounds for grain iteration + logical :: NaN, & + singleRun ! flag indicating computation for single (g,i,e) triple + + eIter = FEsolving_execElem(1:2) + do e = eIter(1),eIter(2) + iIter(1:2,e) = FEsolving_execIP(1:2,e) + gIter(1:2,e) = [ 1_pInt,homogenization_Ngrains(mesh_element(3,e))] + enddo + + singleRun = (eIter(1) == eIter(2) .and. iIter(1,eIter(1)) == iIter(2,eIter(2))) + +!-------------------------------------------------------------------------------------------------- +! initialize dotState + if (.not. singleRun) then + do p = 1_pInt, material_Nphase + plasticState(p)%RK4dotState = 0.0_pReal + do mySource = 1_pInt, phase_Nsources(p) + sourceState(p)%p(mySource)%RK4dotState = 0.0_pReal + enddo + enddo + else + e = eIter(1) + i = iIter(1,e) + do g = gIter(1,e), gIter(2,e) + plasticState(phaseAt(g,i,e))%RK4dotState(:,phasememberAt(g,i,e)) = 0.0_pReal + do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) + sourceState(phaseAt(g,i,e))%p(mySource)%RK4dotState(:,phasememberAt(g,i,e)) = 0.0_pReal + enddo + enddo + endif + +!-------------------------------------------------------------------------------------------------- +! first Runge-Kutta step + !$OMP PARALLEL + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & + crystallite_Fe, & + crystallite_Fp, & + crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP DO PRIVATE(p,c,NaN) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + c = phasememberAt(g,i,e) + p = phaseAt(g,i,e) + NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) + do mySource = 1_pInt, phase_Nsources(p) + NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) + enddo + if (NaN) then ! NaN occured in any dotState + if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + else ! if broken local... + crystallite_todo(g,i,e) = .false. ! ... skip this one next time + endif + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + !$OMP END PARALLEL +!-------------------------------------------------------------------------------------------------- +! --- SECOND TO FOURTH RUNGE KUTTA STEP PLUS FINAL INTEGRATION --- + + do n = 1_pInt,4_pInt + ! --- state update --- + + !$OMP PARALLEL + !$OMP DO PRIVATE(p,c) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + plasticState(p)%RK4dotState(:,c) = plasticState(p)%RK4dotState(:,c) & + + weight(n)*plasticState(p)%dotState(:,c) + do mySource = 1_pInt, phase_Nsources(p) + sourceState(p)%p(mySource)%RK4dotState(:,c) = sourceState(p)%p(mySource)%RK4dotState(:,c) & + + weight(n)*sourceState(p)%p(mySource)%dotState(:,c) + enddo + endif + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,c) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + mySizePlasticDotState = plasticState(p)%sizeDotState + plasticState(p)%state (1:mySizePlasticDotState,c) = & + plasticState(p)%subState0(1:mySizePlasticDotState,c) & + + plasticState(p)%dotState (1:mySizePlasticDotState,c) & + * crystallite_subdt(g,i,e) * timeStepFraction(n) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceState(p)%p(mySource)%state (1:mySizeSourceDotState,c) = & + sourceState(p)%p(mySource)%subState0(1:mySizeSourceDotState,c) & + + sourceState(p)%p(mySource)%dotState (1:mySizeSourceDotState,c) & + * crystallite_subdt(g,i,e) * timeStepFraction(n) + enddo + +#ifndef _OPENMP + if (n == 4 & + .and. iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i .and. g == debug_g) & + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then ! final integration step + + write(6,'(a,i8,1x,i2,1x,i3,/)') '<< CRYST >> updateState at el ip g ',e,i,g + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> dotState', plasticState(p)%dotState(1:mySizePlasticDotState,c) + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state', plasticState(p)%state(1:mySizePlasticDotState,c) + endif +#endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- state jump --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- update dependent states --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + !***dirty way to pass orientation information + call constitutive_microstructure(crystallite_orientation, & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fp(1:3,1:3,g,i,e), & + g, i, e) ! update dependent state variables to be consistent with basic states + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- stress integration --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e,timeStepFraction(n)) ! fraction of original times step + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- dot state and RK dot state--- + + first3steps: if (n < 4) then + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & + crystallite_Fe, & + crystallite_Fp, & + timeStepFraction(n)*crystallite_subdt(g,i,e), & ! fraction of original timestep + crystallite_subFrac, g,i,e) + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP DO PRIVATE(p,c,NaN) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) + do mySource = 1_pInt, phase_Nsources(p) + NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) + enddo + if (NaN) then ! NaN occured in any dotState + if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + else ! if broken local... + crystallite_todo(g,i,e) = .false. ! ... skip this one next time + endif + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + endif first3steps + !$OMP END PARALLEL + + enddo + + + ! --- SET CONVERGENCE FLAG --- + + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + crystallite_converged(g,i,e) = .true. ! if still "to do" then converged per definitionem + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionState) + debug_StateLoopDistribution(4,numerics_integrationMode) = & + debug_StateLoopDistribution(4,numerics_integrationMode) + 1_pInt + !$OMP END CRITICAL (distributionState) + endif + endif + enddo; enddo; enddo + + + ! --- CHECK NONLOCAL CONVERGENCE --- + + if (.not. singleRun) then ! if not requesting Integration of just a single IP + if (any(.not. crystallite_converged .and. .not. crystallite_localPlasticity)) then ! any non-local not yet converged (or broken)... + crystallite_converged = crystallite_converged .and. crystallite_localPlasticity ! ...restart all non-local as not converged + endif + endif + +end subroutine crystallite_integrateStateRK4 + + +!-------------------------------------------------------------------------------------------------- +!> @brief integrate stress, state with 5th order Runge-Kutta Cash-Karp method with +!> adaptive step size (use 5th order solution to advance = "local extrapolation") +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_integrateStateRKCK45() + use prec, only: & + prec_isNaN + use debug, only: & + debug_level, & + debug_crystallite, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_g, & + debug_StateLoopDistribution + use numerics, only: & + rTol_crystalliteState, & + numerics_integrationMode + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP + use mesh, only: & + mesh_element, & + mesh_NcpElems, & + mesh_maxNips + use material, only: & + homogenization_Ngrains, & + plasticState, & + sourceState, & + phase_Nsources, & + phaseAt, phasememberAt, & + homogenization_maxNgrains + use constitutive, only: & + constitutive_collectDotState, & + constitutive_plasticity_maxSizeDotState, & + constitutive_source_maxSizeDotState, & + constitutive_microstructure + + implicit none + real(pReal), dimension(5,5), parameter :: & + A = reshape([& + .2_pReal, .075_pReal, .3_pReal, -11.0_pReal/54.0_pReal, 1631.0_pReal/55296.0_pReal, & + .0_pReal, .225_pReal, -.9_pReal, 2.5_pReal, 175.0_pReal/512.0_pReal, & + .0_pReal, .0_pReal, 1.2_pReal, -70.0_pReal/27.0_pReal, 575.0_pReal/13824.0_pReal, & + .0_pReal, .0_pReal, .0_pReal, 35.0_pReal/27.0_pReal, 44275.0_pReal/110592.0_pReal, & + .0_pReal, .0_pReal, .0_pReal, .0_pReal, 253.0_pReal/4096.0_pReal], & + [5,5], order=[2,1]) !< coefficients in Butcher tableau (used for preliminary integration in stages 2 to 6) + + 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], & !< coefficients in Butcher tableau (used for final integration and error estimate) + 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, 0.25_pReal] !< coefficients in Butcher tableau (used for final integration and error estimate) + + real(pReal), dimension(5), parameter :: & + C = [0.2_pReal, 0.3_pReal, 0.6_pReal, 1.0_pReal, 0.875_pReal] !< coefficients in Butcher tableau (fractions of original time step in stages 2 to 6) + + integer(pInt) :: & + e, & ! element index in element loop + i, & ! integration point index in ip loop + g, & ! grain index in grain loop + stage, & ! stage index in integration stage loop + s, & ! state index + n, & + p, & + cc, & + mySource, & + mySizePlasticDotState, & ! size of dot States + mySizeSourceDotState + integer(pInt), dimension(2) :: & + eIter ! bounds for element iteration + integer(pInt), dimension(2,mesh_NcpElems) :: & + iIter, & ! bounds for ip iteration + gIter ! bounds for grain iteration + + real(pReal), dimension(constitutive_plasticity_maxSizeDotState, & + homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & + plasticStateResiduum, & ! residuum from evolution in microstructure + relPlasticStateResiduum ! relative residuum from evolution in microstructure + real(pReal), dimension(constitutive_source_maxSizeDotState, & + maxval(phase_Nsources), & + homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & + sourceStateResiduum, & ! residuum from evolution in microstructure + relSourceStateResiduum ! relative residuum from evolution in microstructure + logical :: & + NaN, & + singleRun ! flag indicating computation for single (g,i,e) triple + + eIter = FEsolving_execElem(1:2) + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & + write(6,'(a,1x,i1)') '<< CRYST >> Runge--Kutta step',1 + + ! --- LOOP ITERATOR FOR ELEMENT, GRAIN, IP --- + do e = eIter(1),eIter(2) + iIter(1:2,e) = FEsolving_execIP(1:2,e) + gIter(1:2,e) = [ 1_pInt,homogenization_Ngrains(mesh_element(3,e))] + enddo + + singleRun = (eIter(1) == eIter(2) .and. iIter(1,eIter(1)) == iIter(2,eIter(2))) + + + + ! --- FIRST RUNGE KUTTA STEP --- + + !$OMP PARALLEL + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & + crystallite_Fe, & + crystallite_Fp, & + crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) + enddo; enddo; enddo + !$OMP ENDDO + !$OMP DO PRIVATE(p,cc,NaN) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + cc = phasememberAt(g,i,e) + p = phaseAt(g,i,e) + NaN = any(prec_isNaN(plasticState(p)%dotState(:,cc))) + do mySource = 1_pInt, phase_Nsources(p) + NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,cc))) + enddo + if (NaN) then ! NaN occured in any dotState + if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + else ! if broken local... + crystallite_todo(g,i,e) = .false. ! ... skip this one next time + endif + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + !$OMP END PARALLEL + + + ! --- SECOND TO SIXTH RUNGE KUTTA STEP --- + + do stage = 1_pInt,5_pInt + + ! --- state update --- + + !$OMP PARALLEL + !$OMP DO PRIVATE(p,cc) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + cc = phasememberAt(g,i,e) + plasticState(p)%RKCK45dotState(stage,:,cc) = plasticState(p)%dotState(:,cc) ! store Runge-Kutta dotState + do mySource = 1_pInt, phase_Nsources(p) + sourceState(p)%p(mySource)%RKCK45dotState(stage,:,cc) = sourceState(p)%p(mySource)%dotState(:,cc) + enddo + endif + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP DO PRIVATE(p,cc,n) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + cc = phasememberAt(g,i,e) + + plasticState(p)%dotState(:,cc) = A(1,stage) * plasticState(p)%RKCK45dotState(1,:,cc) + do mySource = 1_pInt, phase_Nsources(p) + sourceState(p)%p(mySource)%dotState(:,cc) = A(1,stage) * sourceState(p)%p(mySource)%RKCK45dotState(1,:,cc) + enddo + do n = 2_pInt, stage + plasticState(p)%dotState(:,cc) = & + plasticState(p)%dotState(:,cc) + A(n,stage) * plasticState(p)%RKCK45dotState(n,:,cc) + do mySource = 1_pInt, phase_Nsources(p) + sourceState(p)%p(mySource)%dotState(:,cc) = & + sourceState(p)%p(mySource)%dotState(:,cc) + A(n,stage) * sourceState(p)%p(mySource)%RKCK45dotState(n,:,cc) + enddo + enddo + endif + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,cc) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + cc = phasememberAt(g,i,e) + mySizePlasticDotState = plasticState(p)%sizeDotState + plasticState (p)%state (1:mySizePlasticDotState, cc) = & + plasticState (p)%subState0(1:mySizePlasticDotState, cc) & + + plasticState (p)%dotState (1:mySizePlasticDotState, cc) & + * crystallite_subdt(g,i,e) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceState(p)%p(mySource)%state (1:mySizeSourceDotState,cc) = & + sourceState(p)%p(mySource)%subState0(1:mySizeSourceDotState,cc) & + + sourceState(p)%p(mySource)%dotState (1:mySizeSourceDotState,cc) & + * crystallite_subdt(g,i,e) + enddo + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- state jump --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- update dependent states --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + !***dirty way to pass orientations to constitutive_microstructure + call constitutive_microstructure(crystallite_orientation, & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fp(1:3,1:3,g,i,e), & + g, i, e) ! update dependent state variables to be consistent with basic states + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- stress integration --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e,C(stage)) ! fraction of original time step + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- dot state and RK dot state--- +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & + write(6,'(a,1x,i1)') '<< CRYST >> Runge--Kutta step',stage+1_pInt +#endif + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & + crystallite_Fe, & + crystallite_Fp, & + C(stage)*crystallite_subdt(g,i,e), & ! fraction of original timestep + crystallite_subFrac, g,i,e) + enddo; enddo; enddo + !$OMP ENDDO + !$OMP DO PRIVATE(p,cc,NaN) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + + p = phaseAt(g,i,e) + cc = phasememberAt(g,i,e) + NaN = any(prec_isNaN(plasticState(p)%dotState(:,cc))) + do mySource = 1_pInt, phase_Nsources(p) + NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,cc))) + enddo + if (NaN) then ! NaN occured in any dotState + if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + else ! if broken local... + crystallite_todo(g,i,e) = .false. ! ... skip this one next time + endif + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + !$OMP END PARALLEL + + enddo + + +!-------------------------------------------------------------------------------------------------- +! --- STATE UPDATE WITH ERROR ESTIMATE FOR STATE --- + + relPlasticStateResiduum = 0.0_pReal + relSourceStateResiduum = 0.0_pReal + !$OMP PARALLEL + !$OMP DO PRIVATE(p,cc) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + cc = phasememberAt(g,i,e) + plasticState(p)%RKCK45dotState(6,:,cc) = plasticState (p)%dotState(:,cc) ! store Runge-Kutta dotState + do mySource = 1_pInt, phase_Nsources(p) + sourceState(p)%p(mySource)%RKCK45dotState(6,:,cc) = sourceState(p)%p(mySource)%dotState(:,cc) ! store Runge-Kutta dotState + enddo + endif + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,cc) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + cc = phasememberAt(g,i,e) + + ! --- absolute residuum in state --- + mySizePlasticDotState = plasticState(p)%sizeDotState + plasticStateResiduum(1:mySizePlasticDotState,g,i,e) = & + matmul(transpose(plasticState(p)%RKCK45dotState(1:6,1:mySizePlasticDotState,cc)),DB) & + * crystallite_subdt(g,i,e) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e) = & + matmul(transpose(sourceState(p)%p(mySource)%RKCK45dotState(1:6,1:mySizeSourceDotState,cc)),DB) & + * crystallite_subdt(g,i,e) + enddo + + ! --- dot state --- + plasticState(p)%dotState(:,cc) = & + matmul(transpose(plasticState(p)%RKCK45dotState(1:6,1:mySizePlasticDotState,cc)), B) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceState(p)%p(mySource)%dotState(:,cc) = & + matmul(transpose(sourceState(p)%p(mySource)%RKCK45dotState(1:6,1:mySizeSourceDotState,cc)),B) + enddo + endif + enddo; enddo; enddo + !$OMP ENDDO + + ! --- state and update --- + + !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,cc) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + + p = phaseAt(g,i,e) + cc = phasememberAt(g,i,e) + mySizePlasticDotState = plasticState(p)%sizeDotState + plasticState(p)%state (1:mySizePlasticDotState,cc) = & + plasticState(p)%subState0(1:mySizePlasticDotState,cc) & + + plasticState(p)%dotState (1:mySizePlasticDotState,cc) & + * crystallite_subdt(g,i,e) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceState(p)%p(mySource)%state (1:mySizeSourceDotState,cc) = & + sourceState(p)%p(mySource)%subState0(1:mySizeSourceDotState,cc) & + + sourceState(p)%p(mySource)%dotState (1:mySizeSourceDotState,cc)& + * crystallite_subdt(g,i,e) + enddo + endif + enddo; enddo; enddo + !$OMP ENDDO + + ! --- relative residui and state convergence --- + + !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,cc,s) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + cc = phasememberAt(g,i,e) + mySizePlasticDotState = plasticState(p)%sizeDotState + forall (s = 1_pInt:mySizePlasticDotState, abs(plasticState(p)%state(s,cc)) > 0.0_pReal) & + relPlasticStateResiduum(s,g,i,e) = & + plasticStateResiduum(s,g,i,e) / plasticState(p)%state(s,cc) + + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + forall (s = 1_pInt:mySizeSourceDotState,abs(sourceState(p)%p(mySource)%state(s,cc)) > 0.0_pReal) & + relSourceStateResiduum(s,mySource,g,i,e) = & + sourceStateResiduum(s,mySource,g,i,e) / sourceState(p)%p(mySource)%state(s,cc) + enddo + !$OMP FLUSH(relPlasticStateResiduum) + !$OMP FLUSH(relSourceStateResiduum) +! @Martin: do we need flushing? why..? + crystallite_todo(g,i,e) = all(abs(relPlasticStateResiduum(1:mySizePlasticDotState,g,i,e)) < & + rTol_crystalliteState .or. & + abs(plasticStateResiduum(1:mySizePlasticDotState,g,i,e)) < & + plasticState(p)%aTolState(1:mySizePlasticDotState)) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + crystallite_todo(g,i,e) = crystallite_todo(g,i,e) .and. & + all(abs(relSourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e)) < & + rTol_crystalliteState .or. & + abs(sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e)) < & + sourceState(p)%p(mySource)%aTolState(1:mySizeSourceDotState)) + enddo + +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt& + .and. ((e == debug_e .and. i == debug_i .and. g == debug_g)& + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i8,1x,i3,1x,i3,/)') '<< CRYST >> updateState at el ip ipc ',e,i,g + write(6,'(a,/,(12x,12(f12.1,1x)),/)') '<< CRYST >> absolute residuum tolerance', & + plasticStateResiduum(1:mySizePlasticDotState,g,i,e) / plasticState(p)%aTolState(1:mySizePlasticDotState) + write(6,'(a,/,(12x,12(f12.1,1x)),/)') '<< CRYST >> relative residuum tolerance', & + relPlasticStateResiduum(1:mySizePlasticDotState,g,i,e) / rTol_crystalliteState + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> dotState', & + plasticState(p)%dotState(1:mySizePlasticDotState,cc) + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state', & + plasticState(p)%state(1:mySizePlasticDotState,cc) + endif +#endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- STATE JUMP --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + +!-------------------------------------------------------------------------------------------------- +! --- UPDATE DEPENDENT STATES IF RESIDUUM BELOW TOLERANCE --- + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + !***dirty way to pass orientations to constitutive_microstructure + call constitutive_microstructure(crystallite_orientation, & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fp(1:3,1:3,g,i,e), & + g, i, e) ! update dependent state variables to be consistent with basic states + enddo; enddo; enddo + !$OMP ENDDO + + +!-------------------------------------------------------------------------------------------------- +! --- FINAL STRESS INTEGRATION STEP IF RESIDUUM BELOW TOLERANCE --- + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e) + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + +!-------------------------------------------------------------------------------------------------- +! --- SET CONVERGENCE FLAG --- + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + crystallite_converged(g,i,e) = .true. ! if still "to do" then converged per definition + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionState) + debug_StateLoopDistribution(6,numerics_integrationMode) = & + debug_StateLoopDistribution(6,numerics_integrationMode) + 1_pInt + !$OMP END CRITICAL (distributionState) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP END PARALLEL + + + ! --- nonlocal convergence check --- + + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i8,a,i2,/)') '<< CRYST >> ', count(crystallite_converged(:,:,:)), ' grains converged' ! if not requesting Integration of just a single IP + if ((.not. singleRun) .and. any(.not. crystallite_converged .and. .not. crystallite_localPlasticity)) & ! any non-local not yet converged (or broken)... + crystallite_converged = crystallite_converged .and. crystallite_localPlasticity ! ...restart all non-local as not converged + +end subroutine crystallite_integrateStateRKCK45 + + +!-------------------------------------------------------------------------------------------------- +!> @brief integrate stress, state with 1st order Euler method with adaptive step size +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_integrateStateAdaptiveEuler() + use prec, only: & + prec_isNaN + use debug, only: & + debug_level, & + debug_crystallite, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_g, & + debug_StateLoopDistribution + use numerics, only: & + rTol_crystalliteState, & + numerics_integrationMode + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP + use mesh, only: & + mesh_element, & + mesh_NcpElems, & + mesh_maxNips + use material, only: & + homogenization_Ngrains, & + plasticState, & + sourceState, & + phaseAt, phasememberAt, & + phase_Nsources, & + homogenization_maxNgrains + use constitutive, only: & + constitutive_collectDotState, & + constitutive_microstructure, & + constitutive_plasticity_maxSizeDotState, & + constitutive_source_maxSizeDotState + + implicit none + integer(pInt) :: & + e, & ! element index in element loop + i, & ! integration point index in ip loop + g, & ! grain index in grain loop + s, & ! state index + p, & + c, & + mySource, & + mySizePlasticDotState, & ! size of dot states + mySizeSourceDotState + integer(pInt), dimension(2) :: & + eIter ! bounds for element iteration + integer(pInt), dimension(2,mesh_NcpElems) :: & + iIter, & ! bounds for ip iteration + gIter ! bounds for grain iteration + real(pReal), dimension(constitutive_plasticity_maxSizeDotState, & + homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & + plasticStateResiduum, & ! residuum from evolution in micrstructure + relPlasticStateResiduum ! relative residuum from evolution in microstructure + real(pReal), dimension(constitutive_source_maxSizeDotState,& + maxval(phase_Nsources), & + homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems) :: & + sourceStateResiduum, & ! residuum from evolution in micrstructure + relSourceStateResiduum ! relative residuum from evolution in microstructure + + logical :: & + converged, & + NaN, & + singleRun ! flag indicating computation for single (g,i,e) triple + + + ! --- LOOP ITERATOR FOR ELEMENT, GRAIN, IP --- + eIter = FEsolving_execElem(1:2) + do e = eIter(1),eIter(2) + iIter(1:2,e) = FEsolving_execIP(1:2,e) + gIter(1:2,e) = [ 1_pInt,homogenization_Ngrains(mesh_element(3,e))] + enddo + + singleRun = (eIter(1) == eIter(2) .and. iIter(1,eIter(1)) == iIter(2,eIter(2))) + + + plasticStateResiduum = 0.0_pReal + relPlasticStateResiduum = 0.0_pReal + sourceStateResiduum = 0.0_pReal + relSourceStateResiduum = 0.0_pReal + + integrationMode: if (numerics_integrationMode == 1_pInt) then + + !$OMP PARALLEL + ! --- DOT STATE (EULER INTEGRATION) --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & + crystallite_Fe, & + crystallite_Fp, & + crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) + enddo; enddo; enddo + !$OMP ENDDO + !$OMP DO PRIVATE(p,c,NaN) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) + do mySource = 1_pInt, phase_Nsources(p) + NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) + enddo + if (NaN) then ! NaN occured in any dotState + if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + else ! if broken local... + crystallite_todo(g,i,e) = .false. ! ... skip this one next time + endif + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- STATE UPDATE (EULER INTEGRATION) --- + + !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,c) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + mySizePlasticDotState = plasticState(p)%sizeDotState + plasticStateResiduum(1:mySizePlasticDotState,g,i,e) = & + - 0.5_pReal & + * plasticState(p)%dotstate(1:mySizePlasticDotState,c) & + * crystallite_subdt(g,i,e) ! contribution to absolute residuum in state + plasticState(p)%state (1:mySizePlasticDotState,c) = & + plasticState(p)%state (1:mySizePlasticDotState,c) & + + plasticState(p)%dotstate(1:mySizePlasticDotState,c) & + * crystallite_subdt(g,i,e) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e) = & + - 0.5_pReal & + * sourceState(p)%p(mySource)%dotstate(1:mySizeSourceDotState,c) & + * crystallite_subdt(g,i,e) ! contribution to absolute residuum in state + sourceState(p)%p(mySource)%state (1:mySizeSourceDotState,c) = & + sourceState(p)%p(mySource)%state (1:mySizeSourceDotState,c) & + + sourceState(p)%p(mySource)%dotstate(1:mySizeSourceDotState,c) & + * crystallite_subdt(g,i,e) + enddo + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- STATE JUMP --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- UPDATE DEPENDENT STATES (EULER INTEGRATION) --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + !***dirty way to pass orientations to constitutive_microstructure + call constitutive_microstructure(crystallite_orientation, & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fp(1:3,1:3,g,i,e), & + g, i, e) ! update dependent state variables to be consistent with basic states + enddo; enddo; enddo + !$OMP ENDDO + !$OMP END PARALLEL + endif integrationMode + + + ! --- STRESS INTEGRATION (EULER INTEGRATION) --- + + !$OMP PARALLEL DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e) + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP END PARALLEL DO + + + if (numerics_integrationMode == 1_pInt) then + + !$OMP PARALLEL + ! --- DOT STATE (HEUN METHOD) --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & + crystallite_Fe, & + crystallite_Fp, & + crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) + enddo; enddo; enddo + !$OMP ENDDO + !$OMP DO PRIVATE(p,c,NaN) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) + do mySource = 1_pInt, phase_Nsources(p) + NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) + enddo + if (NaN) then ! NaN occured in any dotState + if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + else ! if broken local... + crystallite_todo(g,i,e) = .false. ! ... skip this one next time + endif + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- ERROR ESTIMATE FOR STATE (HEUN METHOD) --- + + !$OMP SINGLE + relPlasticStateResiduum = 0.0_pReal + relSourceStateResiduum = 0.0_pReal + !$OMP END SINGLE + + !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,converged,p,c,s) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + ! --- contribution of heun step to absolute residui --- + mySizePlasticDotState = plasticState(p)%sizeDotState + plasticStateResiduum(1:mySizePlasticDotState,g,i,e) = & + plasticStateResiduum(1:mySizePlasticDotState,g,i,e) & + + 0.5_pReal * plasticState(p)%dotState(:,c) & + * crystallite_subdt(g,i,e) ! contribution to absolute residuum in state + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e) = & + sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e) & + + 0.5_pReal * sourceState(p)%p(mySource)%dotState(:,c) & + * crystallite_subdt(g,i,e) ! contribution to absolute residuum in state + enddo + !$OMP FLUSH(plasticStateResiduum) + !$OMP FLUSH(sourceStateResiduum) + + ! --- relative residui --- + forall (s = 1_pInt:mySizePlasticDotState, abs(plasticState(p)%dotState(s,c)) > 0.0_pReal) & + relPlasticStateResiduum(s,g,i,e) = & + plasticStateResiduum(s,g,i,e) / plasticState(p)%dotState(s,c) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + forall (s = 1_pInt:mySizeSourceDotState,abs(sourceState(p)%p(mySource)%dotState(s,c)) > 0.0_pReal) & + relSourceStateResiduum(s,mySource,g,i,e) = & + sourceStateResiduum(s,mySource,g,i,e) / sourceState(p)%p(mySource)%dotState(s,c) + enddo + !$OMP FLUSH(relPlasticStateResiduum) + !$OMP FLUSH(relSourceStateResiduum) + +#ifndef _OPENMP + + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i .and. g == debug_g)& + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i8,1x,i2,1x,i3,/)') '<< CRYST >> updateState at el ip g ',e,i,g + write(6,'(a,/,(12x,12(f12.1,1x)),/)') '<< CRYST >> absolute residuum tolerance', & + plasticStateResiduum(1:mySizePlasticDotState,g,i,e) / plasticState(p)%aTolState(1:mySizePlasticDotState) + write(6,'(a,/,(12x,12(f12.1,1x)),/)') '<< CRYST >> relative residuum tolerance', & + relPlasticStateResiduum(1:mySizePlasticDotState,g,i,e) / rTol_crystalliteState + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> dotState', plasticState(p)%dotState(1:mySizePlasticDotState,c) & + - 2.0_pReal * plasticStateResiduum(1:mySizePlasticDotState,g,i,e) / crystallite_subdt(g,i,e) ! calculate former dotstate from higher order solution and state residuum + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state', plasticState(p)%state(1:mySizePlasticDotState,c) + endif +#endif + + ! --- converged ? --- + converged = all(abs(relPlasticStateResiduum(1:mySizePlasticDotState,g,i,e)) < & + rTol_crystalliteState .or. & + abs(plasticStateResiduum(1:mySizePlasticDotState,g,i,e)) < & + plasticState(p)%aTolState(1:mySizePlasticDotState)) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + converged = converged .and. & + all(abs(relSourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e)) < & + rTol_crystalliteState .or. & + abs(sourceStateResiduum(1:mySizeSourceDotState,mySource,g,i,e)) < & + sourceState(p)%p(mySource)%aTolState(1:mySizeSourceDotState)) + enddo + if (converged) then + crystallite_converged(g,i,e) = .true. ! ... converged per definitionem + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionState) + debug_StateLoopDistribution(2,numerics_integrationMode) = & + debug_StateLoopDistribution(2,numerics_integrationMode) + 1_pInt + !$OMP END CRITICAL (distributionState) + endif + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + !$OMP END PARALLEL + + elseif (numerics_integrationMode > 1) then ! stiffness calculation + + !$OMP PARALLEL DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + crystallite_converged(g,i,e) = .true. ! ... converged per definitionem + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionState) + debug_StateLoopDistribution(2,numerics_integrationMode) = & + debug_StateLoopDistribution(2,numerics_integrationMode) + 1_pInt + !$OMP END CRITICAL (distributionState) + endif + endif + enddo; enddo; enddo + !$OMP END PARALLEL DO + + endif + + + + ! --- NONLOCAL CONVERGENCE CHECK --- + + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i8,a,i2,/)') '<< CRYST >> ', count(crystallite_converged(:,:,:)), ' grains converged' + if ((.not. singleRun) .and. any(.not. crystallite_converged .and. .not. crystallite_localPlasticity)) & ! any non-local not yet converged (or broken)... + crystallite_converged = crystallite_converged .and. crystallite_localPlasticity ! ...restart all non-local as not converged + + +end subroutine crystallite_integrateStateAdaptiveEuler + + +!-------------------------------------------------------------------------------------------------- +!> @brief integrate stress, and state with 1st order explicit Euler method +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_integrateStateEuler() + use prec, only: & + prec_isNaN + use debug, only: & + debug_level, & + debug_crystallite, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_g, & + debug_StateLoopDistribution + use numerics, only: & + numerics_integrationMode, & + numerics_timeSyncing + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP + use mesh, only: & + mesh_element, & + mesh_NcpElems + use material, only: & + plasticState, & + sourceState, & + phaseAt, phasememberAt, & + phase_Nsources, & + homogenization_Ngrains + use constitutive, only: & + constitutive_collectDotState, & + constitutive_microstructure + + implicit none + + integer(pInt) :: & + e, & ! element index in element loop + i, & ! integration point index in ip loop + g, & ! grain index in grain loop + p, & ! phase loop + c, & + mySource, & + mySizePlasticDotState, & + mySizeSourceDotState + integer(pInt), dimension(2) :: & + eIter ! bounds for element iteration + integer(pInt), dimension(2,mesh_NcpElems) :: & + iIter, & ! bounds for ip iteration + gIter ! bounds for grain iteration + logical :: & + NaN, & + singleRun ! flag indicating computation for single (g,i,e) triple + + +eIter = FEsolving_execElem(1:2) + do e = eIter(1),eIter(2) + iIter(1:2,e) = FEsolving_execIP(1:2,e) + gIter(1:2,e) = [ 1_pInt,homogenization_Ngrains(mesh_element(3,e))] + enddo + + singleRun = (eIter(1) == eIter(2) .and. iIter(1,eIter(1)) == iIter(2,eIter(2))) + + if (numerics_integrationMode == 1_pInt) then + !$OMP PARALLEL + + ! --- DOT STATE --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) & + call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & + crystallite_Fe, & + crystallite_Fp, & + crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) + enddo; enddo; enddo + !$OMP ENDDO + !$OMP DO PRIVATE(p,c,NaN) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then + c = phasememberAt(g,i,e) + p = phaseAt(g,i,e) + NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) + do mySource = 1_pInt, phase_Nsources(p) + NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) + enddo + if (NaN) then ! NaN occured in any dotState + if (.not. crystallite_localPlasticity(g,i,e) .and. .not. numerics_timeSyncing) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + else ! if broken local... + crystallite_todo(g,i,e) = .false. ! ... skip this one next time + endif + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- UPDATE STATE --- + + !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,c) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + mySizePlasticDotState = plasticState(p)%sizeDotState + plasticState(p)%state( 1:mySizePlasticDotState,c) = & + plasticState(p)%state( 1:mySizePlasticDotState,c) & + + plasticState(p)%dotState(1:mySizePlasticDotState,c) & + * crystallite_subdt(g,i,e) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceState(p)%p(mySource)%state( 1:mySizeSourceDotState,c) = & + sourceState(p)%p(mySource)%state( 1:mySizeSourceDotState,c) & + + sourceState(p)%p(mySource)%dotState(1:mySizeSourceDotState,c) & + * crystallite_subdt(g,i,e) + enddo + +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i .and. g == debug_g) & + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + write(6,'(a,i8,1x,i2,1x,i3,/)') '<< CRYST >> update state at el ip g ',e,i,g + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> dotState', plasticState(p)%dotState(1:mySizePlasticDotState,c) + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state', plasticState(p)%state (1:mySizePlasticDotState,c) + endif +#endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- STATE JUMP --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e) & ! if broken non-local... + .and. .not. numerics_timeSyncing) then + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- UPDATE DEPENDENT STATES --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) & + !***dirty way to pass orientations to constitutive_microstructure + call constitutive_microstructure(crystallite_orientation, & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fp(1:3,1:3,g,i,e), & + g, i, e) ! update dependent state variables to be consistent with basic states + enddo; enddo; enddo + !$OMP ENDDO + !$OMP END PARALLEL + endif + + + !$OMP PARALLEL + ! --- STRESS INTEGRATION --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e) + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e) & ! if broken non-local... + .and. .not. numerics_timeSyncing) then + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + + ! --- SET CONVERGENCE FLAG --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then + crystallite_converged(g,i,e) = .true. ! if still "to do" then converged per definitionem + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionState) + debug_StateLoopDistribution(1,numerics_integrationMode) = & + debug_StateLoopDistribution(1,numerics_integrationMode) + 1_pInt + !$OMP END CRITICAL (distributionState) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP END PARALLEL + + + ! --- CHECK NON-LOCAL CONVERGENCE --- + + if (.not. singleRun) then ! if not requesting Integration of just a single IP + if (any(.not. crystallite_converged .and. .not. crystallite_localPlasticity) & ! any non-local not yet converged (or broken)... + .and. .not. numerics_timeSyncing) & + crystallite_converged = crystallite_converged .and. crystallite_localPlasticity ! ...restart all non-local as not converged + endif + +end subroutine crystallite_integrateStateEuler + + +!-------------------------------------------------------------------------------------------------- +!> @brief integrate stress, state with adaptive 1st order explicit Euler method +!> using Fixed Point Iteration to adapt the stepsize +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_integrateStateFPI() + use prec, only: & + prec_isNaN + use debug, only: & + debug_e, & + debug_i, & + debug_g, & + debug_level,& + debug_crystallite, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_StateLoopDistribution + use numerics, only: & + nState, & + numerics_integrationMode, & + rTol_crystalliteState + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP + use mesh, only: & + mesh_element, & + mesh_NcpElems + use material, only: & + plasticState, & + sourceState, & + phaseAt, phasememberAt, & + phase_Nsources, & + homogenization_Ngrains + use constitutive, only: & + constitutive_collectDotState, & + constitutive_microstructure, & + constitutive_plasticity_maxSizeDotState, & + constitutive_source_maxSizeDotState + + implicit none + + integer(pInt) :: & + NiterationState, & !< number of iterations in state loop + e, & !< element index in element loop + i, & !< integration point index in ip loop + g, & !< grain index in grain loop + p, & + c, & + mySource, & + mySizePlasticDotState, & ! size of dot states + mySizeSourceDotState + integer(pInt), dimension(2) :: & + eIter ! bounds for element iteration + integer(pInt), dimension(2,mesh_NcpElems) :: & + iIter, & ! bounds for ip iteration + gIter ! bounds for grain iteration + real(pReal) :: & + dot_prod12, & + dot_prod22, & + plasticStateDamper, & ! damper for integration of state + sourceStateDamper + real(pReal), dimension(constitutive_plasticity_maxSizeDotState) :: & + plasticStateResiduum, & + tempPlasticState + real(pReal), dimension(constitutive_source_maxSizeDotState, maxval(phase_Nsources)) :: & + sourceStateResiduum, & ! residuum from evolution in micrstructure + tempSourceState + logical :: & + converged, & + NaN, & + singleRun, & ! flag indicating computation for single (g,i,e) triple + doneWithIntegration + + eIter = FEsolving_execElem(1:2) + do e = eIter(1),eIter(2) + iIter(1:2,e) = FEsolving_execIP(1:2,e) + gIter(1:2,e) = [ 1_pInt,homogenization_Ngrains(mesh_element(3,e))] + enddo + + singleRun = (eIter(1) == eIter(2) .and. iIter(1,eIter(1)) == iIter(2,eIter(2))) + +!-------------------------------------------------------------------------------------------------- +! initialize dotState + if (.not. singleRun) then + forall(p = 1_pInt:size(plasticState)) + plasticState(p)%previousDotState = 0.0_pReal + plasticState(p)%previousDotState2 = 0.0_pReal + end forall + do p = 1_pInt, size(sourceState); do mySource = 1_pInt, phase_Nsources(p) + sourceState(p)%p(mySource)%previousDotState = 0.0_pReal + sourceState(p)%p(mySource)%previousDotState2 = 0.0_pReal + enddo; enddo + else + e = eIter(1) + i = iIter(1,e) + do g = gIter(1,e), gIter(2,e) + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + plasticState(p)%previousDotState (:,c) = 0.0_pReal + plasticState(p)%previousDotState2(:,c) = 0.0_pReal + do mySource = 1_pInt, phase_Nsources(p) + sourceState(p)%p(mySource)%previousDotState (:,c) = 0.0_pReal + sourceState(p)%p(mySource)%previousDotState2(:,c) = 0.0_pReal + enddo + enddo + endif + + ! --+>> PREGUESS FOR STATE <<+-- + + ! --- DOT STATES --- + + !$OMP PARALLEL + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) & + call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & + crystallite_Fe, & + crystallite_Fp, & + crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) + enddo; enddo; enddo + + !$OMP ENDDO + !$OMP DO PRIVATE(p,c,NaN) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) + do mySource = 1_pInt, phase_Nsources(p) + NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) + enddo + if (NaN) then ! NaN occured in any dotState + if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken is a non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals done (and broken) + !$OMP END CRITICAL (checkTodo) + else ! broken one was local... + crystallite_todo(g,i,e) = .false. ! ... done (and broken) + endif + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + ! --- UPDATE STATE --- + + !$OMP DO PRIVATE(mySizePlasticDotState,mySizeSourceDotState,p,c) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e)) then + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + mySizePlasticDotState = plasticState(p)%sizeDotState + plasticState(p)%state(1:mySizePlasticDotState,c) = & + plasticState(p)%subState0(1:mySizePlasticDotState,c) & + + plasticState(p)%dotState (1:mySizePlasticDotState,c) & + * crystallite_subdt(g,i,e) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceState(p)%p(mySource)%state(1:mySizeSourceDotState,c) = & + sourceState(p)%p(mySource)%subState0(1:mySizeSourceDotState,c) & + + sourceState(p)%p(mySource)%dotState (1:mySizeSourceDotState,c) & + * crystallite_subdt(g,i,e) + enddo + endif + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP END PARALLEL + + ! --+>> STATE LOOP <<+-- + + NiterationState = 0_pInt + doneWithIntegration = .false. + crystalliteLooping: do while (.not. doneWithIntegration .and. NiterationState < nState) + NiterationState = NiterationState + 1_pInt + + !$OMP PARALLEL + + ! --- UPDATE DEPENDENT STATES --- + + !$OMP DO PRIVATE(p,c) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) & + !***dirty way to pass orientations to constitutive_micrsotructure + call constitutive_microstructure(crystallite_orientation, & + crystallite_Fe(1:3,1:3,g,i,e), & + crystallite_Fp(1:3,1:3,g,i,e), & + g, i, e) ! update dependent state variables to be consistent with basic states + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + plasticState(p)%previousDotState2(:,c) = plasticState(p)%previousDotState(:,c) + plasticState(p)%previousDotState (:,c) = plasticState(p)%dotState(:,c) + do mySource = 1_pInt, phase_Nsources(p) + sourceState(p)%p(mySource)%previousDotState2(:,c) = sourceState(p)%p(mySource)%previousDotState(:,c) + sourceState(p)%p(mySource)%previousDotState (:,c) = sourceState(p)%p(mySource)%dotState(:,c) + enddo + enddo; enddo; enddo + !$OMP ENDDO + + ! --- STRESS INTEGRATION --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then + crystallite_todo(g,i,e) = crystallite_integrateStress(g,i,e) + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e) .and. .not. crystallite_localPlasticity(g,i,e)) then ! broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ... then all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP SINGLE + !$OMP CRITICAL (write2out) + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i8,a)') '<< CRYST >> ', count(crystallite_todo(:,:,:)),' grains todo after stress integration' + !$OMP END CRITICAL (write2out) + !$OMP END SINGLE + + + ! --- DOT STATE --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) & + call constitutive_collectDotState(crystallite_Tstar_v(1:6,g,i,e), & + crystallite_Fe, & + crystallite_Fp, & + crystallite_subdt(g,i,e), crystallite_subFrac, g,i,e) + enddo; enddo; enddo + !$OMP ENDDO + + !$OMP DO PRIVATE(p,c) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + NaN = any(prec_isNaN(plasticState(p)%dotState(:,c))) + do mySource = 1_pInt, phase_Nsources(p) + NaN = NaN .or. any(prec_isNaN(sourceState(p)%p(mySource)%dotState(:,c))) + enddo + if (NaN) then ! NaN occured in any dotState + crystallite_todo(g,i,e) = .false. ! ... skip me next time + if (.not. crystallite_localPlasticity(g,i,e)) then ! if me is non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + + endif + + enddo; enddo; enddo + !$OMP ENDDO + + ! --- UPDATE STATE --- + + !$OMP DO PRIVATE(dot_prod12,dot_prod22, & + !$OMP& mySizePlasticDotState,mySizeSourceDotState, & + !$OMP& plasticStateResiduum,sourceStateResiduum, & + !$OMP& plasticStatedamper,sourceStateDamper, & + !$OMP& tempPlasticState,tempSourceState,converged,p,c) + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then + + p = phaseAt(g,i,e) + c = phasememberAt(g,i,e) + dot_prod12 = dot_product( plasticState(p)%dotState (:,c) & + - plasticState(p)%previousDotState (:,c), & + plasticState(p)%previousDotState (:,c) & + - plasticState(p)%previousDotState2(:,c)) + dot_prod22 = dot_product( plasticState(p)%previousDotState (:,c) & + - plasticState(p)%previousDotState2(:,c), & + plasticState(p)%previousDotState (:,c) & + - plasticState(p)%previousDotState2(:,c)) + if ( dot_prod22 > 0.0_pReal & + .and. ( dot_prod12 < 0.0_pReal & + .or. dot_product(plasticState(p)%dotState(:,c), & + plasticState(p)%previousDotState(:,c)) < 0.0_pReal) ) then + plasticStateDamper = 0.75_pReal + 0.25_pReal * tanh(2.0_pReal + 4.0_pReal * dot_prod12 / dot_prod22) + else + plasticStateDamper = 1.0_pReal + endif + ! --- get residui --- + + mySizePlasticDotState = plasticState(p)%sizeDotState + plasticStateResiduum(1:mySizePlasticDotState) = & + plasticState(p)%state(1:mySizePlasticDotState,c) & + - plasticState(p)%subState0(1:mySizePlasticDotState,c) & + - ( plasticState(p)%dotState(1:mySizePlasticDotState,c) * plasticStateDamper & + + plasticState(p)%previousDotState(1:mySizePlasticDotState,c) & + * (1.0_pReal - plasticStateDamper)) * crystallite_subdt(g,i,e) + + ! --- correct state with residuum --- + tempPlasticState(1:mySizePlasticDotState) = & + plasticState(p)%state(1:mySizePlasticDotState,c) & + - plasticStateResiduum(1:mySizePlasticDotState) ! need to copy to local variable, since we cant flush a pointer in openmp + + ! --- store corrected dotState --- (cannot do this before state update, because not sure how to flush pointers in openmp) + + plasticState(p)%dotState(:,c) = plasticState(p)%dotState(:,c) * plasticStateDamper & + + plasticState(p)%previousDotState(:,c) & + * (1.0_pReal - plasticStateDamper) + + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + dot_prod12 = dot_product( sourceState(p)%p(mySource)%dotState (:,c) & + - sourceState(p)%p(mySource)%previousDotState (:,c), & + sourceState(p)%p(mySource)%previousDotState (:,c) & + - sourceState(p)%p(mySource)%previousDotState2(:,c)) + dot_prod22 = dot_product( sourceState(p)%p(mySource)%previousDotState (:,c) & + - sourceState(p)%p(mySource)%previousDotState2(:,c), & + sourceState(p)%p(mySource)%previousDotState (:,c) & + - sourceState(p)%p(mySource)%previousDotState2(:,c)) + + if ( dot_prod22 > 0.0_pReal & + .and. ( dot_prod12 < 0.0_pReal & + .or. dot_product(sourceState(p)%p(mySource)%dotState(:,c), & + sourceState(p)%p(mySource)%previousDotState(:,c)) < 0.0_pReal) ) then + sourceStateDamper = 0.75_pReal + 0.25_pReal * tanh(2.0_pReal + 4.0_pReal * dot_prod12 / dot_prod22) + else + sourceStateDamper = 1.0_pReal + endif + ! --- get residui --- + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceStateResiduum(1:mySizeSourceDotState,mySource) = & + sourceState(p)%p(mySource)%state(1:mySizeSourceDotState,c) & + - sourceState(p)%p(mySource)%subState0(1:mySizeSourceDotState,c) & + - ( sourceState(p)%p(mySource)%dotState(1:mySizeSourceDotState,c) * sourceStateDamper & + + sourceState(p)%p(mySource)%previousDotState(1:mySizeSourceDotState,c) & + * (1.0_pReal - sourceStateDamper)) * crystallite_subdt(g,i,e) + + ! --- correct state with residuum --- + tempSourceState(1:mySizeSourceDotState,mySource) = & + sourceState(p)%p(mySource)%state(1:mySizeSourceDotState,c) & + - sourceStateResiduum(1:mySizeSourceDotState,mySource) ! need to copy to local variable, since we cant flush a pointer in openmp + + ! --- store corrected dotState --- (cannot do this before state update, because not sure how to flush pointers in openmp) + sourceState(p)%p(mySource)%dotState(:,c) = & + sourceState(p)%p(mySource)%dotState(:,c) * sourceStateDamper & + + sourceState(p)%p(mySource)%previousDotState(:,c) & + * (1.0_pReal - sourceStateDamper) + enddo + +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i .and. g == debug_g) & + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i8,1x,i2,1x,i3,/)') '<< CRYST >> update state at el ip g ',e,i,g + write(6,'(a,f6.1,/)') '<< CRYST >> plasticstatedamper ',plasticStatedamper + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> plastic state residuum',plasticStateResiduum(1:mySizePlasticDotState) + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state',tempPlasticState(1:mySizePlasticDotState) + endif +#endif + + ! --- converged ? --- + converged = all( abs(plasticStateResiduum(1:mySizePlasticDotState)) < & + plasticState(p)%aTolState(1:mySizePlasticDotState) & + .or. abs(plasticStateResiduum(1:mySizePlasticDotState)) < & + rTol_crystalliteState * abs(tempPlasticState(1:mySizePlasticDotState))) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + converged = converged .and. & + all( abs(sourceStateResiduum(1:mySizeSourceDotState,mySource)) < & + sourceState(p)%p(mySource)%aTolState(1:mySizeSourceDotState) & + .or. abs(sourceStateResiduum(1:mySizeSourceDotState,mySource)) < & + rTol_crystalliteState * abs(tempSourceState(1:mySizeSourceDotState,mySource))) + enddo + if (converged) then + crystallite_converged(g,i,e) = .true. ! ... converged per definition + + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionState) + debug_StateLoopDistribution(NiterationState,numerics_integrationMode) = & + debug_StateLoopDistribution(NiterationState,numerics_integrationMode) + 1_pInt + !$OMP END CRITICAL (distributionState) + endif + endif + plasticState(p)%state(1:mySizePlasticDotState,c) = & + tempPlasticState(1:mySizePlasticDotState) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDotState = sourceState(p)%p(mySource)%sizeDotState + sourceState(p)%p(mySource)%state(1:mySizeSourceDotState,c) = & + tempSourceState(1:mySizeSourceDotState,mySource) + enddo + endif + enddo; enddo; enddo + !$OMP ENDDO + ! --- STATE JUMP --- + + !$OMP DO + do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + !$OMP FLUSH(crystallite_todo) + if (crystallite_todo(g,i,e) .and. crystallite_converged(g,i,e)) then ! converged and still alive... + crystallite_todo(g,i,e) = crystallite_stateJump(g,i,e) + !$OMP FLUSH(crystallite_todo) + if (.not. crystallite_todo(g,i,e)) then ! if state jump fails, then convergence is broken + crystallite_converged(g,i,e) = .false. + if (.not. crystallite_localPlasticity(g,i,e)) then ! if broken non-local... + !$OMP CRITICAL (checkTodo) + crystallite_todo = crystallite_todo .and. crystallite_localPlasticity ! ...all non-locals skipped + !$OMP END CRITICAL (checkTodo) + endif + endif + endif + enddo; enddo; enddo + !$OMP ENDDO + !$OMP END PARALLEL + + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) & + write(6,'(a,i8,a,i2,/)') '<< CRYST >> ', count(crystallite_converged(:,:,:)), & + ' grains converged after state integration #', NiterationState + + + ! --- NON-LOCAL CONVERGENCE CHECK --- + + if (.not. singleRun) then ! if not requesting Integration of just a single IP + if (any(.not. crystallite_converged .and. .not. crystallite_localPlasticity)) & ! any non-local not yet converged (or broken)... + crystallite_converged = crystallite_converged .and. crystallite_localPlasticity ! ...restart all non-local as not converged + endif + + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt) then + write(6,'(a,i8,a)') '<< CRYST >> ', count(crystallite_converged(:,:,:)), & + ' grains converged after non-local check' + write(6,'(a,i8,a,i2,/)') '<< CRYST >> ', count(crystallite_todo(:,:,:)), & + ' grains todo after state integration #', NiterationState + endif + ! --- CHECK IF DONE WITH INTEGRATION --- + + doneWithIntegration = .true. + elemLoop: do e = eIter(1),eIter(2) + do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains + if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) then + doneWithIntegration = .false. + exit elemLoop + endif + enddo; enddo + enddo elemLoop + + enddo crystalliteLooping +end subroutine crystallite_integrateStateFPI + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates a jump in the state according to the current state and the current stress +!> returns true, if state jump was successfull or not needed. false indicates NaN in delta state +!-------------------------------------------------------------------------------------------------- +logical function crystallite_stateJump(ipc,ip,el) + use prec, only: & + prec_isNaN + use debug, only: & + debug_level, & + debug_crystallite, & + debug_levelExtensive, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_g + use material, only: & + plasticState, & + sourceState, & + phase_Nsources, & + phaseAt, phasememberAt + use constitutive, only: & + constitutive_collectDeltaState + + implicit none + integer(pInt), intent(in):: & + el, & ! element index + ip, & ! integration point index + ipc ! grain index + + integer(pInt) :: & + c, & + p, & + mySource, & + mySizePlasticDeltaState, & + mySizeSourceDeltaState + + c= phasememberAt(ipc,ip,el) + p = phaseAt(ipc,ip,el) + call constitutive_collectDeltaState(crystallite_Tstar_v(1:6,ipc,ip,el), crystallite_Fe(1:3,1:3,ipc,ip,el), ipc,ip,el) + mySizePlasticDeltaState = plasticState(p)%sizeDeltaState + if( any(prec_isNaN(plasticState(p)%deltaState(:,c)))) then ! NaN occured in deltaState + crystallite_stateJump = .false. + return + endif + plasticState(p)%state(1:mySizePlasticDeltaState,c) = plasticState(p)%state(1:mySizePlasticDeltaState,c) + & + plasticState(p)%deltaState(1:mySizePlasticDeltaState,c) + do mySource = 1_pInt, phase_Nsources(p) + mySizeSourceDeltaState = sourceState(p)%p(mySource)%sizeDeltaState + if( any(prec_isNaN(sourceState(p)%p(mySource)%deltaState(:,c)))) then ! NaN occured in deltaState + crystallite_stateJump = .false. + return + endif + sourceState(p)%p(mySource)%state(1:mySizeSourceDeltaState,c) = & + sourceState(p)%p(mySource)%state(1:mySizeSourceDeltaState,c) + & + sourceState(p)%p(mySource)%deltaState(1:mySizeSourceDeltaState,c) + enddo + +#ifndef _OPENMP + if (any(plasticState(p)%deltaState(1:mySizePlasticDeltaState,c) /= 0.0_pReal) & + .and. iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i8,1x,i2,1x,i3, /)') '<< CRYST >> update state at el ip ipc ',el,ip,ipc + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> deltaState', plasticState(p)%deltaState(1:mySizePlasticDeltaState,c) + write(6,'(a,/,(12x,12(e12.5,1x)),/)') '<< CRYST >> new state', plasticState(p)%state (1:mySizePlasticDeltaState,c) + endif +#endif + + crystallite_stateJump = .true. + +end function crystallite_stateJump + + +!-------------------------------------------------------------------------------------------------- +!> @brief Map 2nd order tensor to reference config +!-------------------------------------------------------------------------------------------------- +function crystallite_push33ToRef(ipc,ip,el, tensor33) + use math, only: & + math_mul33x33, & + math_inv33, & + math_transpose33, & + math_EulerToR + use material, only: & + material_EulerAngles + + implicit none + real(pReal), dimension(3,3) :: crystallite_push33ToRef + real(pReal), dimension(3,3), intent(in) :: tensor33 + real(pReal), dimension(3,3) :: T + integer(pInt), intent(in):: & + el, & ! element index + ip, & ! integration point index + ipc ! grain index + + T = math_mul33x33(math_EulerToR(material_EulerAngles(1:3,ipc,ip,el)), & + math_transpose33(math_inv33(crystallite_subF(1:3,1:3,ipc,ip,el)))) + crystallite_push33ToRef = math_mul33x33(math_transpose33(T),math_mul33x33(tensor33,T)) + +end function crystallite_push33ToRef + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculation of stress (P) with time integration based on a residuum in Lp and +!> intermediate acceleration of the Newton-Raphson correction +!-------------------------------------------------------------------------------------------------- +logical function crystallite_integrateStress(& + ipc,& ! grain number + ip,& ! integration point number + el,& ! element number + timeFraction & + ) + use prec, only: pLongInt, & + tol_math_check, & + prec_isNaN + use numerics, only: nStress, & + aTol_crystalliteStress, & + rTol_crystalliteStress, & + iJacoLpresiduum, & + numerics_integrationMode + use debug, only: debug_level, & + debug_crystallite, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_g, & + debug_cumLpCalls, & + debug_cumLpTicks, & + debug_StressLoopLpDistribution, & + debug_StressLoopLiDistribution + use constitutive, only: constitutive_LpAndItsTangent, & + constitutive_LiAndItsTangent, & + constitutive_TandItsTangent + use math, only: math_mul33x33, & + math_mul33xx33, & + math_mul3333xx3333, & + math_mul66x6, & + math_mul99x99, & + math_transpose33, & + math_inv33, & + math_invert, & + math_det33, & + math_I3, & + math_identity2nd, & + math_Mandel66to3333, & + math_Mandel6to33, & + math_Mandel33to6, & + math_Plain3333to99, & + math_Plain33to9, & + math_Plain9to33, & + math_Plain99to3333 + use mesh, only: mesh_element + + implicit none + integer(pInt), intent(in):: el, & ! element index + ip, & ! integration point index + ipc ! grain index + real(pReal), optional, intent(in) :: timeFraction ! fraction of timestep + + !*** local variables ***! + real(pReal), dimension(3,3):: Fg_new, & ! deformation gradient at end of timestep + Fp_current, & ! plastic deformation gradient at start of timestep + Fi_current, & ! intermediate deformation gradient at start of timestep + Fp_new, & ! plastic deformation gradient at end of timestep + Fe_new, & ! elastic deformation gradient at end of timestep + invFp_new, & ! inverse of Fp_new + Fi_new, & ! gradient of intermediate deformation stages + invFi_new, & + invFp_current, & ! inverse of Fp_current + invFi_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 + 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 + Tstar, & ! 2nd Piola-Kirchhoff Stress in plastic (lattice) configuration + A, & + B, & + Fe, & ! elastic deformation gradient + temp_33 + real(pReal), dimension(6):: Tstar_v ! 2nd Piola-Kirchhoff Stress in Mandel-Notation + real(pReal), dimension(9):: work ! needed for matrix inversion by LAPACK + integer(pInt), dimension(9) :: ipiv ! needed for matrix inversion by LAPACK + real(pReal), dimension(9,9) :: dRLp_dLp, & ! partial derivative of residuum (Jacobian for NEwton-Raphson scheme) + dRLp_dLp2, & ! working copy of dRdLp + dRLi_dLi ! partial derivative of residuumI (Jacobian for NEwton-Raphson scheme) + real(pReal), dimension(3,3,3,3):: dT_dFe3333, & ! partial derivative of 2nd Piola-Kirchhoff stress + dT_dFi3333, & + dFe_dLp3333, & ! partial derivative of elastic deformation gradient + dFe_dLi3333, & + dFi_dLi3333, & + dLp_dFi3333, & + dLi_dFi3333, & + dLp_dT3333, & + dLi_dT3333 + real(pReal) detInvFi, & ! determinant of InvFi + steplengthLp0, & + steplengthLp, & + steplengthLi0, & + steplengthLi, & + dt, & ! time increment + aTolLp, & + aTolLi + integer(pInt) 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 + integer(pLongInt) tick, & + tock, & + tickrate, & + maxticks + + external :: & +#if(FLOAT==8) + dgesv +#elif(FLOAT==4) + sgesv +#endif + + !* be pessimistic + crystallite_integrateStress = .false. +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i8,1x,i2,1x,i3)') '<< CRYST >> integrateStress at el ip ipc ',el,ip,ipc + endif +#endif + + + !* only integrate over fraction of timestep? + + if (present(timeFraction)) then + dt = crystallite_subdt(ipc,ip,el) * timeFraction + Fg_new = 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) + Fg_new = crystallite_subF(1:3,1:3,ipc,ip,el) + endif + + + !* feed local variables + + Fp_current = crystallite_subFp0(1:3,1:3,ipc,ip,el) ! "Fp_current" is only used as temp var here... + Lpguess = crystallite_Lp (1:3,1:3,ipc,ip,el) ! ... and take it as first guess + Fi_current = crystallite_subFi0(1:3,1:3,ipc,ip,el) ! intermediate configuration, assume decomposition as F = Fe Fi Fp + Liguess = crystallite_Li (1:3,1:3,ipc,ip,el) ! ... and take it as first guess + Liguess_old = Liguess + + + !* inversion of Fp_current... + + invFp_current = math_inv33(Fp_current) + if (all(abs(invFp_current) <= tiny(0.0_pReal))) then ! math_inv33 returns zero when failed, avoid floating point comparison +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3)') '<< CRYST >> integrateStress failed on inversion of Fp_current at el (elFE) ip g ',& + el,'(',mesh_element(1,el),')',ip,ipc + if (iand(debug_level(debug_crystallite), debug_levelExtensive) > 0_pInt) & + write(6,'(/,a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Fp_current',math_transpose33(Fp_current(1:3,1:3)) + endif +#endif + return + endif + A = math_mul33x33(Fg_new,invFp_current) ! intermediate tensor needed later to calculate dFe_dLp + + !* inversion of Fi_current... + + invFi_current = math_inv33(Fi_current) + if (all(abs(invFi_current) <= tiny(0.0_pReal))) then ! math_inv33 returns zero when failed, avoid floating point comparison +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3)') '<< CRYST >> integrateStress failed on inversion of Fi_current at el (elFE) ip ipc ',& + el,'(',mesh_element(1,el),')',ip,ipc + if (iand(debug_level(debug_crystallite), debug_levelExtensive) > 0_pInt) & + write(6,'(/,a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Fp_current',math_transpose33(Fi_current(1:3,1:3)) + endif +#endif + return + endif + + !* start LpLoop with normal step length + + NiterationStressLi = 0_pInt + jacoCounterLi = 0_pInt + steplengthLi0 = 1.0_pReal + steplengthLi = steplengthLi0 + residuumLi_old = 0.0_pReal + + LiLoop: do + NiterationStressLi = NiterationStressLi + 1_pInt + IloopsExeced: if (NiterationStressLi > nStress) then +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) & + write(6,'(a,i3,a,i8,1x,a,i8,a,1x,i2,1x,i3,/)') '<< CRYST >> integrateStress reached inelastic loop limit',nStress, & + ' at el (elFE) ip ipc ', el,mesh_element(1,el),ip,ipc +#endif + return + endif IloopsExeced + + invFi_new = math_mul33x33(invFi_current,math_I3 - dt*Liguess) + Fi_new = math_inv33(invFi_new) + detInvFi = math_det33(invFi_new) + + NiterationStressLp = 0_pInt + jacoCounterLp = 0_pInt + steplengthLp0 = 1.0_pReal + steplengthLp = steplengthLp0 + residuumLp_old = 0.0_pReal + Lpguess_old = Lpguess + + LpLoop: do ! inner stress integration loop for consistency with Fi + NiterationStressLp = NiterationStressLp + 1_pInt + loopsExeced: if (NiterationStressLp > nStress) then +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) & + write(6,'(a,i3,a,i8,1x,a,i8,a,1x,i2,1x,i3,/)') '<< CRYST >> integrateStress reached loop limit',nStress, & + ' at el (elFE) ip ipc ', el,mesh_element(1,el),ip,ipc +#endif + return + endif loopsExeced + + !* calculate (elastic) 2nd Piola--Kirchhoff stress tensor and its tangent from constitutive law + + B = math_I3 - dt*Lpguess + Fe = math_mul33x33(math_mul33x33(A,B), invFi_new) ! current elastic deformation tensor + call constitutive_TandItsTangent(Tstar, dT_dFe3333, dT_dFi3333, Fe, Fi_new, ipc, ip, el) ! call constitutive law to calculate 2nd Piola-Kirchhoff stress and its derivative in unloaded configuration + Tstar_v = math_Mandel33to6(Tstar) + + !* calculate plastic velocity gradient and its tangent from constitutive law + + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + call system_clock(count=tick,count_rate=tickrate,count_max=maxticks) + endif + + call constitutive_LpAndItsTangent(Lp_constitutive, dLp_dT3333, dLp_dFi3333, & + Tstar_v, Fi_new, ipc, ip, el) + + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + call system_clock(count=tock,count_rate=tickrate,count_max=maxticks) + !$OMP CRITICAL (debugTimingLpTangent) + debug_cumLpCalls = debug_cumLpCalls + 1_pInt + debug_cumLpTicks = debug_cumLpTicks + tock-tick + !$OMP FLUSH (debug_cumLpTicks) + if (tock < tick) debug_cumLpTicks = debug_cumLpTicks + maxticks + !$OMP END CRITICAL (debugTimingLpTangent) + endif + +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i3,/)') '<< CRYST >> stress iteration ', NiterationStressLp + write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Lp_constitutive', math_transpose33(Lp_constitutive) + write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Lpguess', math_transpose33(Lpguess) + endif +#endif + + + !* update current residuum and check for convergence of loop + + aTolLp = max(rTol_crystalliteStress * max(norm2(Lpguess),norm2(Lp_constitutive)), & ! absolute tolerance from largest acceptable relative error + aTol_crystalliteStress) ! minimum lower cutoff + residuumLp = Lpguess - Lp_constitutive + + if (any(prec_isNaN(residuumLp))) then ! NaN in residuum... +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) & + write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3,a,i3,a)') '<< CRYST >> integrateStress encountered NaN at el (elFE) ip ipc ', & + el,mesh_element(1,el),ip,ipc, & + ' ; iteration ', NiterationStressLp,& + ' >> returning..!' +#endif + return ! ...me = .false. to inform integrator about problem + elseif (norm2(residuumLp) < aTolLp) then ! converged if below absolute tolerance + exit LpLoop ! ...leave iteration loop + elseif ( NiterationStressLp == 1_pInt & + .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 = steplengthLp0 ! ...proceed with normal step length (calculate new search direction) + else ! not converged and residuum not improved... + steplengthLp = 0.5_pReal * steplengthLp ! ...try with smaller step length in same direction + Lpguess = Lpguess_old + steplengthLp * deltaLp + cycle LpLoop + endif + + + !* calculate Jacobian for correction term + + if (mod(jacoCounterLp, iJacoLpresiduum) == 0_pInt) then + dFe_dLp3333 = 0.0_pReal + forall(o=1_pInt:3_pInt,p=1_pInt:3_pInt) & + dFe_dLp3333(o,1:3,p,1:3) = A(o,p)*math_transpose33(invFi_new) ! dFe_dLp(i,j,k,l) = -dt * A(i,k) invFi(l,j) + dFe_dLp3333 = - dt * dFe_dLp3333 + dRLp_dLp = math_identity2nd(9_pInt) & + - math_Plain3333to99(math_mul3333xx3333(math_mul3333xx3333(dLp_dT3333,dT_dFe3333),dFe_dLp3333)) + dRLp_dLp2 = dRLp_dLp ! will be overwritten in first call to LAPACK routine + work = math_plain33to9(residuumLp) +#if(FLOAT==8) + call dgesv(9,1,dRLp_dLp2,9,ipiv,work,9,ierr) ! solve dRLp/dLp * delta Lp = -res for delta Lp +#elif(FLOAT==4) + call sgesv(9,1,dRLp_dLp2,9,ipiv,work,9,ierr) ! solve dRLp/dLp * delta Lp = -res for delta Lp +#endif + if (ierr /= 0_pInt) then +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3,a,i3)') '<< CRYST >> integrateStress failed on dR/dLp inversion at el ip ipc ', & + el,mesh_element(1,el),ip,ipc + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g)& + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + write(6,*) + write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dR_dLp',transpose(dRLp_dLp) + write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dFe_dLp',transpose(math_Plain3333to99(dFe_dLp3333)) + write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dT_dFe_constitutive',transpose(math_Plain3333to99(dT_dFe3333)) + write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dLp_dT_constitutive',transpose(math_Plain3333to99(dLp_dT3333)) + write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> A',math_transpose33(A) + write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> B',math_transpose33(B) + write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Lp_constitutive',math_transpose33(Lp_constitutive) + write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Lpguess',math_transpose33(Lpguess) + endif + endif +#endif + return + endif + deltaLp = - math_plain9to33(work) + endif + jacoCounterLp = jacoCounterLp + 1_pInt ! increase counter for jaco update + + Lpguess = Lpguess + steplengthLp * deltaLp + + enddo LpLoop + + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionStress) + debug_StressLoopLpDistribution(NiterationStressLp,numerics_integrationMode) = & + debug_StressLoopLpDistribution(NiterationStressLp,numerics_integrationMode) + 1_pInt + !$OMP END CRITICAL (distributionStress) + endif + + !* calculate intermediate velocity gradient and its tangent from constitutive law + + call constitutive_LiAndItsTangent(Li_constitutive, dLi_dT3333, dLi_dFi3333, & + Tstar_v, Fi_new, ipc, ip, el) + +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Li_constitutive', math_transpose33(Li_constitutive) + write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Liguess', math_transpose33(Liguess) + endif +#endif + !* update current residuum and check for convergence of loop + + aTolLi = max(rTol_crystalliteStress * max(norm2(Liguess),norm2(Li_constitutive)), & ! absolute tolerance from largest acceptable relative error + aTol_crystalliteStress) ! minimum lower cutoff + residuumLi = Liguess - Li_constitutive + if (any(prec_isNaN(residuumLi))) then ! NaN in residuum... + return ! ...me = .false. to inform integrator about problem + elseif (norm2(residuumLi) < aTolLi) then ! converged if below absolute tolerance + exit LiLoop ! ...leave iteration loop + elseif ( NiterationStressLi == 1_pInt & + .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 = steplengthLi0 ! ...proceed with normal step length (calculate new search direction) + else ! not converged and residuum not improved... + steplengthLi = 0.5_pReal * steplengthLi ! ...try with smaller step length in same direction + Liguess = Liguess_old + steplengthLi * deltaLi + cycle LiLoop + endif + + !* calculate Jacobian for correction term + + if (mod(jacoCounterLi, iJacoLpresiduum) == 0_pInt) then + temp_33 = math_mul33x33(math_mul33x33(A,B),invFi_current) + dFe_dLi3333 = 0.0_pReal + dFi_dLi3333 = 0.0_pReal + forall(o=1_pInt:3_pInt,p=1_pInt:3_pInt) + dFe_dLi3333(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_dLi3333(1:3,o,1:3,p) = -dt*math_I3(o,p)*invFi_current + end forall + forall(o=1_pInt:3_pInt,p=1_pInt:3_pInt) & + dFi_dLi3333(1:3,1:3,o,p) = math_mul33x33(math_mul33x33(Fi_new,dFi_dLi3333(1:3,1:3,o,p)),Fi_new) + + dRLi_dLi = math_identity2nd(9_pInt) & + - math_Plain3333to99(math_mul3333xx3333(dLi_dT3333, math_mul3333xx3333(dT_dFe3333, dFe_dLi3333) + & + math_mul3333xx3333(dT_dFi3333, dFi_dLi3333))) & + - math_Plain3333to99(math_mul3333xx3333(dLi_dFi3333, dFi_dLi3333)) + work = math_plain33to9(residuumLi) +#if(FLOAT==8) + call dgesv(9,1,dRLi_dLi,9,ipiv,work,9,ierr) ! solve dRLi/dLp * delta Li = -res for delta Li +#elif(FLOAT==4) + call sgesv(9,1,dRLi_dLi,9,ipiv,work,9,ierr) ! solve dRLi/dLp * delta Li = -res for delta Li +#endif + if (ierr /= 0_pInt) then +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3,a,i3)') '<< CRYST >> integrateStress failed on dR/dLi inversion at el ip ipc ', & + el,mesh_element(1,el),ip,ipc + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g)& + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + write(6,*) + write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dR_dLi',transpose(dRLi_dLi) + write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dFe_dLi',transpose(math_Plain3333to99(dFe_dLi3333)) + write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dT_dFi_constitutive',transpose(math_Plain3333to99(dT_dFi3333)) + write(6,'(a,/,9(12x,9(e15.3,1x)/))') '<< CRYST >> dLi_dT_constitutive',transpose(math_Plain3333to99(dLi_dT3333)) + write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Li_constitutive',math_transpose33(Li_constitutive) + write(6,'(a,/,3(12x,3(e20.7,1x)/))') '<< CRYST >> Liguess',math_transpose33(Liguess) + endif + endif +#endif + return + endif + + deltaLi = - math_plain9to33(work) + endif + jacoCounterLi = jacoCounterLi + 1_pInt ! increase counter for jaco update + + Liguess = Liguess + steplengthLi * deltaLi + enddo LiLoop + + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionStress) + debug_StressLoopLiDistribution(NiterationStressLi,numerics_integrationMode) = & + debug_StressLoopLiDistribution(NiterationStressLi,numerics_integrationMode) + 1_pInt + !$OMP END CRITICAL (distributionStress) + endif + + !* calculate new plastic and elastic deformation gradient + + invFp_new = math_mul33x33(invFp_current,B) + invFp_new = invFp_new / math_det33(invFp_new)**(1.0_pReal/3.0_pReal) ! regularize by det + Fp_new = math_inv33(invFp_new) + if (all(abs(Fp_new)<= tiny(0.0_pReal))) then ! math_inv33 returns zero when failed, avoid floating point comparison +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite), debug_levelBasic) /= 0_pInt) then + write(6,'(a,i8,1x,a,i8,a,1x,i2,1x,i3,a,i3)') '<< CRYST >> integrateStress failed on invFp_new inversion at el ip ipc ',& + el,mesh_element(1,el),ip,ipc, ' ; iteration ', NiterationStressLp + if (iand(debug_level(debug_crystallite), debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) & + write(6,'(/,a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> invFp_new',math_transpose33(invFp_new) + endif +#endif + return + endif + Fe_new = math_mul33x33(math_mul33x33(Fg_new,invFp_new),invFi_new) ! calc resulting Fe + + !* calculate 1st Piola-Kirchhoff stress + + crystallite_P(1:3,1:3,ipc,ip,el) = math_mul33x33(math_mul33x33(Fg_new,invFp_new), & + math_mul33x33(math_Mandel6to33(Tstar_v), & + math_transpose33(invFp_new))) + + !* store local values in global variables + + crystallite_Lp(1:3,1:3,ipc,ip,el) = Lpguess + crystallite_Li(1:3,1:3,ipc,ip,el) = Liguess + crystallite_Tstar_v(1:6,ipc,ip,el) = Tstar_v + crystallite_Fp(1:3,1:3,ipc,ip,el) = Fp_new + crystallite_Fi(1:3,1:3,ipc,ip,el) = Fi_new + crystallite_Fe(1:3,1:3,ipc,ip,el) = Fe_new + crystallite_invFp(1:3,1:3,ipc,ip,el) = invFp_new + crystallite_invFi(1:3,1:3,ipc,ip,el) = invFi_new + + !* set return flag to true + + crystallite_integrateStress = .true. +#ifndef _OPENMP + if (iand(debug_level(debug_crystallite),debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & + .or. .not. iand(debug_level(debug_crystallite), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> P / MPa',math_transpose33(crystallite_P(1:3,1:3,ipc,ip,el))*1.0e-6_pReal + write(6,'(a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Cauchy / MPa', & + math_mul33x33(crystallite_P(1:3,1:3,ipc,ip,el), math_transpose33(Fg_new)) * 1.0e-6_pReal / math_det33(Fg_new) + write(6,'(a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Fe Lp Fe^-1', & + math_transpose33(math_mul33x33(Fe_new, math_mul33x33(crystallite_Lp(1:3,1:3,ipc,ip,el), math_inv33(Fe_new)))) ! transpose to get correct print out order + write(6,'(a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Fp',math_transpose33(crystallite_Fp(1:3,1:3,ipc,ip,el)) + write(6,'(a,/,3(12x,3(f12.7,1x)/))') '<< CRYST >> Fi',math_transpose33(crystallite_Fi(1:3,1:3,ipc,ip,el)) + endif +#endif + +end function crystallite_integrateStress + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates orientations and disorientations (in case of single grain ips) +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_orientations + use math, only: & + math_rotationalPart33, & + math_RtoQ, & + math_qConj + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP + use material, only: & + material_phase, & + homogenization_Ngrains, & + plasticState + use mesh, only: & + mesh_element, & + mesh_ipNeighborhood, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype + use lattice, only: & + lattice_qDisorientation, & + lattice_structure + use plastic_nonlocal, only: & + plastic_nonlocal_updateCompatibility + + + implicit none + integer(pInt) & + c, & !< counter in integration point component loop + i, & !< counter in integration point loop + e, & !< counter in element loop + n, & !< counter in neighbor loop + neighboring_e, & !< neighbor element + neighboring_i, & !< neighbor integration point + myPhase, & ! phase + neighboringPhase + real(pReal), dimension(4) :: & + orientation + + ! --- CALCULATE ORIENTATION AND LATTICE ROTATION --- + + !$OMP PARALLEL DO PRIVATE(orientation) + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + do c = 1_pInt,homogenization_Ngrains(mesh_element(3,e)) +! somehow this subroutine is not threadsafe, so need critical statement here; not clear, what exactly the problem is + !$OMP CRITICAL (polarDecomp) + orientation = math_RtoQ(transpose(math_rotationalPart33(crystallite_Fe(1:3,1:3,c,i,e)))) ! rotational part from polar decomposition as quaternion + !$OMP END CRITICAL (polarDecomp) + crystallite_rotation(1:4,c,i,e) = lattice_qDisorientation(crystallite_orientation0(1:4,c,i,e), & ! active rotation from ori0 + orientation) ! to current orientation (with no symmetry) + crystallite_orientation(1:4,c,i,e) = orientation + enddo; enddo; enddo + !$OMP END PARALLEL DO + + + ! --- UPDATE SOME ADDITIONAL VARIABLES THAT ARE NEEDED FOR NONLOCAL MATERIAL --- + ! --- we use crystallite_orientation from above, so need a separate loop + + !$OMP PARALLEL DO PRIVATE(myPhase,neighboring_e,neighboring_i,neighboringPhase) + do e = FEsolving_execElem(1),FEsolving_execElem(2) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + myPhase = material_phase(1,i,e) ! get my phase (non-local models make no sense with more than one grain per material point) + if (plasticState(myPhase)%nonLocal) then ! if nonlocal model + ! --- calculate disorientation between me and my neighbor --- + + do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) ! loop through my neighbors + neighboring_e = mesh_ipNeighborhood(1,n,i,e) + neighboring_i = mesh_ipNeighborhood(2,n,i,e) + if (neighboring_e > 0 .and. neighboring_i > 0) then ! if neighbor exists + neighboringPhase = material_phase(1,neighboring_i,neighboring_e) ! get my neighbor's phase + if (plasticState(neighboringPhase)%nonLocal) then ! neighbor got also nonlocal plasticity + if (lattice_structure(myPhase) == lattice_structure(neighboringPhase)) then ! if my neighbor has same crystal structure like me + crystallite_disorientation(:,n,1,i,e) = & + lattice_qDisorientation( crystallite_orientation(1:4,1,i,e), & + crystallite_orientation(1:4,1,neighboring_i,neighboring_e), & + lattice_structure(myPhase)) ! calculate disorientation for given symmetry + else ! for neighbor with different phase + crystallite_disorientation(:,n,1,i,e) = [0.0_pReal, 1.0_pReal, 0.0_pReal, 0.0_pReal] ! 180 degree rotation about 100 axis + endif + else ! for neighbor with local plasticity + crystallite_disorientation(:,n,1,i,e) = [-1.0_pReal, 0.0_pReal, 0.0_pReal, 0.0_pReal] ! homomorphic identity + endif + else ! no existing neighbor + crystallite_disorientation(:,n,1,i,e) = [-1.0_pReal, 0.0_pReal, 0.0_pReal, 0.0_pReal] ! homomorphic identity + endif + enddo + + + ! --- calculate compatibility and transmissivity between me and my neighbor --- + + call plastic_nonlocal_updateCompatibility(crystallite_orientation,i,e) + + endif + enddo; enddo + !$OMP END PARALLEL DO + +end subroutine crystallite_orientations + +!-------------------------------------------------------------------------------------------------- +!> @brief return results of particular grain +!-------------------------------------------------------------------------------------------------- +function crystallite_postResults(ipc, ip, el) + use math, only: & + math_qToEuler, & + math_qToEulerAxisAngle, & + math_mul33x33, & + math_transpose33, & + math_det33, & + math_I3, & + inDeg, & + math_Mandel6to33, & + math_qMul, & + math_qConj + use mesh, only: & + mesh_element, & + mesh_ipVolume, & + mesh_maxNipNeighbors, & + mesh_ipNeighborhood, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype + use material, only: & + plasticState, & + sourceState, & + microstructure_crystallite, & + crystallite_Noutput, & + material_phase, & + material_texture, & + homogenization_Ngrains + use constitutive, only: & + constitutive_homogenizedC, & + constitutive_postResults + + implicit none + integer(pInt), intent(in):: & + el, & !< element index + ip, & !< integration point index + ipc !< grain index + + real(pReal), dimension(1+crystallite_sizePostResults(microstructure_crystallite(mesh_element(4,el))) + & + 1+plasticState(material_phase(ipc,ip,el))%sizePostResults + & + sum(sourceState(material_phase(ipc,ip,el))%p(:)%sizePostResults)) :: & + crystallite_postResults + real(pReal), dimension(3,3) :: & + Ee + real(pReal), dimension(4) :: & + rotation + real(pReal) :: & + detF + integer(pInt) :: & + o, & + c, & + crystID, & + mySize, & + n + + + crystID = microstructure_crystallite(mesh_element(4,el)) + + crystallite_postResults = 0.0_pReal + c = 0_pInt + crystallite_postResults(c+1) = real(crystallite_sizePostResults(crystID),pReal) ! size of results from cryst + c = c + 1_pInt + + do o = 1_pInt,crystallite_Noutput(crystID) + mySize = 0_pInt + select case(crystallite_outputID(o,crystID)) + case (phase_ID) + mySize = 1_pInt + crystallite_postResults(c+1) = real(material_phase(ipc,ip,el),pReal) ! phaseID of grain + case (texture_ID) + mySize = 1_pInt + crystallite_postResults(c+1) = real(material_texture(ipc,ip,el),pReal) ! textureID of grain + case (volume_ID) + mySize = 1_pInt + detF = math_det33(crystallite_partionedF(1:3,1:3,ipc,ip,el)) ! V_current = det(F) * V_reference + crystallite_postResults(c+1) = detF * mesh_ipVolume(ip,el) & + / homogenization_Ngrains(mesh_element(3,el)) ! grain volume (not fraction but absolute) + case (orientation_ID) + mySize = 4_pInt + crystallite_postResults(c+1:c+mySize) = crystallite_orientation(1:4,ipc,ip,el) ! grain orientation as quaternion + case (eulerangles_ID) + mySize = 3_pInt + crystallite_postResults(c+1:c+mySize) = inDeg & + * math_qToEuler(crystallite_orientation(1:4,ipc,ip,el)) ! grain orientation as Euler angles in degree + case (grainrotation_ID) + mySize = 4_pInt + crystallite_postResults(c+1:c+mySize) = & + math_qToEulerAxisAngle(crystallite_rotation(1:4,ipc,ip,el)) ! grain rotation away from initial orientation as axis-angle in sample reference coordinates + crystallite_postResults(c+4) = inDeg * crystallite_postResults(c+4) ! angle in degree + case (grainrotationx_ID) + mySize = 1_pInt + rotation = math_qToEulerAxisAngle(crystallite_rotation(1:4,ipc,ip,el)) ! grain rotation away from initial orientation as axis-angle in sample reference coordinates + crystallite_postResults(c+1) = inDeg * rotation(1) * rotation(4) ! angle in degree + case (grainrotationy_ID) + mySize = 1_pInt + rotation = math_qToEulerAxisAngle(crystallite_rotation(1:4,ipc,ip,el)) ! grain rotation away from initial orientation as axis-angle in sample reference coordinates + crystallite_postResults(c+1) = inDeg * rotation(2) * rotation(4) ! angle in degree + case (grainrotationz_ID) + mySize = 1_pInt + rotation = math_qToEulerAxisAngle(crystallite_rotation(1:4,ipc,ip,el)) ! grain rotation away from initial orientation as axis-angle in sample reference coordinates + crystallite_postResults(c+1) = inDeg * rotation(3) * rotation(4) ! angle in degree + +! remark: tensor output is of the form 11,12,13, 21,22,23, 31,32,33 +! thus row index i is slow, while column index j is fast. reminder: "row is slow" + + case (defgrad_ID) + mySize = 9_pInt + crystallite_postResults(c+1:c+mySize) = & + reshape(math_transpose33(crystallite_partionedF(1:3,1:3,ipc,ip,el)),[mySize]) + case (e_ID) + mySize = 9_pInt + crystallite_postResults(c+1:c+mySize) = 0.5_pReal * reshape((math_mul33x33( & + math_transpose33(crystallite_partionedF(1:3,1:3,ipc,ip,el)), & + crystallite_partionedF(1:3,1:3,ipc,ip,el)) - math_I3),[mySize]) + case (fe_ID) + mySize = 9_pInt + crystallite_postResults(c+1:c+mySize) = & + reshape(math_transpose33(crystallite_Fe(1:3,1:3,ipc,ip,el)),[mySize]) + case (ee_ID) + Ee = 0.5_pReal *(math_mul33x33(math_transpose33(crystallite_Fe(1:3,1:3,ipc,ip,el)), & + crystallite_Fe(1:3,1:3,ipc,ip,el)) - math_I3) + mySize = 9_pInt + crystallite_postResults(c+1:c+mySize) = reshape(Ee,[mySize]) + case (fp_ID) + mySize = 9_pInt + crystallite_postResults(c+1:c+mySize) = & + reshape(math_transpose33(crystallite_Fp(1:3,1:3,ipc,ip,el)),[mySize]) + case (fi_ID) + mySize = 9_pInt + crystallite_postResults(c+1:c+mySize) = & + reshape(math_transpose33(crystallite_Fi(1:3,1:3,ipc,ip,el)),[mySize]) + case (lp_ID) + mySize = 9_pInt + crystallite_postResults(c+1:c+mySize) = & + reshape(math_transpose33(crystallite_Lp(1:3,1:3,ipc,ip,el)),[mySize]) + case (li_ID) + mySize = 9_pInt + crystallite_postResults(c+1:c+mySize) = & + reshape(math_transpose33(crystallite_Li(1:3,1:3,ipc,ip,el)),[mySize]) + case (p_ID) + mySize = 9_pInt + crystallite_postResults(c+1:c+mySize) = & + reshape(math_transpose33(crystallite_P(1:3,1:3,ipc,ip,el)),[mySize]) + case (s_ID) + mySize = 9_pInt + crystallite_postResults(c+1:c+mySize) = & + reshape(math_Mandel6to33(crystallite_Tstar_v(1:6,ipc,ip,el)),[mySize]) + case (elasmatrix_ID) + mySize = 36_pInt + crystallite_postResults(c+1:c+mySize) = reshape(constitutive_homogenizedC(ipc,ip,el),[mySize]) + case(neighboringelement_ID) + mySize = mesh_maxNipNeighbors + crystallite_postResults(c+1:c+mySize) = 0.0_pReal + forall (n = 1_pInt:FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) & + crystallite_postResults(c+n) = real(mesh_ipNeighborhood(1,n,ip,el),pReal) + case(neighboringip_ID) + mySize = mesh_maxNipNeighbors + crystallite_postResults(c+1:c+mySize) = 0.0_pReal + forall (n = 1_pInt:FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) & + crystallite_postResults(c+n) = real(mesh_ipNeighborhood(2,n,ip,el),pReal) + end select + c = c + mySize + enddo + + crystallite_postResults(c+1) = real(plasticState(material_phase(ipc,ip,el))%sizePostResults,pReal) ! size of constitutive results + c = c + 1_pInt + if (size(crystallite_postResults)-c > 0_pInt) & + crystallite_postResults(c+1:size(crystallite_postResults)) = & + constitutive_postResults(crystallite_Tstar_v(1:6,ipc,ip,el), crystallite_Fe, & + ipc, ip, el) + +end function crystallite_postResults + +end module crystallite diff --git a/src/damage_local.f90 b/src/damage_local.f90 new file mode 100644 index 000000000..196382c13 --- /dev/null +++ b/src/damage_local.f90 @@ -0,0 +1,327 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for locally evolving damage field +!-------------------------------------------------------------------------------------------------- +module damage_local + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + damage_local_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + damage_local_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + damage_local_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + damage_local_Noutput !< number of outputs per instance of this damage + + enum, bind(c) + enumerator :: undefined_ID, & + damage_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + damage_local_outputID !< ID of each post result output + + public :: & + damage_local_init, & + damage_local_updateState, & + damage_local_postResults + private :: & + damage_local_getSourceAndItsTangent + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine damage_local_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + damage_type, & + damage_typeInstance, & + homogenization_Noutput, & + DAMAGE_local_label, & + DAMAGE_local_ID, & + material_homog, & + mappingHomogenization, & + damageState, & + damageMapping, & + damage, & + damage_initialPhi, & + material_partHomogenization + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,homog,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_local_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(damage_type == DAMAGE_local_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(damage_local_sizePostResults(maxNinstance), source=0_pInt) + allocate(damage_local_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(damage_local_output (maxval(homogenization_Noutput),maxNinstance)) + damage_local_output = '' + allocate(damage_local_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(damage_local_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + homog = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + homog = homog + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (homog > 0_pInt ) then; if (damage_type(homog) == DAMAGE_local_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = damage_typeInstance(homog) ! which instance of my damage is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('damage') + damage_local_Noutput(instance) = damage_local_Noutput(instance) + 1_pInt + damage_local_outputID(damage_local_Noutput(instance),instance) = damage_ID + damage_local_output(damage_local_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingFile + + initializeInstances: do homog = 1_pInt, size(damage_type) + + myhomog: if (damage_type(homog) == DAMAGE_local_ID) then + NofMyHomog = count(material_homog == homog) + instance = damage_typeInstance(homog) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,damage_local_Noutput(instance) + select case(damage_local_outputID(o,instance)) + case(damage_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + damage_local_sizePostResult(o,instance) = mySize + damage_local_sizePostResults(instance) = damage_local_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 1_pInt + damageState(homog)%sizeState = sizeState + damageState(homog)%sizePostResults = damage_local_sizePostResults(instance) + allocate(damageState(homog)%state0 (sizeState,NofMyHomog), source=damage_initialPhi(homog)) + allocate(damageState(homog)%subState0(sizeState,NofMyHomog), source=damage_initialPhi(homog)) + allocate(damageState(homog)%state (sizeState,NofMyHomog), source=damage_initialPhi(homog)) + + nullify(damageMapping(homog)%p) + damageMapping(homog)%p => mappingHomogenization(1,:,:) + deallocate(damage(homog)%p) + damage(homog)%p => damageState(homog)%state(1,:) + + endif myhomog + enddo initializeInstances + + +end subroutine damage_local_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates local change in damage field +!-------------------------------------------------------------------------------------------------- +function damage_local_updateState(subdt, ip, el) + use numerics, only: & + residualStiffness, & + err_damage_tolAbs, & + err_damage_tolRel + use material, only: & + mappingHomogenization, & + damageState + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + subdt + logical, dimension(2) :: & + damage_local_updateState + integer(pInt) :: & + homog, & + offset + real(pReal) :: & + phi, phiDot, dPhiDot_dPhi + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + phi = damageState(homog)%subState0(1,offset) + call damage_local_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) + phi = max(residualStiffness,min(1.0_pReal,phi + subdt*phiDot)) + + damage_local_updateState = [ abs(phi - damageState(homog)%state(1,offset)) & + <= err_damage_tolAbs & + .or. abs(phi - damageState(homog)%state(1,offset)) & + <= err_damage_tolRel*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) + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + phase_source, & + phase_Nsources, & + SOURCE_damage_isoBrittle_ID, & + SOURCE_damage_isoDuctile_ID, & + SOURCE_damage_anisoBrittle_ID, & + SOURCE_damage_anisoDuctile_ID + use source_damage_isoBrittle, only: & + source_damage_isobrittle_getRateAndItsTangent + use source_damage_isoDuctile, only: & + source_damage_isoductile_getRateAndItsTangent + use source_damage_anisoBrittle, only: & + source_damage_anisobrittle_getRateAndItsTangent + use source_damage_anisoDuctile, only: & + source_damage_anisoductile_getRateAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + phi + integer(pInt) :: & + phase, & + grain, & + source + real(pReal) :: & + phiDot, dPhiDot_dPhi, localphiDot, dLocalphiDot_dPhi + + phiDot = 0.0_pReal + dPhiDot_dPhi = 0.0_pReal + do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) + phase = phaseAt(grain,ip,el) + do source = 1, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_damage_isoBrittle_ID) + call source_damage_isobrittle_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_isoDuctile_ID) + call source_damage_isoductile_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_anisoBrittle_ID) + call source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_anisoDuctile_ID) + call source_damage_anisoductile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case default + localphiDot = 0.0_pReal + dLocalphiDot_dPhi = 0.0_pReal + + end select + phiDot = phiDot + localphiDot + dPhiDot_dPhi = dPhiDot_dPhi + dLocalphiDot_dPhi + enddo + enddo + + phiDot = phiDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + dPhiDot_dPhi = dPhiDot_dPhi/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + +end subroutine damage_local_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of damage results +!-------------------------------------------------------------------------------------------------- +function damage_local_postResults(ip,el) + use material, only: & + mappingHomogenization, & + damage_typeInstance, & + damageMapping, & + damage + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(damage_local_sizePostResults(damage_typeInstance(mappingHomogenization(2,ip,el)))) :: & + damage_local_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = damageMapping(homog)%p(ip,el) + instance = damage_typeInstance(homog) + + c = 0_pInt + damage_local_postResults = 0.0_pReal + + do o = 1_pInt,damage_local_Noutput(instance) + select case(damage_local_outputID(o,instance)) + + case (damage_ID) + damage_local_postResults(c+1_pInt) = damage(homog)%p(offset) + c = c + 1 + end select + enddo +end function damage_local_postResults + +end module damage_local diff --git a/src/damage_none.f90 b/src/damage_none.f90 new file mode 100644 index 000000000..956ba5cc8 --- /dev/null +++ b/src/damage_none.f90 @@ -0,0 +1,60 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for constant damage field +!-------------------------------------------------------------------------------------------------- +module damage_none + + implicit none + private + + public :: & + damage_none_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine damage_none_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_none_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (damage_type(homog) == DAMAGE_none_ID) then + NofMyHomog = count(material_homog == homog) + damageState(homog)%sizeState = 0_pInt + damageState(homog)%sizePostResults = 0_pInt + allocate(damageState(homog)%state0 (0_pInt,NofMyHomog)) + allocate(damageState(homog)%subState0(0_pInt,NofMyHomog)) + allocate(damageState(homog)%state (0_pInt,NofMyHomog)) + + deallocate(damage(homog)%p) + allocate (damage(homog)%p(1), source=damage_initialPhi(homog)) + + endif myhomog + enddo initializeInstances + + +end subroutine damage_none_init + +end module damage_none diff --git a/src/damage_nonlocal.f90 b/src/damage_nonlocal.f90 new file mode 100644 index 000000000..311570781 --- /dev/null +++ b/src/damage_nonlocal.f90 @@ -0,0 +1,380 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for non-locally evolving damage field +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module damage_nonlocal + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + damage_nonlocal_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + damage_nonlocal_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + damage_nonlocal_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + damage_nonlocal_Noutput !< number of outputs per instance of this damage + + enum, bind(c) + enumerator :: undefined_ID, & + damage_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + damage_nonlocal_outputID !< ID of each post result output + + + public :: & + damage_nonlocal_init, & + damage_nonlocal_getSourceAndItsTangent, & + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility, & + damage_nonlocal_putNonLocalDamage, & + damage_nonlocal_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine damage_nonlocal_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + damage_type, & + damage_typeInstance, & + homogenization_Noutput, & + DAMAGE_nonlocal_label, & + DAMAGE_nonlocal_ID, & + material_homog, & + mappingHomogenization, & + damageState, & + damageMapping, & + damage, & + damage_initialPhi, & + material_partHomogenization + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- damage_'//DAMAGE_nonlocal_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(damage_type == DAMAGE_nonlocal_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(damage_nonlocal_sizePostResults(maxNinstance), source=0_pInt) + allocate(damage_nonlocal_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(damage_nonlocal_output (maxval(homogenization_Noutput),maxNinstance)) + damage_nonlocal_output = '' + allocate(damage_nonlocal_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(damage_nonlocal_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (damage_type(section) == DAMAGE_nonlocal_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = damage_typeInstance(section) ! which instance of my damage is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('damage') + damage_nonlocal_Noutput(instance) = damage_nonlocal_Noutput(instance) + 1_pInt + damage_nonlocal_outputID(damage_nonlocal_Noutput(instance),instance) = damage_ID + damage_nonlocal_output(damage_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingFile + + initializeInstances: do section = 1_pInt, size(damage_type) + if (damage_type(section) == DAMAGE_nonlocal_ID) then + NofMyHomog=count(material_homog==section) + instance = damage_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,damage_nonlocal_Noutput(instance) + select case(damage_nonlocal_outputID(o,instance)) + case(damage_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + damage_nonlocal_sizePostResult(o,instance) = mySize + damage_nonlocal_sizePostResults(instance) = damage_nonlocal_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 0_pInt + damageState(section)%sizeState = sizeState + damageState(section)%sizePostResults = damage_nonlocal_sizePostResults(instance) + allocate(damageState(section)%state0 (sizeState,NofMyHomog)) + allocate(damageState(section)%subState0(sizeState,NofMyHomog)) + allocate(damageState(section)%state (sizeState,NofMyHomog)) + + nullify(damageMapping(section)%p) + damageMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(damage(section)%p) + allocate(damage(section)%p(NofMyHomog), source=damage_initialPhi(section)) + + endif + + enddo initializeInstances +end subroutine damage_nonlocal_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates homogenized damage driving forces +!-------------------------------------------------------------------------------------------------- +subroutine damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + phase_source, & + phase_Nsources, & + SOURCE_damage_isoBrittle_ID, & + SOURCE_damage_isoDuctile_ID, & + SOURCE_damage_anisoBrittle_ID, & + SOURCE_damage_anisoDuctile_ID + use source_damage_isoBrittle, only: & + source_damage_isobrittle_getRateAndItsTangent + use source_damage_isoDuctile, only: & + source_damage_isoductile_getRateAndItsTangent + use source_damage_anisoBrittle, only: & + source_damage_anisobrittle_getRateAndItsTangent + use source_damage_anisoDuctile, only: & + source_damage_anisoductile_getRateAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + phi + integer(pInt) :: & + phase, & + grain, & + source + real(pReal) :: & + phiDot, dPhiDot_dPhi, localphiDot, dLocalphiDot_dPhi + + phiDot = 0.0_pReal + dPhiDot_dPhi = 0.0_pReal + do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) + phase = phaseAt(grain,ip,el) + do source = 1_pInt, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_damage_isoBrittle_ID) + call source_damage_isobrittle_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_isoDuctile_ID) + call source_damage_isoductile_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_anisoBrittle_ID) + call source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case (SOURCE_damage_anisoDuctile_ID) + call source_damage_anisoductile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, grain, ip, el) + + case default + localphiDot = 0.0_pReal + dLocalphiDot_dPhi = 0.0_pReal + + end select + phiDot = phiDot + localphiDot + dPhiDot_dPhi = dPhiDot_dPhi + dLocalphiDot_dPhi + enddo + enddo + + phiDot = phiDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + dPhiDot_dPhi = dPhiDot_dPhi/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + +end subroutine damage_nonlocal_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized non local damage diffusion tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function damage_nonlocal_getDiffusion33(ip,el) + use numerics, only: & + charLength + use lattice, only: & + lattice_DamageDiffusion33 + use material, only: & + homogenization_Ngrains, & + material_phase, & + mappingHomogenization + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + damage_nonlocal_getDiffusion33 + integer(pInt) :: & + homog, & + grain + + homog = mappingHomogenization(2,ip,el) + damage_nonlocal_getDiffusion33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(homog) + damage_nonlocal_getDiffusion33 = damage_nonlocal_getDiffusion33 + & + crystallite_push33ToRef(grain,ip,el,lattice_DamageDiffusion33(1:3,1:3,material_phase(grain,ip,el))) + enddo + + damage_nonlocal_getDiffusion33 = & + charLength*charLength* & + damage_nonlocal_getDiffusion33/ & + homogenization_Ngrains(homog) + +end function damage_nonlocal_getDiffusion33 + +!-------------------------------------------------------------------------------------------------- +!> @brief Returns homogenized nonlocal damage mobility +!-------------------------------------------------------------------------------------------------- +real(pReal) function damage_nonlocal_getMobility(ip,el) + use mesh, only: & + mesh_element + use lattice, only: & + lattice_damageMobility + use material, only: & + material_phase, & + homogenization_Ngrains + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + integer(pInt) :: & + ipc + + damage_nonlocal_getMobility = 0.0_pReal + + do ipc = 1, homogenization_Ngrains(mesh_element(3,el)) + damage_nonlocal_getMobility = damage_nonlocal_getMobility + lattice_DamageMobility(material_phase(ipc,ip,el)) + enddo + + damage_nonlocal_getMobility = damage_nonlocal_getMobility /homogenization_Ngrains(mesh_element(3,el)) + +end function damage_nonlocal_getMobility + +!-------------------------------------------------------------------------------------------------- +!> @brief updated nonlocal damage field with solution from damage phase field PDE +!-------------------------------------------------------------------------------------------------- +subroutine damage_nonlocal_putNonLocalDamage(phi,ip,el) + use material, only: & + material_homog, & + damageMapping, & + damage + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + phi + integer(pInt) :: & + homog, & + offset + + homog = material_homog(ip,el) + offset = damageMapping(homog)%p(ip,el) + damage(homog)%p(offset) = phi + +end subroutine damage_nonlocal_putNonLocalDamage + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of damage results +!-------------------------------------------------------------------------------------------------- +function damage_nonlocal_postResults(ip,el) + use material, only: & + mappingHomogenization, & + damage_typeInstance, & + damage + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(damage_nonlocal_sizePostResults(damage_typeInstance(mappingHomogenization(2,ip,el)))) :: & + damage_nonlocal_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + instance = damage_typeInstance(homog) + + c = 0_pInt + damage_nonlocal_postResults = 0.0_pReal + + do o = 1_pInt,damage_nonlocal_Noutput(instance) + select case(damage_nonlocal_outputID(o,instance)) + + case (damage_ID) + damage_nonlocal_postResults(c+1_pInt) = damage(homog)%p(offset) + c = c + 1 + end select + enddo +end function damage_nonlocal_postResults + +end module damage_nonlocal diff --git a/src/damask.core.pyf b/src/damask.core.pyf new file mode 100644 index 000000000..e6396ee1d --- /dev/null +++ b/src/damask.core.pyf @@ -0,0 +1,126 @@ +! $Id$ +! -*- f90 -*- +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! Note: the syntax of this file is case sensitive. +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! This file was auto-generated with f2py (version:2_5972). +! See http://cens.ioc.ee/projects/f2py2e/ +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! The auto-generated file is quite heavily corrected +! For modifying, notice the following hints: +! - if the dimension of an array depend on a array that is itself an input, use the C-Syntax: (1) becomes [0] etc. +! - be sure that the precision defined is integer, real*8, and complex*16 +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +python module core ! in + interface ! in :core + + module prec + subroutine prec_init + end subroutine prec_init + end module prec + + module damask_interface ! in :damask_interface:DAMASK_spectral_interface.f90 + subroutine DAMASK_interface_init(loadcaseParameterIn,geometryParameterIn) ! in :damask_interface:DAMASK_spectral_interface.f90 + character(len=1024), intent(in) :: loadcaseParameterIn + character(len=1024), intent(in) :: geometryParameterIn + end subroutine DAMASK_interface_init + end module damask_interface + + module io + subroutine IO_init + end subroutine IO_init + end module io + + module numerics + subroutine numerics_init + end subroutine numerics_init + end module numerics + + module debug + subroutine debug_init + end subroutine debug_init + end module debug + + module math ! in :math:math.f90 + subroutine math_init + end subroutine math_init + + function math_tensorAvg(field) ! in :math:math.f90 + ! input variables + real*8 dimension(:,:,:,:,:), intent(in), :: field + ! function definition + real*8 dimension(3,3), :: math_tensorAvg + end function math_tensorAvg + + end module math + + module fesolving + subroutine FE_init + end subroutine FE_init + end module fesolving + + module mesh ! in :mesh:mesh.f90 + subroutine mesh_init(ip,element) + integer, parameter :: ip = 1 + integer, parameter :: element = 1 + end subroutine mesh_init + + function mesh_nodesAroundCentres(gDim,Favg,centres) ! in :mesh:mesh.f90 + real*8, dimension(:,:,:,:), intent(in) :: centres + real*8, dimension(3), intent(in) :: gDim + real*8, dimension(3,3), intent(in) :: Favg + real*8, dimension(3,size(centres,2)+1,size(centres,3)+1,size(centres,4)+1), depend(centres) :: mesh_nodesAroundCentres + real*8, dimension(3,size(centres,2)+1,size(centres,3)+1,size(centres,4)+1), depend(centres) :: wrappedCentres + end function mesh_nodesAroundCentres + + function mesh_deformedCoordsFFT(gDim,F,FavgIn,scalingIn) ! in :mesh:mesh.f90 + real*8, dimension(:,:,:,:,:), intent(in) :: F + real*8, dimension(3), intent(in) :: gDim + real*8, dimension(3,3), intent(in), optional :: FavgIn = -1.0 + real*8, dimension(3), intent(in), optional :: scalingIn = -1.0 + real*8, dimension(3,size(F,3),size(F,4),size(F,5)), depend(F) :: mesh_deformedCoordsFFT + end function mesh_deformedCoordsFFT + + function mesh_volumeMismatch(gDim,F,nodes) ! in :mesh:mesh.f90 + real*8, dimension(:,:,:,:,:), intent(in) :: F + real*8, dimension(:,:,:,:), intent(in) :: nodes + real*8, dimension(3), intent(in) :: gDim + real*8, dimension(size(F,3),size(F,4),size(F,5)), depend(F) :: mesh_volumeMismatch + end function mesh_volumeMismatch + + function mesh_shapeMismatch(gDim,F,nodes,centres) ! in :mesh:mesh.f90 + real*8, dimension(:,:,:,:,:), intent(in) :: F + real*8, dimension(:,:,:,:), intent(in) :: nodes + real*8, dimension(:,:,:,:), intent(in) :: centres + real*8, dimension(3), intent(in) :: gDim + real*8, dimension(size(F,3),size(F,4),size(F,5)), depend(F) :: mesh_shapeMismatch + end function mesh_shapeMismatch + + function mesh_init_postprocessing(filepath) ! in :mesh:mesh.f90 + character(len=*), intent(in) :: filepath + end function mesh_init_postprocessing + + function mesh_build_cellnodes(nodes,Ncellnodes) ! in :mesh:mesh.f90 + integer, intent(in) :: Ncellnodes + real*8, dimension(3,:), intent(in) :: nodes + real*8, dimension(3,Ncellnodes), depend(Ncellnodes) :: mesh_build_cellnodes + end function mesh_build_cellnodes + + function mesh_get_Ncellnodes() ! in :mesh:mesh.f90 + integer :: mesh_get_Ncellnodes + end function mesh_get_Ncellnodes + + function mesh_get_unitlength() ! in :mesh:mesh.f90 + real*8 :: mesh_get_unitlength + end function mesh_get_unitlength + + function mesh_get_nodeAtIP(elemtypeFE,ip) ! in :mesh:mesh.f90 + character(len=*), intent(in) :: elemtypeFE + integer, intent(in) :: ip + integer :: mesh_get_nodeAtIP + end function mesh_get_nodeAtIP + + end module mesh + end interface +end python module core + diff --git a/src/damask_hdf5.f90 b/src/damask_hdf5.f90 new file mode 100644 index 000000000..34479f9b3 --- /dev/null +++ b/src/damask_hdf5.f90 @@ -0,0 +1,16 @@ +module HDF5_io + use prec + use IO + use hdf5 + +contains + +subroutine HDF5_init(filename, total_inc, total_time) + integer(pInt), intent(in) :: total_inc + real(pReal), intent(in) :: total_time + + write(6,*) 'pretend to write something' + +end subroutine HDF5_init + +end module HDF5_io \ No newline at end of file diff --git a/src/debug.f90 b/src/debug.f90 new file mode 100644 index 000000000..2a9c6d800 --- /dev/null +++ b/src/debug.f90 @@ -0,0 +1,476 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @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 Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Reading in and interpretating the debugging settings for the various modules +!-------------------------------------------------------------------------------------------------- +module debug + use prec, only: & + pInt, & + pReal, & + pLongInt + + implicit none + private + integer(pInt), parameter, public :: & + debug_LEVELSELECTIVE = 2_pInt**0_pInt, & + debug_LEVELBASIC = 2_pInt**1_pInt, & + debug_LEVELEXTENSIVE = 2_pInt**2_pInt + integer(pInt), parameter, private :: & + debug_MAXGENERAL = debug_LEVELEXTENSIVE ! must be set to the last bitcode used by (potentially) all debug types + integer(pInt), parameter, public :: & + debug_SPECTRALRESTART = debug_MAXGENERAL*2_pInt**1_pInt, & + debug_SPECTRALFFTW = debug_MAXGENERAL*2_pInt**2_pInt, & + debug_SPECTRALDIVERGENCE = debug_MAXGENERAL*2_pInt**3_pInt, & + debug_SPECTRALROTATION = debug_MAXGENERAL*2_pInt**4_pInt, & + debug_SPECTRALPETSC = debug_MAXGENERAL*2_pInt**5_pInt + + integer(pInt), parameter, public :: & + debug_DEBUG = 1_pInt, & + debug_MATH = 2_pInt, & + debug_FESOLVING = 3_pInt, & + debug_MESH = 4_pInt, & !< stores debug level for mesh part of DAMASK bitwise coded + debug_MATERIAL = 5_pInt, & !< stores debug level for material part of DAMASK bitwise coded + debug_LATTICE = 6_pInt, & !< stores debug level for lattice part of DAMASK bitwise coded + debug_CONSTITUTIVE = 7_pInt, & !< stores debug level for constitutive part of DAMASK bitwise coded + debug_CRYSTALLITE = 8_pInt, & + debug_HOMOGENIZATION = 9_pInt, & + debug_CPFEM = 10_pInt, & + debug_SPECTRAL = 11_pInt, & + debug_MARC = 12_pInt, & + debug_ABAQUS = 13_pInt + integer(pInt), parameter, private :: & + debug_MAXNTYPE = debug_ABAQUS !< must be set to the maximum defined debug type + + integer(pInt),protected, dimension(debug_maxNtype+2_pInt), public :: & ! specific ones, and 2 for "all" and "other" + debug_level = 0_pInt + + integer(pInt), public :: & + debug_cumLpCalls = 0_pInt, & !< total number of calls to LpAndItsTangent + debug_cumDeltaStateCalls = 0_pInt, & !< total number of calls to deltaState + debug_cumDotStateCalls = 0_pInt !< total number of calls to dotState + + integer(pInt), protected, public :: & + debug_e = 1_pInt, & + debug_i = 1_pInt, & + debug_g = 1_pInt + + integer(pLongInt), public :: & + debug_cumLpTicks = 0_pLongInt, & !< total cpu ticks spent in LpAndItsTangent + debug_cumDeltaStateTicks = 0_pLongInt, & !< total cpu ticks spent in deltaState + debug_cumDotStateTicks = 0_pLongInt !< total cpu ticks spent in dotState + + integer(pInt), dimension(2), public :: & + debug_stressMaxLocation = 0_pInt, & + debug_stressMinLocation = 0_pInt, & + debug_jacobianMaxLocation = 0_pInt, & + debug_jacobianMinLocation = 0_pInt + + integer(pInt), dimension(:), allocatable, public :: & + debug_CrystalliteLoopDistribution, & !< distribution of crystallite cutbacks + debug_MaterialpointStateLoopDistribution, & + debug_MaterialpointLoopDistribution + + integer(pInt), dimension(:,:), allocatable, public :: & + debug_StressLoopLiDistribution, & !< distribution of stress iterations until convergence + debug_StressLoopLpDistribution, & !< distribution of stress iterations until convergence + debug_StateLoopDistribution !< distribution of state iterations until convergence + + real(pReal), public :: & + debug_stressMax = -huge(1.0_pReal), & + debug_stressMin = huge(1.0_pReal), & + debug_jacobianMax = -huge(1.0_pReal), & + debug_jacobianMin = huge(1.0_pReal) + + character(len=64), parameter, private :: & + debug_CONFIGFILE = 'debug.config' !< name of configuration file + +#ifdef PETSc + character(len=1024), parameter, public :: & + PETSCDEBUG = ' -snes_view -snes_monitor ' +#endif + public :: debug_init, & + debug_reset, & + debug_info + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads in parameters from debug.config and allocates arrays +!-------------------------------------------------------------------------------------------------- +subroutine debug_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use numerics, only: & + worldrank, & + nStress, & + nState, & + nCryst, & + nMPstate, & + nHomog + use IO, only: & + IO_read, & + IO_error, & + IO_open_file_stat, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_lc, & + IO_floatValue, & + IO_intValue, & + IO_timeStamp, & + IO_EOF + + implicit none + integer(pInt), parameter :: FILEUNIT = 300_pInt + + integer(pInt) :: i, what + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=65536) :: tag, line + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- debug init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + if (allocated(debug_StressLoopLpDistribution)) & + deallocate(debug_StressLoopLpDistribution) + allocate(debug_StressLoopLpDistribution(nStress+1,2)) + debug_StressLoopLpDistribution = 0_pInt + if (allocated(debug_StressLoopLiDistribution)) & + deallocate(debug_StressLoopLiDistribution) + allocate(debug_StressLoopLiDistribution(nStress+1,2)) + debug_StressLoopLiDistribution = 0_pInt + if (allocated(debug_StateLoopDistribution)) & + deallocate(debug_StateLoopDistribution) + allocate(debug_StateLoopDistribution(nState+1,2)) + debug_StateLoopDistribution = 0_pInt + if (allocated(debug_CrystalliteLoopDistribution)) & + deallocate(debug_CrystalliteLoopDistribution) + allocate(debug_CrystalliteLoopDistribution(nCryst+1)) + debug_CrystalliteLoopDistribution = 0_pInt + if (allocated(debug_MaterialpointStateLoopDistribution)) & + deallocate(debug_MaterialpointStateLoopDistribution) + allocate(debug_MaterialpointStateLoopDistribution(nMPstate)) + debug_MaterialpointStateLoopDistribution = 0_pInt + if (allocated(debug_MaterialpointLoopDistribution)) & + deallocate(debug_MaterialpointLoopDistribution) + allocate(debug_MaterialpointLoopDistribution(nHomog+1)) + debug_MaterialpointLoopDistribution = 0_pInt + +!-------------------------------------------------------------------------------------------------- +! try to open the config file + + line = '' + fileExists: if(IO_open_file_stat(FILEUNIT,debug_configFile)) then + do while (trim(line) /= IO_EOF) ! read thru sections of phase part + line = IO_read(FILEUNIT) + if (IO_isBlank(line)) cycle ! skip empty lines + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('element','e','el') + debug_e = IO_intValue(line,chunkPos,2_pInt) + case ('integrationpoint','i','ip') + debug_i = IO_intValue(line,chunkPos,2_pInt) + case ('grain','g','gr') + debug_g = IO_intValue(line,chunkPos,2_pInt) + end select + + what = 0_pInt + select case(tag) + case ('debug') + what = debug_DEBUG + case ('math') + what = debug_MATH + case ('fesolving', 'fe') + what = debug_FESOLVING + case ('mesh') + what = debug_MESH + case ('material') + what = debug_MATERIAL + case ('lattice') + what = debug_LATTICE + case ('constitutive') + what = debug_CONSTITUTIVE + case ('crystallite') + what = debug_CRYSTALLITE + case ('homogenization') + what = debug_HOMOGENIZATION + case ('cpfem') + what = debug_CPFEM + case ('spectral') + what = debug_SPECTRAL + case ('marc') + what = debug_MARC + case ('abaqus') + what = debug_ABAQUS + case ('all') + what = debug_MAXNTYPE + 1_pInt + case ('other') + what = debug_MAXNTYPE + 2_pInt + end select + if (what /= 0) then + do i = 2_pInt, chunkPos(1) + select case(IO_lc(IO_stringValue(line,chunkPos,i))) + case('basic') + debug_level(what) = ior(debug_level(what), debug_LEVELBASIC) + case('extensive') + debug_level(what) = ior(debug_level(what), debug_LEVELEXTENSIVE) + case('selective') + debug_level(what) = ior(debug_level(what), debug_LEVELSELECTIVE) + case('restart') + debug_level(what) = ior(debug_level(what), debug_SPECTRALRESTART) + case('fft','fftw') + debug_level(what) = ior(debug_level(what), debug_SPECTRALFFTW) + case('divergence') + debug_level(what) = ior(debug_level(what), debug_SPECTRALDIVERGENCE) + case('rotation') + debug_level(what) = ior(debug_level(what), debug_SPECTRALROTATION) + case('petsc') + debug_level(what) = ior(debug_level(what), debug_SPECTRALPETSC) + end select + enddo + endif + enddo + close(FILEUNIT) + + do i = 1_pInt, debug_maxNtype + if (debug_level(i) == 0) & + debug_level(i) = ior(debug_level(i), debug_level(debug_MAXNTYPE + 2_pInt)) ! fill undefined debug types with levels specified by "other" + + debug_level(i) = ior(debug_level(i), debug_level(debug_MAXNTYPE + 1_pInt)) ! fill all debug types with levels specified by "all" + enddo + + if (iand(debug_level(debug_debug),debug_LEVELBASIC) /= 0) & + write(6,'(a,/)') ' using values from config file' + else fileExists + if (iand(debug_level(debug_debug),debug_LEVELBASIC) /= 0) & + write(6,'(a,/)') ' using standard values' + endif fileExists + +!-------------------------------------------------------------------------------------------------- +! output switched on (debug level for debug must be extensive) + if (iand(debug_level(debug_debug),debug_LEVELEXTENSIVE) /= 0) then + do i = 1_pInt, debug_MAXNTYPE + select case(i) + case (debug_DEBUG) + tag = ' Debug' + case (debug_MATH) + tag = ' Math' + case (debug_FESOLVING) + tag = ' FEsolving' + case (debug_MESH) + tag = ' Mesh' + case (debug_MATERIAL) + tag = ' Material' + case (debug_LATTICE) + tag = ' Lattice' + case (debug_CONSTITUTIVE) + tag = ' Constitutive' + case (debug_CRYSTALLITE) + tag = ' Crystallite' + case (debug_HOMOGENIZATION) + tag = ' Homogenizaiton' + case (debug_CPFEM) + tag = ' CPFEM' + case (debug_SPECTRAL) + tag = ' Spectral solver' + case (debug_MARC) + tag = ' MSC.MARC FEM solver' + case (debug_ABAQUS) + tag = ' ABAQUS FEM solver' + end select + + if(debug_level(i) /= 0) then + write(6,'(3a)') ' debug level for ', trim(tag), ':' + if(iand(debug_level(i),debug_LEVELBASIC) /= 0) write(6,'(a)') ' basic' + if(iand(debug_level(i),debug_LEVELEXTENSIVE) /= 0) write(6,'(a)') ' extensive' + if(iand(debug_level(i),debug_LEVELSELECTIVE) /= 0) then + write(6,'(a)') ' selective on:' + write(6,'(a24,1x,i8)') ' element: ',debug_e + write(6,'(a24,1x,i8)') ' ip: ',debug_i + write(6,'(a24,1x,i8)') ' grain: ',debug_g + endif + if(iand(debug_level(i),debug_SPECTRALRESTART) /= 0) write(6,'(a)') ' restart' + if(iand(debug_level(i),debug_SPECTRALFFTW) /= 0) write(6,'(a)') ' FFTW' + if(iand(debug_level(i),debug_SPECTRALDIVERGENCE)/= 0) write(6,'(a)') ' divergence' + if(iand(debug_level(i),debug_SPECTRALROTATION) /= 0) write(6,'(a)') ' rotation' + if(iand(debug_level(i),debug_SPECTRALPETSC) /= 0) write(6,'(a)') ' PETSc' + endif + enddo + endif + +end subroutine debug_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief resets all debug values +!-------------------------------------------------------------------------------------------------- +subroutine debug_reset + + implicit none + + debug_StressLoopLpDistribution = 0_pInt + debug_StressLoopLiDistribution = 0_pInt + debug_StateLoopDistribution = 0_pInt + debug_CrystalliteLoopDistribution = 0_pInt + debug_MaterialpointStateLoopDistribution = 0_pInt + debug_MaterialpointLoopDistribution = 0_pInt + debug_cumLpTicks = 0_pLongInt + debug_cumDeltaStateTicks = 0_pLongInt + debug_cumDotStateTicks = 0_pLongInt + debug_cumLpCalls = 0_pInt + debug_cumDeltaStateCalls = 0_pInt + debug_cumDotStateCalls = 0_pInt + debug_stressMaxLocation = 0_pInt + debug_stressMinLocation = 0_pInt + debug_jacobianMaxLocation = 0_pInt + debug_jacobianMinLocation = 0_pInt + debug_stressMax = -huge(1.0_pReal) + debug_stressMin = huge(1.0_pReal) + debug_jacobianMax = -huge(1.0_pReal) + debug_jacobianMin = huge(1.0_pReal) + +end subroutine debug_reset + + +!-------------------------------------------------------------------------------------------------- +!> @brief writes debug statements to standard out +!-------------------------------------------------------------------------------------------------- +subroutine debug_info + use numerics, only: & + nStress, & + nState, & + nCryst, & + nMPstate, & + nHomog + + implicit none + integer(pInt) :: j,integral + integer(pLongInt) :: tickrate + character(len=1) :: exceed + + call system_clock(count_rate=tickrate) + + !$OMP CRITICAL (write2out) + debugOutputCryst: if (iand(debug_level(debug_CRYSTALLITE),debug_LEVELBASIC) /= 0) then + write(6,'(/,a,/)') ' DEBUG Info (from previous cycle)' + write(6,'(a33,1x,i12)') 'total calls to LpAndItsTangent :',debug_cumLpCalls + if (debug_cumLpCalls > 0_pInt) then + write(6,'(a33,1x,f12.3)') 'total CPU time/s :',& + real(debug_cumLpTicks,pReal)/real(tickrate,pReal) + write(6,'(a33,1x,f12.6)') 'avg CPU time/microsecs per call :',& + real(debug_cumLpTicks,pReal)*1.0e6_pReal/real(tickrate*debug_cumLpCalls,pReal) + endif + write(6,'(/,a33,1x,i12)') 'total calls to collectDotState :',debug_cumDotStateCalls + if (debug_cumdotStateCalls > 0_pInt) then + write(6,'(a33,1x,f12.3)') 'total CPU time/s :',& + real(debug_cumDotStateTicks,pReal)/real(tickrate,pReal) + write(6,'(a33,1x,f12.6)') 'avg CPU time/microsecs per call :',& + real(debug_cumDotStateTicks,pReal)*1.0e6_pReal/real(tickrate*debug_cumDotStateCalls,pReal) + endif + write(6,'(/,a33,1x,i12)') 'total calls to collectDeltaState:',debug_cumDeltaStateCalls + if (debug_cumDeltaStateCalls > 0_pInt) then + write(6,'(a33,1x,f12.3)') 'total CPU time/s :',& + real(debug_cumDeltaStateTicks,pReal)/real(tickrate,pReal) + write(6,'(a33,1x,f12.6)') 'avg CPU time/microsecs per call :',& + real(debug_cumDeltaStateTicks,pReal)*1.0e6_pReal/real(tickrate*debug_cumDeltaStateCalls,pReal) + endif + + integral = 0_pInt + write(6,'(3/,a)') 'distribution_StressLoopLp : stress stiffness' + do j=1_pInt,nStress+1_pInt + if (any(debug_StressLoopLpDistribution(j,:) /= 0_pInt )) then + integral = integral + j*(debug_StressLoopLpDistribution(j,1) + debug_StressLoopLpDistribution(j,2)) + exceed = ' ' + if (j > nStress) exceed = '+' ! last entry gets "+" + write(6,'(i25,a1,i10,1x,i10)') min(nStress,j),exceed,debug_StressLoopLpDistribution(j,1),& + debug_StressLoopLpDistribution(j,2) + endif + enddo + write(6,'(a15,i10,2(1x,i10))') ' total',integral,sum(debug_StressLoopLpDistribution(:,1)), & + sum(debug_StressLoopLpDistribution(:,2)) + + integral = 0_pInt + write(6,'(3/,a)') 'distribution_StressLoopLi : stress stiffness' + do j=1_pInt,nStress+1_pInt + if (any(debug_StressLoopLiDistribution(j,:) /= 0_pInt )) then + integral = integral + j*(debug_StressLoopLiDistribution(j,1) + debug_StressLoopLiDistribution(j,2)) + exceed = ' ' + if (j > nStress) exceed = '+' ! last entry gets "+" + write(6,'(i25,a1,i10,1x,i10)') min(nStress,j),exceed,debug_StressLoopLiDistribution(j,1),& + debug_StressLoopLiDistribution(j,2) + endif + enddo + write(6,'(a15,i10,2(1x,i10))') ' total',integral,sum(debug_StressLoopLiDistribution(:,1)), & + sum(debug_StressLoopLiDistribution(:,2)) + + integral = 0_pInt + write(6,'(2/,a)') 'distribution_CrystalliteStateLoop :' + do j=1_pInt,nState+1_pInt + if (any(debug_StateLoopDistribution(j,:) /= 0)) then + integral = integral + j*(debug_StateLoopDistribution(j,1) + debug_StateLoopDistribution(j,2)) + exceed = ' ' + if (j > nState) exceed = '+' ! last entry gets "+" + write(6,'(i25,a1,i10,1x,i10)') min(nState,j),exceed,debug_StateLoopDistribution(j,1),& + debug_StateLoopDistribution(j,2) + endif + enddo + write(6,'(a15,i10,2(1x,i10))') ' total',integral,sum(debug_StateLoopDistribution(:,1)), & + sum(debug_StateLoopDistribution(:,2)) + + integral = 0_pInt + write(6,'(2/,a)') 'distribution_CrystalliteCutbackLoop :' + do j=1_pInt,nCryst+1_pInt + if (debug_CrystalliteLoopDistribution(j) /= 0) then + integral = integral + j*debug_CrystalliteLoopDistribution(j) + exceed = ' ' + if (j > nCryst) exceed = '+' + write(6,'(i25,a1,i10)') min(nCryst,j),exceed,debug_CrystalliteLoopDistribution(j) + endif + enddo + write(6,'(a15,i10,1x,i10)') ' total',integral,sum(debug_CrystalliteLoopDistribution) + endif debugOutputCryst + + debugOutputHomog: if (iand(debug_level(debug_HOMOGENIZATION),debug_LEVELBASIC) /= 0) then + integral = 0_pInt + write(6,'(2/,a)') 'distribution_MaterialpointStateLoop :' + do j=1_pInt,nMPstate + if (debug_MaterialpointStateLoopDistribution(j) /= 0) then + integral = integral + j*debug_MaterialpointStateLoopDistribution(j) + write(6,'(i25,1x,i10)') j,debug_MaterialpointStateLoopDistribution(j) + endif + enddo + write(6,'(a15,i10,1x,i10)') ' total',integral,sum(debug_MaterialpointStateLoopDistribution) + + integral = 0_pInt + write(6,'(2/,a)') 'distribution_MaterialpointCutbackLoop :' + do j=1_pInt,nHomog+1_pInt + if (debug_MaterialpointLoopDistribution(j) /= 0) then + integral = integral + j*debug_MaterialpointLoopDistribution(j) + exceed = ' ' + if (j > nHomog) exceed = '+' + write(6,'(i25,a1,i10)') min(nHomog,j),exceed,debug_MaterialpointLoopDistribution(j) + endif + enddo + write(6,'(a15,i10,1x,i10)') ' total',integral,sum(debug_MaterialpointLoopDistribution) + endif debugOutputHomog + + debugOutputCPFEM: if (iand(debug_level(debug_CPFEM),debug_LEVELBASIC) /= 0) then + write(6,'(2/,a,/)') ' Extreme values of returned stress and jacobian' + write(6,'(a39)') ' value el ip' + write(6,'(a14,1x,e12.3,1x,i6,1x,i4)') ' stress min :', debug_stressMin, debug_stressMinLocation + write(6,'(a14,1x,e12.3,1x,i6,1x,i4)') ' max :', debug_stressMax, debug_stressMaxLocation + write(6,'(a14,1x,e12.3,1x,i6,1x,i4)') ' jacobian min :', debug_jacobianMin, debug_jacobianMinLocation + write(6,'(a14,1x,e12.3,1x,i6,1x,i4,/)') ' max :', debug_jacobianMax, debug_jacobianMaxLocation + endif debugOutputCPFEM + !$OMP END CRITICAL (write2out) + +end subroutine debug_info + +end module debug diff --git a/src/homogenization.f90 b/src/homogenization.f90 new file mode 100644 index 000000000..00186ff06 --- /dev/null +++ b/src/homogenization.f90 @@ -0,0 +1,1396 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Denny Tjahjanto, Max-Planck-Institut für Eisenforschung GmbH +!> @brief homogenization manager, organizing deformation partitioning and stress homogenization +!-------------------------------------------------------------------------------------------------- +module homogenization + use prec, only: & +#ifdef FEM + tOutputData, & +#endif + pInt, & + pReal + +!-------------------------------------------------------------------------------------------------- +! General variables for the homogenization at a material point + implicit none + private + real(pReal), dimension(:,:,:,:), allocatable, public :: & + materialpoint_F0, & !< def grad of IP at start of FE increment + materialpoint_F, & !< def grad of IP to be reached at end of FE increment + materialpoint_P !< first P--K stress of IP + real(pReal), dimension(:,:,:,:,:,:), allocatable, public :: & + materialpoint_dPdF !< tangent of first P--K stress at IP +#ifdef FEM + type(tOutputData), dimension(:), allocatable, public :: & + homogOutput + type(tOutputData), dimension(:,:), allocatable, public :: & + crystalliteOutput, & + phaseOutput +#else + real(pReal), dimension(:,:,:), allocatable, public :: & + materialpoint_results !< results array of material point +#endif + integer(pInt), public, protected :: & + materialpoint_sizeResults, & + homogenization_maxSizePostResults, & + thermal_maxSizePostResults, & + damage_maxSizePostResults, & + vacancyflux_maxSizePostResults, & + porosity_maxSizePostResults, & + hydrogenflux_maxSizePostResults + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + materialpoint_subF0, & !< def grad of IP at beginning of homogenization increment + materialpoint_subF !< def grad of IP to be reached at end of homog inc + real(pReal), dimension(:,:), allocatable, private :: & + materialpoint_subFrac, & + materialpoint_subStep, & + materialpoint_subdt + logical, dimension(:,:), allocatable, private :: & + materialpoint_requested, & + materialpoint_converged + logical, dimension(:,:,:), allocatable, private :: & + materialpoint_doneAndHappy + + public :: & + homogenization_init, & + materialpoint_stressAndItsTangent, & + materialpoint_postResults + private :: & + homogenization_partitionDeformation, & + homogenization_updateState, & + homogenization_averageStressAndItsTangent, & + homogenization_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_init +#ifdef HDF + use hdf5, only: & + HID_T + use IO, only : & + HDF5_mappingHomogenization +#endif + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use math, only: & + math_I3 + use debug, only: & + debug_level, & + debug_homogenization, & + debug_levelBasic, & + debug_e, & + debug_g + use mesh, only: & + mesh_maxNips, & + mesh_NcpElems, & + mesh_element, & + FE_Nips, & + FE_geomtype +#ifdef FEM + use crystallite, only: & + crystallite_sizePostResults +#else + use constitutive, only: & + constitutive_plasticity_maxSizePostResults, & + constitutive_source_maxSizePostResults + use crystallite, only: & + crystallite_maxSizePostResults +#endif + use material + use homogenization_none + use homogenization_isostrain + use homogenization_RGC + use thermal_isothermal + use thermal_adiabatic + use thermal_conduction + use damage_none + use damage_local + use damage_nonlocal + use vacancyflux_isoconc + use vacancyflux_isochempot + use vacancyflux_cahnhilliard + use porosity_none + use porosity_phasefield + use hydrogenflux_isoconc + use hydrogenflux_cahnhilliard + use IO + use numerics, only: & + worldrank + + implicit none + integer(pInt), parameter :: FILEUNIT = 200_pInt + integer(pInt) :: e,i,p + integer(pInt), dimension(:,:), pointer :: thisSize + integer(pInt), dimension(:) , pointer :: thisNoutput + character(len=64), dimension(:,:), pointer :: thisOutput + character(len=32) :: outputName !< name of output, intermediate fix until HDF5 output is ready + logical :: knownHomogenization, knownThermal, knownDamage, knownVacancyflux, knownPorosity, knownHydrogenflux +#ifdef HDF + integer(pInt), dimension(:,:), allocatable :: mapping + integer(pInt), dimension(:), allocatable :: InstancePosition + allocate(mapping(mesh_ncpelems,4),source=0_pInt) + allocate(InstancePosition(material_Nhomogenization),source=0_pInt) +#endif + + +!-------------------------------------------------------------------------------------------------- +! open material.config + if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... + call IO_open_file(FILEUNIT,material_configFile) ! ... open material.config file + +!-------------------------------------------------------------------------------------------------- +! parse homogenization from config file + if (any(homogenization_type == HOMOGENIZATION_NONE_ID)) & + call homogenization_none_init() + if (any(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID)) & + call homogenization_isostrain_init(FILEUNIT) + if (any(homogenization_type == HOMOGENIZATION_RGC_ID)) & + call homogenization_RGC_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse thermal from config file + call IO_checkAndRewind(FILEUNIT) + if (any(thermal_type == THERMAL_isothermal_ID)) & + call thermal_isothermal_init() + if (any(thermal_type == THERMAL_adiabatic_ID)) & + call thermal_adiabatic_init(FILEUNIT) + if (any(thermal_type == THERMAL_conduction_ID)) & + call thermal_conduction_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse damage from config file + call IO_checkAndRewind(FILEUNIT) + if (any(damage_type == DAMAGE_none_ID)) & + call damage_none_init() + if (any(damage_type == DAMAGE_local_ID)) & + call damage_local_init(FILEUNIT) + if (any(damage_type == DAMAGE_nonlocal_ID)) & + call damage_nonlocal_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse vacancy transport from config file + call IO_checkAndRewind(FILEUNIT) + if (any(vacancyflux_type == VACANCYFLUX_isoconc_ID)) & + call vacancyflux_isoconc_init() + if (any(vacancyflux_type == VACANCYFLUX_isochempot_ID)) & + call vacancyflux_isochempot_init(FILEUNIT) + if (any(vacancyflux_type == VACANCYFLUX_cahnhilliard_ID)) & + call vacancyflux_cahnhilliard_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse porosity from config file + call IO_checkAndRewind(FILEUNIT) + if (any(porosity_type == POROSITY_none_ID)) & + call porosity_none_init() + if (any(porosity_type == POROSITY_phasefield_ID)) & + call porosity_phasefield_init(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! parse hydrogen transport from config file + call IO_checkAndRewind(FILEUNIT) + if (any(hydrogenflux_type == HYDROGENFLUX_isoconc_ID)) & + call hydrogenflux_isoconc_init() + if (any(hydrogenflux_type == HYDROGENFLUX_cahnhilliard_ID)) & + call hydrogenflux_cahnhilliard_init(FILEUNIT) + close(FILEUNIT) + +!-------------------------------------------------------------------------------------------------- +! write description file for homogenization output + mainProcess2: if (worldrank == 0) then + call IO_write_jobFile(FILEUNIT,'outputHomogenization') + do p = 1,material_Nhomogenization + if (any(material_homog == p)) then + i = homogenization_typeInstance(p) ! which instance of this homogenization type + knownHomogenization = .true. ! assume valid + select case(homogenization_type(p)) ! split per homogenization type + case (HOMOGENIZATION_NONE_ID) + outputName = HOMOGENIZATION_NONE_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (HOMOGENIZATION_ISOSTRAIN_ID) + outputName = HOMOGENIZATION_ISOSTRAIN_label + thisNoutput => homogenization_isostrain_Noutput + thisOutput => homogenization_isostrain_output + thisSize => homogenization_isostrain_sizePostResult + case (HOMOGENIZATION_RGC_ID) + outputName = HOMOGENIZATION_RGC_label + thisNoutput => homogenization_RGC_Noutput + thisOutput => homogenization_RGC_output + thisSize => homogenization_RGC_sizePostResult + case default + knownHomogenization = .false. + end select + write(FILEUNIT,'(/,a,/)') '['//trim(homogenization_name(p))//']' + if (knownHomogenization) then + write(FILEUNIT,'(a)') '(type)'//char(9)//trim(outputName) + write(FILEUNIT,'(a,i4)') '(ngrains)'//char(9),homogenization_Ngrains(p) + if (homogenization_type(p) /= HOMOGENIZATION_NONE_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + i = thermal_typeInstance(p) ! which instance of this thermal type + knownThermal = .true. ! assume valid + select case(thermal_type(p)) ! split per thermal type + case (THERMAL_isothermal_ID) + outputName = THERMAL_isothermal_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (THERMAL_adiabatic_ID) + outputName = THERMAL_adiabatic_label + thisNoutput => thermal_adiabatic_Noutput + thisOutput => thermal_adiabatic_output + thisSize => thermal_adiabatic_sizePostResult + case (THERMAL_conduction_ID) + outputName = THERMAL_conduction_label + thisNoutput => thermal_conduction_Noutput + thisOutput => thermal_conduction_output + thisSize => thermal_conduction_sizePostResult + case default + knownThermal = .false. + end select + if (knownThermal) then + write(FILEUNIT,'(a)') '(thermal)'//char(9)//trim(outputName) + if (thermal_type(p) /= THERMAL_isothermal_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + i = damage_typeInstance(p) ! which instance of this damage type + knownDamage = .true. ! assume valid + select case(damage_type(p)) ! split per damage type + case (DAMAGE_none_ID) + outputName = DAMAGE_none_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (DAMAGE_local_ID) + outputName = DAMAGE_local_label + thisNoutput => damage_local_Noutput + thisOutput => damage_local_output + thisSize => damage_local_sizePostResult + case (DAMAGE_nonlocal_ID) + outputName = DAMAGE_nonlocal_label + thisNoutput => damage_nonlocal_Noutput + thisOutput => damage_nonlocal_output + thisSize => damage_nonlocal_sizePostResult + case default + knownDamage = .false. + end select + if (knownDamage) then + write(FILEUNIT,'(a)') '(damage)'//char(9)//trim(outputName) + if (damage_type(p) /= DAMAGE_none_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + i = vacancyflux_typeInstance(p) ! which instance of this vacancy flux type + knownVacancyflux = .true. ! assume valid + select case(vacancyflux_type(p)) ! split per vacancy flux type + case (VACANCYFLUX_isoconc_ID) + outputName = VACANCYFLUX_isoconc_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (VACANCYFLUX_isochempot_ID) + outputName = VACANCYFLUX_isochempot_label + thisNoutput => vacancyflux_isochempot_Noutput + thisOutput => vacancyflux_isochempot_output + thisSize => vacancyflux_isochempot_sizePostResult + case (VACANCYFLUX_cahnhilliard_ID) + outputName = VACANCYFLUX_cahnhilliard_label + thisNoutput => vacancyflux_cahnhilliard_Noutput + thisOutput => vacancyflux_cahnhilliard_output + thisSize => vacancyflux_cahnhilliard_sizePostResult + case default + knownVacancyflux = .false. + end select + if (knownVacancyflux) then + write(FILEUNIT,'(a)') '(vacancyflux)'//char(9)//trim(outputName) + if (vacancyflux_type(p) /= VACANCYFLUX_isoconc_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + i = porosity_typeInstance(p) ! which instance of this porosity type + knownPorosity = .true. ! assume valid + select case(porosity_type(p)) ! split per porosity type + case (POROSITY_none_ID) + outputName = POROSITY_none_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (POROSITY_phasefield_ID) + outputName = POROSITY_phasefield_label + thisNoutput => porosity_phasefield_Noutput + thisOutput => porosity_phasefield_output + thisSize => porosity_phasefield_sizePostResult + case default + knownPorosity = .false. + end select + if (knownPorosity) then + write(FILEUNIT,'(a)') '(porosity)'//char(9)//trim(outputName) + if (porosity_type(p) /= POROSITY_none_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + i = hydrogenflux_typeInstance(p) ! which instance of this hydrogen flux type + knownHydrogenflux = .true. ! assume valid + select case(hydrogenflux_type(p)) ! split per hydrogen flux type + case (HYDROGENFLUX_isoconc_ID) + outputName = HYDROGENFLUX_isoconc_label + thisNoutput => null() + thisOutput => null() + thisSize => null() + case (HYDROGENFLUX_cahnhilliard_ID) + outputName = HYDROGENFLUX_cahnhilliard_label + thisNoutput => hydrogenflux_cahnhilliard_Noutput + thisOutput => hydrogenflux_cahnhilliard_output + thisSize => hydrogenflux_cahnhilliard_sizePostResult + case default + knownHydrogenflux = .false. + end select + if (knownHydrogenflux) then + write(FILEUNIT,'(a)') '(hydrogenflux)'//char(9)//trim(outputName) + if (hydrogenflux_type(p) /= HYDROGENFLUX_isoconc_ID) then + do e = 1,thisNoutput(i) + write(FILEUNIT,'(a,i4)') trim(thisOutput(e,i))//char(9),thisSize(e,i) + enddo + endif + endif + endif + enddo + close(FILEUNIT) + endif mainProcess2 + +!-------------------------------------------------------------------------------------------------- +! allocate and initialize global variables + allocate(materialpoint_dPdF(3,3,3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_F0(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + materialpoint_F0 = spread(spread(math_I3,3,mesh_maxNips),4,mesh_NcpElems) ! initialize to identity + allocate(materialpoint_F(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + materialpoint_F = materialpoint_F0 ! initialize to identity + allocate(materialpoint_subF0(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_subF(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_P(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_subFrac(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_subStep(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_subdt(mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(materialpoint_requested(mesh_maxNips,mesh_NcpElems), source=.false.) + allocate(materialpoint_converged(mesh_maxNips,mesh_NcpElems), source=.true.) + allocate(materialpoint_doneAndHappy(2,mesh_maxNips,mesh_NcpElems), source=.true.) + +!-------------------------------------------------------------------------------------------------- +! allocate and initialize global state and postresutls variables +#ifdef HDF + elementLooping: do e = 1,mesh_NcpElems + myInstance = homogenization_typeInstance(mesh_element(3,e)) + IpLooping: do i = 1,FE_Nips(FE_geomtype(mesh_element(2,e))) + InstancePosition(myInstance) = InstancePosition(myInstance)+1_pInt + mapping(e,1:4) = [instancePosition(myinstance),myinstance,e,i] + enddo IpLooping + enddo elementLooping + call HDF5_mappingHomogenization(mapping) +#endif + + homogenization_maxSizePostResults = 0_pInt + thermal_maxSizePostResults = 0_pInt + damage_maxSizePostResults = 0_pInt + vacancyflux_maxSizePostResults = 0_pInt + porosity_maxSizePostResults = 0_pInt + hydrogenflux_maxSizePostResults = 0_pInt + do p = 1,material_Nhomogenization + homogenization_maxSizePostResults = max(homogenization_maxSizePostResults,homogState (p)%sizePostResults) + thermal_maxSizePostResults = max(thermal_maxSizePostResults, thermalState (p)%sizePostResults) + damage_maxSizePostResults = max(damage_maxSizePostResults ,damageState (p)%sizePostResults) + vacancyflux_maxSizePostResults = max(vacancyflux_maxSizePostResults ,vacancyfluxState (p)%sizePostResults) + porosity_maxSizePostResults = max(porosity_maxSizePostResults ,porosityState (p)%sizePostResults) + hydrogenflux_maxSizePostResults = max(hydrogenflux_maxSizePostResults ,hydrogenfluxState(p)%sizePostResults) + enddo + +#ifdef FEM + allocate(homogOutput (material_Nhomogenization )) + allocate(crystalliteOutput(material_Ncrystallite, homogenization_maxNgrains)) + allocate(phaseOutput (material_Nphase, homogenization_maxNgrains)) + do p = 1, material_Nhomogenization + homogOutput(p)%sizeResults = homogState (p)%sizePostResults + & + thermalState (p)%sizePostResults + & + damageState (p)%sizePostResults + & + vacancyfluxState (p)%sizePostResults + & + porosityState (p)%sizePostResults + & + hydrogenfluxState(p)%sizePostResults + homogOutput(p)%sizeIpCells = count(material_homog==p) + allocate(homogOutput(p)%output(homogOutput(p)%sizeResults,homogOutput(p)%sizeIpCells)) + enddo + do p = 1, material_Ncrystallite; do e = 1, homogenization_maxNgrains + crystalliteOutput(p,e)%sizeResults = crystallite_sizePostResults(p) + crystalliteOutput(p,e)%sizeIpCells = count(microstructure_crystallite(mesh_element(4,:)) == p .and. & + homogenization_Ngrains (mesh_element(3,:)) >= e)*mesh_maxNips + allocate(crystalliteOutput(p,e)%output(crystalliteOutput(p,e)%sizeResults,crystalliteOutput(p,e)%sizeIpCells)) + enddo; enddo + do p = 1, material_Nphase; do e = 1, homogenization_maxNgrains + phaseOutput(p,e)%sizeResults = plasticState (p)%sizePostResults + & + sum(sourceState (p)%p(:)%sizePostResults) + phaseOutput(p,e)%sizeIpCells = count(material_phase(e,:,:) == p) + allocate(phaseOutput(p,e)%output(phaseOutput(p,e)%sizeResults,phaseOutput(p,e)%sizeIpCells)) + enddo; enddo +#else + materialpoint_sizeResults = 1 & ! grain count + + 1 + homogenization_maxSizePostResults & ! homogSize & homogResult + + thermal_maxSizePostResults & + + damage_maxSizePostResults & + + vacancyflux_maxSizePostResults & + + porosity_maxSizePostResults & + + hydrogenflux_maxSizePostResults & + + homogenization_maxNgrains * (1 + crystallite_maxSizePostResults & ! crystallite size & crystallite results + + 1 + constitutive_plasticity_maxSizePostResults & ! constitutive size & constitutive results + + constitutive_source_maxSizePostResults) + allocate(materialpoint_results(materialpoint_sizeResults,mesh_maxNips,mesh_NcpElems)) +#endif + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- homogenization init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then +#ifdef TODO + write(6,'(a32,1x,7(i8,1x))') 'homogenization_state0: ', shape(homogenization_state0) + write(6,'(a32,1x,7(i8,1x))') 'homogenization_subState0: ', shape(homogenization_subState0) + write(6,'(a32,1x,7(i8,1x))') 'homogenization_state: ', shape(homogenization_state) +#endif + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_dPdF: ', shape(materialpoint_dPdF) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_F0: ', shape(materialpoint_F0) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_F: ', shape(materialpoint_F) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subF0: ', shape(materialpoint_subF0) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subF: ', shape(materialpoint_subF) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_P: ', shape(materialpoint_P) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subFrac: ', shape(materialpoint_subFrac) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subStep: ', shape(materialpoint_subStep) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_subdt: ', shape(materialpoint_subdt) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_requested: ', shape(materialpoint_requested) + write(6,'(a32,1x,7(i8,1x))') 'materialpoint_converged: ', shape(materialpoint_converged) + write(6,'(a32,1x,7(i8,1x),/)') 'materialpoint_doneAndHappy: ', shape(materialpoint_doneAndHappy) +#ifndef FEM + write(6,'(a32,1x,7(i8,1x),/)') 'materialpoint_results: ', shape(materialpoint_results) +#endif + write(6,'(a32,1x,7(i8,1x))') 'maxSizePostResults: ', homogenization_maxSizePostResults + endif + flush(6) + + if (debug_g < 1 .or. debug_g > homogenization_Ngrains(mesh_element(3,debug_e))) & + call IO_error(602_pInt,ext_msg='component (grain)') + +end subroutine homogenization_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief parallelized calculation of stress and corresponding tangent at material points +!-------------------------------------------------------------------------------------------------- +subroutine materialpoint_stressAndItsTangent(updateJaco,dt) + use numerics, only: & + subStepMinHomog, & + subStepSizeHomog, & + stepIncreaseHomog, & + nHomog, & + nMPstate + use math, only: & + math_transpose33 + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP, & + terminallyIll + use mesh, only: & + mesh_element + use material, only: & + plasticState, & + sourceState, & + homogState, & + thermalState, & + damageState, & + vacancyfluxState, & + porosityState, & + hydrogenfluxState, & + phase_Nsources, & + mappingHomogenization, & + phaseAt, phasememberAt, & + homogenization_Ngrains + use crystallite, only: & + crystallite_F0, & + crystallite_Fp0, & + crystallite_Fp, & + crystallite_Fi0, & + crystallite_Fi, & + crystallite_Lp0, & + crystallite_Lp, & + crystallite_Li0, & + crystallite_Li, & + crystallite_dPdF, & + crystallite_dPdF0, & + crystallite_Tstar0_v, & + crystallite_Tstar_v, & + crystallite_partionedF0, & + crystallite_partionedF, & + crystallite_partionedFp0, & + crystallite_partionedLp0, & + crystallite_partionedFi0, & + crystallite_partionedLi0, & + crystallite_partioneddPdF0, & + crystallite_partionedTstar0_v, & + crystallite_dt, & + crystallite_requested, & + crystallite_converged, & + crystallite_stressAndItsTangent, & + crystallite_orientations + use debug, only: & + debug_level, & + debug_homogenization, & + debug_levelBasic, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_MaterialpointLoopDistribution, & + debug_MaterialpointStateLoopDistribution + + implicit none + real(pReal), intent(in) :: dt !< time increment + logical, intent(in) :: updateJaco !< initiating Jacobian update + integer(pInt) :: & + NiterationHomog, & + NiterationMPstate, & + g, & !< grain number + i, & !< integration point number + e, & !< element number + mySource, & + myNgrains + +!-------------------------------------------------------------------------------------------------- +! initialize to starting condition + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(/a,i5,1x,i2)') '<< HOMOG >> Material Point start at el ip ', debug_e, debug_i + + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< HOMOG >> F0', & + math_transpose33(materialpoint_F0(1:3,1:3,debug_i,debug_e)) + write(6,'(a,/,3(12x,3(f14.9,1x)/))') '<< HOMOG >> F', & + math_transpose33(materialpoint_F(1:3,1:3,debug_i,debug_e)) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! initialize restoration points of ... + do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNgrains = homogenization_Ngrains(mesh_element(3,e)) + do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e); do g = 1,myNgrains + + plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) = & + plasticState (phaseAt(g,i,e))%state0( :,phasememberAt(g,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) + sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) = & + sourceState(phaseAt(g,i,e))%p(mySource)%state0( :,phasememberAt(g,i,e)) + enddo + + crystallite_partionedFp0(1:3,1:3,g,i,e) = crystallite_Fp0(1:3,1:3,g,i,e) ! ...plastic def grads + crystallite_partionedLp0(1:3,1:3,g,i,e) = crystallite_Lp0(1:3,1:3,g,i,e) ! ...plastic velocity grads + crystallite_partionedFi0(1:3,1:3,g,i,e) = crystallite_Fi0(1:3,1:3,g,i,e) ! ...intermediate def grads + crystallite_partionedLi0(1:3,1:3,g,i,e) = crystallite_Li0(1:3,1:3,g,i,e) ! ...intermediate velocity grads + crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,g,i,e) = crystallite_dPdF0(1:3,1:3,1:3,1:3,g,i,e) ! ...stiffness + crystallite_partionedF0(1:3,1:3,g,i,e) = crystallite_F0(1:3,1:3,g,i,e) ! ...def grads + crystallite_partionedTstar0_v(1:6,g,i,e) = crystallite_Tstar0_v(1:6,g,i,e) ! ...2nd PK stress + + enddo; enddo + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e)) + materialpoint_subF0(1:3,1:3,i,e) = materialpoint_F0(1:3,1:3,i,e) ! ...def grad + materialpoint_subFrac(i,e) = 0.0_pReal + materialpoint_subStep(i,e) = 1.0_pReal/subStepSizeHomog ! <> + materialpoint_converged(i,e) = .false. ! pretend failed step of twice the required size + materialpoint_requested(i,e) = .true. ! everybody requires calculation + endforall + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + homogState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal homogenization state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + thermalState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal thermal state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + damageState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal damage state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + vacancyfluxState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal vacancy transport state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + porosityState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal porosity state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + hydrogenfluxState(mappingHomogenization(2,i,e))%State0( :,mappingHomogenization(1,i,e)) ! ...internal hydrogen transport state + enddo + NiterationHomog = 0_pInt + + cutBackLooping: do while (.not. terminallyIll .and. & + any(materialpoint_subStep(:,FEsolving_execELem(1):FEsolving_execElem(2)) > subStepMinHomog)) + + !$OMP PARALLEL DO PRIVATE(myNgrains) + elementLooping1: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNgrains = homogenization_Ngrains(mesh_element(3,e)) + IpLooping1: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + + converged: if ( materialpoint_converged(i,e) ) then +#ifndef _OPENMP + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i) & + .or. .not. iand(debug_level(debug_homogenization),debug_levelSelective) /= 0_pInt)) then + write(6,'(a,1x,f12.8,1x,a,1x,f12.8,1x,a,i8,1x,i2/)') '<< HOMOG >> winding forward from', & + materialpoint_subFrac(i,e), 'to current materialpoint_subFrac', & + materialpoint_subFrac(i,e)+materialpoint_subStep(i,e),'in materialpoint_stressAndItsTangent at el ip',e,i + endif +#endif + +!--------------------------------------------------------------------------------------------------- +! calculate new subStep and new subFrac + materialpoint_subFrac(i,e) = materialpoint_subFrac(i,e) + materialpoint_subStep(i,e) + !$OMP FLUSH(materialpoint_subFrac) + materialpoint_subStep(i,e) = min(1.0_pReal-materialpoint_subFrac(i,e), & + stepIncreaseHomog*materialpoint_subStep(i,e)) ! introduce flexibility for step increase/acceleration + !$OMP FLUSH(materialpoint_subStep) + + steppingNeeded: if (materialpoint_subStep(i,e) > subStepMinHomog) then + + ! wind forward grain starting point of... + crystallite_partionedF0(1:3,1:3,1:myNgrains,i,e) = & + crystallite_partionedF(1:3,1:3,1:myNgrains,i,e) ! ...def grads + + crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) = & + crystallite_Fp(1:3,1:3,1:myNgrains,i,e) ! ...plastic def grads + + crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) = & + crystallite_Lp(1:3,1:3,1:myNgrains,i,e) ! ...plastic velocity grads + + crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) = & + crystallite_Fi(1:3,1:3,1:myNgrains,i,e) ! ...intermediate def grads + + crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) = & + crystallite_Li(1:3,1:3,1:myNgrains,i,e) ! ...intermediate velocity grads + + crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,1:myNgrains,i,e) = & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:myNgrains,i,e) ! ...stiffness + + crystallite_partionedTstar0_v(1:6,1:myNgrains,i,e) = & + crystallite_Tstar_v(1:6,1:myNgrains,i,e) ! ...2nd PK stress + + do g = 1,myNgrains + plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) = & + plasticState (phaseAt(g,i,e))%state( :,phasememberAt(g,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) + sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) = & + sourceState(phaseAt(g,i,e))%p(mySource)%state( :,phasememberAt(g,i,e)) + enddo + enddo + + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + homogState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal homogenization state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + thermalState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal thermal state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + damageState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) ! ...internal damage state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + vacancyfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal vacancy transport state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + porosityState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal porosity state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) = & + hydrogenfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e))! ...internal hydrogen transport state + materialpoint_subF0(1:3,1:3,i,e) = materialpoint_subF(1:3,1:3,i,e) ! ...def grad + !$OMP FLUSH(materialpoint_subF0) + elseif (materialpoint_requested(i,e)) then steppingNeeded ! already at final time (??) + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionHomog) + debug_MaterialpointLoopDistribution(min(nHomog+1,NiterationHomog)) = & + debug_MaterialpointLoopDistribution(min(nHomog+1,NiterationHomog)) + 1 + !$OMP END CRITICAL (distributionHomog) + endif + endif steppingNeeded + + else converged + if ( (myNgrains == 1_pInt .and. materialpoint_subStep(i,e) <= 1.0 ) .or. & ! single grain already tried internal subStepping in crystallite + subStepSizeHomog * materialpoint_subStep(i,e) <= subStepMinHomog ) then ! would require too small subStep + ! cutback makes no sense + !$OMP FLUSH(terminallyIll) + if (.not. terminallyIll) then ! so first signals terminally ill... + !$OMP CRITICAL (write2out) + write(6,*) 'Integration point ', i,' at element ', e, ' terminally ill' + !$OMP END CRITICAL (write2out) + endif + !$OMP CRITICAL (setTerminallyIll) + terminallyIll = .true. ! ...and kills all others + !$OMP END CRITICAL (setTerminallyIll) + else ! cutback makes sense + materialpoint_subStep(i,e) = subStepSizeHomog * materialpoint_subStep(i,e) ! crystallite had severe trouble, so do a significant cutback + !$OMP FLUSH(materialpoint_subStep) + +#ifndef _OPENMP + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt & + .and. ((e == debug_e .and. i == debug_i) & + .or. .not. iand(debug_level(debug_homogenization), debug_levelSelective) /= 0_pInt)) then + write(6,'(a,1x,f12.8,a,i8,1x,i2/)') & + '<< HOMOG >> cutback step in materialpoint_stressAndItsTangent with new materialpoint_subStep:',& + materialpoint_subStep(i,e),' at el ip',e,i + endif +#endif + +!-------------------------------------------------------------------------------------------------- +! restore... + crystallite_Fp(1:3,1:3,1:myNgrains,i,e) = & + crystallite_partionedFp0(1:3,1:3,1:myNgrains,i,e) ! ...plastic def grads + crystallite_Lp(1:3,1:3,1:myNgrains,i,e) = & + crystallite_partionedLp0(1:3,1:3,1:myNgrains,i,e) ! ...plastic velocity grads + crystallite_Fi(1:3,1:3,1:myNgrains,i,e) = & + crystallite_partionedFi0(1:3,1:3,1:myNgrains,i,e) ! ...intermediate def grads + crystallite_Li(1:3,1:3,1:myNgrains,i,e) = & + crystallite_partionedLi0(1:3,1:3,1:myNgrains,i,e) ! ...intermediate velocity grads + crystallite_dPdF(1:3,1:3,1:3,1:3,1:myNgrains,i,e) = & + crystallite_partioneddPdF0(1:3,1:3,1:3,1:3,1:myNgrains,i,e) ! ...stiffness + crystallite_Tstar_v(1:6,1:myNgrains,i,e) = & + crystallite_partionedTstar0_v(1:6,1:myNgrains,i,e) ! ...2nd PK stress + do g = 1, myNgrains + plasticState (phaseAt(g,i,e))%state( :,phasememberAt(g,i,e)) = & + plasticState (phaseAt(g,i,e))%partionedState0(:,phasememberAt(g,i,e)) + do mySource = 1_pInt, phase_Nsources(phaseAt(g,i,e)) + sourceState(phaseAt(g,i,e))%p(mySource)%state( :,phasememberAt(g,i,e)) = & + sourceState(phaseAt(g,i,e))%p(mySource)%partionedState0(:,phasememberAt(g,i,e)) + enddo + enddo + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + homogState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + homogState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + homogState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal homogenization state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + thermalState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + thermalState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + thermalState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal thermal state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + damageState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + damageState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + damageState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e)) ! ...internal damage state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + vacancyfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + vacancyfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + vacancyfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal vacancy transport state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + porosityState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + porosityState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + porosityState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal porosity state + forall(i = FEsolving_execIP(1,e):FEsolving_execIP(2,e), & + hydrogenfluxState(mappingHomogenization(2,i,e))%sizeState > 0_pInt) & + hydrogenfluxState(mappingHomogenization(2,i,e))%State( :,mappingHomogenization(1,i,e)) = & + hydrogenfluxState(mappingHomogenization(2,i,e))%subState0(:,mappingHomogenization(1,i,e))! ...internal hydrogen transport state + endif + endif converged + + if (materialpoint_subStep(i,e) > subStepMinHomog) then + materialpoint_requested(i,e) = .true. + materialpoint_subF(1:3,1:3,i,e) = materialpoint_subF0(1:3,1:3,i,e) + & + materialpoint_subStep(i,e) * (materialpoint_F(1:3,1:3,i,e) - materialpoint_F0(1:3,1:3,i,e)) + materialpoint_subdt(i,e) = materialpoint_subStep(i,e) * dt + materialpoint_doneAndHappy(1:2,i,e) = [.false.,.true.] + endif + enddo IpLooping1 + enddo elementLooping1 + !$OMP END PARALLEL DO + + NiterationMPstate = 0_pInt + + convergenceLooping: do while (.not. terminallyIll .and. & + any( materialpoint_requested(:,FEsolving_execELem(1):FEsolving_execElem(2)) & + .and. .not. materialpoint_doneAndHappy(1,:,FEsolving_execELem(1):FEsolving_execElem(2)) & + ) .and. & + NiterationMPstate < nMPstate) + NiterationMPstate = NiterationMPstate + 1 + +!-------------------------------------------------------------------------------------------------- +! deformation partitioning +! based on materialpoint_subF0,.._subF,crystallite_partionedF0, and homogenization_state, +! results in crystallite_partionedF + !$OMP PARALLEL DO PRIVATE(myNgrains) + elementLooping2: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNgrains = homogenization_Ngrains(mesh_element(3,e)) + IpLooping2: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if ( materialpoint_requested(i,e) .and. & ! process requested but... + .not. materialpoint_doneAndHappy(1,i,e)) then ! ...not yet done material points + call homogenization_partitionDeformation(i,e) ! partition deformation onto constituents + crystallite_dt(1:myNgrains,i,e) = materialpoint_subdt(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 +! based on crystallite_partionedF0,.._partionedF +! incrementing by crystallite_dt + call crystallite_stressAndItsTangent(updateJaco) ! request stress and tangent calculation for constituent grains + +!-------------------------------------------------------------------------------------------------- +! state update + !$OMP PARALLEL DO + elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) + IpLooping3: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + if ( materialpoint_requested(i,e) .and. & + .not. materialpoint_doneAndHappy(1,i,e)) then + if (.not. all(crystallite_converged(:,i,e))) then + materialpoint_doneAndHappy(1:2,i,e) = [.true.,.false.] + materialpoint_converged(i,e) = .false. + else + materialpoint_doneAndHappy(1:2,i,e) = homogenization_updateState(i,e) + materialpoint_converged(i,e) = all(materialpoint_doneAndHappy(1:2,i,e)) ! converged if done and happy + endif + !$OMP FLUSH(materialpoint_converged) + if (materialpoint_converged(i,e)) then + if (iand(debug_level(debug_homogenization), debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (distributionMPState) + debug_MaterialpointStateLoopdistribution(NiterationMPstate) = & + debug_MaterialpointStateLoopdistribution(NiterationMPstate) + 1_pInt + !$OMP END CRITICAL (distributionMPState) + endif + endif + endif + enddo IpLooping3 + enddo elementLooping3 + !$OMP END PARALLEL DO + + enddo convergenceLooping + + NiterationHomog = NiterationHomog + 1_pInt + + enddo cutBackLooping + + 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,e),FEsolving_execIP(2,e) + call homogenization_averageStressAndItsTangent(i,e) + enddo IpLooping4 + enddo elementLooping4 + !$OMP END PARALLEL DO + else + !$OMP CRITICAL (write2out) + write(6,'(/,a,/)') '<< HOMOG >> Material Point terminally ill' + !$OMP END CRITICAL (write2out) + endif + +end subroutine materialpoint_stressAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief parallelized calculation of result array at material points +!-------------------------------------------------------------------------------------------------- +subroutine materialpoint_postResults + use FEsolving, only: & + FEsolving_execElem, & + FEsolving_execIP + use mesh, only: & + mesh_element + use material, only: & + mappingHomogenization, & +#ifdef FEM + phaseAt, phasememberAt, & + homogenization_maxNgrains, & + material_Ncrystallite, & + material_Nphase, & +#else + homogState, & + thermalState, & + damageState, & + vacancyfluxState, & + porosityState, & + hydrogenfluxState, & +#endif + plasticState, & + sourceState, & + material_phase, & + homogenization_Ngrains, & + microstructure_crystallite + use constitutive, only: & +#ifdef FEM + constitutive_plasticity_maxSizePostResults, & + constitutive_source_maxSizePostResults, & +#endif + constitutive_postResults + use crystallite, only: & +#ifdef FEM + crystallite_maxSizePostResults, & +#endif + crystallite_sizePostResults, & + crystallite_postResults + + implicit none + integer(pInt) :: & + thePos, & + theSize, & + myNgrains, & + myCrystallite, & + g, & !< grain number + i, & !< integration point number + e !< element number +#ifdef FEM + integer(pInt) :: & + myHomog, & + myPhase, & + crystalliteCtr(material_Ncrystallite, homogenization_maxNgrains), & + phaseCtr (material_Nphase, homogenization_maxNgrains) + real(pReal), dimension(1+crystallite_maxSizePostResults + & + 1+constitutive_plasticity_maxSizePostResults + & + constitutive_source_maxSizePostResults) :: & + crystalliteResults + + + + crystalliteCtr = 0_pInt; phaseCtr = 0_pInt + elementLooping: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNgrains = homogenization_Ngrains(mesh_element(3,e)) + myCrystallite = microstructure_crystallite(mesh_element(4,e)) + IpLooping: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + myHomog = mappingHomogenization(2,i,e) + thePos = mappingHomogenization(1,i,e) + homogOutput(myHomog)%output(1: & + homogOutput(myHomog)%sizeResults, & + thePos) = homogenization_postResults(i,e) + + grainLooping :do g = 1,myNgrains + myPhase = phaseAt(g,i,e) + crystalliteResults(1:1+crystallite_sizePostResults(myCrystallite) + & + 1+plasticState(myPhase)%sizePostResults + & + sum(sourceState(myPhase)%p(:)%sizePostResults)) = crystallite_postResults(g,i,e) + if (microstructure_crystallite(mesh_element(4,e)) == myCrystallite .and. & + homogenization_Ngrains (mesh_element(3,e)) >= g) then + crystalliteCtr(myCrystallite,g) = crystalliteCtr(myCrystallite,g) + 1_pInt + crystalliteOutput(myCrystallite,g)% & + output(1:crystalliteOutput(myCrystallite,g)%sizeResults,crystalliteCtr(myCrystallite,g)) = & + crystalliteResults(2:1+crystalliteOutput(myCrystallite,g)%sizeResults) + endif + if (material_phase(g,i,e) == myPhase) then + phaseCtr(myPhase,g) = phaseCtr(myPhase,g) + 1_pInt + phaseOutput(myPhase,g)% & + output(1:phaseOutput(myPhase,g)%sizeResults,phaseCtr(myPhase,g)) = & + crystalliteResults(3 + crystalliteOutput(myCrystallite,g)%sizeResults: & + 1 + crystalliteOutput(myCrystallite,g)%sizeResults + & + 1 + plasticState (myphase)%sizePostResults + & + sum(sourceState(myphase)%p(:)%sizePostResults)) + endif + enddo grainLooping + enddo IpLooping + enddo elementLooping +#else + + !$OMP PARALLEL DO PRIVATE(myNgrains,myCrystallite,thePos,theSize) + elementLooping: do e = FEsolving_execElem(1),FEsolving_execElem(2) + myNgrains = homogenization_Ngrains(mesh_element(3,e)) + myCrystallite = microstructure_crystallite(mesh_element(4,e)) + IpLooping: do i = FEsolving_execIP(1,e),FEsolving_execIP(2,e) + thePos = 0_pInt + + theSize = homogState (mappingHomogenization(2,i,e))%sizePostResults & + + thermalState (mappingHomogenization(2,i,e))%sizePostResults & + + damageState (mappingHomogenization(2,i,e))%sizePostResults & + + vacancyfluxState (mappingHomogenization(2,i,e))%sizePostResults & + + porosityState (mappingHomogenization(2,i,e))%sizePostResults & + + hydrogenfluxState(mappingHomogenization(2,i,e))%sizePostResults + materialpoint_results(thePos+1,i,e) = real(theSize,pReal) ! tell size of homogenization results + thePos = thePos + 1_pInt + + if (theSize > 0_pInt) then ! any homogenization results to mention? + materialpoint_results(thePos+1:thePos+theSize,i,e) = homogenization_postResults(i,e) ! tell homogenization results + thePos = thePos + theSize + endif + + materialpoint_results(thePos+1,i,e) = real(myNgrains,pReal) ! tell number of grains at materialpoint + thePos = thePos + 1_pInt + + grainLooping :do g = 1,myNgrains + theSize = 1 + crystallite_sizePostResults(myCrystallite) + & + 1 + plasticState (material_phase(g,i,e))%sizePostResults + & !ToDo + sum(sourceState(material_phase(g,i,e))%p(:)%sizePostResults) + materialpoint_results(thePos+1:thePos+theSize,i,e) = crystallite_postResults(g,i,e) ! tell crystallite results + thePos = thePos + theSize + enddo grainLooping + enddo IpLooping + enddo elementLooping + !$OMP END PARALLEL DO +#endif + +end subroutine materialpoint_postResults + + +!-------------------------------------------------------------------------------------------------- +!> @brief partition material point def grad onto constituents +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_partitionDeformation(ip,el) + use mesh, only: & + mesh_element + use material, only: & + homogenization_type, & + homogenization_maxNgrains, & + HOMOGENIZATION_NONE_ID, & + HOMOGENIZATION_ISOSTRAIN_ID, & + HOMOGENIZATION_RGC_ID + use crystallite, only: & + crystallite_partionedF + use homogenization_isostrain, only: & + homogenization_isostrain_partitionDeformation + use homogenization_RGC, only: & + homogenization_RGC_partitionDeformation + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element number + + chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) + + case (HOMOGENIZATION_NONE_ID) chosenHomogenization + crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el) = 0.0_pReal + crystallite_partionedF(1:3,1:3,1:1,ip,el) = & + spread(materialpoint_subF(1:3,1:3,ip,el),3,1) + + case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization + call homogenization_isostrain_partitionDeformation(& + crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + materialpoint_subF(1:3,1:3,ip,el),& + el) + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + call homogenization_RGC_partitionDeformation(& + crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + materialpoint_subF(1:3,1:3,ip,el),& + ip, & + el) + end select chosenHomogenization + +end subroutine homogenization_partitionDeformation + + +!-------------------------------------------------------------------------------------------------- +!> @brief update the internal state of the homogenization scheme and tell whether "done" and +!> "happy" with result +!-------------------------------------------------------------------------------------------------- +function homogenization_updateState(ip,el) + use mesh, only: & + mesh_element + use material, only: & + homogenization_type, & + thermal_type, & + damage_type, & + vacancyflux_type, & + homogenization_maxNgrains, & + HOMOGENIZATION_RGC_ID, & + THERMAL_adiabatic_ID, & + DAMAGE_local_ID, & + VACANCYFLUX_isochempot_ID + use crystallite, only: & + crystallite_P, & + crystallite_dPdF, & + crystallite_partionedF,& + crystallite_partionedF0 + use homogenization_RGC, only: & + homogenization_RGC_updateState + use thermal_adiabatic, only: & + thermal_adiabatic_updateState + use damage_local, only: & + damage_local_updateState + use vacancyflux_isochempot, only: & + vacancyflux_isochempot_updateState + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element number + logical, dimension(2) :: homogenization_updateState + + homogenization_updateState = .true. + chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + homogenization_updateState = & + homogenization_updateState .and. & + homogenization_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + crystallite_partionedF(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + crystallite_partionedF0(1:3,1:3,1:homogenization_maxNgrains,ip,el),& + materialpoint_subF(1:3,1:3,ip,el),& + materialpoint_subdt(ip,el), & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & + ip, & + el) + end select chosenHomogenization + + chosenThermal: select case (thermal_type(mesh_element(3,el))) + case (THERMAL_adiabatic_ID) chosenThermal + homogenization_updateState = & + homogenization_updateState .and. & + thermal_adiabatic_updateState(materialpoint_subdt(ip,el), & + ip, & + el) + end select chosenThermal + + chosenDamage: select case (damage_type(mesh_element(3,el))) + case (DAMAGE_local_ID) chosenDamage + homogenization_updateState = & + homogenization_updateState .and. & + damage_local_updateState(materialpoint_subdt(ip,el), & + ip, & + el) + end select chosenDamage + + chosenVacancyflux: select case (vacancyflux_type(mesh_element(3,el))) + case (VACANCYFLUX_isochempot_ID) chosenVacancyflux + homogenization_updateState = & + homogenization_updateState .and. & + vacancyflux_isochempot_updateState(materialpoint_subdt(ip,el), & + ip, & + el) + end select chosenVacancyflux + +end function homogenization_updateState + + +!-------------------------------------------------------------------------------------------------- +!> @brief derive average stress and stiffness from constituent quantities +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_averageStressAndItsTangent(ip,el) + use mesh, only: & + mesh_element + use material, only: & + homogenization_type, & + homogenization_maxNgrains, & + HOMOGENIZATION_NONE_ID, & + HOMOGENIZATION_ISOSTRAIN_ID, & + HOMOGENIZATION_RGC_ID + use crystallite, only: & + crystallite_P,crystallite_dPdF + use homogenization_isostrain, only: & + homogenization_isostrain_averageStressAndItsTangent + use homogenization_RGC, only: & + homogenization_RGC_averageStressAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element number + + chosenHomogenization: select case(homogenization_type(mesh_element(3,el))) + case (HOMOGENIZATION_NONE_ID) chosenHomogenization + materialpoint_P(1:3,1:3,ip,el) = sum(crystallite_P(1:3,1:3,1:1,ip,el),3) + materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el) & + = sum(crystallite_dPdF(1:3,1:3,1:3,1:3,1:1,ip,el),5) + + case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization + call homogenization_isostrain_averageStressAndItsTangent(& + materialpoint_P(1:3,1:3,ip,el), & + materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& + crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & + el) + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + call homogenization_RGC_averageStressAndItsTangent(& + materialpoint_P(1:3,1:3,ip,el), & + materialpoint_dPdF(1:3,1:3,1:3,1:3,ip,el),& + crystallite_P(1:3,1:3,1:homogenization_maxNgrains,ip,el), & + crystallite_dPdF(1:3,1:3,1:3,1:3,1:homogenization_maxNgrains,ip,el), & + el) + end select chosenHomogenization + +end subroutine homogenization_averageStressAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of homogenization results for post file inclusion. call only, +!> if homogenization_sizePostResults(i,e) > 0 !! +!-------------------------------------------------------------------------------------------------- +function homogenization_postResults(ip,el) + use mesh, only: & + mesh_element + use material, only: & + mappingHomogenization, & + homogState, & + thermalState, & + damageState, & + vacancyfluxState, & + porosityState, & + hydrogenfluxState, & + homogenization_type, & + thermal_type, & + damage_type, & + vacancyflux_type, & + porosity_type, & + hydrogenflux_type, & + HOMOGENIZATION_NONE_ID, & + HOMOGENIZATION_ISOSTRAIN_ID, & + HOMOGENIZATION_RGC_ID, & + THERMAL_isothermal_ID, & + THERMAL_adiabatic_ID, & + THERMAL_conduction_ID, & + DAMAGE_none_ID, & + DAMAGE_local_ID, & + DAMAGE_nonlocal_ID, & + VACANCYFLUX_isoconc_ID, & + VACANCYFLUX_isochempot_ID, & + VACANCYFLUX_cahnhilliard_ID, & + POROSITY_none_ID, & + POROSITY_phasefield_ID, & + HYDROGENFLUX_isoconc_ID, & + HYDROGENFLUX_cahnhilliard_ID + use homogenization_isostrain, only: & + homogenization_isostrain_postResults + use homogenization_RGC, only: & + homogenization_RGC_postResults + use thermal_adiabatic, only: & + thermal_adiabatic_postResults + use thermal_conduction, only: & + thermal_conduction_postResults + use damage_local, only: & + damage_local_postResults + use damage_nonlocal, only: & + damage_nonlocal_postResults + use vacancyflux_isochempot, only: & + vacancyflux_isochempot_postResults + use vacancyflux_cahnhilliard, only: & + vacancyflux_cahnhilliard_postResults + use porosity_phasefield, only: & + porosity_phasefield_postResults + use hydrogenflux_cahnhilliard, only: & + hydrogenflux_cahnhilliard_postResults + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element number + real(pReal), dimension( homogState (mappingHomogenization(2,ip,el))%sizePostResults & + + thermalState (mappingHomogenization(2,ip,el))%sizePostResults & + + damageState (mappingHomogenization(2,ip,el))%sizePostResults & + + vacancyfluxState (mappingHomogenization(2,ip,el))%sizePostResults & + + porosityState (mappingHomogenization(2,ip,el))%sizePostResults & + + hydrogenfluxState(mappingHomogenization(2,ip,el))%sizePostResults) :: & + homogenization_postResults + integer(pInt) :: & + startPos, endPos + + homogenization_postResults = 0.0_pReal + + startPos = 1_pInt + endPos = homogState(mappingHomogenization(2,ip,el))%sizePostResults + chosenHomogenization: select case (homogenization_type(mesh_element(3,el))) + case (HOMOGENIZATION_NONE_ID) chosenHomogenization + + case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization + homogenization_postResults(startPos:endPos) = & + homogenization_isostrain_postResults(& + ip, & + el, & + materialpoint_P(1:3,1:3,ip,el), & + materialpoint_F(1:3,1:3,ip,el)) + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + homogenization_postResults(startPos:endPos) = & + homogenization_RGC_postResults(& + ip, & + el, & + materialpoint_P(1:3,1:3,ip,el), & + materialpoint_F(1:3,1:3,ip,el)) + end select chosenHomogenization + + startPos = endPos + 1_pInt + endPos = endPos + thermalState(mappingHomogenization(2,ip,el))%sizePostResults + chosenThermal: select case (thermal_type(mesh_element(3,el))) + case (THERMAL_isothermal_ID) chosenThermal + + case (THERMAL_adiabatic_ID) chosenThermal + homogenization_postResults(startPos:endPos) = & + thermal_adiabatic_postResults(ip, el) + case (THERMAL_conduction_ID) chosenThermal + homogenization_postResults(startPos:endPos) = & + thermal_conduction_postResults(ip, el) + end select chosenThermal + + startPos = endPos + 1_pInt + endPos = endPos + damageState(mappingHomogenization(2,ip,el))%sizePostResults + chosenDamage: select case (damage_type(mesh_element(3,el))) + case (DAMAGE_none_ID) chosenDamage + + case (DAMAGE_local_ID) chosenDamage + homogenization_postResults(startPos:endPos) = & + damage_local_postResults(ip, el) + + case (DAMAGE_nonlocal_ID) chosenDamage + homogenization_postResults(startPos:endPos) = & + damage_nonlocal_postResults(ip, el) + end select chosenDamage + + startPos = endPos + 1_pInt + endPos = endPos + vacancyfluxState(mappingHomogenization(2,ip,el))%sizePostResults + chosenVacancyflux: select case (vacancyflux_type(mesh_element(3,el))) + case (VACANCYFLUX_isoconc_ID) chosenVacancyflux + + case (VACANCYFLUX_isochempot_ID) chosenVacancyflux + homogenization_postResults(startPos:endPos) = & + vacancyflux_isochempot_postResults(ip, el) + case (VACANCYFLUX_cahnhilliard_ID) chosenVacancyflux + homogenization_postResults(startPos:endPos) = & + vacancyflux_cahnhilliard_postResults(ip, el) + end select chosenVacancyflux + + startPos = endPos + 1_pInt + endPos = endPos + porosityState(mappingHomogenization(2,ip,el))%sizePostResults + chosenPorosity: select case (porosity_type(mesh_element(3,el))) + case (POROSITY_none_ID) chosenPorosity + + case (POROSITY_phasefield_ID) chosenPorosity + homogenization_postResults(startPos:endPos) = & + porosity_phasefield_postResults(ip, el) + end select chosenPorosity + + startPos = endPos + 1_pInt + endPos = endPos + hydrogenfluxState(mappingHomogenization(2,ip,el))%sizePostResults + chosenHydrogenflux: select case (hydrogenflux_type(mesh_element(3,el))) + case (HYDROGENFLUX_isoconc_ID) chosenHydrogenflux + + case (HYDROGENFLUX_cahnhilliard_ID) chosenHydrogenflux + homogenization_postResults(startPos:endPos) = & + hydrogenflux_cahnhilliard_postResults(ip, el) + end select chosenHydrogenflux + +end function homogenization_postResults + +end module homogenization diff --git a/src/homogenization_RGC.f90 b/src/homogenization_RGC.f90 new file mode 100644 index 000000000..323ca2934 --- /dev/null +++ b/src/homogenization_RGC.f90 @@ -0,0 +1,1558 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Denny Tjahjanto, 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 +!> @brief Relaxed grain cluster (RGC) homogenization scheme +!> Ngrains is defined as p x q x r (cluster) +!-------------------------------------------------------------------------------------------------- +module homogenization_RGC + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public :: & + homogenization_RGC_sizeState, & + homogenization_RGC_sizePostResults + integer(pInt), dimension(:,:), allocatable,target, public :: & + homogenization_RGC_sizePostResult + character(len=64), dimension(:,:), allocatable,target, public :: & + homogenization_RGC_output ! name of each post result output + integer(pInt), dimension(:), allocatable,target, public :: & + homogenization_RGC_Noutput !< number of outputs per homog instance + integer(pInt), dimension(:,:), allocatable, private :: & + homogenization_RGC_Ngrains + real(pReal), dimension(:,:), allocatable, private :: & + homogenization_RGC_dAlpha, & + homogenization_RGC_angles + real(pReal), dimension(:,:,:,:), allocatable, private :: & + homogenization_RGC_orientation + real(pReal), dimension(:), allocatable, private :: & + homogenization_RGC_xiAlpha, & + homogenization_RGC_ciAlpha + enum, bind(c) + enumerator :: undefined_ID, & + constitutivework_ID, & + penaltyenergy_ID, & + volumediscrepancy_ID, & + averagerelaxrate_ID,& + maximumrelaxrate_ID,& + ipcoords_ID,& + magnitudemismatch_ID,& + avgdefgrad_ID,& + avgfirstpiola_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + homogenization_RGC_outputID !< ID of each post result output + + public :: & + homogenization_RGC_init, & + homogenization_RGC_partitionDeformation, & + homogenization_RGC_averageStressAndItsTangent, & + homogenization_RGC_updateState, & + homogenization_RGC_postResults + private :: & + homogenization_RGC_stressPenalty, & + homogenization_RGC_volumePenalty, & + homogenization_RGC_grainDeformation, & + homogenization_RGC_surfaceCorrection, & + homogenization_RGC_equivalentModuli, & + homogenization_RGC_relaxationVector, & + homogenization_RGC_interfaceNormal, & + homogenization_RGC_getInterface, & + homogenization_RGC_grain1to3, & + homogenization_RGC_grain3to1, & + homogenization_RGC_interface4to1, & + homogenization_RGC_interface1to4 + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use debug, only: & + debug_level, & + debug_homogenization, & + debug_levelBasic, & + debug_levelExtensive + use math, only: & + math_Mandel3333to66,& + math_Voigt66to3333, & + math_I3, & + math_sampleRandomOri,& + math_EulerToR,& + INRAD + use mesh, only: & + mesh_maxNips, & + mesh_NcpElems,& + mesh_element, & + FE_Nips, & + FE_geomtype + use IO + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit !< file pointer to material configuration + integer(pInt), allocatable, dimension(:) :: chunkPos + integer :: & + homog, & + NofMyHomog, & + o, & + instance, & + sizeHState + integer(pInt) :: section=0_pInt, maxNinstance, i,j,e, mySize, myInstance + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_RGC_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(homogenization_type == HOMOGENIZATION_RGC_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_HOMOGENIZATION),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + allocate(homogenization_RGC_sizeState(maxNinstance), source=0_pInt) + allocate(homogenization_RGC_sizePostResults(maxNinstance), source=0_pInt) + allocate(homogenization_RGC_Noutput(maxNinstance), source=0_pInt) + allocate(homogenization_RGC_Ngrains(3,maxNinstance), source=0_pInt) + allocate(homogenization_RGC_ciAlpha(maxNinstance), source=0.0_pReal) + allocate(homogenization_RGC_xiAlpha(maxNinstance), source=0.0_pReal) + allocate(homogenization_RGC_dAlpha(3,maxNinstance), source=0.0_pReal) + allocate(homogenization_RGC_angles(3,maxNinstance), source=400.0_pReal) + allocate(homogenization_RGC_output(maxval(homogenization_Noutput),maxNinstance)) + homogenization_RGC_output='' + allocate(homogenization_RGC_outputID(maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(homogenization_RGC_sizePostResult(maxval(homogenization_Noutput),maxNinstance),& + source=0_pInt) + allocate(homogenization_RGC_orientation(3,3,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + homogenization_RGC_orientation = spread(spread(math_I3,3,mesh_maxNips),4,mesh_NcpElems) ! initialize to identity + + rewind(fileUnit) + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>'))/=material_partHomogenization) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homogenization part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + cycle + endif + if (section > 0_pInt ) then ! do not short-circuit here (.and. with next if-statement). It's not safe in Fortran + if (homogenization_type(section) == HOMOGENIZATION_RGC_ID) then ! one of my sections + i = homogenization_typeInstance(section) ! which instance of my type is present homogenization + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case('constitutivework') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = constitutivework_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('penaltyenergy') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = penaltyenergy_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('volumediscrepancy') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = volumediscrepancy_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('averagerelaxrate') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = averagerelaxrate_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('maximumrelaxrate') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = maximumrelaxrate_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('magnitudemismatch') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = magnitudemismatch_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('ipcoords') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = ipcoords_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('avgdefgrad','avgf') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = avgdefgrad_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('avgp','avgfirstpiola','avg1stpiola') + homogenization_RGC_Noutput(i) = homogenization_RGC_Noutput(i) + 1_pInt + homogenization_RGC_outputID(homogenization_RGC_Noutput(i),i) = avgfirstpiola_ID + homogenization_RGC_output(homogenization_RGC_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + + end select + case ('clustersize') + homogenization_RGC_Ngrains(1,i) = IO_intValue(line,chunkPos,2_pInt) + homogenization_RGC_Ngrains(2,i) = IO_intValue(line,chunkPos,3_pInt) + homogenization_RGC_Ngrains(3,i) = IO_intValue(line,chunkPos,4_pInt) + if (homogenization_Ngrains(section) /= product(homogenization_RGC_Ngrains(1:3,i))) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//HOMOGENIZATION_RGC_label//')') + case ('scalingparameter') + homogenization_RGC_xiAlpha(i) = IO_floatValue(line,chunkPos,2_pInt) + case ('overproportionality') + homogenization_RGC_ciAlpha(i) = IO_floatValue(line,chunkPos,2_pInt) + case ('grainsize') + homogenization_RGC_dAlpha(1,i) = IO_floatValue(line,chunkPos,2_pInt) + homogenization_RGC_dAlpha(2,i) = IO_floatValue(line,chunkPos,3_pInt) + homogenization_RGC_dAlpha(3,i) = IO_floatValue(line,chunkPos,4_pInt) + case ('clusterorientation') + homogenization_RGC_angles(1,i) = IO_floatValue(line,chunkPos,2_pInt) + homogenization_RGC_angles(2,i) = IO_floatValue(line,chunkPos,3_pInt) + homogenization_RGC_angles(3,i) = IO_floatValue(line,chunkPos,4_pInt) + + end select + endif + endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! * assigning cluster orientations + elementLooping: do e = 1_pInt,mesh_NcpElems + if (homogenization_type(mesh_element(3,e)) == HOMOGENIZATION_RGC_ID) then + myInstance = homogenization_typeInstance(mesh_element(3,e)) + if (all (homogenization_RGC_angles(1:3,myInstance) >= 399.9_pReal)) then + homogenization_RGC_orientation(1:3,1:3,1,e) = math_EulerToR(math_sampleRandomOri()) + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + if (microstructure_elemhomo(mesh_element(4,e))) then + homogenization_RGC_orientation(1:3,1:3,i,e) = homogenization_RGC_orientation(1:3,1:3,1,e) + else + homogenization_RGC_orientation(1:3,1:3,i,e) = math_EulerToR(math_sampleRandomOri()) + endif + enddo + else + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + homogenization_RGC_orientation(1:3,1:3,i,e) = & + math_EulerToR(homogenization_RGC_angles(1:3,myInstance)*inRad) + enddo + endif + endif + enddo elementLooping + + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + do i = 1_pInt,maxNinstance + write(6,'(a15,1x,i4,/)') 'instance: ', i + write(6,'(a25,3(1x,i8))') 'cluster size: ',(homogenization_RGC_Ngrains(j,i),j=1_pInt,3_pInt) + write(6,'(a25,1x,e10.3)') 'scaling parameter: ', homogenization_RGC_xiAlpha(i) + write(6,'(a25,1x,e10.3)') 'over-proportionality: ', homogenization_RGC_ciAlpha(i) + write(6,'(a25,3(1x,e10.3))') 'grain size: ',(homogenization_RGC_dAlpha(j,i),j=1_pInt,3_pInt) + write(6,'(a25,3(1x,e10.3))') 'cluster orientation: ',(homogenization_RGC_angles(j,i),j=1_pInt,3_pInt) + enddo + endif +!-------------------------------------------------------------------------------------------------- + initializeInstances: do homog = 1_pInt, material_Nhomogenization + myHomog: if (homogenization_type(homog) == HOMOGENIZATION_RGC_ID) then + NofMyHomog = count(material_homog == homog) + instance = homogenization_typeInstance(homog) + +! * Determine size of postResults array + outputsLoop: do o = 1_pInt, homogenization_RGC_Noutput(instance) + select case(homogenization_RGC_outputID(o,instance)) + case(constitutivework_ID,penaltyenergy_ID,volumediscrepancy_ID, & + averagerelaxrate_ID,maximumrelaxrate_ID) + mySize = 1_pInt + case(ipcoords_ID,magnitudemismatch_ID) + mySize = 3_pInt + case(avgdefgrad_ID,avgfirstpiola_ID) + mySize = 9_pInt + case default + mySize = 0_pInt + end select + + outputFound: if (mySize > 0_pInt) then + homogenization_RGC_sizePostResult(o,instance) = mySize + homogenization_RGC_sizePostResults(instance) = & + homogenization_RGC_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop + + sizeHState = & + 3_pInt*(homogenization_RGC_Ngrains(1,instance)-1_pInt)* & + homogenization_RGC_Ngrains(2,instance)*homogenization_RGC_Ngrains(3,instance) & + + 3_pInt*homogenization_RGC_Ngrains(1,instance)*(homogenization_RGC_Ngrains(2,instance)-1_pInt)* & + homogenization_RGC_Ngrains(3,instance) & + + 3_pInt*homogenization_RGC_Ngrains(1,instance)*homogenization_RGC_Ngrains(2,instance)* & + (homogenization_RGC_Ngrains(3,instance)-1_pInt) & + + 8_pInt ! (1) Average constitutive work, (2-4) Overall mismatch, (5) Average penalty energy, + ! (6) Volume discrepancy, (7) Avg relaxation rate component, (8) Max relaxation rate component + +! allocate state arrays + homogState(homog)%sizeState = sizeHState + homogState(homog)%sizePostResults = homogenization_RGC_sizePostResults(instance) + allocate(homogState(homog)%state0 (sizeHState,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%subState0(sizeHState,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%state (sizeHState,NofMyHomog), source=0.0_pReal) + + endif myHomog + enddo initializeInstances + + + +end subroutine homogenization_RGC_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief partitions the deformation gradient onto the constituents +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_partitionDeformation(F,avgF,ip,el) + use debug, only: & + debug_level, & + debug_homogenization, & + debug_levelExtensive + use mesh, only: & + mesh_element + use material, only: & + homogenization_maxNgrains, & + homogenization_Ngrains,& + homogenization_typeInstance + + implicit none + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned F per grain + real(pReal), dimension (3,3), intent(in) :: avgF !< averaged F + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension (3) :: aVect,nVect + integer(pInt), dimension (4) :: intFace + integer(pInt), dimension (3) :: iGrain3 + integer(pInt) :: homID, iGrain,iFace,i,j + integer(pInt), parameter :: nFace = 6_pInt + +!-------------------------------------------------------------------------------------------------- +! compute the deformation gradient of individual grains due to relaxations + homID = homogenization_typeInstance(mesh_element(3,el)) + F = 0.0_pReal + do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) + iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) + do iFace = 1_pInt,nFace + intFace = homogenization_RGC_getInterface(iFace,iGrain3) ! identifying 6 interfaces of each grain + + aVect = homogenization_RGC_relaxationVector(intFace,homID, ip, el) ! get the relaxation vectors for each interface from global relaxation vector array + + nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the normal of each interface + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) & + 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 + +!-------------------------------------------------------------------------------------------------- +! debugging the grain deformation gradients + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a32,1x,i3)')'Deformation gradient of grain: ',iGrain + do i = 1_pInt,3_pInt + write(6,'(1x,3(e15.8,1x))')(F(i,j,iGrain), j = 1_pInt,3_pInt) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + + enddo + +end subroutine homogenization_RGC_partitionDeformation + + +!-------------------------------------------------------------------------------------------------- +!> @brief update the internal state of the homogenization scheme and tell whether "done" and +! "happy" with result +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) + use debug, only: & + debug_level, & + debug_homogenization,& + debug_levelExtensive, & + debug_e, & + debug_i + use math, only: & + math_invert + use mesh, only: & + mesh_element + use material, only: & + homogenization_maxNgrains, & + homogenization_typeInstance, & + homogState, & + mappingHomogenization, & + homogenization_Ngrains + use numerics, only: & + absTol_RGC, & + relTol_RGC, & + absMax_RGC, & + relMax_RGC, & + pPert_RGC, & + maxdRelax_RGC, & + viscPower_RGC, & + viscModus_RGC, & + refRelaxRate_RGC + + implicit none + + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: & + P,& !< array of P + F,& !< array of F + F0 !< array of initial F + real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffness + real(pReal), dimension (3,3), intent(in) :: avgF !< average F + real(pReal), intent(in) :: dt !< time increment + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + logical, dimension(2) :: homogenization_RGC_updateState + integer(pInt), dimension (4) :: intFaceN,intFaceP,faceID + integer(pInt), dimension (3) :: nGDim,iGr3N,iGr3P,stresLoc + integer(pInt), dimension (2) :: residLoc + integer(pInt) homID,iNum,i,j,nIntFaceTot,iGrN,iGrP,iMun,iFace,k,l,ipert,iGrain,nGrain + real(pReal), dimension (3,3,homogenization_maxNgrains) :: R,pF,pR,D,pD + real(pReal), dimension (3,homogenization_maxNgrains) :: NN,pNN + real(pReal), dimension (3) :: normP,normN,mornP,mornN + real(pReal) :: residMax,stresMax,constitutiveWork,penaltyEnergy,volDiscrep + logical error + + integer(pInt), parameter :: nFace = 6_pInt + + real(pReal), dimension(:,:), allocatable :: tract,jmatrix,jnverse,smatrix,pmatrix,rmatrix + real(pReal), dimension(:), allocatable :: resid,relax,p_relax,p_resid,drelax + + if(abs(dt) < tiny(0.0_pReal)) then ! zero time step + homogenization_RGC_updateState = .true. ! pretend everything is fine and return + return + endif + +!-------------------------------------------------------------------------------------------------- +! get the dimension of the cluster (grains and interfaces) + homID = homogenization_typeInstance(mesh_element(3,el)) + nGDim = homogenization_RGC_Ngrains(1:3,homID) + nGrain = homogenization_Ngrains(mesh_element(3,el)) + nIntFaceTot = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) + nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) & + + nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) + +!-------------------------------------------------------------------------------------------------- +! allocate the size of the global relaxation arrays/jacobian matrices depending on the size of the cluster + allocate(resid(3_pInt*nIntFaceTot), source=0.0_pReal) + allocate(tract(nIntFaceTot,3), source=0.0_pReal) + allocate(relax(3_pInt*nIntFaceTot)); relax= homogState(mappingHomogenization(2,ip,el))% & + state(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) + allocate(drelax(3_pInt*nIntFaceTot)); drelax= homogState(mappingHomogenization(2,ip,el))% & + state(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) - & + homogState(mappingHomogenization(2,ip,el))% & + state0(1:3_pInt*nIntFaceTot,mappingHomogenization(1,ip,el)) +!-------------------------------------------------------------------------------------------------- +! debugging the obtained state + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Obtained state: ' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,2(e15.8,1x))')homogState(mappingHomogenization(2,ip,el))%state(i,mappingHomogenization(1,ip,el)) + enddo + write(6,*)' ' + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! computing interface mismatch and stress penalty tensor for all interfaces of all grains + call homogenization_RGC_stressPenalty(R,NN,avgF,F,ip,el,homID) + +!-------------------------------------------------------------------------------------------------- +! calculating volume discrepancy and stress penalty related to overall volume discrepancy + call homogenization_RGC_volumePenalty(D,volDiscrep,F,avgF,ip,el) + +!-------------------------------------------------------------------------------------------------- +! debugging the mismatch, stress and penalties of grains + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + do iGrain = 1_pInt,nGrain + write(6,'(1x,a30,1x,i3,1x,a4,3(1x,e15.8))')'Mismatch magnitude of grain(',iGrain,') :',& + NN(1,iGrain),NN(2,iGrain),NN(3,iGrain) + write(6,'(/,1x,a30,1x,i3)')'Stress and penalties of grain: ',iGrain + do i = 1_pInt,3_pInt + write(6,'(1x,3(e15.8,1x),1x,3(e15.8,1x),1x,3(e15.8,1x))')(P(i,j,iGrain), j = 1_pInt,3_pInt), & + (R(i,j,iGrain), j = 1_pInt,3_pInt), & + (D(i,j,iGrain), j = 1_pInt,3_pInt) + enddo + write(6,*)' ' + enddo + !$OMP END CRITICAL (write2out) + endif + +!------------------------------------------------------------------------------------------------ +! computing the residual stress from the balance of traction at all (interior) interfaces + do iNum = 1_pInt,nIntFaceTot + faceID = homogenization_RGC_interface1to4(iNum,homID) ! identifying the interface ID in local coordinate system (4-dimensional index) + +!-------------------------------------------------------------------------------------------------- +! identify the left/bottom/back grain (-|N) + iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate system (3-dimensional index) + iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) + intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) + normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the interface normal + +!-------------------------------------------------------------------------------------------------- +! identify the right/up/front grain (+|P) + iGr3P = iGr3N + iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate system (3-dimensional index) + iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) + intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) + normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the interface normal + +!-------------------------------------------------------------------------------------------------- +! compute the residual of traction at the interface (in local system, 4-dimensional index) + do i = 1_pInt,3_pInt + tract(iNum,i) = sign(viscModus_RGC*(abs(drelax(i+3*(iNum-1_pInt)))/(refRelaxRate_RGC*dt))**viscPower_RGC, & + drelax(i+3*(iNum-1_pInt))) ! contribution from the relaxation viscosity + do j = 1_pInt,3_pInt + tract(iNum,i) = tract(iNum,i) + (P(i,j,iGrP) + R(i,j,iGrP) + D(i,j,iGrP))*normP(j) & ! contribution from material stress P, mismatch penalty R, and volume penalty D projected into the interface + + (P(i,j,iGrN) + R(i,j,iGrN) + D(i,j,iGrN))*normN(j) + resid(i+3_pInt*(iNum-1_pInt)) = tract(iNum,i) ! translate the local residual into global 1-dimensional residual array + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! debugging the residual stress + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30,1x,i3)')'Traction at interface: ',iNum + write(6,'(1x,3(e15.8,1x))')(tract(iNum,j), j = 1_pInt,3_pInt) + write(6,*)' ' + !$OMP END CRITICAL (write2out) + endif + enddo + +!-------------------------------------------------------------------------------------------------- +! convergence check for stress residual + stresMax = maxval(abs(P)) ! get the maximum of first Piola-Kirchhoff (material) stress + stresLoc = int(maxloc(abs(P)),pInt) ! get the location of the maximum stress + residMax = maxval(abs(tract)) ! get the maximum of the residual + residLoc = int(maxloc(abs(tract)),pInt) ! get the position of the maximum residual + +!-------------------------------------------------------------------------------------------------- +! Debugging the convergent criteria + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a)')' ' + write(6,'(1x,a,1x,i2,1x,i4)')'RGC residual check ...',ip,el + write(6,'(1x,a15,1x,e15.8,1x,a7,i3,1x,a12,i2,i2)')'Max stress: ',stresMax, & + '@ grain',stresLoc(3),'in component',stresLoc(1),stresLoc(2) + write(6,'(1x,a15,1x,e15.8,1x,a7,i3,1x,a12,i2)')'Max residual: ',residMax, & + '@ iface',residLoc(1),'in direction',residLoc(2) + flush(6) + !$OMP END CRITICAL (write2out) + endif + + homogenization_RGC_updateState = .false. + +!-------------------------------------------------------------------------------------------------- +! If convergence reached => done and happy + if (residMax < relTol_RGC*stresMax .or. residMax < absTol_RGC) then + homogenization_RGC_updateState = .true. + + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a55,/)')'... done and happy' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! compute/update the state for postResult, i.e., all energy densities computed by time-integration + constitutiveWork = homogState(mappingHomogenization(2,ip,el))%state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) + penaltyEnergy = homogState(mappingHomogenization(2,ip,el))%state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) + do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) ! time-integration loop for the calculating the work and energy + do i = 1_pInt,3_pInt + do j = 1_pInt,3_pInt + constitutiveWork = constitutiveWork + P(i,j,iGrain)*(F(i,j,iGrain) - F0(i,j,iGrain))/real(nGrain,pReal) + penaltyEnergy = penaltyEnergy + R(i,j,iGrain)*(F(i,j,iGrain) - F0(i,j,iGrain))/real(nGrain,pReal) + enddo + enddo + enddo + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) = constitutiveWork ! the bulk mechanical/constitutive work + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+2,mappingHomogenization(1,ip,el)) = sum(NN(1,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e1-direction + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+3,mappingHomogenization(1,ip,el)) = sum(NN(2,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e2-direction + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+4,mappingHomogenization(1,ip,el)) = sum(NN(3,:))/real(nGrain,pReal) ! the overall mismatch of all interface normal to e3-direction + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) = penaltyEnergy ! the overall penalty energy + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+6,mappingHomogenization(1,ip,el)) = volDiscrep ! the overall volume discrepancy + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+7,mappingHomogenization(1,ip,el)) = & + sum(abs(drelax))/dt/real(3_pInt*nIntFaceTot,pReal) ! the average rate of relaxation vectors + homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+8,mappingHomogenization(1,ip,el)) = maxval(abs(drelax))/dt ! the maximum rate of relaxation vectors + + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30,1x,e15.8)') 'Constitutive work: ',constitutiveWork + write(6,'(1x,a30,3(1x,e15.8))')'Magnitude mismatch: ',sum(NN(1,:))/real(nGrain,pReal), & + sum(NN(2,:))/real(nGrain,pReal), & + sum(NN(3,:))/real(nGrain,pReal) + write(6,'(1x,a30,1x,e15.8)') 'Penalty energy: ',penaltyEnergy + write(6,'(1x,a30,1x,e15.8,/)') 'Volume discrepancy: ',volDiscrep + write(6,'(1x,a30,1x,e15.8)') 'Maximum relaxation rate: ',maxval(abs(drelax))/dt + write(6,'(1x,a30,1x,e15.8,/)') 'Average relaxation rate: ',sum(abs(drelax))/dt/real(3_pInt*nIntFaceTot,pReal) + flush(6) + !$OMP END CRITICAL (write2out) + endif + + deallocate(tract,resid,relax,drelax) + return + +!-------------------------------------------------------------------------------------------------- +! if residual blows-up => done but unhappy + elseif (residMax > relMax_RGC*stresMax .or. residMax > absMax_RGC) then ! try to restart when residual blows up exceeding maximum bound + homogenization_RGC_updateState = [.true.,.false.] ! with direct cut-back + + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a55,/)')'... broken' + flush(6) + !$OMP END CRITICAL (write2out) + endif + + deallocate(tract,resid,relax,drelax) + return + else ! proceed with computing the Jacobian and state update + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a55,/)')'... not yet done' + flush(6) + !$OMP END CRITICAL (write2out) + endif + + endif + +!--------------------------------------------------------------------------------------------------- +! construct the global Jacobian matrix for updating the global relaxation vector array when +! convergence is not yet reached ... + +!-------------------------------------------------------------------------------------------------- +! ... of the constitutive stress tangent, assembled from dPdF or material constitutive model "smatrix" + allocate(smatrix(3*nIntFaceTot,3*nIntFaceTot), source=0.0_pReal) + do iNum = 1_pInt,nIntFaceTot + faceID = homogenization_RGC_interface1to4(iNum,homID) ! assembling of local dPdF into global Jacobian matrix + +!-------------------------------------------------------------------------------------------------- +! identify the left/bottom/back grain (-|N) + iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate sytem + iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate into global grain ID + intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) ! identifying the connecting interface in local coordinate system + normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the interface normal + do iFace = 1_pInt,nFace + intFaceN = homogenization_RGC_getInterface(iFace,iGr3N) ! identifying all interfaces that influence relaxation of the above interface + mornN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get normal of the interfaces + iMun = homogenization_RGC_interface4to1(intFaceN,homID) ! translate the interfaces ID into local 4-dimensional index + if (iMun > 0) then ! get the corresponding tangent + do i=1_pInt,3_pInt; do j=1_pInt,3_pInt; do k=1_pInt,3_pInt; do l=1_pInt,3_pInt + smatrix(3*(iNum-1)+i,3*(iMun-1)+j) = smatrix(3*(iNum-1)+i,3*(iMun-1)+j) + dPdF(i,k,j,l,iGrN)*normN(k)*mornN(l) + enddo;enddo;enddo;enddo +! projecting the material tangent dPdF into the interface +! to obtain the Jacobian matrix contribution of dPdF + endif + enddo + +!-------------------------------------------------------------------------------------------------- +! identify the right/up/front grain (+|P) + iGr3P = iGr3N + iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate sytem + iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate into global grain ID + intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) ! identifying the connecting interface in local coordinate system + normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the interface normal + do iFace = 1_pInt,nFace + intFaceP = homogenization_RGC_getInterface(iFace,iGr3P) ! identifying all interfaces that influence relaxation of the above interface + mornP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get normal of the interfaces + iMun = homogenization_RGC_interface4to1(intFaceP,homID) ! translate the interfaces ID into local 4-dimensional index + if (iMun > 0_pInt) then ! get the corresponding tangent + do i=1_pInt,3_pInt; do j=1_pInt,3_pInt; do k=1_pInt,3_pInt; do l=1_pInt,3_pInt + smatrix(3*(iNum-1)+i,3*(iMun-1)+j) = smatrix(3*(iNum-1)+i,3*(iMun-1)+j) + dPdF(i,k,j,l,iGrP)*normP(k)*mornP(l) + enddo;enddo;enddo;enddo + endif + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! debugging the global Jacobian matrix of stress tangent + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Jacobian matrix of stress' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,100(e11.4,1x))')(smatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! ... of the stress penalty tangent (mismatch penalty and volume penalty, computed using numerical +! perturbation method) "pmatrix" + allocate(pmatrix(3*nIntFaceTot,3*nIntFaceTot), source=0.0_pReal) + allocate(p_relax(3*nIntFaceTot), source=0.0_pReal) + allocate(p_resid(3*nIntFaceTot), source=0.0_pReal) + do ipert = 1_pInt,3_pInt*nIntFaceTot + p_relax = relax + p_relax(ipert) = relax(ipert) + pPert_RGC ! perturb the relaxation vector + homogState(mappingHomogenization(2,ip,el))%state(1:3*nIntFaceTot,mappingHomogenization(1,ip,el)) = p_relax + call homogenization_RGC_grainDeformation(pF,avgF,ip,el) ! compute the grains deformation from perturbed state + call homogenization_RGC_stressPenalty(pR,pNN,avgF,pF,ip,el,homID) ! compute stress penalty due to interface mismatch from perturbed state + call homogenization_RGC_volumePenalty(pD,volDiscrep,pF,avgF,ip,el) ! compute stress penalty due to volume discrepancy from perturbed state + +!-------------------------------------------------------------------------------------------------- +! computing the global stress residual array from the perturbed state + p_resid = 0.0_pReal + do iNum = 1_pInt,nIntFaceTot + faceID = homogenization_RGC_interface1to4(iNum,homID) ! identifying the interface ID in local coordinate system (4-dimensional index) + +!-------------------------------------------------------------------------------------------------- +! identify the left/bottom/back grain (-|N) + iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate system (3-dimensional index) + iGrN = homogenization_RGC_grain3to1(iGr3N,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) + intFaceN = homogenization_RGC_getInterface(2_pInt*faceID(1),iGr3N) ! identifying the interface ID of the grain + normN = homogenization_RGC_interfaceNormal(intFaceN,ip,el) ! get the corresponding interface normal + +!-------------------------------------------------------------------------------------------------- +! identify the right/up/front grain (+|P) + iGr3P = iGr3N + iGr3P(faceID(1)) = iGr3N(faceID(1))+1_pInt ! identifying the grain ID in local coordinate system (3-dimensional index) + iGrP = homogenization_RGC_grain3to1(iGr3P,homID) ! translate the local grain ID into global coordinate system (1-dimensional index) + intFaceP = homogenization_RGC_getInterface(2_pInt*faceID(1)-1_pInt,iGr3P) ! identifying the interface ID of the grain + normP = homogenization_RGC_interfaceNormal(intFaceP,ip,el) ! get the corresponding normal + +!-------------------------------------------------------------------------------------------------- +! compute the residual stress (contribution of mismatch and volume penalties) from perturbed state +! at all interfaces + do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt + p_resid(i+3*(iNum-1)) = p_resid(i+3*(iNum-1)) + (pR(i,j,iGrP) - R(i,j,iGrP))*normP(j) & + + (pR(i,j,iGrN) - R(i,j,iGrN))*normN(j) & + + (pD(i,j,iGrP) - D(i,j,iGrP))*normP(j) & + + (pD(i,j,iGrN) - D(i,j,iGrN))*normN(j) + enddo; enddo + enddo + pmatrix(:,ipert) = p_resid/pPert_RGC + enddo + +!-------------------------------------------------------------------------------------------------- +! debugging the global Jacobian matrix of penalty tangent + if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Jacobian matrix of penalty' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,100(e11.4,1x))')(pmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! ... of the numerical viscosity traction "rmatrix" + allocate(rmatrix(3*nIntFaceTot,3*nIntFaceTot),source=0.0_pReal) + forall (i=1_pInt:3_pInt*nIntFaceTot) & + rmatrix(i,i) = viscModus_RGC*viscPower_RGC/(refRelaxRate_RGC*dt)* & ! tangent due to numerical viscosity traction appears + (abs(drelax(i))/(refRelaxRate_RGC*dt))**(viscPower_RGC - 1.0_pReal) ! only in the main diagonal term + + + +!-------------------------------------------------------------------------------------------------- +! debugging the global Jacobian matrix of numerical viscosity tangent + if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Jacobian matrix of penalty' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,100(e11.4,1x))')(rmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! The overall Jacobian matrix summarizing contributions of smatrix, pmatrix, rmatrix + allocate(jmatrix(3*nIntFaceTot,3*nIntFaceTot)); jmatrix = smatrix + pmatrix + rmatrix + + if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Jacobian matrix (total)' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,100(e11.4,1x))')(jmatrix(i,j), j = 1_pInt,3_pInt*nIntFaceTot) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! computing the update of the state variable (relaxation vectors) using the Jacobian matrix + allocate(jnverse(3_pInt*nIntFaceTot,3_pInt*nIntFaceTot),source=0.0_pReal) + call math_invert(size(jmatrix,1),jmatrix,jnverse,error) ! Compute the inverse of the overall Jacobian matrix + +!-------------------------------------------------------------------------------------------------- +! debugging the inverse Jacobian matrix + if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Jacobian inverse' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,100(e11.4,1x))')(jnverse(i,j), j = 1_pInt,3_pInt*nIntFaceTot) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! calculate the state update (global relaxation vectors) for the next Newton-Raphson iteration + drelax = 0.0_pReal + do i = 1_pInt,3_pInt*nIntFaceTot + do j = 1_pInt,3_pInt*nIntFaceTot + drelax(i) = drelax(i) - jnverse(i,j)*resid(j) ! Calculate the correction for the state variable + enddo + enddo + relax = relax + drelax ! Updateing the state variable for the next iteration + homogState(mappingHomogenization(2,ip,el))%state(1:3*nIntFaceTot,mappingHomogenization(1,ip,el)) = relax + if (any(abs(drelax) > maxdRelax_RGC)) then ! Forcing cutback when the incremental change of relaxation vector becomes too large + homogenization_RGC_updateState = [.true.,.false.] + !$OMP CRITICAL (write2out) + write(6,'(1x,a,1x,i3,1x,a,1x,i3,1x,a)')'RGC_updateState: ip',ip,'| el',el,'enforces cutback' + write(6,'(1x,a,1x,e15.8)')'due to large relaxation change =',maxval(abs(drelax)) + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! debugging the return state + if (iand(debug_homogenization, debug_levelExtensive) > 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30)')'Returned state: ' + do i = 1_pInt,3_pInt*nIntFaceTot + write(6,'(1x,2(e15.8,1x))')homogState(mappingHomogenization(2,ip,el))%state(i,mappingHomogenization(1,ip,el)) + enddo + write(6,*)' ' + flush(6) + !$OMP END CRITICAL (write2out) + endif + + deallocate(tract,resid,jmatrix,jnverse,relax,drelax,pmatrix,smatrix,p_relax,p_resid) + +end function homogenization_RGC_updateState + + +!-------------------------------------------------------------------------------------------------- +!> @brief derive average stress and stiffness from constituent quantities +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,el) + use debug, only: & + debug_level, & + debug_homogenization,& + debug_levelExtensive + use mesh, only: mesh_element + use material, only: & + homogenization_maxNgrains, & + homogenization_Ngrains, & + homogenization_typeInstance + use math, only: math_Plain3333to99 + + implicit none + 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 (3,3,homogenization_maxNgrains), intent(in) :: P !< array of current grain stresses + real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffnesses + integer(pInt), intent(in) :: el !< element number + real(pReal), dimension (9,9) :: dPdF99 + + integer(pInt) :: homID, i, j, Ngrains, iGrain + + homID = homogenization_typeInstance(mesh_element(3,el)) + Ngrains = homogenization_Ngrains(mesh_element(3,el)) + +!-------------------------------------------------------------------------------------------------- +! debugging the grain tangent + if (iand(debug_level(debug_homogenization), debug_levelExtensive) /= 0_pInt) then + !$OMP CRITICAL (write2out) + do iGrain = 1_pInt,Ngrains + dPdF99 = math_Plain3333to99(dPdF(1:3,1:3,1:3,1:3,iGrain)) + write(6,'(1x,a30,1x,i3)')'Stress tangent of grain: ',iGrain + do i = 1_pInt,9_pInt + write(6,'(1x,(e15.8,1x))') (dPdF99(i,j), j = 1_pInt,9_pInt) + enddo + write(6,*)' ' + enddo + flush(6) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! computing the average first Piola-Kirchhoff stress P and the average tangent dPdF + avgP = sum(P,3)/real(Ngrains,pReal) + dAvgPdAvgF = sum(dPdF,5)/real(Ngrains,pReal) + +end subroutine homogenization_RGC_averageStressAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of homogenization results for post file inclusion +!-------------------------------------------------------------------------------------------------- +pure function homogenization_RGC_postResults(ip,el,avgP,avgF) + use mesh, only: & + mesh_element, & + mesh_ipCoordinates + use material, only: & + homogenization_typeInstance,& + homogState, & + mappingHomogenization, & + homogenization_Noutput + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3), intent(in) :: & + avgP, & !< average stress at material point + avgF !< average deformation gradient at material point + + integer(pInt) homID,o,c,nIntFaceTot + real(pReal), dimension(homogenization_RGC_sizePostResults(homogenization_typeInstance(mesh_element(3,el)))) :: & + homogenization_RGC_postResults + + homID = homogenization_typeInstance(mesh_element(3,el)) + nIntFaceTot=(homogenization_RGC_Ngrains(1,homID)-1_pInt)*homogenization_RGC_Ngrains(2,homID)*homogenization_RGC_Ngrains(3,homID)& + + homogenization_RGC_Ngrains(1,homID)*(homogenization_RGC_Ngrains(2,homID)-1_pInt)*homogenization_RGC_Ngrains(3,homID)& + + homogenization_RGC_Ngrains(1,homID)*homogenization_RGC_Ngrains(2,homID)*(homogenization_RGC_Ngrains(3,homID)-1_pInt) + + c = 0_pInt + homogenization_RGC_postResults = 0.0_pReal + do o = 1_pInt,homogenization_Noutput(mesh_element(3,el)) + select case(homogenization_RGC_outputID(o,homID)) + case (avgdefgrad_ID) + homogenization_RGC_postResults(c+1_pInt:c+9_pInt) = reshape(avgF,[9]) + c = c + 9_pInt + case (avgfirstpiola_ID) + homogenization_RGC_postResults(c+1_pInt:c+9_pInt) = reshape(avgP,[9]) + c = c + 9_pInt + case (ipcoords_ID) + homogenization_RGC_postResults(c+1_pInt:c+3_pInt) = mesh_ipCoordinates(1:3,ip,el) ! current ip coordinates + c = c + 3_pInt + case (constitutivework_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+1,mappingHomogenization(1,ip,el)) + c = c + 1_pInt + case (magnitudemismatch_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+2,mappingHomogenization(1,ip,el)) + homogenization_RGC_postResults(c+2) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+3,mappingHomogenization(1,ip,el)) + homogenization_RGC_postResults(c+3) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+4,mappingHomogenization(1,ip,el)) + c = c + 3_pInt + case (penaltyenergy_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+5,mappingHomogenization(1,ip,el)) + c = c + 1_pInt + case (volumediscrepancy_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+6,mappingHomogenization(1,ip,el)) + c = c + 1_pInt + case (averagerelaxrate_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+7,mappingHomogenization(1,ip,el)) + c = c + 1_pInt + case (maximumrelaxrate_ID) + homogenization_RGC_postResults(c+1) = homogState(mappingHomogenization(2,ip,el))% & + state(3*nIntFaceTot+8,mappingHomogenization(1,ip,el)) + c = c + 1_pInt + end select + enddo + +end function homogenization_RGC_postResults + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate stress-like penalty due to deformation mismatch +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_stressPenalty(rPen,nMis,avgF,fDef,ip,el,homID) + use debug, only: & + debug_level, & + debug_homogenization,& + debug_levelExtensive, & + debug_e, & + debug_i + use mesh, only: & + mesh_element + use constitutive, only: & + constitutive_homogenizedC + use math, only: & + math_civita + use material, only: & + homogenization_maxNgrains,& + homogenization_Ngrains + use numerics, only: & + xSmoo_RGC + + implicit none + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: rPen !< stress-like penalty + real(pReal), dimension (3,homogenization_maxNgrains), intent(out) :: nMis !< total amount of mismatch + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: fDef !< deformation gradients + real(pReal), dimension (3,3), intent(in) :: avgF !< initial effective stretch tensor + integer(pInt), intent(in) :: ip,el + integer(pInt), dimension (4) :: intFace + integer(pInt), dimension (3) :: iGrain3,iGNghb3,nGDim + real(pReal), dimension (3,3) :: gDef,nDef + real(pReal), dimension (3) :: nVect,surfCorr + real(pReal), dimension (2) :: Gmoduli + integer(pInt) :: homID,iGrain,iGNghb,iFace,i,j,k,l + real(pReal) :: muGrain,muGNghb,nDefNorm,bgGrain,bgGNghb + + integer(pInt), parameter :: nFace = 6_pInt + real(pReal), parameter :: nDefToler = 1.0e-10_pReal + + nGDim = homogenization_RGC_Ngrains(1:3,homID) + rPen = 0.0_pReal + nMis = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! get the correction factor the modulus of penalty stress representing the evolution of area of +! the interfaces due to deformations + surfCorr = homogenization_RGC_surfaceCorrection(avgF,ip,el) + +!-------------------------------------------------------------------------------------------------- +! debugging the surface correction factor + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a20,2(1x,i3))')'Correction factor: ',ip,el + write(6,'(1x,3(e11.4,1x))')(surfCorr(i), i = 1,3) + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! computing the mismatch and penalty stress tensor of all grains + do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) + Gmoduli = homogenization_RGC_equivalentModuli(iGrain,ip,el) + muGrain = Gmoduli(1) ! collecting the equivalent shear modulus of grain + bgGrain = Gmoduli(2) ! and the lengthh of Burgers vector + iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) ! get the grain ID in local 3-dimensional index (x,y,z)-position + +!* Looping over all six interfaces of each grain + do iFace = 1_pInt,nFace + intFace = homogenization_RGC_getInterface(iFace,iGrain3) ! get the 4-dimensional index of the interface in local numbering system of the grain + nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the interface normal + iGNghb3 = iGrain3 ! identify the neighboring grain across the interface + iGNghb3(abs(intFace(1))) = iGNghb3(abs(intFace(1))) + int(real(intFace(1),pReal)/real(abs(intFace(1)),pReal),pInt) + if (iGNghb3(1) < 1) iGNghb3(1) = nGDim(1) ! with periodicity along e1 direction + if (iGNghb3(1) > nGDim(1)) iGNghb3(1) = 1_pInt + if (iGNghb3(2) < 1) iGNghb3(2) = nGDim(2) ! with periodicity along e2 direction + if (iGNghb3(2) > nGDim(2)) iGNghb3(2) = 1_pInt + if (iGNghb3(3) < 1) iGNghb3(3) = nGDim(3) ! with periodicity along e3 direction + if (iGNghb3(3) > nGDim(3)) iGNghb3(3) = 1_pInt + iGNghb = homogenization_RGC_grain3to1(iGNghb3,homID) ! get the ID of the neighboring grain + Gmoduli = homogenization_RGC_equivalentModuli(iGNghb,ip,el) ! collecting the shear modulus and Burgers vector of the neighbor + muGNghb = Gmoduli(1) + bgGNghb = Gmoduli(2) + gDef = 0.5_pReal*(fDef(1:3,1:3,iGNghb) - fDef(1:3,1:3,iGrain)) ! compute the difference/jump in deformation gradeint across the neighbor + +!-------------------------------------------------------------------------------------------------- +! compute the mismatch tensor of all interfaces + nDefNorm = 0.0_pReal + nDef = 0.0_pReal + do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt + do k = 1_pInt,3_pInt; do l = 1_pInt,3_pInt + nDef(i,j) = nDef(i,j) - nVect(k)*gDef(i,l)*math_civita(j,k,l) ! compute the interface mismatch tensor from the jump of deformation gradient + enddo; enddo + nDefNorm = nDefNorm + nDef(i,j)*nDef(i,j) ! compute the norm of the mismatch tensor + 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) + +!-------------------------------------------------------------------------------------------------- +! debuggin the mismatch tensor + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a20,i2,1x,a20,1x,i3)')'Mismatch to face: ',intFace(1),'neighbor grain: ',iGNghb + do i = 1,3 + write(6,'(1x,3(e11.4,1x))')(nDef(i,j), j = 1,3) + enddo + write(6,'(1x,a20,e11.4)')'with magnitude: ',nDefNorm + !$OMP END CRITICAL (write2out) + endif + +!-------------------------------------------------------------------------------------------------- +! compute the stress penalty of all interfaces + do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt + do k = 1_pInt,3_pInt; do l = 1_pInt,3_pInt + rPen(i,j,iGrain) = rPen(i,j,iGrain) + 0.5_pReal*(muGrain*bgGrain + muGNghb*bgGNghb)*homogenization_RGC_xiAlpha(homID) & + *surfCorr(abs(intFace(1)))/homogenization_RGC_dAlpha(abs(intFace(1)),homID) & + *cosh(homogenization_RGC_ciAlpha(homID)*nDefNorm) & + *0.5_pReal*nVect(l)*nDef(i,k)/nDefNorm*math_civita(k,l,j) & + *tanh(nDefNorm/xSmoo_RGC) + enddo; enddo + enddo; enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! debugging the stress-like penalty + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a20,i2)')'Penalty of grain: ',iGrain + do i = 1,3 + write(6,'(1x,3(e11.4,1x))')(rPen(i,j,iGrain), j = 1,3) + enddo + !$OMP END CRITICAL (write2out) + endif + + enddo + +end subroutine homogenization_RGC_stressPenalty + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate stress-like penalty due to volume discrepancy +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_volumePenalty(vPen,vDiscrep,fDef,fAvg,ip,el) + use debug, only: & + debug_level, & + debug_homogenization,& + debug_levelExtensive, & + debug_e, & + debug_i + use mesh, only: & + mesh_element + use math, only: & + math_det33, & + math_inv33 + use material, only: & + homogenization_maxNgrains,& + homogenization_Ngrains + use numerics, only: & + maxVolDiscr_RGC,& + volDiscrMod_RGC,& + volDiscrPow_RGC + + implicit none + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: vPen ! stress-like penalty due to volume + real(pReal), intent(out) :: vDiscrep ! total volume discrepancy + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(in) :: fDef ! deformation gradients + real(pReal), dimension (3,3), intent(in) :: fAvg ! overall deformation gradient + integer(pInt), intent(in) :: ip,& ! integration point + el + real(pReal), dimension (homogenization_maxNgrains) :: gVol + integer(pInt) :: iGrain,nGrain,i,j + + nGrain = homogenization_Ngrains(mesh_element(3,el)) + +!-------------------------------------------------------------------------------------------------- +! compute the volumes of grains and of cluster + vDiscrep = math_det33(fAvg) ! compute the volume of the cluster + do iGrain = 1_pInt,nGrain + gVol(iGrain) = math_det33(fDef(1:3,1:3,iGrain)) ! compute the volume of individual grains + vDiscrep = vDiscrep - gVol(iGrain)/real(nGrain,pReal) ! calculate the difference/dicrepancy between + ! the volume of the cluster and the the total volume of grains + enddo + +!-------------------------------------------------------------------------------------------------- +! calculate the stress and penalty due to volume discrepancy + vPen = 0.0_pReal + do iGrain = 1_pInt,nGrain + vPen(:,:,iGrain) = -1.0_pReal/real(nGrain,pReal)*volDiscrMod_RGC*volDiscrPow_RGC/maxVolDiscr_RGC* & + sign((abs(vDiscrep)/maxVolDiscr_RGC)**(volDiscrPow_RGC - 1.0),vDiscrep)* & + gVol(iGrain)*transpose(math_inv33(fDef(:,:,iGrain))) + +!-------------------------------------------------------------------------------------------------- +! debugging the stress-like penalty + if (iand(debug_level(debug_homogenization),debug_levelExtensive) /= 0_pInt & + .and. debug_e == el .and. debug_i == ip) then + !$OMP CRITICAL (write2out) + write(6,'(1x,a30,i2)')'Volume penalty of grain: ',iGrain + do i = 1,3 + write(6,'(1x,3(e11.4,1x))')(vPen(i,j,iGrain), j = 1,3) + enddo + !$OMP END CRITICAL (write2out) + endif + enddo + +end subroutine homogenization_RGC_volumePenalty + + +!-------------------------------------------------------------------------------------------------- +!> @brief compute the correction factor accouted for surface evolution (area change) due to +! deformation +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_surfaceCorrection(avgF,ip,el) + use math, only: & + math_invert33, & + math_mul33x33 + + implicit none + real(pReal), dimension(3) :: homogenization_RGC_surfaceCorrection + real(pReal), dimension(3,3), intent(in) :: avgF !< average F + integer(pInt), intent(in) :: ip,& !< integration point number + el !< element number + real(pReal), dimension(3,3) :: invC,avgC + real(pReal), dimension(3) :: nVect + real(pReal) :: detF + integer(pInt), dimension(4) :: intFace + integer(pInt) :: i,j,iBase + logical :: error + + avgC = math_mul33x33(transpose(avgF),avgF) + call math_invert33(avgC,invC,detF,error) + homogenization_RGC_surfaceCorrection = 0.0_pReal + do iBase = 1_pInt,3_pInt + intFace = [iBase,1_pInt,1_pInt,1_pInt] + nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) ! get the normal of the interface + do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt + homogenization_RGC_surfaceCorrection(iBase) = & ! compute the component of (the inverse of) the stretch in the direction of the normal + homogenization_RGC_surfaceCorrection(iBase) + invC(i,j)*nVect(i)*nVect(j) + enddo; enddo + homogenization_RGC_surfaceCorrection(iBase) = & ! get the surface correction factor (area contraction/enlargement) + sqrt(homogenization_RGC_surfaceCorrection(iBase))*detF + enddo + +end function homogenization_RGC_surfaceCorrection + + +!-------------------------------------------------------------------------------------------------- +!> @brief compute the equivalent shear and bulk moduli from the elasticity tensor +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_equivalentModuli(grainID,ip,el) + use constitutive, only: & + constitutive_homogenizedC + + implicit none + integer(pInt), intent(in) :: & + grainID,& + ip, & !< integration point number + el !< element number + real(pReal), dimension (6,6) :: elasTens + real(pReal), dimension(2) :: homogenization_RGC_equivalentModuli + 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 + homogenization_RGC_equivalentModuli(1) = 0.2_pReal*(cEquiv_11 - cEquiv_12) + 0.6_pReal*cEquiv_44 + +!-------------------------------------------------------------------------------------------------- +! obtain the length of Burgers vector (could be model dependend) + homogenization_RGC_equivalentModuli(2) = 2.5e-10_pReal + +end function homogenization_RGC_equivalentModuli + + +!-------------------------------------------------------------------------------------------------- +!> @brief collect relaxation vectors of an interface +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_relaxationVector(intFace,homID, ip, el) + use material, only: & + homogState, & + mappingHomogenization + + implicit none + integer(pInt), intent(in) :: ip, el + real(pReal), dimension (3) :: homogenization_RGC_relaxationVector + integer(pInt), dimension (4), intent(in) :: intFace !< set of interface ID in 4D array (normal and position) + integer(pInt), dimension (3) :: nGDim + integer(pInt) :: & + iNum, & + homID !< homogenization ID + +!-------------------------------------------------------------------------------------------------- +! collect the interface relaxation vector from the global state array + homogenization_RGC_relaxationVector = 0.0_pReal + nGDim = homogenization_RGC_Ngrains(1:3,homID) + iNum = homogenization_RGC_interface4to1(intFace,homID) ! identify the position of the interface in global state array + if (iNum > 0_pInt) homogenization_RGC_relaxationVector = homogState(mappingHomogenization(2,ip,el))% & + state((3*iNum-2):(3*iNum),mappingHomogenization(1,ip,el)) ! get the corresponding entries + +end function homogenization_RGC_relaxationVector + + +!-------------------------------------------------------------------------------------------------- +!> @brief identify the normal of an interface +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_interfaceNormal(intFace,ip,el) + use debug, only: & + debug_homogenization,& + debug_levelExtensive + use math, only: & + math_mul33x3 + + implicit none + real(pReal), dimension (3) :: homogenization_RGC_interfaceNormal + integer(pInt), dimension (4), intent(in) :: intFace !< interface ID in 4D array (normal and position) + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + integer(pInt) :: nPos + +!-------------------------------------------------------------------------------------------------- +! get the normal of the interface, identified from the value of intFace(1) + homogenization_RGC_interfaceNormal = 0.0_pReal + nPos = abs(intFace(1)) ! identify the position of the interface in global state array + homogenization_RGC_interfaceNormal(nPos) = real(intFace(1)/abs(intFace(1)),pReal) ! get the normal vector w.r.t. cluster axis + + homogenization_RGC_interfaceNormal = & + math_mul33x3(homogenization_RGC_orientation(1:3,1:3,ip,el),homogenization_RGC_interfaceNormal) + ! map the normal vector into sample coordinate system (basis) + +end function homogenization_RGC_interfaceNormal + + +!-------------------------------------------------------------------------------------------------- +!> @brief collect six faces of a grain in 4D (normal and position) +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_getInterface(iFace,iGrain3) + + implicit none + integer(pInt), dimension (4) :: homogenization_RGC_getInterface + integer(pInt), dimension (3), intent(in) :: iGrain3 !< grain ID in 3D array + integer(pInt), intent(in) :: iFace !< face index (1..6) mapped like (-e1,-e2,-e3,+e1,+e2,+e3) or iDir = (-1,-2,-3,1,2,3) + integer(pInt) :: iDir + +!* Direction of interface normal + iDir = (int(real(iFace-1_pInt,pReal)/2.0_pReal,pInt)+1_pInt)*(-1_pInt)**iFace + homogenization_RGC_getInterface(1) = iDir + +!-------------------------------------------------------------------------------------------------- +! identify the interface position by the direction of its normal + homogenization_RGC_getInterface(2:4) = iGrain3 + if (iDir < 0_pInt) & ! to have a correlation with coordinate/position in real space + homogenization_RGC_getInterface(1_pInt-iDir) = homogenization_RGC_getInterface(1_pInt-iDir)-1_pInt + +end function homogenization_RGC_getInterface + +!-------------------------------------------------------------------------------------------------- +!> @brief map grain ID from in 1D (global array) to in 3D (local position) +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_grain1to3(grain1,homID) + + implicit none + integer(pInt), dimension (3) :: homogenization_RGC_grain1to3 + integer(pInt), intent(in) :: & + grain1,& !< grain ID in 1D array + homID !< homogenization ID + integer(pInt), dimension (3) :: nGDim + +!-------------------------------------------------------------------------------------------------- +! get the grain position + nGDim = homogenization_RGC_Ngrains(1:3,homID) + homogenization_RGC_grain1to3(3) = 1_pInt+(grain1-1_pInt)/(nGDim(1)*nGDim(2)) + homogenization_RGC_grain1to3(2) = 1_pInt+mod((grain1-1_pInt)/nGDim(1),nGDim(2)) + homogenization_RGC_grain1to3(1) = 1_pInt+mod((grain1-1_pInt),nGDim(1)) + +end function homogenization_RGC_grain1to3 + + +!-------------------------------------------------------------------------------------------------- +!> @brief map grain ID from in 3D (local position) to in 1D (global array) +!-------------------------------------------------------------------------------------------------- +pure function homogenization_RGC_grain3to1(grain3,homID) + + implicit none + integer(pInt), dimension (3), intent(in) :: grain3 !< grain ID in 3D array (pos.x,pos.y,pos.z) + integer(pInt) :: homogenization_RGC_grain3to1 + integer(pInt), dimension (3) :: nGDim + integer(pInt), intent(in) :: homID ! homogenization ID + +!-------------------------------------------------------------------------------------------------- +! get the grain ID + nGDim = homogenization_RGC_Ngrains(1:3,homID) + homogenization_RGC_grain3to1 = grain3(1) + nGDim(1)*(grain3(2)-1_pInt) + nGDim(1)*nGDim(2)*(grain3(3)-1_pInt) + +end function homogenization_RGC_grain3to1 + + +!-------------------------------------------------------------------------------------------------- +!> @brief maps interface ID from 4D (normal and local position) into 1D (global array) +!-------------------------------------------------------------------------------------------------- +integer(pInt) pure function homogenization_RGC_interface4to1(iFace4D, homID) + + implicit none + integer(pInt), dimension (4), intent(in) :: iFace4D !< interface ID in 4D array (n.dir,pos.x,pos.y,pos.z) + integer(pInt), dimension (3) :: nGDim,nIntFace + integer(pInt), intent(in) :: homID !< homogenization ID + + nGDim = homogenization_RGC_Ngrains(1:3,homID) + +!-------------------------------------------------------------------------------------------------- +! compute the total number of interfaces, which ... + nIntFace(1) = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) ! ... normal //e1 + nIntFace(2) = nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) ! ... normal //e2 + nIntFace(3) = nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) ! ... normal //e3 + + homogenization_RGC_interface4to1 = -1_pInt + +!-------------------------------------------------------------------------------------------------- +! get the corresponding interface ID in 1D global array + if (abs(iFace4D(1)) == 1_pInt) then ! interface with normal //e1 + homogenization_RGC_interface4to1 = iFace4D(3) + nGDim(2)*(iFace4D(4)-1_pInt) & + + nGDim(2)*nGDim(3)*(iFace4D(2)-1_pInt) + if ((iFace4D(2) == 0_pInt) .or. (iFace4D(2) == nGDim(1))) homogenization_RGC_interface4to1 = 0_pInt + elseif (abs(iFace4D(1)) == 2_pInt) then ! interface with normal //e2 + homogenization_RGC_interface4to1 = iFace4D(4) + nGDim(3)*(iFace4D(2)-1_pInt) & + + nGDim(3)*nGDim(1)*(iFace4D(3)-1_pInt) + nIntFace(1) + if ((iFace4D(3) == 0_pInt) .or. (iFace4D(3) == nGDim(2))) homogenization_RGC_interface4to1 = 0_pInt + elseif (abs(iFace4D(1)) == 3_pInt) then ! interface with normal //e3 + homogenization_RGC_interface4to1 = iFace4D(2) + nGDim(1)*(iFace4D(3)-1_pInt) & + + nGDim(1)*nGDim(2)*(iFace4D(4)-1_pInt) + nIntFace(1) + nIntFace(2) + if ((iFace4D(4) == 0_pInt) .or. (iFace4D(4) == nGDim(3))) homogenization_RGC_interface4to1 = 0_pInt + endif + +end function homogenization_RGC_interface4to1 + + +!-------------------------------------------------------------------------------------------------- +!> @brief maps interface ID from 1D (global array) into 4D (normal and local position) +!-------------------------------------------------------------------------------------------------- +function homogenization_RGC_interface1to4(iFace1D, homID) + + implicit none + integer(pInt), dimension (4) :: homogenization_RGC_interface1to4 + integer(pInt), intent(in) :: iFace1D !< interface ID in 1D array + integer(pInt), dimension (3) :: nGDim,nIntFace + integer(pInt), intent(in) :: homID !< homogenization ID + + nGDim = homogenization_RGC_Ngrains(:,homID) + +!-------------------------------------------------------------------------------------------------- +! compute the total number of interfaces, which ... + nIntFace(1) = (nGDim(1)-1_pInt)*nGDim(2)*nGDim(3) ! ... normal //e1 + nIntFace(2) = nGDim(1)*(nGDim(2)-1_pInt)*nGDim(3) ! ... normal //e2 + nIntFace(3) = nGDim(1)*nGDim(2)*(nGDim(3)-1_pInt) ! ... normal //e3 + +!-------------------------------------------------------------------------------------------------- +! get the corresponding interface ID in 4D (normal and local position) + if (iFace1D > 0 .and. iFace1D <= nIntFace(1)) then ! interface with normal //e1 + homogenization_RGC_interface1to4(1) = 1_pInt + homogenization_RGC_interface1to4(3) = mod((iFace1D-1_pInt),nGDim(2))+1_pInt + homogenization_RGC_interface1to4(4) = mod(& + int(& + real(iFace1D-1_pInt,pReal)/& + real(nGDim(2),pReal)& + ,pInt)& + ,nGDim(3))+1_pInt + homogenization_RGC_interface1to4(2) = int(& + real(iFace1D-1_pInt,pReal)/& + real(nGDim(2),pReal)/& + real(nGDim(3),pReal)& + ,pInt)+1_pInt + elseif (iFace1D > nIntFace(1) .and. iFace1D <= (nIntFace(2) + nIntFace(1))) then ! interface with normal //e2 + homogenization_RGC_interface1to4(1) = 2_pInt + homogenization_RGC_interface1to4(4) = mod((iFace1D-nIntFace(1)-1_pInt),nGDim(3))+1_pInt + homogenization_RGC_interface1to4(2) = mod(& + int(& + real(iFace1D-nIntFace(1)-1_pInt,pReal)/& + real(nGDim(3),pReal)& + ,pInt)& + ,nGDim(1))+1_pInt + homogenization_RGC_interface1to4(3) = int(& + real(iFace1D-nIntFace(1)-1_pInt,pReal)/& + real(nGDim(3),pReal)/& + real(nGDim(1),pReal)& + ,pInt)+1_pInt + elseif (iFace1D > nIntFace(2) + nIntFace(1) .and. iFace1D <= (nIntFace(3) + nIntFace(2) + nIntFace(1))) then ! interface with normal //e3 + homogenization_RGC_interface1to4(1) = 3_pInt + homogenization_RGC_interface1to4(2) = mod((iFace1D-nIntFace(2)-nIntFace(1)-1_pInt),nGDim(1))+1_pInt + homogenization_RGC_interface1to4(3) = mod(& + int(& + real(iFace1D-nIntFace(2)-nIntFace(1)-1_pInt,pReal)/& + real(nGDim(1),pReal)& + ,pInt)& + ,nGDim(2))+1_pInt + homogenization_RGC_interface1to4(4) = int(& + real(iFace1D-nIntFace(2)-nIntFace(1)-1_pInt,pReal)/& + real(nGDim(1),pReal)/& + real(nGDim(2),pReal)& + ,pInt)+1_pInt + endif + +end function homogenization_RGC_interface1to4 + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculating the grain deformation gradient (the same with +! homogenization_RGC_partionDeformation, but used only for perturbation scheme) +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_RGC_grainDeformation(F, avgF, ip, el) + use mesh, only: & + mesh_element + use material, only: & + homogenization_maxNgrains,& + homogenization_Ngrains, & + homogenization_typeInstance + + implicit none + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned F per grain + real(pReal), dimension (3,3), intent(in) :: avgF !< + integer(pInt), intent(in) :: & + el, & !< element number + ip !< integration point number + real(pReal), dimension (3) :: aVect,nVect + integer(pInt), dimension (4) :: intFace + integer(pInt), dimension (3) :: iGrain3 + integer(pInt) :: homID, iGrain,iFace,i,j + integer(pInt), parameter :: nFace = 6_pInt + +!-------------------------------------------------------------------------------------------------- +! compute the deformation gradient of individual grains due to relaxations + homID = homogenization_typeInstance(mesh_element(3,el)) + F = 0.0_pReal + do iGrain = 1_pInt,homogenization_Ngrains(mesh_element(3,el)) + iGrain3 = homogenization_RGC_grain1to3(iGrain,homID) + do iFace = 1_pInt,nFace + intFace = homogenization_RGC_getInterface(iFace,iGrain3) + aVect = homogenization_RGC_relaxationVector(intFace,homID, ip, el) + nVect = homogenization_RGC_interfaceNormal(intFace,ip,el) + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) & + F(i,j,iGrain) = F(i,j,iGrain) + aVect(i)*nVect(j) ! effective relaxations + enddo + F(1:3,1:3,iGrain) = F(1:3,1:3,iGrain) + avgF ! relaxed deformation gradient + enddo + +end subroutine homogenization_RGC_grainDeformation + +end module homogenization_RGC diff --git a/src/homogenization_isostrain.f90 b/src/homogenization_isostrain.f90 new file mode 100644 index 000000000..083107d9f --- /dev/null +++ b/src/homogenization_isostrain.f90 @@ -0,0 +1,317 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Isostrain (full constraint Taylor assuption) homogenization scheme +!-------------------------------------------------------------------------------------------------- +module homogenization_isostrain + use prec, only: & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + homogenization_isostrain_sizePostResults + integer(pInt), dimension(:,:), allocatable, target, public :: & + homogenization_isostrain_sizePostResult + + character(len=64), dimension(:,:), allocatable, target, public :: & + homogenization_isostrain_output !< name of each post result output + integer(pInt), dimension(:), allocatable, target, public :: & + homogenization_isostrain_Noutput !< number of outputs per homog instance + integer(pInt), dimension(:), allocatable, private :: & + homogenization_isostrain_Ngrains + enum, bind(c) + enumerator :: undefined_ID, & + nconstituents_ID, & + ipcoords_ID, & + avgdefgrad_ID, & + avgfirstpiola_ID + end enum + enum, bind(c) + enumerator :: parallel_ID, & + average_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + homogenization_isostrain_outputID !< ID of each post result output + integer(kind(average_ID)), dimension(:), allocatable, private :: & + homogenization_isostrain_mapping !< mapping type + + + public :: & + homogenization_isostrain_init, & + homogenization_isostrain_partitionDeformation, & + homogenization_isostrain_averageStressAndItsTangent, & + homogenization_isostrain_postResults + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_isostrain_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal + use debug, only: & + debug_HOMOGENIZATION, & + debug_level, & + debug_levelBasic + use IO + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + section = 0_pInt, i, mySize, o + integer :: & + maxNinstance, & + homog, & + instance + integer :: & + NofMyHomog ! no pInt (stores a system dependen value from 'count' + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_ISOSTRAIN_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = count(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID) + if (maxNinstance == 0) return + + if (iand(debug_level(debug_HOMOGENIZATION),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + allocate(homogenization_isostrain_sizePostResults(maxNinstance), source=0_pInt) + allocate(homogenization_isostrain_sizePostResult(maxval(homogenization_Noutput),maxNinstance), & + source=0_pInt) + allocate(homogenization_isostrain_Noutput(maxNinstance), source=0_pInt) + allocate(homogenization_isostrain_Ngrains(maxNinstance), source=0_pInt) + allocate(homogenization_isostrain_mapping(maxNinstance), source=average_ID) + allocate(homogenization_isostrain_output(maxval(homogenization_Noutput),maxNinstance)) + homogenization_isostrain_output = '' + allocate(homogenization_isostrain_outputID(maxval(homogenization_Noutput),maxNinstance), & + source=undefined_ID) + + rewind(fileUnit) + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homogenization part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + cycle + endif + if (section > 0_pInt ) then ! do not short-circuit here (.and. with next if-statement). It's not safe in Fortran + if (homogenization_type(section) == HOMOGENIZATION_ISOSTRAIN_ID) then ! one of my sections + i = homogenization_typeInstance(section) ! which instance of my type is present homogenization + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case('nconstituents','ngrains') + homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt + homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = nconstituents_ID + homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('ipcoords') + homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt + homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = ipcoords_ID + homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('avgdefgrad','avgf') + homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt + homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = avgdefgrad_ID + homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case('avgp','avgfirstpiola','avg1stpiola') + homogenization_isostrain_Noutput(i) = homogenization_isostrain_Noutput(i) + 1_pInt + homogenization_isostrain_outputID(homogenization_isostrain_Noutput(i),i) = avgfirstpiola_ID + homogenization_isostrain_output(homogenization_isostrain_Noutput(i),i) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + + end select + case ('nconstituents','ngrains') + homogenization_isostrain_Ngrains(i) = IO_intValue(line,chunkPos,2_pInt) + case ('mapping') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('parallel','sum') + homogenization_isostrain_mapping(i) = parallel_ID + case ('average','mean','avg') + homogenization_isostrain_mapping(i) = average_ID + case default + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//HOMOGENIZATION_isostrain_label//')') + end select + + end select + endif + endif + enddo parsingFile + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + myHomog: if (homogenization_type(homog) == HOMOGENIZATION_ISOSTRAIN_ID) then + NofMyHomog = count(material_homog == homog) + instance = homogenization_typeInstance(homog) + +! * Determine size of postResults array + outputsLoop: do o = 1_pInt, homogenization_isostrain_Noutput(instance) + select case(homogenization_isostrain_outputID(o,instance)) + case(nconstituents_ID) + mySize = 1_pInt + case(ipcoords_ID) + mySize = 3_pInt + case(avgdefgrad_ID, avgfirstpiola_ID) + mySize = 9_pInt + case default + mySize = 0_pInt + end select + + outputFound: if (mySize > 0_pInt) then + homogenization_isostrain_sizePostResult(o,instance) = mySize + homogenization_isostrain_sizePostResults(instance) = & + homogenization_isostrain_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop + +! allocate state arrays + homogState(homog)%sizeState = 0_pInt + homogState(homog)%sizePostResults = homogenization_isostrain_sizePostResults(instance) + allocate(homogState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) + + endif myHomog + enddo initializeInstances + +end subroutine homogenization_isostrain_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief partitions the deformation gradient onto the constituents +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_isostrain_partitionDeformation(F,avgF,el) + use prec, only: & + pReal + use mesh, only: & + mesh_element + use material, only: & + homogenization_maxNgrains, & + homogenization_Ngrains + + implicit none + real(pReal), dimension (3,3,homogenization_maxNgrains), intent(out) :: F !< partioned def grad per grain + real(pReal), dimension (3,3), intent(in) :: avgF !< my average def grad + integer(pInt), intent(in) :: & + el !< element number + F=0.0_pReal + F(1:3,1:3,1:homogenization_Ngrains(mesh_element(3,el)))= & + spread(avgF,3,homogenization_Ngrains(mesh_element(3,el))) + +end subroutine homogenization_isostrain_partitionDeformation + + +!-------------------------------------------------------------------------------------------------- +!> @brief derive average stress and stiffness from constituent quantities +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_isostrain_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,el) + use prec, only: & + pReal + use mesh, only: & + mesh_element + use material, only: & + homogenization_maxNgrains, & + homogenization_Ngrains, & + homogenization_typeInstance + + implicit none + 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 (3,3,homogenization_maxNgrains), intent(in) :: P !< array of current grain stresses + real(pReal), dimension (3,3,3,3,homogenization_maxNgrains), intent(in) :: dPdF !< array of current grain stiffnesses + integer(pInt), intent(in) :: el !< element number + integer(pInt) :: & + homID, & + Ngrains + + homID = homogenization_typeInstance(mesh_element(3,el)) + Ngrains = homogenization_Ngrains(mesh_element(3,el)) + + select case (homogenization_isostrain_mapping(homID)) + case (parallel_ID) + avgP = sum(P,3) + dAvgPdAvgF = sum(dPdF,5) + case (average_ID) + avgP = sum(P,3) /real(Ngrains,pReal) + dAvgPdAvgF = sum(dPdF,5)/real(Ngrains,pReal) + end select + +end subroutine homogenization_isostrain_averageStressAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of homogenization results for post file inclusion +!-------------------------------------------------------------------------------------------------- +pure function homogenization_isostrain_postResults(ip,el,avgP,avgF) + use prec, only: & + pReal + use mesh, only: & + mesh_element, & + mesh_ipCoordinates + use material, only: & + homogenization_typeInstance, & + homogenization_Noutput + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3), intent(in) :: & + avgP, & !< average stress at material point + avgF !< average deformation gradient at material point + real(pReal), dimension(homogenization_isostrain_sizePostResults & + (homogenization_typeInstance(mesh_element(3,el)))) :: & + homogenization_isostrain_postResults + + integer(pInt) :: & + homID, & + o, c + + c = 0_pInt + homID = homogenization_typeInstance(mesh_element(3,el)) + homogenization_isostrain_postResults = 0.0_pReal + + do o = 1_pInt,homogenization_Noutput(mesh_element(3,el)) + select case(homogenization_isostrain_outputID(o,homID)) + case (nconstituents_ID) + homogenization_isostrain_postResults(c+1_pInt) = real(homogenization_isostrain_Ngrains(homID),pReal) + c = c + 1_pInt + case (avgdefgrad_ID) + homogenization_isostrain_postResults(c+1_pInt:c+9_pInt) = reshape(avgF,[9]) + c = c + 9_pInt + case (avgfirstpiola_ID) + homogenization_isostrain_postResults(c+1_pInt:c+9_pInt) = reshape(avgP,[9]) + c = c + 9_pInt + case (ipcoords_ID) + homogenization_isostrain_postResults(c+1_pInt:c+3_pInt) = mesh_ipCoordinates(1:3,ip,el) ! current ip coordinates + c = c + 3_pInt + end select + enddo + +end function homogenization_isostrain_postResults + +end module homogenization_isostrain diff --git a/src/homogenization_none.f90 b/src/homogenization_none.f90 new file mode 100644 index 000000000..59e483c27 --- /dev/null +++ b/src/homogenization_none.f90 @@ -0,0 +1,60 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief dummy homogenization homogenization scheme +!-------------------------------------------------------------------------------------------------- +module homogenization_none + + implicit none + private + + public :: & + homogenization_none_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_none_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- homogenization_'//HOMOGENIZATION_NONE_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (homogenization_type(homog) == HOMOGENIZATION_none_ID) then + NofMyHomog = count(material_homog == homog) + homogState(homog)%sizeState = 0_pInt + homogState(homog)%sizePostResults = 0_pInt + allocate(homogState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) + allocate(homogState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) + + endif myhomog + enddo initializeInstances + + +end subroutine homogenization_none_init + +end module homogenization_none diff --git a/src/hydrogenflux_cahnhilliard.f90 b/src/hydrogenflux_cahnhilliard.f90 new file mode 100644 index 000000000..d8cb71edc --- /dev/null +++ b/src/hydrogenflux_cahnhilliard.f90 @@ -0,0 +1,513 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for conservative transport of solute hydrogen +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module hydrogenflux_cahnhilliard + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + hydrogenflux_cahnhilliard_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + hydrogenflux_cahnhilliard_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + hydrogenflux_cahnhilliard_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + hydrogenflux_cahnhilliard_Noutput !< number of outputs per instance of this damage + + real(pReal), parameter, private :: & + kB = 1.3806488e-23_pReal !< Boltzmann constant in J/Kelvin + + enum, bind(c) + enumerator :: undefined_ID, & + hydrogenConc_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + hydrogenflux_cahnhilliard_outputID !< ID of each post result output + + + public :: & + hydrogenflux_cahnhilliard_init, & + hydrogenflux_cahnhilliard_getMobility33, & + hydrogenflux_cahnhilliard_getDiffusion33, & + hydrogenflux_cahnhilliard_getFormationEnergy, & + hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent, & + hydrogenflux_cahnhilliard_getChemPotAndItsTangent, & + hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate, & + hydrogenflux_cahnhilliard_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine hydrogenflux_cahnhilliard_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + hydrogenflux_type, & + hydrogenflux_typeInstance, & + homogenization_Noutput, & + HYDROGENFLUX_cahnhilliard_label, & + HYDROGENFLUX_cahnhilliard_ID, & + material_homog, & + mappingHomogenization, & + hydrogenfluxState, & + hydrogenfluxMapping, & + hydrogenConc, & + hydrogenConcRate, & + hydrogenflux_initialCh, & + material_partHomogenization, & + material_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- hydrogenflux_'//HYDROGENFLUX_cahnhilliard_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(hydrogenflux_type == HYDROGENFLUX_cahnhilliard_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(hydrogenflux_cahnhilliard_sizePostResults(maxNinstance), source=0_pInt) + allocate(hydrogenflux_cahnhilliard_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(hydrogenflux_cahnhilliard_output (maxval(homogenization_Noutput),maxNinstance)) + hydrogenflux_cahnhilliard_output = '' + allocate(hydrogenflux_cahnhilliard_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(hydrogenflux_cahnhilliard_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (hydrogenflux_type(section) == HYDROGENFLUX_cahnhilliard_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = hydrogenflux_typeInstance(section) ! which instance of my hydrogenflux is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('hydrogenconc') + hydrogenflux_cahnhilliard_Noutput(instance) = hydrogenflux_cahnhilliard_Noutput(instance) + 1_pInt + hydrogenflux_cahnhilliard_outputID(hydrogenflux_cahnhilliard_Noutput(instance),instance) = hydrogenConc_ID + hydrogenflux_cahnhilliard_output(hydrogenflux_cahnhilliard_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingHomog + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + initializeInstances: do section = 1_pInt, size(hydrogenflux_type) + if (hydrogenflux_type(section) == HYDROGENFLUX_cahnhilliard_ID) then + NofMyHomog=count(material_homog==section) + instance = hydrogenflux_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,hydrogenflux_cahnhilliard_Noutput(instance) + select case(hydrogenflux_cahnhilliard_outputID(o,instance)) + case(hydrogenConc_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + hydrogenflux_cahnhilliard_sizePostResult(o,instance) = mySize + hydrogenflux_cahnhilliard_sizePostResults(instance) = hydrogenflux_cahnhilliard_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 0_pInt + hydrogenfluxState(section)%sizeState = sizeState + hydrogenfluxState(section)%sizePostResults = hydrogenflux_cahnhilliard_sizePostResults(instance) + allocate(hydrogenfluxState(section)%state0 (sizeState,NofMyHomog)) + allocate(hydrogenfluxState(section)%subState0(sizeState,NofMyHomog)) + allocate(hydrogenfluxState(section)%state (sizeState,NofMyHomog)) + + nullify(hydrogenfluxMapping(section)%p) + hydrogenfluxMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(hydrogenConc (section)%p) + deallocate(hydrogenConcRate(section)%p) + allocate (hydrogenConc (section)%p(NofMyHomog), source=hydrogenflux_initialCh(section)) + allocate (hydrogenConcRate(section)%p(NofMyHomog), source=0.0_pReal) + + endif + + enddo initializeInstances + +end subroutine hydrogenflux_cahnhilliard_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized solute mobility tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function hydrogenflux_cahnhilliard_getMobility33(ip,el) + use lattice, only: & + lattice_hydrogenfluxMobility33 + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + hydrogenflux_cahnhilliard_getMobility33 + integer(pInt) :: & + grain + + hydrogenflux_cahnhilliard_getMobility33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + hydrogenflux_cahnhilliard_getMobility33 = hydrogenflux_cahnhilliard_getMobility33 + & + crystallite_push33ToRef(grain,ip,el,lattice_hydrogenfluxMobility33(:,:,material_phase(grain,ip,el))) + enddo + + hydrogenflux_cahnhilliard_getMobility33 = & + hydrogenflux_cahnhilliard_getMobility33/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function hydrogenflux_cahnhilliard_getMobility33 + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized solute nonlocal diffusion tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function hydrogenflux_cahnhilliard_getDiffusion33(ip,el) + use lattice, only: & + lattice_hydrogenfluxDiffusion33 + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + hydrogenflux_cahnhilliard_getDiffusion33 + integer(pInt) :: & + grain + + hydrogenflux_cahnhilliard_getDiffusion33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + hydrogenflux_cahnhilliard_getDiffusion33 = hydrogenflux_cahnhilliard_getDiffusion33 + & + crystallite_push33ToRef(grain,ip,el,lattice_hydrogenfluxDiffusion33(:,:,material_phase(grain,ip,el))) + enddo + + hydrogenflux_cahnhilliard_getDiffusion33 = & + hydrogenflux_cahnhilliard_getDiffusion33/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function hydrogenflux_cahnhilliard_getDiffusion33 + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized solution energy +!-------------------------------------------------------------------------------------------------- +function hydrogenflux_cahnhilliard_getFormationEnergy(ip,el) + use lattice, only: & + lattice_hydrogenFormationEnergy, & + lattice_hydrogenVol, & + lattice_hydrogenSurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + hydrogenflux_cahnhilliard_getFormationEnergy + integer(pInt) :: & + grain + + hydrogenflux_cahnhilliard_getFormationEnergy = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + hydrogenflux_cahnhilliard_getFormationEnergy = hydrogenflux_cahnhilliard_getFormationEnergy + & + lattice_hydrogenFormationEnergy(material_phase(grain,ip,el))/ & + lattice_hydrogenVol(material_phase(grain,ip,el))/ & + lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) + enddo + + hydrogenflux_cahnhilliard_getFormationEnergy = & + hydrogenflux_cahnhilliard_getFormationEnergy/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function hydrogenflux_cahnhilliard_getFormationEnergy + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized hydrogen entropy coefficient +!-------------------------------------------------------------------------------------------------- +function hydrogenflux_cahnhilliard_getEntropicCoeff(ip,el) + use lattice, only: & + lattice_hydrogenVol, & + lattice_hydrogenSurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_homog, & + material_phase, & + temperature, & + thermalMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + hydrogenflux_cahnhilliard_getEntropicCoeff + integer(pInt) :: & + grain + + hydrogenflux_cahnhilliard_getEntropicCoeff = 0.0_pReal + do grain = 1, homogenization_Ngrains(material_homog(ip,el)) + hydrogenflux_cahnhilliard_getEntropicCoeff = hydrogenflux_cahnhilliard_getEntropicCoeff + & + kB/ & + lattice_hydrogenVol(material_phase(grain,ip,el))/ & + lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) + enddo + + hydrogenflux_cahnhilliard_getEntropicCoeff = & + hydrogenflux_cahnhilliard_getEntropicCoeff* & + temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))/ & + homogenization_Ngrains(material_homog(ip,el)) + +end function hydrogenflux_cahnhilliard_getEntropicCoeff + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized kinematic contribution to chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCh, Ch, ip, el) + use lattice, only: & + lattice_hydrogenSurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_homog, & + phase_kinematics, & + phase_Nkinematics, & + material_phase, & + KINEMATICS_hydrogen_strain_ID + use crystallite, only: & + crystallite_Tstar_v, & + crystallite_Fi0, & + crystallite_Fi + use kinematics_hydrogen_strain, only: & + kinematics_hydrogen_strain_ChemPotAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Ch + real(pReal), intent(out) :: & + KPot, dKPot_dCh + real(pReal) :: & + my_KPot, my_dKPot_dCh + integer(pInt) :: & + grain, kinematics + + KPot = 0.0_pReal + dKPot_dCh = 0.0_pReal + do grain = 1_pInt,homogenization_Ngrains(material_homog(ip,el)) + do kinematics = 1_pInt, phase_Nkinematics(material_phase(grain,ip,el)) + select case (phase_kinematics(kinematics,material_phase(grain,ip,el))) + case (KINEMATICS_hydrogen_strain_ID) + call kinematics_hydrogen_strain_ChemPotAndItsTangent(my_KPot, my_dKPot_dCh, & + crystallite_Tstar_v(1:6,grain,ip,el), & + crystallite_Fi0(1:3,1:3,grain,ip,el), & + crystallite_Fi (1:3,1:3,grain,ip,el), & + grain,ip, el) + + case default + my_KPot = 0.0_pReal + my_dKPot_dCh = 0.0_pReal + + end select + KPot = KPot + my_KPot/lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) + dKPot_dCh = dKPot_dCh + my_dKPot_dCh/lattice_hydrogenSurfaceEnergy(material_phase(grain,ip,el)) + enddo + enddo + + KPot = KPot/homogenization_Ngrains(material_homog(ip,el)) + dKPot_dCh = dKPot_dCh/homogenization_Ngrains(material_homog(ip,el)) + +end subroutine hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine hydrogenflux_cahnhilliard_getChemPotAndItsTangent(ChemPot,dChemPot_dCh,Ch,ip,el) + use numerics, only: & + hydrogenBoundPenalty, & + hydrogenPolyOrder + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Ch + real(pReal), intent(out) :: & + ChemPot, & + dChemPot_dCh + real(pReal) :: & + kBT, KPot, dKPot_dCh + integer(pInt) :: & + o + + ChemPot = hydrogenflux_cahnhilliard_getFormationEnergy(ip,el) + dChemPot_dCh = 0.0_pReal + kBT = hydrogenflux_cahnhilliard_getEntropicCoeff(ip,el) + do o = 1_pInt, hydrogenPolyOrder + ChemPot = ChemPot + kBT*((2.0_pReal*Ch - 1.0_pReal)**real(2_pInt*o-1_pInt,pReal))/ & + real(2_pInt*o-1_pInt,pReal) + dChemPot_dCh = dChemPot_dCh + 2.0_pReal*kBT*(2.0_pReal*Ch - 1.0_pReal)**real(2_pInt*o-2_pInt,pReal) + enddo + + call hydrogenflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCh, Ch, ip, el) + ChemPot = ChemPot + KPot + dChemPot_dCh = dChemPot_dCh + dKPot_dCh + + if (Ch < 0.0_pReal) then + ChemPot = ChemPot - 3.0_pReal*hydrogenBoundPenalty*Ch*Ch + dChemPot_dCh = dChemPot_dCh - 6.0_pReal*hydrogenBoundPenalty*Ch + elseif (Ch > 1.0_pReal) then + ChemPot = ChemPot + 3.0_pReal*hydrogenBoundPenalty*(1.0_pReal - Ch)*(1.0_pReal - Ch) + dChemPot_dCh = dChemPot_dCh - 6.0_pReal*hydrogenBoundPenalty*(1.0_pReal - Ch) + endif + +end subroutine hydrogenflux_cahnhilliard_getChemPotAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief updates hydrogen concentration with solution from Cahn-Hilliard PDE for solute transport +!-------------------------------------------------------------------------------------------------- +subroutine hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate(Ch,Chdot,ip,el) + use material, only: & + mappingHomogenization, & + hydrogenConc, & + hydrogenConcRate, & + hydrogenfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Ch, & + Chdot + integer(pInt) :: & + homog, & + offset + + homog = mappingHomogenization(2,ip,el) + offset = hydrogenfluxMapping(homog)%p(ip,el) + hydrogenConc (homog)%p(offset) = Ch + hydrogenConcRate(homog)%p(offset) = Chdot + +end subroutine hydrogenflux_cahnhilliard_putHydrogenConcAndItsRate + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of hydrogen transport results +!-------------------------------------------------------------------------------------------------- +function hydrogenflux_cahnhilliard_postResults(ip,el) + use material, only: & + mappingHomogenization, & + hydrogenflux_typeInstance, & + hydrogenConc, & + hydrogenfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(hydrogenflux_cahnhilliard_sizePostResults(hydrogenflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & + hydrogenflux_cahnhilliard_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = hydrogenfluxMapping(homog)%p(ip,el) + instance = hydrogenflux_typeInstance(homog) + + c = 0_pInt + hydrogenflux_cahnhilliard_postResults = 0.0_pReal + + do o = 1_pInt,hydrogenflux_cahnhilliard_Noutput(instance) + select case(hydrogenflux_cahnhilliard_outputID(o,instance)) + + case (hydrogenConc_ID) + hydrogenflux_cahnhilliard_postResults(c+1_pInt) = hydrogenConc(homog)%p(offset) + c = c + 1 + end select + enddo +end function hydrogenflux_cahnhilliard_postResults + +end module hydrogenflux_cahnhilliard diff --git a/src/hydrogenflux_isoconc.f90 b/src/hydrogenflux_isoconc.f90 new file mode 100644 index 000000000..74759d4c3 --- /dev/null +++ b/src/hydrogenflux_isoconc.f90 @@ -0,0 +1,63 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for constant hydrogen concentration +!-------------------------------------------------------------------------------------------------- +module hydrogenflux_isoconc + + implicit none + private + + public :: & + hydrogenflux_isoconc_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine hydrogenflux_isoconc_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- hydrogenflux_'//HYDROGENFLUX_isoconc_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (hydrogenflux_type(homog) == HYDROGENFLUX_isoconc_ID) then + NofMyHomog = count(material_homog == homog) + hydrogenfluxState(homog)%sizeState = 0_pInt + hydrogenfluxState(homog)%sizePostResults = 0_pInt + allocate(hydrogenfluxState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) + allocate(hydrogenfluxState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) + allocate(hydrogenfluxState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) + + deallocate(hydrogenConc (homog)%p) + deallocate(hydrogenConcRate(homog)%p) + allocate (hydrogenConc (homog)%p(1), source=hydrogenflux_initialCh(homog)) + allocate (hydrogenConcRate(homog)%p(1), source=0.0_pReal) + + endif myhomog + enddo initializeInstances + + +end subroutine hydrogenflux_isoconc_init + +end module hydrogenflux_isoconc diff --git a/src/kinematics_cleavage_opening.f90 b/src/kinematics_cleavage_opening.f90 new file mode 100644 index 000000000..945e2d08a --- /dev/null +++ b/src/kinematics_cleavage_opening.f90 @@ -0,0 +1,303 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from opening of cleavage planes +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_cleavage_opening + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_cleavage_opening_sizePostResults, & !< cumulative size of post results + kinematics_cleavage_opening_offset, & !< which kinematics is my current damage mechanism? + kinematics_cleavage_opening_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_cleavage_opening_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_cleavage_opening_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_cleavage_opening_Noutput !< number of outputs per instance of this damage + + integer(pInt), dimension(:), allocatable, private :: & + kinematics_cleavage_opening_totalNcleavage !< total number of cleavage systems + + integer(pInt), dimension(:,:), allocatable, private :: & + kinematics_cleavage_opening_Ncleavage !< number of cleavage systems per family + + real(pReal), dimension(:), allocatable, private :: & + kinematics_cleavage_opening_sdot_0, & + kinematics_cleavage_opening_N + + real(pReal), dimension(:,:), allocatable, private :: & + kinematics_cleavage_opening_critDisp, & + kinematics_cleavage_opening_critLoad + + public :: & + kinematics_cleavage_opening_init, & + kinematics_cleavage_opening_LiAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_cleavage_opening_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_cleavage_opening_label, & + KINEMATICS_cleavage_opening_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + use lattice, only: & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_cleavage_opening_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_cleavage_opening_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_cleavage_opening_offset(material_Nphase), source=0_pInt) + allocate(kinematics_cleavage_opening_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_cleavage_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_cleavage_opening_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_cleavage_opening_ID) & + kinematics_cleavage_opening_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_cleavage_opening_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_output(maxval(phase_Noutput),maxNinstance)) + kinematics_cleavage_opening_output = '' + allocate(kinematics_cleavage_opening_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(kinematics_cleavage_opening_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(kinematics_cleavage_opening_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_totalNcleavage(maxNinstance), source=0_pInt) + allocate(kinematics_cleavage_opening_sdot_0(maxNinstance), source=0.0_pReal) + allocate(kinematics_cleavage_opening_N(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_cleavage_opening_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('anisobrittle_sdot0') + kinematics_cleavage_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisobrittle_ratesensitivity') + kinematics_cleavage_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('ncleavage') ! + Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_CleavageFamilies + kinematics_cleavage_opening_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticaldisplacement') + do j = 1_pInt, Nchunks_CleavageFamilies + kinematics_cleavage_opening_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticalload') + do j = 1_pInt, Nchunks_CleavageFamilies + kinematics_cleavage_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_cleavage_opening_ID)) then + instance = kinematics_cleavage_opening_instance(phase) + kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & + min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested + kinematics_cleavage_opening_Ncleavage(1:lattice_maxNcleavageFamily,instance)) + kinematics_cleavage_opening_totalNcleavage(instance) = sum(kinematics_cleavage_opening_Ncleavage(:,instance)) ! how many cleavage systems altogether + if (kinematics_cleavage_opening_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_cleavage_opening_LABEL//')') + if (any(kinematics_cleavage_opening_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//KINEMATICS_cleavage_opening_LABEL//')') + if (any(kinematics_cleavage_opening_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//KINEMATICS_cleavage_opening_LABEL//')') + if (kinematics_cleavage_opening_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_cleavage_opening_LABEL//')') + endif myPhase + enddo sanityChecks + +end subroutine kinematics_cleavage_opening_init + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) + use prec, only: & + tol_math_check + use material, only: & + phaseAt, phasememberAt, & + material_homog, & + damage, & + damageMapping + use lattice, only: & + lattice_Scleavage, & + lattice_Scleavage_v, & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola-Kirchhoff stress + real(pReal), intent(out), dimension(3,3) :: & + Ld !< damage velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) + integer(pInt) :: & + phase, & + constituent, & + instance, & + homog, damageOffset, & + f, i, index_myFamily, k, l, m, n + real(pReal) :: & + traction_d, traction_t, traction_n, traction_crit, & + udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = kinematics_cleavage_opening_instance(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + Ld = 0.0_pReal + dLd_dTstar3333 = 0.0_pReal + do f = 1_pInt,lattice_maxNcleavageFamily + index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family + do i = 1_pInt,kinematics_cleavage_opening_Ncleavage(f,instance) ! process each (active) cleavage system in family + traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) + traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) + traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) + traction_crit = kinematics_cleavage_opening_critLoad(f,instance)* & + damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) + udotd = & + sign(1.0_pReal,traction_d)* & + kinematics_cleavage_opening_sdot_0(instance)* & + (max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) + if (abs(udotd) > tol_math_check) then + Ld = Ld + udotd*lattice_Scleavage(1:3,1:3,1,index_myFamily+i,phase) + dudotd_dt = sign(1.0_pReal,traction_d)*udotd*kinematics_cleavage_opening_N(instance)/ & + max(0.0_pReal, abs(traction_d) - traction_crit) + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotd_dt*lattice_Scleavage(k,l,1,index_myFamily+i,phase)* & + lattice_Scleavage(m,n,1,index_myFamily+i,phase) + endif + + udott = & + sign(1.0_pReal,traction_t)* & + kinematics_cleavage_opening_sdot_0(instance)* & + (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) + if (abs(udott) > tol_math_check) then + Ld = Ld + udott*lattice_Scleavage(1:3,1:3,2,index_myFamily+i,phase) + dudott_dt = sign(1.0_pReal,traction_t)*udott*kinematics_cleavage_opening_N(instance)/ & + max(0.0_pReal, abs(traction_t) - traction_crit) + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudott_dt*lattice_Scleavage(k,l,2,index_myFamily+i,phase)* & + lattice_Scleavage(m,n,2,index_myFamily+i,phase) + endif + + udotn = & + sign(1.0_pReal,traction_n)* & + kinematics_cleavage_opening_sdot_0(instance)* & + (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**kinematics_cleavage_opening_N(instance) + if (abs(udotn) > tol_math_check) then + Ld = Ld + udotn*lattice_Scleavage(1:3,1:3,3,index_myFamily+i,phase) + dudotn_dt = sign(1.0_pReal,traction_n)*udotn*kinematics_cleavage_opening_N(instance)/ & + max(0.0_pReal, abs(traction_n) - traction_crit) + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotn_dt*lattice_Scleavage(k,l,3,index_myFamily+i,phase)* & + lattice_Scleavage(m,n,3,index_myFamily+i,phase) + endif + + enddo + enddo + +end subroutine kinematics_cleavage_opening_LiAndItsTangent + +end module kinematics_cleavage_opening diff --git a/src/kinematics_hydrogen_strain.f90 b/src/kinematics_hydrogen_strain.f90 new file mode 100644 index 000000000..ceb3b1ef3 --- /dev/null +++ b/src/kinematics_hydrogen_strain.f90 @@ -0,0 +1,264 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from interstitial hydrogen +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_hydrogen_strain + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_hydrogen_strain_sizePostResults, & !< cumulative size of post results + kinematics_hydrogen_strain_offset, & !< which kinematics is my current damage mechanism? + kinematics_hydrogen_strain_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_hydrogen_strain_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_hydrogen_strain_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_hydrogen_strain_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + kinematics_hydrogen_strain_coeff + + public :: & + kinematics_hydrogen_strain_init, & + kinematics_hydrogen_strain_initialStrain, & + kinematics_hydrogen_strain_LiAndItsTangent, & + kinematics_hydrogen_strain_ChemPotAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_hydrogen_strain_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_hydrogen_strain_label, & + KINEMATICS_hydrogen_strain_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_hydrogen_strain_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_hydrogen_strain_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_hydrogen_strain_offset(material_Nphase), source=0_pInt) + allocate(kinematics_hydrogen_strain_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_hydrogen_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_hydrogen_strain_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_hydrogen_strain_ID) & + kinematics_hydrogen_strain_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_hydrogen_strain_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_hydrogen_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_hydrogen_strain_output(maxval(phase_Noutput),maxNinstance)) + kinematics_hydrogen_strain_output = '' + allocate(kinematics_hydrogen_strain_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_hydrogen_strain_coeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_hydrogen_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_hydrogen_strain_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('hydrogen_strain_coeff') + kinematics_hydrogen_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + +end subroutine kinematics_hydrogen_strain_init + +!-------------------------------------------------------------------------------------------------- +!> @brief report initial hydrogen strain based on current hydrogen conc deviation from +!> equillibrium (0) +!-------------------------------------------------------------------------------------------------- +pure function kinematics_hydrogen_strain_initialStrain(ipc, ip, el) + use math, only: & + math_I3 + use material, only: & + material_phase, & + material_homog, & + hydrogenConc, & + hydrogenfluxMapping + use lattice, only: & + lattice_equilibriumHydrogenConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + kinematics_hydrogen_strain_initialStrain !< initial thermal strain (should be small strain, though) + integer(pInt) :: & + phase, & + homog, offset, instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_hydrogen_strain_instance(phase) + homog = material_homog(ip,el) + offset = hydrogenfluxMapping(homog)%p(ip,el) + + kinematics_hydrogen_strain_initialStrain = & + (hydrogenConc(homog)%p(offset) - lattice_equilibriumHydrogenConcentration(phase)) * & + kinematics_hydrogen_strain_coeff(instance)* math_I3 + +end function kinematics_hydrogen_strain_initialStrain + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_hydrogen_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + hydrogenConc, & + hydrogenConcRate, & + hydrogenfluxMapping + use math, only: & + math_I3 + use lattice, only: & + lattice_equilibriumHydrogenConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out), dimension(3,3) :: & + Li !< thermal velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) + integer(pInt) :: & + phase, & + instance, & + homog, offset + real(pReal) :: & + Ch, ChEq, ChDot + + phase = material_phase(ipc,ip,el) + instance = kinematics_hydrogen_strain_instance(phase) + homog = material_homog(ip,el) + offset = hydrogenfluxMapping(homog)%p(ip,el) + Ch = hydrogenConc(homog)%p(offset) + ChDot = hydrogenConcRate(homog)%p(offset) + ChEq = lattice_equilibriumHydrogenConcentration(phase) + + Li = ChDot*math_I3* & + kinematics_hydrogen_strain_coeff(instance)/ & + (1.0_pReal + kinematics_hydrogen_strain_coeff(instance)*(Ch - ChEq)) + dLi_dTstar3333 = 0.0_pReal + +end subroutine kinematics_hydrogen_strain_LiAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the kinematic contribution to hydrogen chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCh, Tstar_v, Fi0, Fi, ipc, ip, el) + use material, only: & + material_phase + use math, only: & + math_inv33, & + math_mul33x33, & + math_Mandel6to33, & + math_transpose33 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v + real(pReal), intent(in), dimension(3,3) :: & + Fi0, Fi + real(pReal), intent(out) :: & + ChemPot, dChemPot_dCh + integer(pInt) :: & + phase, & + instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_hydrogen_strain_instance(phase) + + ChemPot = -kinematics_hydrogen_strain_coeff(instance)* & + sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & + math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) + dChemPot_dCh = 0.0_pReal + +end subroutine kinematics_hydrogen_strain_ChemPotAndItsTangent + +end module kinematics_hydrogen_strain diff --git a/src/kinematics_slipplane_opening.f90 b/src/kinematics_slipplane_opening.f90 new file mode 100644 index 000000000..8b49e1cf3 --- /dev/null +++ b/src/kinematics_slipplane_opening.f90 @@ -0,0 +1,323 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from opening of slip planes +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_slipplane_opening + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_slipplane_opening_sizePostResults, & !< cumulative size of post results + kinematics_slipplane_opening_offset, & !< which kinematics is my current damage mechanism? + kinematics_slipplane_opening_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_slipplane_opening_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_slipplane_opening_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_slipplane_opening_Noutput !< number of outputs per instance of this damage + + integer(pInt), dimension(:), allocatable, private :: & + kinematics_slipplane_opening_totalNslip !< total number of slip systems + + integer(pInt), dimension(:,:), allocatable, private :: & + kinematics_slipplane_opening_Nslip !< number of slip systems per family + + real(pReal), dimension(:), allocatable, private :: & + kinematics_slipplane_opening_sdot_0, & + kinematics_slipplane_opening_N + + real(pReal), dimension(:,:), allocatable, private :: & + kinematics_slipplane_opening_critPlasticStrain, & + kinematics_slipplane_opening_critLoad + + public :: & + kinematics_slipplane_opening_init, & + kinematics_slipplane_opening_LiAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_slipplane_opening_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_slipplane_opening_label, & + KINEMATICS_slipplane_opening_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + use lattice, only: & + lattice_maxNslipFamily, & + lattice_NslipSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_slipplane_opening_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_slipplane_opening_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_slipplane_opening_offset(material_Nphase), source=0_pInt) + allocate(kinematics_slipplane_opening_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_slipplane_opening_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_slipplane_opening_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_slipplane_opening_ID) & + kinematics_slipplane_opening_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_slipplane_opening_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_slipplane_opening_output(maxval(phase_Noutput),maxNinstance)) + kinematics_slipplane_opening_output = '' + allocate(kinematics_slipplane_opening_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(kinematics_slipplane_opening_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(kinematics_slipplane_opening_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_totalNslip(maxNinstance), source=0_pInt) + allocate(kinematics_slipplane_opening_N(maxNinstance), source=0.0_pReal) + allocate(kinematics_slipplane_opening_sdot_0(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_slipplane_opening_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('nslip') ! + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + kinematics_slipplane_opening_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_sdot0') + kinematics_slipplane_opening_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalplasticstrain') + do j = 1_pInt, Nchunks_SlipFamilies + kinematics_slipplane_opening_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_ratesensitivity') + kinematics_slipplane_opening_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalload') + do j = 1_pInt, Nchunks_SlipFamilies + kinematics_slipplane_opening_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_kinematics(:,phase) == KINEMATICS_slipplane_opening_ID)) then + instance = kinematics_slipplane_opening_instance(phase) + kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested + kinematics_slipplane_opening_Nslip(1:lattice_maxNslipFamily,instance)) + kinematics_slipplane_opening_totalNslip(instance) = sum(kinematics_slipplane_opening_Nslip(:,instance)) + if (kinematics_slipplane_opening_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//KINEMATICS_slipplane_opening_LABEL//')') + if (any(kinematics_slipplane_opening_critPlasticStrain(:,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//KINEMATICS_slipplane_opening_LABEL//')') + if (kinematics_slipplane_opening_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//KINEMATICS_slipplane_opening_LABEL//')') + endif myPhase + enddo sanityChecks + + +end subroutine kinematics_slipplane_opening_init + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar3333, Tstar_v, ipc, ip, el) + use prec, only: & + tol_math_check + use lattice, only: & + lattice_maxNslipFamily, & + lattice_NslipSystem, & + lattice_sd, & + lattice_st, & + lattice_sn + use material, only: & + phaseAt, phasememberAt, & + material_homog, & + damage, & + damageMapping + use math, only: & + math_Plain3333to99, & + math_I3, & + math_identity4th, & + math_symmetric33, & + math_Mandel33to6, & + math_tensorproduct33, & + math_det33, & + math_mul33x33 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola-Kirchhoff stress + real(pReal), intent(out), dimension(3,3) :: & + Ld !< damage velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLd_dTstar3333 !< derivative of Ld with respect to Tstar (4th-order tensor) + real(pReal), dimension(3,3) :: & + projection_d, projection_t, projection_n !< projection modes 3x3 tensor + real(pReal), dimension(6) :: & + projection_d_v, projection_t_v, projection_n_v !< projection modes 3x3 vector + integer(pInt) :: & + phase, & + constituent, & + instance, & + homog, damageOffset, & + f, i, index_myFamily, k, l, m, n + real(pReal) :: & + traction_d, traction_t, traction_n, traction_crit, & + udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = kinematics_slipplane_opening_instance(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + Ld = 0.0_pReal + dLd_dTstar3333 = 0.0_pReal + do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,phase)) ! at which index starts my family + do i = 1_pInt,kinematics_slipplane_opening_Nslip(f,instance) ! process each (active) slip system in family + projection_d = math_tensorproduct33(lattice_sd(1:3,index_myFamily+i,phase),& + lattice_sn(1:3,index_myFamily+i,phase)) + projection_t = math_tensorproduct33(lattice_st(1:3,index_myFamily+i,phase),& + lattice_sn(1:3,index_myFamily+i,phase)) + projection_n = math_tensorproduct33(lattice_sn(1:3,index_myFamily+i,phase),& + lattice_sn(1:3,index_myFamily+i,phase)) + + projection_d_v(1:6) = math_Mandel33to6(math_symmetric33(projection_d(1:3,1:3))) + projection_t_v(1:6) = math_Mandel33to6(math_symmetric33(projection_t(1:3,1:3))) + projection_n_v(1:6) = math_Mandel33to6(math_symmetric33(projection_n(1:3,1:3))) + + traction_d = dot_product(Tstar_v,projection_d_v(1:6)) + traction_t = dot_product(Tstar_v,projection_t_v(1:6)) + traction_n = dot_product(Tstar_v,projection_n_v(1:6)) + + traction_crit = kinematics_slipplane_opening_critLoad(f,instance)* & + damage(homog)%p(damageOffset) ! degrading critical load carrying capacity by damage + + udotd = & + sign(1.0_pReal,traction_d)* & + kinematics_slipplane_opening_sdot_0(instance)* & + (abs(traction_d)/traction_crit - & + abs(traction_d)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) + if (abs(udotd) > tol_math_check) then + Ld = Ld + udotd*projection_d + dudotd_dt = udotd*kinematics_slipplane_opening_N(instance)/traction_d + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotd_dt*projection_d(k,l)*projection_d(m,n) + endif + + udott = & + sign(1.0_pReal,traction_t)* & + kinematics_slipplane_opening_sdot_0(instance)* & + (abs(traction_t)/traction_crit - & + abs(traction_t)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) + if (abs(udott) > tol_math_check) then + Ld = Ld + udott*projection_t + dudott_dt = udott*kinematics_slipplane_opening_N(instance)/traction_t + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudott_dt*projection_t(k,l)*projection_t(m,n) + endif + udotn = & + kinematics_slipplane_opening_sdot_0(instance)* & + (max(0.0_pReal,traction_n)/traction_crit - & + max(0.0_pReal,traction_n)/kinematics_slipplane_opening_critLoad(f,instance))**kinematics_slipplane_opening_N(instance) + if (abs(udotn) > tol_math_check) then + Ld = Ld + udotn*projection_n + dudotn_dt = udotn*kinematics_slipplane_opening_N(instance)/traction_n + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLd_dTstar3333(k,l,m,n) = dLd_dTstar3333(k,l,m,n) + & + dudotn_dt*projection_n(k,l)*projection_n(m,n) + endif + enddo + enddo + +end subroutine kinematics_slipplane_opening_LiAndItsTangent + +end module kinematics_slipplane_opening diff --git a/src/kinematics_thermal_expansion.f90 b/src/kinematics_thermal_expansion.f90 new file mode 100644 index 000000000..b99c499f3 --- /dev/null +++ b/src/kinematics_thermal_expansion.f90 @@ -0,0 +1,228 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from thermal expansion +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_thermal_expansion + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_thermal_expansion_sizePostResults, & !< cumulative size of post results + kinematics_thermal_expansion_offset, & !< which kinematics is my current damage mechanism? + kinematics_thermal_expansion_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_thermal_expansion_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_thermal_expansion_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_thermal_expansion_Noutput !< number of outputs per instance of this damage + +! enum, bind(c) ! ToDo kinematics need state machinery to deal with sizePostResult +! enumerator :: undefined_ID, & ! possible remedy is to decouple having state vars from having output +! thermalexpansionrate_ID ! which means to separate user-defined types tState + tOutput... +! end enum + public :: & + kinematics_thermal_expansion_init, & + kinematics_thermal_expansion_initialStrain, & + kinematics_thermal_expansion_LiAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_thermal_expansion_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_thermal_expansion_label, & + KINEMATICS_thermal_expansion_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + character(len=65536) :: & + tag = '', & + output = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_thermal_expansion_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_thermal_expansion_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_thermal_expansion_offset(material_Nphase), source=0_pInt) + allocate(kinematics_thermal_expansion_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_thermal_expansion_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_thermal_expansion_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_thermal_expansion_ID) & + kinematics_thermal_expansion_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_thermal_expansion_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_thermal_expansion_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_thermal_expansion_output(maxval(phase_Noutput),maxNinstance)) + kinematics_thermal_expansion_output = '' + allocate(kinematics_thermal_expansion_Noutput(maxNinstance), source=0_pInt) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_thermal_expansion_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_thermal_expansion_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key... + select case(tag) +! case ('(output)') +! output = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) ! ...and corresponding output +! select case(output) +! case ('thermalexpansionrate') +! kinematics_thermal_expansion_Noutput(instance) = kinematics_thermal_expansion_Noutput(instance) + 1_pInt +! kinematics_thermal_expansion_outputID(kinematics_thermal_expansion_Noutput(instance),instance) = & +! thermalexpansionrate_ID +! kinematics_thermal_expansion_output(kinematics_thermal_expansion_Noutput(instance),instance) = output +! ToDo add sizePostResult loop afterwards... + + end select + endif; endif + enddo parsingFile + +end subroutine kinematics_thermal_expansion_init + +!-------------------------------------------------------------------------------------------------- +!> @brief report initial thermal strain based on current temperature deviation from reference +!-------------------------------------------------------------------------------------------------- +pure function kinematics_thermal_expansion_initialStrain(ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + temperature, & + thermalMapping + use lattice, only: & + lattice_thermalExpansion33, & + lattice_referenceTemperature + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + kinematics_thermal_expansion_initialStrain !< initial thermal strain (should be small strain, though) + integer(pInt) :: & + phase, & + homog, offset + + phase = material_phase(ipc,ip,el) + homog = material_homog(ip,el) + offset = thermalMapping(homog)%p(ip,el) + + kinematics_thermal_expansion_initialStrain = & + (temperature(homog)%p(offset) - lattice_referenceTemperature(phase)) * & + lattice_thermalExpansion33(1:3,1:3,phase) + +end function kinematics_thermal_expansion_initialStrain + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + temperature, & + temperatureRate, & + thermalMapping + use lattice, only: & + lattice_thermalExpansion33, & + lattice_referenceTemperature + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out), dimension(3,3) :: & + Li !< thermal velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor defined to be zero) + integer(pInt) :: & + phase, & + homog, offset + real(pReal) :: & + T, TRef, TDot + + phase = material_phase(ipc,ip,el) + homog = material_homog(ip,el) + offset = thermalMapping(homog)%p(ip,el) + T = temperature(homog)%p(offset) + TDot = temperatureRate(homog)%p(offset) + TRef = lattice_referenceTemperature(phase) + + Li = TDot* & + lattice_thermalExpansion33(1:3,1:3,phase)/ & + (1.0_pReal + lattice_thermalExpansion33(1:3,1:3,phase)*(T - TRef)) + dLi_dTstar3333 = 0.0_pReal + +end subroutine kinematics_thermal_expansion_LiAndItsTangent + +end module kinematics_thermal_expansion diff --git a/src/kinematics_vacancy_strain.f90 b/src/kinematics_vacancy_strain.f90 new file mode 100644 index 000000000..899bccd9f --- /dev/null +++ b/src/kinematics_vacancy_strain.f90 @@ -0,0 +1,265 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating kinematics resulting from vacancy point defects +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module kinematics_vacancy_strain + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + kinematics_vacancy_strain_sizePostResults, & !< cumulative size of post results + kinematics_vacancy_strain_offset, & !< which kinematics is my current damage mechanism? + kinematics_vacancy_strain_instance !< instance of damage kinematics mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + kinematics_vacancy_strain_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + kinematics_vacancy_strain_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + kinematics_vacancy_strain_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + kinematics_vacancy_strain_coeff + + public :: & + kinematics_vacancy_strain_init, & + kinematics_vacancy_strain_initialStrain, & + kinematics_vacancy_strain_LiAndItsTangent, & + kinematics_vacancy_strain_ChemPotAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_vacancy_strain_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_kinematics, & + phase_Nkinematics, & + phase_Noutput, & + KINEMATICS_vacancy_strain_label, & + KINEMATICS_vacancy_strain_ID, & + material_Nphase, & + MATERIAL_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,kinematics + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- kinematics_'//KINEMATICS_vacancy_strain_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_kinematics == KINEMATICS_vacancy_strain_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(kinematics_vacancy_strain_offset(material_Nphase), source=0_pInt) + allocate(kinematics_vacancy_strain_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + kinematics_vacancy_strain_instance(phase) = count(phase_kinematics(:,1:phase) == kinematics_vacancy_strain_ID) + do kinematics = 1, phase_Nkinematics(phase) + if (phase_kinematics(kinematics,phase) == kinematics_vacancy_strain_ID) & + kinematics_vacancy_strain_offset(phase) = kinematics + enddo + enddo + + allocate(kinematics_vacancy_strain_sizePostResults(maxNinstance), source=0_pInt) + allocate(kinematics_vacancy_strain_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(kinematics_vacancy_strain_output(maxval(phase_Noutput),maxNinstance)) + kinematics_vacancy_strain_output = '' + allocate(kinematics_vacancy_strain_Noutput(maxNinstance), source=0_pInt) + allocate(kinematics_vacancy_strain_coeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_kinematics(:,phase) == KINEMATICS_vacancy_strain_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = kinematics_vacancy_strain_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('vacancy_strain_coeff') + kinematics_vacancy_strain_coeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + +end subroutine kinematics_vacancy_strain_init + +!-------------------------------------------------------------------------------------------------- +!> @brief report initial vacancy strain based on current vacancy conc deviation from equillibrium +!-------------------------------------------------------------------------------------------------- +pure function kinematics_vacancy_strain_initialStrain(ipc, ip, el) + use math, only: & + math_I3 + use material, only: & + material_phase, & + material_homog, & + vacancyConc, & + vacancyfluxMapping + use lattice, only: & + lattice_equilibriumVacancyConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + kinematics_vacancy_strain_initialStrain !< initial thermal strain (should be small strain, though) + integer(pInt) :: & + phase, & + homog, offset, instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_vacancy_strain_instance(phase) + homog = material_homog(ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + + kinematics_vacancy_strain_initialStrain = & + (vacancyConc(homog)%p(offset) - lattice_equilibriumVacancyConcentration(phase)) * & + kinematics_vacancy_strain_coeff(instance)* math_I3 + +end function kinematics_vacancy_strain_initialStrain + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the velocity gradient +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_vacancy_strain_LiAndItsTangent(Li, dLi_dTstar3333, ipc, ip, el) + use material, only: & + material_phase, & + material_homog, & + vacancyConc, & + vacancyConcRate, & + vacancyfluxMapping + use math, only: & + math_I3 + use lattice, only: & + lattice_equilibriumVacancyConcentration + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out), dimension(3,3) :: & + Li !< thermal velocity gradient + real(pReal), intent(out), dimension(3,3,3,3) :: & + dLi_dTstar3333 !< derivative of Li with respect to Tstar (4th-order tensor) + integer(pInt) :: & + phase, & + instance, & + homog, offset + real(pReal) :: & + Cv, CvEq, CvDot + + phase = material_phase(ipc,ip,el) + instance = kinematics_vacancy_strain_instance(phase) + homog = material_homog(ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + + Cv = vacancyConc(homog)%p(offset) + CvDot = vacancyConcRate(homog)%p(offset) + CvEq = lattice_equilibriumvacancyConcentration(phase) + + Li = CvDot*math_I3* & + kinematics_vacancy_strain_coeff(instance)/ & + (1.0_pReal + kinematics_vacancy_strain_coeff(instance)*(Cv - CvEq)) + + dLi_dTstar3333 = 0.0_pReal + +end subroutine kinematics_vacancy_strain_LiAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief contains the kinematic contribution to vacancy chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine kinematics_vacancy_strain_ChemPotAndItsTangent(ChemPot, dChemPot_dCv, Tstar_v, Fi0, Fi, ipc, ip, el) + use material, only: & + material_phase + use math, only: & + math_inv33, & + math_mul33x33, & + math_Mandel6to33, & + math_transpose33 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v + real(pReal), intent(in), dimension(3,3) :: & + Fi0, Fi + real(pReal), intent(out) :: & + ChemPot, dChemPot_dCv + integer(pInt) :: & + phase, & + instance + + phase = material_phase(ipc,ip,el) + instance = kinematics_vacancy_strain_instance(phase) + + ChemPot = -kinematics_vacancy_strain_coeff(instance)* & + sum(math_mul33x33(Fi,math_Mandel6to33(Tstar_v))* & + math_mul33x33(math_mul33x33(Fi,math_inv33(Fi0)),Fi)) + dChemPot_dCv = 0.0_pReal + +end subroutine kinematics_vacancy_strain_ChemPotAndItsTangent + +end module kinematics_vacancy_strain diff --git a/src/lattice.f90 b/src/lattice.f90 new file mode 100644 index 000000000..8e87ba2a9 --- /dev/null +++ b/src/lattice.f90 @@ -0,0 +1,2239 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief defines lattice structure definitions, slip and twin system definitions, Schimd matrix +!> calculation and non-Schmid behavior +!-------------------------------------------------------------------------------------------------- +module lattice + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), parameter, public :: & + LATTICE_maxNslipFamily = 13_pInt, & !< max # of slip system families over lattice structures + LATTICE_maxNtwinFamily = 4_pInt, & !< max # of twin system families over lattice structures + LATTICE_maxNtransFamily = 2_pInt, & !< max # of transformation system families over lattice structures + LATTICE_maxNcleavageFamily = 3_pInt, & !< max # of transformation system families over lattice structures + LATTICE_maxNslip = 52_pInt, & !< max # of slip systems over lattice structures + LATTICE_maxNtwin = 24_pInt, & !< max # of twin systems over lattice structures + LATTICE_maxNinteraction = 182_pInt, & !< max # of interaction types (in hardening matrix part) + LATTICE_maxNnonSchmid = 6_pInt, & !< max # of non schmid contributions over lattice structures + LATTICE_maxNtrans = 12_pInt, & !< max # of transformations over lattice structures + LATTICE_maxNcleavage = 9_pInt !< max # of cleavage over lattice structures + + integer(pInt), allocatable, dimension(:,:), protected, public :: & + lattice_NslipSystem, & !< total # of slip systems in each family + lattice_NtwinSystem, & !< total # of twin systems in each family + lattice_NtransSystem, & !< total # of transformation systems in each family + lattice_NcleavageSystem !< total # of transformation systems in each family + + integer(pInt), allocatable, dimension(:,:,:), protected, public :: & + lattice_interactionSlipSlip, & !< Slip--slip interaction type + lattice_interactionSlipTwin, & !< Slip--twin interaction type + lattice_interactionTwinSlip, & !< Twin--slip interaction type + lattice_interactionTwinTwin, & !< Twin--twin interaction type + lattice_interactionSlipTrans, & !< Slip--trans interaction type + lattice_interactionTransSlip, & !< Trans--slip interaction type + lattice_interactionTransTrans !< Trans--trans interaction type + + real(pReal), allocatable, dimension(:,:,:,:,:), protected, public :: & + lattice_Sslip, & !< Schmid and non-Schmid matrices + lattice_Scleavage !< Schmid matrices for cleavage systems + + real(pReal), allocatable, dimension(:,:,:,:), protected, public :: & + lattice_Sslip_v, & !< Mandel notation of lattice_Sslip + lattice_Scleavage_v !< Mandel notation of lattice_Scleavege + + real(pReal), allocatable, dimension(:,:,:), protected, public :: & + lattice_sn, & !< normal direction of slip system + lattice_sd, & !< slip direction of slip system + lattice_st !< sd x sn + +! rotation and Schmid matrices, normal, shear direction and d x n of twin systems + real(pReal), allocatable, dimension(:,:,:,:), protected, public :: & + lattice_Stwin, & + lattice_Qtwin + + real(pReal), allocatable, dimension(:,:,:), protected, public :: & + lattice_Stwin_v, & + lattice_tn, & + lattice_td, & + lattice_tt + + real(pReal), allocatable, dimension(:,:,:), protected, public :: & + lattice_Strans_v, & !< Eigendeformation tensor in vector form + lattice_projectionTrans !< Matrix for projection of slip to fault-band (twin) systems for strain-induced martensite nucleation + + real(pReal), allocatable, dimension(:,:,:,:), protected, public :: & + lattice_Qtrans, & !< Total rotation: Q = R*B + lattice_Strans !< Eigendeformation tensor for phase transformation + + real(pReal), allocatable, dimension(:,:), protected, public :: & + lattice_shearTwin, & !< characteristic twin shear + lattice_shearTrans !< characteristic transformation shear + + integer(pInt), allocatable, dimension(:), protected, public :: & + lattice_NnonSchmid !< total # of non-Schmid contributions for each structure + +!-------------------------------------------------------------------------------------------------- +! fcc + integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & + LATTICE_fcc_NslipSystem = int([12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],pInt) !< total # of slip systems per family for fcc + + integer(pInt), dimension(LATTICE_maxNtwinFamily), parameter, public :: & + LATTICE_fcc_NtwinSystem = int([12, 0, 0, 0],pInt) !< total # of twin systems per family for fcc + + integer(pInt), dimension(LATTICE_maxNtransFamily), parameter, public :: & + LATTICE_fcc_NtransSystem = int([12, 0],pInt) !< total # of transformation systems per family for fcc + + integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & + LATTICE_fcc_NcleavageSystem = int([3, 4, 0],pInt) !< total # of cleavage systems per family for fcc + + integer(pInt), parameter, private :: & + LATTICE_fcc_Nslip = 12_pInt, & ! sum(lattice_fcc_NslipSystem), & !< total # of slip systems for fcc + LATTICE_fcc_Ntwin = 12_pInt, & ! sum(lattice_fcc_NtwinSystem) !< total # of twin systems for fcc + LATTICE_fcc_NnonSchmid = 0_pInt, & !< total # of non-Schmid contributions for fcc + LATTICE_fcc_Ntrans = 12_pInt, & !< total # of transformations for fcc + LATTICE_fcc_Ncleavage = 7_pInt !< total # of cleavage systems for fcc + + real(pReal), dimension(3+3,LATTICE_fcc_Nslip), parameter, private :: & + LATTICE_fcc_systemSlip = reshape(real([& + ! Slip direction Plane normal + 0, 1,-1, 1, 1, 1, & + -1, 0, 1, 1, 1, 1, & + 1,-1, 0, 1, 1, 1, & + 0,-1,-1, -1,-1, 1, & + 1, 0, 1, -1,-1, 1, & + -1, 1, 0, -1,-1, 1, & + 0,-1, 1, 1,-1,-1, & + -1, 0,-1, 1,-1,-1, & + 1, 1, 0, 1,-1,-1, & + 0, 1, 1, -1, 1,-1, & + 1, 0,-1, -1, 1,-1, & + -1,-1, 0, -1, 1,-1 & + ],pReal),[ 3_pInt + 3_pInt,LATTICE_fcc_Nslip]) !< Slip system <110>{111} directions. Sorted according to Eisenlohr & Hantcherli + + real(pReal), dimension(3+3,LATTICE_fcc_Ntwin), parameter, private :: & + LATTICE_fcc_systemTwin = reshape(real( [& + -2, 1, 1, 1, 1, 1, & + 1,-2, 1, 1, 1, 1, & + 1, 1,-2, 1, 1, 1, & + 2,-1, 1, -1,-1, 1, & + -1, 2, 1, -1,-1, 1, & + -1,-1,-2, -1,-1, 1, & + -2,-1,-1, 1,-1,-1, & + 1, 2,-1, 1,-1,-1, & + 1,-1, 2, 1,-1,-1, & + 2, 1,-1, -1, 1,-1, & + -1,-2,-1, -1, 1,-1, & + -1, 1, 2, -1, 1,-1 & + ],pReal),[ 3_pInt + 3_pInt,LATTICE_fcc_Ntwin]) !< Twin system <112>{111} directions. Sorted according to Eisenlohr & Hantcherli + + real(pReal), dimension(3+3,LATTICE_fcc_Ntrans), parameter, private :: & + LATTICE_fccTohex_systemTrans = reshape(real( [& + -2, 1, 1, 1, 1, 1, & + 1,-2, 1, 1, 1, 1, & + 1, 1,-2, 1, 1, 1, & + 2,-1, 1, -1,-1, 1, & + -1, 2, 1, -1,-1, 1, & + -1,-1,-2, -1,-1, 1, & + -2,-1,-1, 1,-1,-1, & + 1, 2,-1, 1,-1,-1, & + 1,-1, 2, 1,-1,-1, & + 2, 1,-1, -1, 1,-1, & + -1,-2,-1, -1, 1,-1, & + -1, 1, 2, -1, 1,-1 & + ],pReal),[ 3_pInt + 3_pInt,LATTICE_fcc_Ntrans]) + + real(pReal), dimension(LATTICE_fcc_Ntwin), parameter, private :: & + LATTICE_fcc_shearTwin = 0.5_pReal*sqrt(2.0_pReal) !< Twin system <112>{111} ??? Sorted according to Eisenlohr & Hantcherli + + integer(pInt), dimension(2_pInt,LATTICE_fcc_Ntwin), parameter, public :: & + LATTICE_fcc_twinNucleationSlipPair = reshape(int( [& + 2,3, & + 1,3, & + 1,2, & + 5,6, & + 4,6, & + 4,5, & + 8,9, & + 7,9, & + 7,8, & + 11,12, & + 10,12, & + 10,11 & + ],pInt),[2_pInt,LATTICE_fcc_Ntwin]) + + integer(pInt), dimension(LATTICE_fcc_Nslip,lattice_fcc_Nslip), parameter, public :: & + LATTICE_fcc_interactionSlipSlip = reshape(int( [& + 1,2,2,4,6,5,3,5,5,4,5,6, & ! ---> slip + 2,1,2,6,4,5,5,4,6,5,3,5, & ! | + 2,2,1,5,5,3,5,6,4,6,5,4, & ! | + 4,6,5,1,2,2,4,5,6,3,5,5, & ! v slip + 6,4,5,2,1,2,5,3,5,5,4,6, & + 5,5,3,2,2,1,6,5,4,5,6,4, & + 3,5,5,4,5,6,1,2,2,4,6,5, & + 5,4,6,5,3,5,2,1,2,6,4,5, & + 5,6,4,6,5,4,2,2,1,5,5,3, & + 4,5,6,3,5,5,4,6,5,1,2,2, & + 5,3,5,5,4,6,6,4,5,2,1,2, & + 6,5,4,5,6,4,5,5,3,2,2,1 & + ],pInt),[LATTICE_fcc_Nslip,LATTICE_fcc_Nslip],order=[2,1]) !< Slip--slip interaction types for fcc + !< 1: self interaction + !< 2: coplanar interaction + !< 3: collinear interaction + !< 4: Hirth locks + !< 5: glissile junctions + !< 6: Lomer locks + integer(pInt), dimension(LATTICE_fcc_Nslip,LATTICE_fcc_Ntwin), parameter, public :: & + LATTICE_fcc_interactionSlipTwin = reshape(int( [& + 1,1,1,3,3,3,2,2,2,3,3,3, & ! ---> twin + 1,1,1,3,3,3,3,3,3,2,2,2, & ! | + 1,1,1,2,2,2,3,3,3,3,3,3, & ! | + 3,3,3,1,1,1,3,3,3,2,2,2, & ! v slip + 3,3,3,1,1,1,2,2,2,3,3,3, & + 2,2,2,1,1,1,3,3,3,3,3,3, & + 2,2,2,3,3,3,1,1,1,3,3,3, & + 3,3,3,2,2,2,1,1,1,3,3,3, & + 3,3,3,3,3,3,1,1,1,2,2,2, & + 3,3,3,2,2,2,3,3,3,1,1,1, & + 2,2,2,3,3,3,3,3,3,1,1,1, & + 3,3,3,3,3,3,2,2,2,1,1,1 & + ],pInt),[LATTICE_fcc_Nslip,LATTICE_fcc_Ntwin],order=[2,1]) !< Slip--twin interaction types for fcc + !< 1: coplanar interaction + !< 2: screw trace between slip system and twin habit plane (easy cross slip) + !< 3: other interaction + integer(pInt), dimension(LATTICE_fcc_Ntwin,LATTICE_fcc_Nslip), parameter, public :: & + LATTICE_fcc_interactionTwinSlip = 1_pInt !< Twin--Slip interaction types for fcc + + integer(pInt), dimension(LATTICE_fcc_Ntwin,LATTICE_fcc_Ntwin), parameter,public :: & + LATTICE_fcc_interactionTwinTwin = reshape(int( [& + 1,1,1,2,2,2,2,2,2,2,2,2, & ! ---> twin + 1,1,1,2,2,2,2,2,2,2,2,2, & ! | + 1,1,1,2,2,2,2,2,2,2,2,2, & ! | + 2,2,2,1,1,1,2,2,2,2,2,2, & ! v twin + 2,2,2,1,1,1,2,2,2,2,2,2, & + 2,2,2,1,1,1,2,2,2,2,2,2, & + 2,2,2,2,2,2,1,1,1,2,2,2, & + 2,2,2,2,2,2,1,1,1,2,2,2, & + 2,2,2,2,2,2,1,1,1,2,2,2, & + 2,2,2,2,2,2,2,2,2,1,1,1, & + 2,2,2,2,2,2,2,2,2,1,1,1, & + 2,2,2,2,2,2,2,2,2,1,1,1 & + ],pInt),[lattice_fcc_Ntwin,lattice_fcc_Ntwin],order=[2,1]) !< Twin--twin interaction types for fcc + + integer(pInt), dimension(LATTICE_fcc_Nslip,LATTICE_fcc_Ntrans), parameter, public :: & + LATTICE_fccTohex_interactionSlipTrans = reshape(int( [& + 1,1,1,3,3,3,2,2,2,3,3,3, & ! ---> trans + 1,1,1,3,3,3,3,3,3,2,2,2, & ! | + 1,1,1,2,2,2,3,3,3,3,3,3, & ! | + 3,3,3,1,1,1,3,3,3,2,2,2, & ! v slip + 3,3,3,1,1,1,2,2,2,3,3,3, & + 2,2,2,1,1,1,3,3,3,3,3,3, & + 2,2,2,3,3,3,1,1,1,3,3,3, & + 3,3,3,2,2,2,1,1,1,3,3,3, & + 3,3,3,3,3,3,1,1,1,2,2,2, & + 3,3,3,2,2,2,3,3,3,1,1,1, & + 2,2,2,3,3,3,3,3,3,1,1,1, & + 3,3,3,3,3,3,2,2,2,1,1,1 & + ],pInt),[LATTICE_fcc_Nslip,LATTICE_fcc_Ntrans],order=[2,1]) !< Slip--trans interaction types for fcc + + integer(pInt), dimension(LATTICE_fcc_Ntrans,LATTICE_fcc_Nslip), parameter, public :: & + LATTICE_fccTohex_interactionTransSlip = 1_pInt !< Trans--Slip interaction types for fcc + + integer(pInt), dimension(LATTICE_fcc_Ntrans,LATTICE_fcc_Ntrans), parameter,public :: & + LATTICE_fccTohex_interactionTransTrans = reshape(int( [& + 1,1,1,2,2,2,2,2,2,2,2,2, & ! ---> trans + 1,1,1,2,2,2,2,2,2,2,2,2, & ! | + 1,1,1,2,2,2,2,2,2,2,2,2, & ! | + 2,2,2,1,1,1,2,2,2,2,2,2, & ! v trans + 2,2,2,1,1,1,2,2,2,2,2,2, & + 2,2,2,1,1,1,2,2,2,2,2,2, & + 2,2,2,2,2,2,1,1,1,2,2,2, & + 2,2,2,2,2,2,1,1,1,2,2,2, & + 2,2,2,2,2,2,1,1,1,2,2,2, & + 2,2,2,2,2,2,2,2,2,1,1,1, & + 2,2,2,2,2,2,2,2,2,1,1,1, & + 2,2,2,2,2,2,2,2,2,1,1,1 & + ],pInt),[LATTICE_fcc_Ntrans,LATTICE_fcc_Ntrans],order=[2,1]) !< Trans--trans interaction types for fcc + + real(pReal), dimension(LATTICE_fcc_Ntrans), parameter, private :: & + LATTICE_fccTohex_shearTrans = sqrt(2.0_pReal)/4.0_pReal + + real(pReal), dimension(4,LATTICE_fcc_Ntrans), parameter, private :: & + LATTICE_fccTobcc_systemTrans = reshape([& + 0.0, 1.0, 0.0, 10.26, & ! Pitsch OR (Ma & Hartmaier 2014, Table 3) + 0.0, 1.0, 0.0, -10.26, & + 0.0, 0.0, 1.0, 10.26, & + 0.0, 0.0, 1.0, -10.26, & + 1.0, 0.0, 0.0, 10.26, & + 1.0, 0.0, 0.0, -10.26, & + 0.0, 0.0, 1.0, 10.26, & + 0.0, 0.0, 1.0, -10.26, & + 1.0, 0.0, 0.0, 10.26, & + 1.0, 0.0, 0.0, -10.26, & + 0.0, 1.0, 0.0, 10.26, & + 0.0, 1.0, 0.0, -10.26 & + ],[ 4_pInt,LATTICE_fcc_Ntrans]) + + integer(pInt), dimension(9,LATTICE_fcc_Ntrans), parameter, private :: & + LATTICE_fccTobcc_bainVariant = reshape(int( [& + 1, 0, 0, 0, 1, 0, 0, 0, 1, & ! Pitsch OR (Ma & Hartmaier 2014, Table 3) + 1, 0, 0, 0, 1, 0, 0, 0, 1, & + 1, 0, 0, 0, 1, 0, 0, 0, 1, & + 1, 0, 0, 0, 1, 0, 0, 0, 1, & + 0, 1, 0, 1, 0, 0, 0, 0, 1, & + 0, 1, 0, 1, 0, 0, 0, 0, 1, & + 0, 1, 0, 1, 0, 0, 0, 0, 1, & + 0, 1, 0, 1, 0, 0, 0, 0, 1, & + 0, 0, 1, 1, 0, 0, 0, 1, 0, & + 0, 0, 1, 1, 0, 0, 0, 1, 0, & + 0, 0, 1, 1, 0, 0, 0, 1, 0, & + 0, 0, 1, 1, 0, 0, 0, 1, 0 & + ],pInt),[ 9_pInt, LATTICE_fcc_Ntrans]) + + real(pReal), dimension(4,LATTICE_fcc_Ntrans), parameter, private :: & + LATTICE_fccTobcc_bainRot = reshape([& + 1.0, 0.0, 0.0, 45.0, & ! Rotate fcc austensite to bain variant + 1.0, 0.0, 0.0, 45.0, & + 1.0, 0.0, 0.0, 45.0, & + 1.0, 0.0, 0.0, 45.0, & + 0.0, 1.0, 0.0, 45.0, & + 0.0, 1.0, 0.0, 45.0, & + 0.0, 1.0, 0.0, 45.0, & + 0.0, 1.0, 0.0, 45.0, & + 0.0, 0.0, 1.0, 45.0, & + 0.0, 0.0, 1.0, 45.0, & + 0.0, 0.0, 1.0, 45.0, & + 0.0, 0.0, 1.0, 45.0 & + ],[ 4_pInt,LATTICE_fcc_Ntrans]) + + real(pReal), dimension(LATTICE_fcc_Ntrans,LATTICE_fcc_Ntrans), parameter, private :: & ! Matrix for projection of shear from slip system to fault-band (twin) systems + LATTICE_fccTobcc_projectionTrans = reshape(real([& ! For ns = nt = nr + 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, & + -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, & + 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & + 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, & + 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, & + 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, & + 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, & + 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, & + 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, & + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, & + 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, & + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, 0 & + ],pReal),[LATTICE_fcc_Ntrans,LATTICE_fcc_Ntrans],order=[2,1]) + + real(pReal), parameter, private :: & + LATTICE_fccTobcc_projectionTransFactor = sqrt(3.0_pReal/4.0_pReal) + + real(pReal), parameter, public :: & + LATTICE_fccTobcc_shearCritTrans = 0.0224 + + integer(pInt), dimension(2_pInt,LATTICE_fcc_Ntrans), parameter, public :: & + LATTICE_fccTobcc_transNucleationTwinPair = reshape(int( [& + 4, 7, & + 1, 10, & + 1, 4, & + 7, 10, & + 2, 8, & + 5, 11, & + 8, 11, & + 2, 5, & + 6, 12, & + 3, 9, & + 3, 12, & + 6, 9 & + ],pInt),[2_pInt,LATTICE_fcc_Ntrans]) + + real(pReal), dimension(3+3,LATTICE_fcc_Ncleavage), parameter, private :: & + LATTICE_fcc_systemCleavage = reshape(real([& + ! Cleavage direction Plane normal + 0, 1, 0, 1, 0, 0, & + 0, 0, 1, 0, 1, 0, & + 1, 0, 0, 0, 0, 1, & + 0, 1,-1, 1, 1, 1, & + 0,-1,-1, -1,-1, 1, & + -1, 0,-1, 1,-1,-1, & + 0, 1, 1, -1, 1,-1 & + ],pReal),[ 3_pInt + 3_pInt,LATTICE_fcc_Ncleavage]) + +!-------------------------------------------------------------------------------------------------- +! bcc + integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & + LATTICE_bcc_NslipSystem = int([ 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], pInt) !< total # of slip systems per family for bcc + + integer(pInt), dimension(LATTICE_maxNtwinFamily), parameter, public :: & + LATTICE_bcc_NtwinSystem = int([ 12, 0, 0, 0], pInt) !< total # of twin systems per family for bcc + + integer(pInt), dimension(LATTICE_maxNtransFamily), parameter, public :: & + LATTICE_bcc_NtransSystem = int([0,0],pInt) !< total # of transformation systems per family for bcc + + integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & + LATTICE_bcc_NcleavageSystem = int([3,6,0],pInt) !< total # of cleavage systems per family for bcc + + integer(pInt), parameter, private :: & + LATTICE_bcc_Nslip = 24_pInt, & ! sum(lattice_bcc_NslipSystem), & !< total # of slip systems for bcc + LATTICE_bcc_Ntwin = 12_pInt, & ! sum(lattice_bcc_NtwinSystem) !< total # of twin systems for bcc + LATTICE_bcc_NnonSchmid = 6_pInt, & !< # of non-Schmid contributions for bcc. 6 known non schmid contributions for BCC (A. Koester, A. Ma, A. Hartmaier 2012) + LATTICE_bcc_Ntrans = 0_pInt, & !< total # of transformations for bcc + LATTICE_bcc_Ncleavage = 9_pInt !< total # of cleavage systems for bcc + + + real(pReal), dimension(3+3,LATTICE_bcc_Nslip), parameter, private :: & + LATTICE_bcc_systemSlip = reshape(real([& + ! Slip direction Plane normal + ! Slip system <111>{110} + 1,-1, 1, 0, 1, 1, & + -1,-1, 1, 0, 1, 1, & + 1, 1, 1, 0,-1, 1, & + -1, 1, 1, 0,-1, 1, & + -1, 1, 1, 1, 0, 1, & + -1,-1, 1, 1, 0, 1, & + 1, 1, 1, -1, 0, 1, & + 1,-1, 1, -1, 0, 1, & + -1, 1, 1, 1, 1, 0, & + -1, 1,-1, 1, 1, 0, & + 1, 1, 1, -1, 1, 0, & + 1, 1,-1, -1, 1, 0, & + ! Slip system <111>{112} + -1, 1, 1, 2, 1, 1, & + 1, 1, 1, -2, 1, 1, & + 1, 1,-1, 2,-1, 1, & + 1,-1, 1, 2, 1,-1, & + 1,-1, 1, 1, 2, 1, & + 1, 1,-1, -1, 2, 1, & + 1, 1, 1, 1,-2, 1, & + -1, 1, 1, 1, 2,-1, & + 1, 1,-1, 1, 1, 2, & + 1,-1, 1, -1, 1, 2, & + -1, 1, 1, 1,-1, 2, & + 1, 1, 1, 1, 1,-2 & + ! Slip system <111>{123} + ! 1, 1,-1, 1, 2, 3, & + ! 1,-1, 1, -1, 2, 3, & + ! -1, 1, 1, 1,-2, 3, & + ! 1, 1, 1, 1, 2,-3, & + ! 1,-1, 1, 1, 3, 2, & + ! 1, 1,-1, -1, 3, 2, & + ! 1, 1, 1, 1,-3, 2, & + ! -1, 1, 1, 1, 3,-2, & + ! 1, 1,-1, 2, 1, 3, & + ! 1,-1, 1, -2, 1, 3, & + ! -1, 1, 1, 2,-1, 3, & + ! 1, 1, 1, 2, 1,-3, & + ! 1,-1, 1, 2, 3, 1, & + ! 1, 1,-1, -2, 3, 1, & + ! 1, 1, 1, 2,-3, 1, & + ! -1, 1, 1, 2, 3,-1, & + ! -1, 1, 1, 3, 1, 2, & + ! 1, 1, 1, -3, 1, 2, & + ! 1, 1,-1, 3,-1, 2, & + ! 1,-1, 1, 3, 1,-2, & + ! -1, 1, 1, 3, 2, 1, & + ! 1, 1, 1, -3, 2, 1, & + ! 1, 1,-1, 3,-2, 1, & + ! 1,-1, 1, 3, 2,-1 & + ],pReal),[ 3_pInt + 3_pInt ,LATTICE_bcc_Nslip]) + + real(pReal), dimension(3+3,LATTICE_bcc_Ntwin), parameter, private :: & + LATTICE_bcc_systemTwin = reshape(real([& + ! Twin system <111>{112} + -1, 1, 1, 2, 1, 1, & + 1, 1, 1, -2, 1, 1, & + 1, 1,-1, 2,-1, 1, & + 1,-1, 1, 2, 1,-1, & + 1,-1, 1, 1, 2, 1, & + 1, 1,-1, -1, 2, 1, & + 1, 1, 1, 1,-2, 1, & + -1, 1, 1, 1, 2,-1, & + 1, 1,-1, 1, 1, 2, & + 1,-1, 1, -1, 1, 2, & + -1, 1, 1, 1,-1, 2, & + 1, 1, 1, 1, 1,-2 & + ],pReal),[ 3_pInt + 3_pInt,LATTICE_bcc_Ntwin]) + + real(pReal), dimension(LATTICE_bcc_Ntwin), parameter, private :: & + LATTICE_bcc_shearTwin = 0.5_pReal*sqrt(2.0_pReal) + + integer(pInt), dimension(LATTICE_bcc_Nslip,LATTICE_bcc_Nslip), parameter, public :: & + LATTICE_bcc_interactionSlipSlip = reshape(int( [& + 1,2,6,6,5,4,4,3,4,3,5,4, 6,6,4,3,3,4,6,6,4,3,6,6, & ! ---> slip + 2,1,6,6,4,3,5,4,5,4,4,3, 6,6,3,4,4,3,6,6,3,4,6,6, & ! | + 6,6,1,2,4,5,3,4,4,5,3,4, 4,3,6,6,6,6,3,4,6,6,4,3, & ! | + 6,6,2,1,3,4,4,5,3,4,4,5, 3,4,6,6,6,6,4,3,6,6,3,4, & ! v slip + 5,4,4,3,1,2,6,6,3,4,5,4, 3,6,4,6,6,4,6,3,4,6,3,6, & + 4,3,5,4,2,1,6,6,4,5,4,3, 4,6,3,6,6,3,6,4,3,6,4,6, & + 4,5,3,4,6,6,1,2,5,4,3,4, 6,3,6,4,4,6,3,6,6,4,6,3, & + 3,4,4,5,6,6,2,1,4,3,4,5, 6,4,6,3,3,6,4,6,6,3,6,4, & + 4,5,4,3,3,4,5,4,1,2,6,6, 3,6,6,4,4,6,6,3,6,4,3,6, & + 3,4,5,4,4,5,4,3,2,1,6,6, 4,6,6,3,3,6,6,4,6,3,4,6, & + 5,4,3,4,5,4,3,4,6,6,1,2, 6,3,4,6,6,4,3,6,4,6,6,3, & + 4,3,4,5,4,3,4,5,6,6,2,1, 6,4,3,6,6,3,4,6,3,6,6,4, & + ! + 6,6,4,3,3,4,6,6,3,4,6,6, 1,5,6,6,5,6,6,3,5,6,3,6, & + 6,6,3,4,6,6,3,4,6,6,3,4, 5,1,6,6,6,5,3,6,6,5,6,3, & + 4,3,6,6,4,3,6,6,6,6,4,3, 6,6,1,5,6,3,5,6,3,6,5,6, & + 3,4,6,6,6,6,4,3,4,3,6,6, 6,6,5,1,3,6,6,5,6,3,6,5, & + 3,4,6,6,6,6,4,3,4,3,6,6, 5,6,6,3,1,6,5,6,5,3,6,6, & + 4,3,6,6,4,3,6,6,6,6,4,3, 6,5,3,6,6,1,6,5,3,5,6,6, & + 6,6,3,4,6,6,3,4,6,6,3,4, 6,3,5,6,5,6,1,6,6,6,5,3, & + 6,6,4,3,3,4,6,6,3,4,6,6, 3,6,6,5,6,5,6,1,6,6,3,5, & + 4,3,6,6,4,3,6,6,6,6,4,3, 5,6,3,6,5,3,6,6,1,6,6,5, & + 3,4,6,6,6,6,4,3,4,3,6,6, 6,5,6,3,3,5,6,6,6,1,5,6, & + 6,6,4,3,3,4,6,6,3,4,6,6, 3,6,5,6,6,6,5,3,6,5,1,6, & + 6,6,3,4,6,6,3,4,6,6,3,4, 6,3,6,5,6,6,3,5,5,6,6,1 & + ],pInt),[lattice_bcc_Nslip,lattice_bcc_Nslip],order=[2,1]) !< Slip--slip interaction types for bcc from Queyreau et al. Int J Plast 25 (2009) 361–377 + !< 1: self interaction + !< 2: coplanar interaction + !< 3: collinear interaction + !< 4: mixed-asymmetrical junction + !< 5: mixed-symmetrical junction + !< 6: edge junction + integer(pInt), dimension(LATTICE_bcc_Nslip,LATTICE_bcc_Ntwin), parameter, public :: & + LATTICE_bcc_interactionSlipTwin = reshape(int( [& + 3,3,3,2,2,3,3,3,3,2,3,3, & ! ---> twin + 3,3,2,3,3,2,3,3,2,3,3,3, & ! | + 3,2,3,3,3,3,2,3,3,3,3,2, & ! | + 2,3,3,3,3,3,3,2,3,3,2,3, & ! v slip + 2,3,3,3,3,3,3,2,3,3,2,3, & + 3,3,2,3,3,2,3,3,2,3,3,3, & + 3,2,3,3,3,3,2,3,3,3,3,2, & + 3,3,3,2,2,3,3,3,3,2,3,3, & + 2,3,3,3,3,3,3,2,3,3,2,3, & + 3,3,3,2,2,3,3,3,3,2,3,3, & + 3,2,3,3,3,3,2,3,3,3,3,2, & + 3,3,2,3,3,2,3,3,2,3,3,3, & + ! + 1,3,3,3,3,3,3,2,3,3,2,3, & + 3,1,3,3,3,3,2,3,3,3,3,2, & + 3,3,1,3,3,2,3,3,2,3,3,3, & + 3,3,3,1,2,3,3,3,3,2,3,3, & + 3,3,3,2,1,3,3,3,3,2,3,3, & + 3,3,2,3,3,1,3,3,2,3,3,3, & + 3,2,3,3,3,3,1,3,3,3,3,2, & + 2,3,3,3,3,3,3,1,3,3,2,3, & + 3,3,2,3,3,2,3,3,1,3,3,3, & + 3,3,3,2,2,3,3,3,3,1,3,3, & + 2,3,3,3,3,3,3,2,3,3,1,3, & + 3,2,3,3,3,3,2,3,3,3,3,1 & + ],pInt),[LATTICE_bcc_Nslip,LATTICE_bcc_Ntwin],order=[2,1]) !< Slip--twin interaction types for bcc + !< 1: coplanar interaction + !< 2: screw trace between slip system and twin habit plane (easy cross slip) + !< 3: other interaction + integer(pInt), dimension(LATTICE_bcc_Ntwin,LATTICE_bcc_Nslip), parameter, public :: & + LATTICE_bcc_interactionTwinSlip = 1_pInt !< Twin--slip interaction types for bcc @todo not implemented yet + + integer(pInt), dimension(LATTICE_bcc_Ntwin,LATTICE_bcc_Ntwin), parameter, public :: & + LATTICE_bcc_interactionTwinTwin = reshape(int( [& + 1,3,3,3,3,3,3,2,3,3,2,3, & ! ---> twin + 3,1,3,3,3,3,2,3,3,3,3,2, & ! | + 3,3,1,3,3,2,3,3,2,3,3,3, & ! | + 3,3,3,1,2,3,3,3,3,2,3,3, & ! v twin + 3,3,3,2,1,3,3,3,3,2,3,3, & + 3,3,2,3,3,1,3,3,2,3,3,3, & + 3,2,3,3,3,3,1,3,3,3,3,2, & + 2,3,3,3,3,3,3,1,3,3,2,3, & + 3,3,2,3,3,2,3,3,1,3,3,3, & + 3,3,3,2,2,3,3,3,3,1,3,3, & + 2,3,3,3,3,3,3,2,3,3,1,3, & + 3,2,3,3,3,3,2,3,3,3,3,1 & + ],pInt),[LATTICE_bcc_Ntwin,LATTICE_bcc_Ntwin],order=[2,1]) !< Twin--twin interaction types for bcc + !< 1: self interaction + !< 2: collinear interaction + !< 3: other interaction + real(pReal), dimension(3+3,LATTICE_bcc_Ncleavage), parameter, private :: & + LATTICE_bcc_systemCleavage = reshape(real([& + ! Cleavage direction Plane normal + 0, 1, 0, 1, 0, 0, & + 0, 0, 1, 0, 1, 0, & + 1, 0, 0, 0, 0, 1, & + 1,-1, 1, 0, 1, 1, & + 1, 1, 1, 0,-1, 1, & + -1, 1, 1, 1, 0, 1, & + 1, 1, 1, -1, 0, 1, & + -1, 1, 1, 1, 1, 0, & + 1, 1, 1, -1, 1, 0 & + ],pReal),[ 3_pInt + 3_pInt,LATTICE_bcc_Ncleavage]) + +!-------------------------------------------------------------------------------------------------- +! hex + integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & + lattice_hex_NslipSystem = int([ 3, 3, 3, 6, 12, 6, 0, 0, 0, 0, 0, 0, 0],pInt) !< # of slip systems per family for hex + + integer(pInt), dimension(LATTICE_maxNtwinFamily), parameter, public :: & + lattice_hex_NtwinSystem = int([ 6, 6, 6, 6],pInt) !< # of slip systems per family for hex + + integer(pInt), dimension(LATTICE_maxNtransFamily), parameter, public :: & + LATTICE_hex_NtransSystem = int([0,0],pInt) !< total # of transformation systems per family for hex + + integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & + LATTICE_hex_NcleavageSystem = int([3,0,0],pInt) !< total # of cleavage systems per family for hex + + integer(pInt), parameter , private :: & + LATTICE_hex_Nslip = 33_pInt, & ! sum(lattice_hex_NslipSystem), !< total # of slip systems for hex + LATTICE_hex_Ntwin = 24_pInt, & ! sum(lattice_hex_NtwinSystem) !< total # of twin systems for hex + LATTICE_hex_NnonSchmid = 0_pInt, & !< # of non-Schmid contributions for hex + LATTICE_hex_Ntrans = 0_pInt, & !< total # of transformations for hex + LATTICE_hex_Ncleavage = 3_pInt !< total # of transformations for hex + + real(pReal), dimension(4+4,LATTICE_hex_Nslip), parameter, private :: & + LATTICE_hex_systemSlip = reshape(real([& + ! Slip direction Plane normal + ! Basal systems <11.0>{00.1} (independent of c/a-ratio, Bravais notation (4 coordinate base)) + 2, -1, -1, 0, 0, 0, 0, 1, & + -1, 2, -1, 0, 0, 0, 0, 1, & + -1, -1, 2, 0, 0, 0, 0, 1, & + ! 1st type prismatic systems <11.0>{10.0} (independent of c/a-ratio) + 2, -1, -1, 0, 0, 1, -1, 0, & + -1, 2, -1, 0, -1, 0, 1, 0, & + -1, -1, 2, 0, 1, -1, 0, 0, & + ! 2nd type prismatic systems <10.0>{11.0} -- a slip; plane normals independent of c/a-ratio + 0, 1, -1, 0, 2, -1, -1, 0, & + -1, 0, 1, 0, -1, 2, -1, 0, & + 1, -1, 0, 0, -1, -1, 2, 0, & + ! 1st type 1st order pyramidal systems <11.0>{-11.1} -- plane normals depend on the c/a-ratio + 2, -1, -1, 0, 0, 1, -1, 1, & + -1, 2, -1, 0, -1, 0, 1, 1, & + -1, -1, 2, 0, 1, -1, 0, 1, & + 1, 1, -2, 0, -1, 1, 0, 1, & + -2, 1, 1, 0, 0, -1, 1, 1, & + 1, -2, 1, 0, 1, 0, -1, 1, & + ! pyramidal system: c+a slip <11.3>{-10.1} -- plane normals depend on the c/a-ratio + 2, -1, -1, 3, -1, 1, 0, 1, & + 1, -2, 1, 3, -1, 1, 0, 1, & + -1, -1, 2, 3, 1, 0, -1, 1, & + -2, 1, 1, 3, 1, 0, -1, 1, & + -1, 2, -1, 3, 0, -1, 1, 1, & + 1, 1, -2, 3, 0, -1, 1, 1, & + -2, 1, 1, 3, 1, -1, 0, 1, & + -1, 2, -1, 3, 1, -1, 0, 1, & + 1, 1, -2, 3, -1, 0, 1, 1, & + 2, -1, -1, 3, -1, 0, 1, 1, & + 1, -2, 1, 3, 0, 1, -1, 1, & + -1, -1, 2, 3, 0, 1, -1, 1, & + ! pyramidal system: c+a slip <11.3>{-1-1.2} -- as for hexagonal ice (Castelnau et al. 1996, similar to twin system found below) + 2, -1, -1, 3, -2, 1, 1, 2, & ! sorted according to similar twin system + -1, 2, -1, 3, 1, -2, 1, 2, & ! <11.3>{-1-1.2} shear = 2((c/a)^2-2)/(3 c/a) + -1, -1, 2, 3, 1, 1, -2, 2, & + -2, 1, 1, 3, 2, -1, -1, 2, & + 1, -2, 1, 3, -1, 2, -1, 2, & + 1, 1, -2, 3, -1, -1, 2, 2 & + ],pReal),[ 4_pInt + 4_pInt,LATTICE_hex_Nslip]) !< slip systems for hex sorted by A. Alankar & P. Eisenlohr + + real(pReal), dimension(4+4,LATTICE_hex_Ntwin), parameter, private :: & + LATTICE_hex_systemTwin = reshape(real([& + ! Compression or Tension =f(twinning shear=f(c/a)) for each metal ! (according to Yoo 1981) + 1, -1, 0, 1, -1, 1, 0, 2, & ! <-10.1>{10.2} shear = (3-(c/a)^2)/(sqrt(3) c/a) + -1, 0, 1, 1, 1, 0, -1, 2, & + 0, 1, -1, 1, 0, -1, 1, 2, & + -1, 1, 0, 1, 1, -1, 0, 2, & + 1, 0, -1, 1, -1, 0, 1, 2, & + 0, -1, 1, 1, 0, 1, -1, 2, & +! + 2, -1, -1, 6, -2, 1, 1, 1, & ! <11.6>{-1-1.1} shear = 1/(c/a) + -1, 2, -1, 6, 1, -2, 1, 1, & + -1, -1, 2, 6, 1, 1, -2, 1, & + -2, 1, 1, 6, 2, -1, -1, 1, & + 1, -2, 1, 6, -1, 2, -1, 1, & + 1, 1, -2, 6, -1, -1, 2, 1, & +! + -1, 1, 0, -2, -1, 1, 0, 1, & !! <10.-2>{10.1} shear = (4(c/a)^2-9)/(4 sqrt(3) c/a) + 1, 0, -1, -2, 1, 0, -1, 1, & + 0, -1, 1, -2, 0, -1, 1, 1, & + 1, -1, 0, -2, 1, -1, 0, 1, & + -1, 0, 1, -2, -1, 0, 1, 1, & + 0, 1, -1, -2, 0, 1, -1, 1, & +! + 2, -1, -1, -3, 2, -1, -1, 2, & ! <11.-3>{11.2} shear = 2((c/a)^2-2)/(3 c/a) + -1, 2, -1, -3, -1, 2, -1, 2, & + -1, -1, 2, -3, -1, -1, 2, 2, & + -2, 1, 1, -3, -2, 1, 1, 2, & + 1, -2, 1, -3, 1, -2, 1, 2, & + 1, 1, -2, -3, 1, 1, -2, 2 & + ],pReal),[ 4_pInt + 4_pInt ,LATTICE_hex_Ntwin]) !< twin systems for hex, order follows Prof. Tom Bieler's scheme; but numbering in data was restarted from 1 + + integer(pInt), dimension(LATTICE_hex_Ntwin), parameter, private :: & + LATTICE_hex_shearTwin = reshape(int( [& ! indicator to formula further below + 1, & ! <-10.1>{10.2} + 1, & + 1, & + 1, & + 1, & + 1, & + 2, & ! <11.6>{-1-1.1} + 2, & + 2, & + 2, & + 2, & + 2, & + 3, & ! <10.-2>{10.1} + 3, & + 3, & + 3, & + 3, & + 3, & + 4, & ! <11.-3>{11.2} + 4, & + 4, & + 4, & + 4, & + 4 & + ],pInt),[LATTICE_hex_Ntwin]) + + integer(pInt), dimension(LATTICE_hex_Nslip,LATTICE_hex_Nslip), parameter, public :: & + LATTICE_hex_interactionSlipSlip = reshape(int( [& + 1, 2, 2, 3, 3, 3, 7, 7, 7, 13,13,13,13,13,13, 21,21,21,21,21,21,21,21,21,21,21,21, 31,31,31,31,31,31, & ! ---> slip + 2, 1, 2, 3, 3, 3, 7, 7, 7, 13,13,13,13,13,13, 21,21,21,21,21,21,21,21,21,21,21,21, 31,31,31,31,31,31, & ! | + 2, 2, 1, 3, 3, 3, 7, 7, 7, 13,13,13,13,13,13, 21,21,21,21,21,21,21,21,21,21,21,21, 31,31,31,31,31,31, & ! | + ! v slip + 6, 6, 6, 4, 5, 5, 8, 8, 8, 14,14,14,14,14,14, 22,22,22,22,22,22,22,22,22,22,22,22, 32,32,32,32,32,32, & + 6, 6, 6, 5, 4, 5, 8, 8, 8, 14,14,14,14,14,14, 22,22,22,22,22,22,22,22,22,22,22,22, 32,32,32,32,32,32, & + 6, 6, 6, 5, 5, 4, 8, 8, 8, 14,14,14,14,14,14, 22,22,22,22,22,22,22,22,22,22,22,22, 32,32,32,32,32,32, & + ! + 12,12,12, 11,11,11, 9,10,10, 15,15,15,15,15,15, 23,23,23,23,23,23,23,23,23,23,23,23, 33,33,33,33,33,33, & + 12,12,12, 11,11,11, 10, 9,10, 15,15,15,15,15,15, 23,23,23,23,23,23,23,23,23,23,23,23, 33,33,33,33,33,33, & + 12,12,12, 11,11,11, 10,10, 9, 15,15,15,15,15,15, 23,23,23,23,23,23,23,23,23,23,23,23, 33,33,33,33,33,33, & + ! + 20,20,20, 19,19,19, 18,18,18, 16,17,17,17,17,17, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & + 20,20,20, 19,19,19, 18,18,18, 17,16,17,17,17,17, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & + 20,20,20, 19,19,19, 18,18,18, 17,17,16,17,17,17, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & + 20,20,20, 19,19,19, 18,18,18, 17,17,17,16,17,17, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & + 20,20,20, 19,19,19, 18,18,18, 17,17,17,17,16,17, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & + 20,20,20, 19,19,19, 18,18,18, 17,17,17,17,17,16, 24,24,24,24,24,24,24,24,24,24,24,24, 34,34,34,34,34,34, & + ! + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 25,26,26,26,26,26,26,26,26,26,26,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,25,26,26,26,26,26,26,26,26,26,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,25,26,26,26,26,26,26,26,26,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,25,26,26,26,26,26,26,26,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,25,26,26,26,26,26,26,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,25,26,26,26,26,26,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,25,26,26,26,26,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,26,25,26,26,26,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,26,26,25,26,26,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,26,26,26,25,26,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,26,26,26,26,25,26, 35,35,35,35,35,35, & + 30,30,30, 29,29,29, 28,28,28, 27,27,27,27,27,27, 26,26,26,26,26,26,26,26,26,26,26,25, 35,35,35,35,35,35, & + ! + 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 36,37,37,37,37,37, & + 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 37,36,37,37,37,37, & + 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 37,37,36,37,37,37, & + 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 37,37,37,36,37,37, & + 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 37,37,37,37,36,37, & + 42,42,42, 41,41,41, 40,40,40, 39,39,39,39,39,39, 38,38,38,38,38,38,38,38,38,38,38,38, 37,37,37,37,37,36 & + ! + ],pInt),[LATTICE_hex_Nslip,LATTICE_hex_Nslip],order=[2,1]) !< Slip--slip interaction types for hex (onion peel naming scheme) + + integer(pInt), dimension(LATTICE_hex_Nslip,LATTICE_hex_Ntwin), parameter, public :: & + LATTICE_hex_interactionSlipTwin = reshape(int( [& + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, & ! --> twin + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, & ! | + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, & ! | + ! v + 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, & ! slip + 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, & + 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, & + ! + 9, 9, 9, 9, 9, 9, 10,10,10,10,10,10, 11,11,11,11,11,11, 12,12,12,12,12,12, & + 9, 9, 9, 9, 9, 9, 10,10,10,10,10,10, 11,11,11,11,11,11, 12,12,12,12,12,12, & + 9, 9, 9, 9, 9, 9, 10,10,10,10,10,10, 11,11,11,11,11,11, 12,12,12,12,12,12, & + ! + 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & + 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & + 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & + 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & + 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & + 13,13,13,13,13,13, 14,14,14,14,14,14, 15,15,15,15,15,15, 16,16,16,16,16,16, & + ! + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + 17,17,17,17,17,17, 18,18,18,18,18,18, 19,19,19,19,19,19, 20,20,20,20,20,20, & + ! + 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24, & + 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24, & + 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24, & + 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24, & + 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24, & + 21,21,21,21,21,21, 22,22,22,22,22,22, 23,23,23,23,23,23, 24,24,24,24,24,24 & + ! + ],pInt),[LATTICE_hex_Nslip,LATTICE_hex_Ntwin],order=[2,1]) !< Slip--twin interaction types for hex (isotropic, 24 in total) + + integer(pInt), dimension(LATTICE_hex_Ntwin,LATTICE_hex_Nslip), parameter, public :: & + LATTICE_hex_interactionTwinSlip = reshape(int( [& + 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & ! --> slip + 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & ! | + 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & ! | + 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & ! v + 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & ! twin + 1, 1, 1, 5, 5, 5, 9, 9, 9, 13,13,13,13,13,13, 17,17,17,17,17,17,17,17,17,17,17,17, 21,21,21,21,21,21, & + ! + 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & + 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & + 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & + 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & + 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & + 2, 2, 2, 6, 6, 6, 10,10,10, 14,14,14,14,14,14, 18,18,18,18,18,18,18,18,18,18,18,18, 22,22,22,22,22,22, & + ! + 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & + 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & + 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & + 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & + 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & + 3, 3, 3, 7, 7, 7, 11,11,11, 15,15,15,15,15,15, 19,19,19,19,19,19,19,19,19,19,19,19, 23,23,23,23,23,23, & + ! + 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24, & + 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24, & + 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24, & + 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24, & + 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24, & + 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24 & + ],pInt),[LATTICE_hex_Ntwin,LATTICE_hex_Nslip],order=[2,1]) !< Twin--twin interaction types for hex (isotropic, 20 in total) + + integer(pInt), dimension(LATTICE_hex_Ntwin,LATTICE_hex_Ntwin), parameter, public :: & + LATTICE_hex_interactionTwinTwin = reshape(int( [& + 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & ! ---> twin + 2, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & ! | + 2, 2, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & ! | + 2, 2, 2, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & ! v twin + 2, 2, 2, 2, 1, 2, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & + 2, 2, 2, 2, 2, 1, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 13,13,13,13,13,13, & + ! + 6, 6, 6, 6, 6, 6, 4, 5, 5, 5, 5, 5, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & + 6, 6, 6, 6, 6, 6, 5, 4, 5, 5, 5, 5, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & + 6, 6, 6, 6, 6, 6, 5, 5, 4, 5, 5, 5, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & + 6, 6, 6, 6, 6, 6, 5, 5, 5, 4, 5, 5, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & + 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, 5, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & + 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 8, 8, 8, 8, 8, 8, 14,14,14,14,14,14, & + ! + 12,12,12,12,12,12, 11,11,11,11,11,11, 9,10,10,10,10,10, 15,15,15,15,15,15, & + 12,12,12,12,12,12, 11,11,11,11,11,11, 10, 9,10,10,10,10, 15,15,15,15,15,15, & + 12,12,12,12,12,12, 11,11,11,11,11,11, 10,10, 9,10,10,10, 15,15,15,15,15,15, & + 12,12,12,12,12,12, 11,11,11,11,11,11, 10,10,10, 9,10,10, 15,15,15,15,15,15, & + 12,12,12,12,12,12, 11,11,11,11,11,11, 10,10,10,10, 9,10, 15,15,15,15,15,15, & + 12,12,12,12,12,12, 11,11,11,11,11,11, 10,10,10,10,10, 9, 15,15,15,15,15,15, & + ! + 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 16,17,17,17,17,17, & + 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,16,17,17,17,17, & + 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,17,16,17,17,17, & + 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,17,17,16,17,17, & + 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,17,17,17,16,17, & + 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,17,17,17,17,16 & + ],pInt),[lattice_hex_Ntwin,lattice_hex_Ntwin],order=[2,1]) !< Twin--slip interaction types for hex (isotropic, 16 in total) + + real(pReal), dimension(4+4,LATTICE_hex_Ncleavage), parameter, private :: & + LATTICE_hex_systemCleavage = reshape(real([& + ! Cleavage direction Plane normal + 2,-1,-1, 0, 0, 0, 0, 1, & + 0, 0, 0, 1, 2,-1,-1, 0, & + 0, 0, 0, 1, 0, 1,-1, 0 & + ],pReal),[ 4_pInt + 4_pInt,LATTICE_hex_Ncleavage]) + + + +!-------------------------------------------------------------------------------------------------- +! bct + integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & + LATTICE_bct_NslipSystem = int([2, 2, 2, 4, 2, 4, 2, 2, 4, 8, 4, 8, 8 ],pInt) !< # of slip systems per family for bct (Sn) Bieler J. Electr Mater 2009 + + integer(pInt), dimension(LATTICE_maxNtwinFamily), parameter, public :: & + LATTICE_bct_NtwinSystem = int([0, 0, 0, 0], pInt) !< total # of twin systems per family for bct-example + + integer(pInt), dimension(LATTICE_maxNtransFamily), parameter, public :: & + LATTICE_bct_NtransSystem = int([0,0],pInt) !< total # of transformation systems per family for bct + + integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & + LATTICE_bct_NcleavageSystem = int([0,0,0],pInt) !< total # of cleavage systems per family for bct + + + integer(pInt), parameter , private :: & + LATTICE_bct_Nslip = 52_pInt, & ! sum(lattice_bct_NslipSystem), !< total # of slip systems for bct + LATTICE_bct_Ntwin = 0_pInt, & ! sum(lattice_bcc_NtwinSystem) !< total # of twin systems for bct + LATTICE_bct_NnonSchmid = 0_pInt, & !< # of non-Schmid contributions for bct + LATTICE_bct_Ntrans = 0_pInt, & !< total # of transformations for bct + LATTICE_bct_Ncleavage = 0_pInt !< total # of transformations for bct + + real(pReal), dimension(3+3,LATTICE_bct_Nslip), parameter, private :: & + LATTICE_bct_systemSlip = reshape(real([& + ! Slip direction Plane normal + ! Slip family 1 {100)<001] (Bravais notation {hkl) @brief Module initialization +!-------------------------------------------------------------------------------------------------- +subroutine lattice_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_open_file,& + IO_open_jobFile_stat, & + IO_countSections, & + IO_error, & + IO_timeStamp, & + IO_EOF, & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue + use material, only: & + material_configfile, & + material_localFileExt, & + material_partPhase + use debug, only: & + debug_level, & + debug_lattice, & + debug_levelBasic + use numerics, only: & + worldrank + + implicit none + integer(pInt), parameter :: FILEUNIT = 200_pInt + integer(pInt) :: Nphases + character(len=65536) :: & + tag = '', & + line = '' + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: section = 0_pInt,i + real(pReal), dimension(:), allocatable :: & + CoverA, & !!!!!!< c/a ratio for low symmetry type lattice + CoverA_trans, & !< c/a ratio for transformed hex type lattice + a_fcc, & !< lattice parameter a for fcc austenite + a_bcc !< lattice paramater a for bcc martensite + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- lattice init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! consistency checks + + if (LATTICE_maxNslip /= maxval([LATTICE_fcc_Nslip,LATTICE_bcc_Nslip,LATTICE_hex_Nslip,LATTICE_bct_Nslip])) & + call IO_error(0_pInt,ext_msg = 'LATTICE_maxNslip') + if (LATTICE_maxNtwin /= maxval([LATTICE_fcc_Ntwin,LATTICE_bcc_Ntwin,LATTICE_hex_Ntwin])) & + call IO_error(0_pInt,ext_msg = 'LATTICE_maxNtwin') + if (LATTICE_maxNtrans /= maxval([LATTICE_fcc_Ntrans,LATTICE_bcc_Ntrans,LATTICE_hex_Ntrans])) & + call IO_error(0_pInt,ext_msg = 'LATTICE_maxNtrans') + if (LATTICE_maxNnonSchmid /= maxval([lattice_fcc_NnonSchmid,lattice_bcc_NnonSchmid,& + lattice_hex_NnonSchmid])) call IO_error(0_pInt,ext_msg = 'LATTICE_maxNnonSchmid') + + if (LATTICE_fcc_Nslip /= sum(lattice_fcc_NslipSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_fcc_Nslip') + if (LATTICE_bcc_Nslip /= sum(lattice_bcc_NslipSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_bcc_Nslip') + if (LATTICE_hex_Nslip /= sum(lattice_hex_NslipSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_hex_Nslip') + if (LATTICE_bct_Nslip /= sum(lattice_bct_NslipSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_bct_Nslip') + + if (LATTICE_fcc_Ntwin /= sum(lattice_fcc_NtwinSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_fcc_Ntwin') + if (LATTICE_bcc_Ntwin /= sum(lattice_bcc_NtwinSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_bcc_Ntwin') + if (LATTICE_hex_Ntwin /= sum(lattice_hex_NtwinSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_hex_Ntwin') + if (LATTICE_bct_Ntwin /= sum(lattice_bct_NtwinSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_bct_Ntwin') + + if (LATTICE_fcc_Ntrans /= sum(lattice_fcc_NtransSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_fcc_Ntrans') + if (LATTICE_bcc_Ntrans /= sum(lattice_bcc_NtransSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_bcc_Ntrans') + if (LATTICE_hex_Ntrans /= sum(lattice_hex_NtransSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_hex_Ntrans') + if (LATTICE_bct_Ntrans /= sum(lattice_bct_NtransSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_bct_Ntrans') + + if (LATTICE_fcc_Ncleavage /= sum(lattice_fcc_NcleavageSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_fcc_Ncleavage') + if (LATTICE_bcc_Ncleavage /= sum(lattice_bcc_NcleavageSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_bcc_Ncleavage') + if (LATTICE_hex_Ncleavage /= sum(lattice_hex_NcleavageSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_hex_Ncleavage') + if (LATTICE_bct_Ncleavage /= sum(lattice_bct_NcleavageSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_bct_Ncleavage') + if (LATTICE_iso_Ncleavage /= sum(lattice_iso_NcleavageSystem)) & + call IO_error(0_pInt,ext_msg = 'LATTICE_iso_Ncleavage') + + if (LATTICE_maxNinteraction /= max(& + maxval(lattice_fcc_interactionSlipSlip), & + maxval(lattice_bcc_interactionSlipSlip), & + maxval(lattice_hex_interactionSlipSlip), & + maxval(lattice_bct_interactionSlipSlip), & + ! + maxval(lattice_fcc_interactionSlipTwin), & + maxval(lattice_bcc_interactionSlipTwin), & + maxval(lattice_hex_interactionSlipTwin), & +! maxval(lattice_bct_interactionSlipTwin), & + ! + maxval(lattice_fcc_interactionTwinSlip), & + maxval(lattice_bcc_interactionTwinSlip), & + maxval(lattice_hex_interactionTwinSlip), & +! maxval(lattice_bct_interactionTwinSlip), & + ! + maxval(lattice_fcc_interactionTwinTwin), & + maxval(lattice_bcc_interactionTwinTwin), & + maxval(lattice_hex_interactionTwinTwin))) & +! maxval(lattice_bct_interactionTwinTwin))) & + call IO_error(0_pInt,ext_msg = 'LATTICE_maxNinteraction') + +!-------------------------------------------------------------------------------------------------- +! read from material configuration file + if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... + call IO_open_file(FILEUNIT,material_configFile) ! ... open material.config file + Nphases = IO_countSections(FILEUNIT,material_partPhase) + + if(Nphases<1_pInt) & + call IO_error(160_pInt,Nphases, ext_msg='No phases found') + + if (iand(debug_level(debug_lattice),debug_levelBasic) /= 0_pInt) then + write(6,'(a16,1x,i5)') ' # phases:',Nphases + endif + + allocate(lattice_structure(Nphases),source = LATTICE_undefined_ID) + allocate(trans_lattice_structure(Nphases),source = LATTICE_undefined_ID) + allocate(lattice_C66(6,6,Nphases), source=0.0_pReal) + allocate(lattice_C3333(3,3,3,3,Nphases), source=0.0_pReal) + allocate(lattice_trans_C66(6,6,Nphases), source=0.0_pReal) + allocate(lattice_trans_C3333(3,3,3,3,Nphases), source=0.0_pReal) + allocate(lattice_thermalConductivity33 (3,3,Nphases), source=0.0_pReal) + allocate(lattice_thermalExpansion33 (3,3,Nphases), source=0.0_pReal) + allocate(lattice_damageDiffusion33 (3,3,Nphases), source=0.0_pReal) + allocate(lattice_vacancyfluxDiffusion33 (3,3,Nphases), source=0.0_pReal) + allocate(lattice_vacancyfluxMobility33 (3,3,Nphases), source=0.0_pReal) + allocate(lattice_PorosityDiffusion33 (3,3,Nphases), source=0.0_pReal) + allocate(lattice_hydrogenfluxDiffusion33(3,3,Nphases), source=0.0_pReal) + allocate(lattice_hydrogenfluxMobility33 (3,3,Nphases), source=0.0_pReal) + allocate(lattice_damageMobility ( Nphases), source=0.0_pReal) + allocate(lattice_PorosityMobility ( Nphases), source=0.0_pReal) + allocate(lattice_massDensity ( Nphases), source=0.0_pReal) + allocate(lattice_specificHeat ( Nphases), source=0.0_pReal) + allocate(lattice_vacancyFormationEnergy ( Nphases), source=0.0_pReal) + allocate(lattice_vacancySurfaceEnergy ( Nphases), source=0.0_pReal) + allocate(lattice_vacancyVol ( Nphases), source=0.0_pReal) + allocate(lattice_hydrogenFormationEnergy( Nphases), source=0.0_pReal) + allocate(lattice_hydrogenSurfaceEnergy ( Nphases), source=0.0_pReal) + allocate(lattice_hydrogenVol ( Nphases), source=0.0_pReal) + allocate(lattice_referenceTemperature ( Nphases), source=300.0_pReal) + allocate(lattice_equilibriumVacancyConcentration(Nphases), source=0.0_pReal) + allocate(lattice_equilibriumHydrogenConcentration(Nphases),source=0.0_pReal) + + allocate(lattice_mu(Nphases), source=0.0_pReal) + allocate(lattice_nu(Nphases), source=0.0_pReal) + allocate(lattice_trans_mu(Nphases), source=0.0_pReal) + allocate(lattice_trans_nu(Nphases), source=0.0_pReal) + + allocate(lattice_NnonSchmid(Nphases), source=0_pInt) + allocate(lattice_Sslip(3,3,1+2*lattice_maxNnonSchmid,lattice_maxNslip,Nphases),source=0.0_pReal) + allocate(lattice_Sslip_v(6,1+2*lattice_maxNnonSchmid,lattice_maxNslip,Nphases),source=0.0_pReal) + allocate(lattice_Scleavage(3,3,3,lattice_maxNslip,Nphases),source=0.0_pReal) + allocate(lattice_Scleavage_v(6,3,lattice_maxNslip,Nphases),source=0.0_pReal) + allocate(lattice_sd(3,lattice_maxNslip,Nphases),source=0.0_pReal) + allocate(lattice_st(3,lattice_maxNslip,Nphases),source=0.0_pReal) + allocate(lattice_sn(3,lattice_maxNslip,Nphases),source=0.0_pReal) + + allocate(lattice_Qtwin(3,3,lattice_maxNtwin,Nphases),source=0.0_pReal) + allocate(lattice_Stwin(3,3,lattice_maxNtwin,Nphases),source=0.0_pReal) + allocate(lattice_Stwin_v(6,lattice_maxNtwin,Nphases),source=0.0_pReal) + allocate(lattice_td(3,lattice_maxNtwin,Nphases),source=0.0_pReal) + allocate(lattice_tt(3,lattice_maxNtwin,Nphases),source=0.0_pReal) + allocate(lattice_tn(3,lattice_maxNtwin,Nphases),source=0.0_pReal) + + allocate(lattice_shearTwin(lattice_maxNtwin,Nphases),source=0.0_pReal) + allocate(lattice_shearTrans(lattice_maxNtrans,Nphases),source=0.0_pReal) + + allocate(lattice_Qtrans(3,3,lattice_maxNtrans,Nphases),source=0.0_pReal) + allocate(lattice_Strans(3,3,lattice_maxNtrans,Nphases),source=0.0_pReal) + allocate(lattice_Strans_v(6,lattice_maxNtrans,Nphases),source=0.0_pReal) + allocate(lattice_projectionTrans(lattice_maxNtrans,lattice_maxNtrans,Nphases),source=0.0_pReal) + + allocate(lattice_NslipSystem(lattice_maxNslipFamily,Nphases),source=0_pInt) + allocate(lattice_NtwinSystem(lattice_maxNtwinFamily,Nphases),source=0_pInt) + allocate(lattice_NtransSystem(lattice_maxNtransFamily,Nphases),source=0_pInt) + allocate(lattice_NcleavageSystem(lattice_maxNcleavageFamily,Nphases),source=0_pInt) + + allocate(lattice_interactionSlipSlip(lattice_maxNslip,lattice_maxNslip,Nphases),source=0_pInt) ! other:me + allocate(lattice_interactionSlipTwin(lattice_maxNslip,lattice_maxNtwin,Nphases),source=0_pInt) ! other:me + allocate(lattice_interactionTwinSlip(lattice_maxNtwin,lattice_maxNslip,Nphases),source=0_pInt) ! other:me + allocate(lattice_interactionTwinTwin(lattice_maxNtwin,lattice_maxNtwin,Nphases),source=0_pInt) ! other:me + allocate(lattice_interactionSlipTrans(lattice_maxNslip,lattice_maxNtrans,Nphases),source=0_pInt) ! other:me + allocate(lattice_interactionTransSlip(lattice_maxNtrans,lattice_maxNslip,Nphases),source=0_pInt) ! other:me + allocate(lattice_interactionTransTrans(lattice_maxNtrans,lattice_maxNtrans,Nphases),source=0_pInt) ! other:me + + allocate(CoverA(Nphases),source=0.0_pReal) + allocate(CoverA_trans(Nphases),source=0.0_pReal) + allocate(a_fcc(Nphases),source=0.0_pReal) + allocate(a_bcc(Nphases),source=0.0_pReal) + + rewind(fileUnit) + line = '' ! to have it initialized + section = 0_pInt ! - " - + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + do while (trim(line) /= IO_EOF) ! read through sections of material part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + endif + if (section > 0_pInt) then + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('lattice_structure') + select case(trim(IO_lc(IO_stringValue(line,chunkPos,2_pInt)))) + case('iso','isotropic') + lattice_structure(section) = LATTICE_iso_ID + case('fcc') + lattice_structure(section) = LATTICE_fcc_ID + case('bcc') + lattice_structure(section) = LATTICE_bcc_ID + case('hex','hexagonal') + lattice_structure(section) = LATTICE_hex_ID + case('bct') + lattice_structure(section) = LATTICE_bct_ID + case('ort','orthorhombic') + lattice_structure(section) = LATTICE_ort_ID + case default + call IO_error(130_pInt,ext_msg=trim(IO_lc(IO_stringValue(line,chunkPos,2_pInt)))) + end select + case('trans_lattice_structure') + select case(trim(IO_lc(IO_stringValue(line,chunkPos,2_pInt)))) + case('bcc') + trans_lattice_structure(section) = LATTICE_bcc_ID + case('hex','hexagonal','hcp') + trans_lattice_structure(section) = LATTICE_hex_ID + end select + case ('c11') + lattice_C66(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c12') + lattice_C66(1,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c13') + lattice_C66(1,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c22') + lattice_C66(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c23') + lattice_C66(2,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c33') + lattice_C66(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c44') + lattice_C66(4,4,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c55') + lattice_C66(5,5,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c66') + lattice_C66(6,6,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c11_trans') + lattice_trans_C66(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c12_trans') + lattice_trans_C66(1,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c13_trans') + lattice_trans_C66(1,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c22_trans') + lattice_trans_C66(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c23_trans') + lattice_trans_C66(2,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c33_trans') + lattice_trans_C66(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c44_trans') + lattice_trans_C66(4,4,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c55_trans') + lattice_trans_C66(5,5,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c66_trans') + lattice_trans_C66(6,6,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('covera_ratio','c/a_ratio','c/a') + CoverA(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('c/a_trans','c/a_martensite','c/a_mart') + CoverA_trans(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('a_fcc') + a_fcc(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('a_bcc') + a_bcc(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('thermal_conductivity11') + lattice_thermalConductivity33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('thermal_conductivity22') + lattice_thermalConductivity33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('thermal_conductivity33') + lattice_thermalConductivity33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('thermal_expansion11') + lattice_thermalExpansion33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('thermal_expansion22') + lattice_thermalExpansion33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('thermal_expansion33') + lattice_thermalExpansion33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('specific_heat') + lattice_specificHeat(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancyformationenergy') + lattice_vacancyFormationEnergy(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancysurfaceenergy') + lattice_vacancySurfaceEnergy(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancyvolume') + lattice_vacancyVol(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogenformationenergy') + lattice_hydrogenFormationEnergy(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogensurfaceenergy') + lattice_hydrogenSurfaceEnergy(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogenvolume') + lattice_hydrogenVol(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('mass_density') + lattice_massDensity(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('reference_temperature') + lattice_referenceTemperature(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('damage_diffusion11') + lattice_DamageDiffusion33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('damage_diffusion22') + lattice_DamageDiffusion33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('damage_diffusion33') + lattice_DamageDiffusion33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('damage_mobility') + lattice_DamageMobility(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancyflux_diffusion11') + lattice_vacancyfluxDiffusion33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancyflux_diffusion22') + lattice_vacancyfluxDiffusion33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancyflux_diffusion33') + lattice_vacancyfluxDiffusion33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancyflux_mobility11') + lattice_vacancyfluxMobility33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancyflux_mobility22') + lattice_vacancyfluxMobility33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancyflux_mobility33') + lattice_vacancyfluxMobility33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('porosity_diffusion11') + lattice_PorosityDiffusion33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('porosity_diffusion22') + lattice_PorosityDiffusion33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('porosity_diffusion33') + lattice_PorosityDiffusion33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('porosity_mobility') + lattice_PorosityMobility(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogenflux_diffusion11') + lattice_hydrogenfluxDiffusion33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogenflux_diffusion22') + lattice_hydrogenfluxDiffusion33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogenflux_diffusion33') + lattice_hydrogenfluxDiffusion33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogenflux_mobility11') + lattice_hydrogenfluxMobility33(1,1,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogenflux_mobility22') + lattice_hydrogenfluxMobility33(2,2,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogenflux_mobility33') + lattice_hydrogenfluxMobility33(3,3,section) = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancy_eqcv') + lattice_equilibriumVacancyConcentration(section) = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogen_eqch') + lattice_equilibriumHydrogenConcentration(section) = IO_floatValue(line,chunkPos,2_pInt) + end select + endif + enddo + + do i = 1_pInt,Nphases + if ((CoverA(i) < 1.0_pReal .or. CoverA(i) > 2.0_pReal) & + .and. lattice_structure(i) == LATTICE_hex_ID) call IO_error(131_pInt,el=i) ! checking physical significance of c/a + if ((CoverA(i) > 2.0_pReal) & + .and. lattice_structure(i) == LATTICE_bct_ID) call IO_error(131_pInt,el=i) ! checking physical significance of c/a + call lattice_initializeStructure(i, CoverA(i), CoverA_trans(i), a_fcc(i), a_bcc(i)) + enddo + + deallocate(CoverA,CoverA_trans,a_fcc,a_bcc) + +end subroutine lattice_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief Calculation of Schmid matrices, etc. +!-------------------------------------------------------------------------------------------------- +subroutine lattice_initializeStructure(myPhase,CoverA,CoverA_trans,a_fcc,a_bcc) + use prec, only: & + tol_math_check + use math, only: & + math_crossproduct, & + math_tensorproduct33, & + math_mul33x33, & + math_mul33x3, & + math_transpose33, & + math_trace33, & + math_symmetric33, & + math_Mandel33to6, & + math_Mandel3333to66, & + math_Voigt66to3333, & + math_axisAngleToR, & + INRAD, & + MATH_I3 + use IO, only: & + IO_error, & + IO_warning + + implicit none + integer(pInt), intent(in) :: myPhase + real(pReal), intent(in) :: & + CoverA, & + CoverA_trans, & + a_fcc, & + a_bcc + + real(pReal), dimension(3) :: & + sdU, snU, & + np, nn + real(pReal), dimension(3,3) :: & + sstr, sdtr, sttr + real(pReal), dimension(3,lattice_maxNslip) :: & + sd, sn + real(pReal), dimension(3,3,2,lattice_maxNnonSchmid,lattice_maxNslip) :: & + sns + real(pReal), dimension(3,lattice_maxNtwin) :: & + td, tn + real(pReal), dimension(lattice_maxNtwin) :: & + ts + real(pReal), dimension(lattice_maxNtrans) :: & + trs + real(pReal), dimension(3,lattice_maxNtrans) :: & + xtr, ytr, ztr + real(pReal), dimension(3,3,lattice_maxNtrans) :: & + Rtr, Utr, Btr, Qtr, Str + real(pReal), dimension(3,lattice_maxNcleavage) :: & + cd, cn, ct + integer(pInt) :: & + i,j, & + myNslip = 0_pInt, myNtwin = 0_pInt, myNtrans = 0_pInt, myNcleavage = 0_pInt + real(pReal) :: c11bar, c12bar, c13bar, c14bar, c33bar, c44bar, A, B + + lattice_C66(1:6,1:6,myPhase) = lattice_symmetrizeC66(lattice_structure(myPhase),& + lattice_C66(1:6,1:6,myPhase)) + + lattice_mu(myPhase) = 0.2_pReal *( lattice_C66(1,1,myPhase) & + - lattice_C66(1,2,myPhase) & + + 3.0_pReal*lattice_C66(4,4,myPhase)) ! (C11iso-C12iso)/2 with C11iso=(3*C11+2*C12+4*C44)/5 and C12iso=(C11+4*C12-2*C44)/5 + lattice_nu(myPhase) = ( lattice_C66(1,1,myPhase) & + + 4.0_pReal*lattice_C66(1,2,myPhase) & + - 2.0_pReal*lattice_C66(4,4,myPhase)) & + /( 4.0_pReal*lattice_C66(1,1,myPhase) & + + 6.0_pReal*lattice_C66(1,2,myPhase) & + + 2.0_pReal*lattice_C66(4,4,myPhase))! C12iso/(C11iso+C12iso) with C11iso=(3*C11+2*C12+4*C44)/5 and C12iso=(C11+4*C12-2*C44)/5 + lattice_C3333(1:3,1:3,1:3,1:3,myPhase) = math_Voigt66to3333(lattice_C66(1:6,1:6,myPhase)) ! Literature data is Voigt + lattice_C66(1:6,1:6,myPhase) = math_Mandel3333to66(lattice_C3333(1:3,1:3,1:3,1:3,myPhase)) ! DAMASK uses Mandel + do i = 1_pInt, 6_pInt + if (abs(lattice_C66(i,i,myPhase)) 0.0_pReal) .and. (a_bcc > 0.0_pReal)) then + Utr(1:3,1:3,i) = (a_bcc/a_fcc)*math_tensorproduct33(xtr(1:3,i), xtr(1:3,i)) + & + sqrt(2.0_pReal)*(a_bcc/a_fcc)*math_tensorproduct33(ytr(1:3,i), ytr(1:3,i)) + & + sqrt(2.0_pReal)*(a_bcc/a_fcc)*math_tensorproduct33(ztr(1:3,i), ztr(1:3,i)) + endif + Qtr(1:3,1:3,i) = math_mul33x33(Rtr(1:3,1:3,i), Btr(1:3,1:3,i)) + Str(1:3,1:3,i) = math_mul33x33(Rtr(1:3,1:3,i), Utr(1:3,1:3,i)) - MATH_I3 + enddo + case (LATTICE_hex_ID) + sstr(1:3,1:3) = MATH_I3 + sstr(1,3) = sqrt(2.0_pReal)/4.0_pReal + sdtr(1:3,1:3) = MATH_I3 + if (CoverA_trans > 1.0_pReal .and. CoverA_trans < 2.0_pReal) then + sdtr(3,3) = CoverA_trans/sqrt(8.0_pReal/3.0_pReal) + endif + sttr = math_mul33x33(sdtr, sstr) + do i = 1_pInt,myNtrans + xtr(1:3,i) = lattice_fccTohex_systemTrans(1:3,i)/norm2(lattice_fccTohex_systemTrans(1:3,i)) + ztr(1:3,i) = lattice_fccTohex_systemTrans(4:6,i)/norm2(lattice_fccTohex_systemTrans(4:6,i)) + ytr(1:3,i) = -math_crossproduct(xtr(1:3,i), ztr(1:3,i)) + Rtr(1:3,1,i) = xtr(1:3,i) + Rtr(1:3,2,i) = ytr(1:3,i) + Rtr(1:3,3,i) = ztr(1:3,i) + Qtr(1:3,1:3,i) = Rtr(1:3,1:3,i) + Str(1:3,1:3,i) = math_mul33x33(Rtr(1:3,1:3,i), math_mul33x33(sttr, math_transpose33(Rtr(1:3,1:3,i)))) + Str(1:3,1:3,i) = Str(1:3,1:3,i) - MATH_I3 + trs(i) = lattice_fccTohex_shearTrans(i) + enddo + case default + Qtr = 0.0_pReal + Str = 0.0_pReal + end select + + lattice_NslipSystem(1:lattice_maxNslipFamily,myPhase) = lattice_fcc_NslipSystem + lattice_NtwinSystem(1:lattice_maxNtwinFamily,myPhase) = lattice_fcc_NtwinSystem + lattice_NtransSystem(1:lattice_maxNtransFamily,myPhase) = lattice_fcc_NtransSystem + lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_fcc_NcleavageSystem + lattice_NnonSchmid(myPhase) = lattice_fcc_NnonSchmid + lattice_interactionSlipSlip(1:myNslip,1:myNslip,myPhase) = lattice_fcc_interactionSlipSlip + lattice_interactionSlipTwin(1:myNslip,1:myNtwin,myPhase) = lattice_fcc_interactionSlipTwin + lattice_interactionTwinSlip(1:myNtwin,1:myNslip,myPhase) = lattice_fcc_interactionTwinSlip + lattice_interactionTwinTwin(1:myNtwin,1:myNtwin,myPhase) = lattice_fcc_interactionTwinTwin + lattice_interactionSlipTrans(1:myNslip,1:myNtrans,myPhase) = lattice_fccTohex_interactionSlipTrans + lattice_interactionTransSlip(1:myNtrans,1:myNslip,myPhase) = lattice_fccTohex_interactionTransSlip + lattice_interactionTransTrans(1:myNtrans,1:myNtrans,myPhase) = lattice_fccTohex_interactionTransTrans + lattice_projectionTrans(1:myNtrans,1:myNtrans,myPhase) = LATTICE_fccTobcc_projectionTrans*& + LATTICE_fccTobcc_projectionTransFactor + +!-------------------------------------------------------------------------------------------------- +! bcc + case (LATTICE_bcc_ID) + myNslip = lattice_bcc_Nslip + myNtwin = lattice_bcc_Ntwin + myNtrans = lattice_bcc_Ntrans + myNcleavage = lattice_bcc_Ncleavage + do i = 1_pInt,myNslip ! assign slip system vectors + sd(1:3,i) = lattice_bcc_systemSlip(1:3,i) + sn(1:3,i) = lattice_bcc_systemSlip(4:6,i) + sdU = sd(1:3,i) / norm2(sd(1:3,i)) + snU = sn(1:3,i) / norm2(sn(1:3,i)) + ! "np" and "nn" according to Gröger_etal2008, Acta Materialia 56 (2008) 5412–5425, table 1 (corresponds to their "n1" for positive and negative slip direction respectively) + np = math_mul33x3(math_axisAngleToR(sdU,60.0_pReal*INRAD), snU) + nn = math_mul33x3(math_axisAngleToR(-sdU,60.0_pReal*INRAD), snU) + ! Schmid matrices with non-Schmid contributions according to Koester_etal2012, Acta Materialia 60 (2012) 3894–3901, eq. (17) ("n1" is replaced by either "np" or "nn" according to either positive or negative slip direction) + sns(1:3,1:3,1,1,i) = math_tensorproduct33(sdU, np) + sns(1:3,1:3,2,1,i) = math_tensorproduct33(-sdU, nn) + sns(1:3,1:3,1,2,i) = math_tensorproduct33(math_crossproduct(snU, sdU), snU) + sns(1:3,1:3,2,2,i) = math_tensorproduct33(math_crossproduct(snU, -sdU), snU) + sns(1:3,1:3,1,3,i) = math_tensorproduct33(math_crossproduct(np, sdU), np) + sns(1:3,1:3,2,3,i) = math_tensorproduct33(math_crossproduct(nn, -sdU), nn) + sns(1:3,1:3,1,4,i) = math_tensorproduct33(snU, snU) + sns(1:3,1:3,2,4,i) = math_tensorproduct33(snU, snU) + sns(1:3,1:3,1,5,i) = math_tensorproduct33(math_crossproduct(snU, sdU), math_crossproduct(snU, sdU)) + sns(1:3,1:3,2,5,i) = math_tensorproduct33(math_crossproduct(snU, -sdU), math_crossproduct(snU, -sdU)) + sns(1:3,1:3,1,6,i) = math_tensorproduct33(sdU, sdU) + sns(1:3,1:3,2,6,i) = math_tensorproduct33(-sdU, -sdU) + enddo + do i = 1_pInt,myNtwin ! assign twin system vectors and shears + td(1:3,i) = lattice_bcc_systemTwin(1:3,i) + tn(1:3,i) = lattice_bcc_systemTwin(4:6,i) + ts(i) = lattice_bcc_shearTwin(i) + enddo + do i = 1_pInt, myNcleavage ! assign cleavage system vectors + cd(1:3,i) = lattice_bcc_systemCleavage(1:3,i)/norm2(lattice_bcc_systemCleavage(1:3,i)) + cn(1:3,i) = lattice_bcc_systemCleavage(4:6,i)/norm2(lattice_bcc_systemCleavage(4:6,i)) + ct(1:3,i) = math_crossproduct(cd(1:3,i),cn(1:3,i)) + enddo + lattice_NslipSystem(1:lattice_maxNslipFamily,myPhase) = lattice_bcc_NslipSystem + lattice_NtwinSystem(1:lattice_maxNtwinFamily,myPhase) = lattice_bcc_NtwinSystem + lattice_NtransSystem(1:lattice_maxNtransFamily,myPhase) = lattice_bcc_NtransSystem + lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_bcc_NcleavageSystem + lattice_NnonSchmid(myPhase) = lattice_bcc_NnonSchmid + lattice_interactionSlipSlip(1:myNslip,1:myNslip,myPhase) = lattice_bcc_interactionSlipSlip + lattice_interactionSlipTwin(1:myNslip,1:myNtwin,myPhase) = lattice_bcc_interactionSlipTwin + lattice_interactionTwinSlip(1:myNtwin,1:myNslip,myPhase) = lattice_bcc_interactionTwinSlip + lattice_interactionTwinTwin(1:myNtwin,1:myNtwin,myPhase) = lattice_bcc_interactionTwinTwin + +!-------------------------------------------------------------------------------------------------- +! hex (including conversion from miller-bravais (a1=a2=a3=c) to miller (a, b, c) indices) + case (LATTICE_hex_ID) + myNslip = lattice_hex_Nslip + myNtwin = lattice_hex_Ntwin + myNtrans = lattice_hex_Ntrans + myNcleavage = lattice_hex_Ncleavage + do i = 1_pInt,myNslip ! assign slip system vectors + sd(1,i) = lattice_hex_systemSlip(1,i)*1.5_pReal ! direction [uvtw]->[3u/2 (u+2v)*sqrt(3)/2 w*(c/a)] + sd(2,i) = (lattice_hex_systemSlip(1,i)+2.0_pReal*lattice_hex_systemSlip(2,i))*& + 0.5_pReal*sqrt(3.0_pReal) + sd(3,i) = lattice_hex_systemSlip(4,i)*CoverA + sn(1,i) = lattice_hex_systemSlip(5,i) ! plane (hkil)->(h (h+2k)/sqrt(3) l/(c/a)) + sn(2,i) = (lattice_hex_systemSlip(5,i)+2.0_pReal*lattice_hex_systemSlip(6,i))/sqrt(3.0_pReal) + sn(3,i) = lattice_hex_systemSlip(8,i)/CoverA + enddo + do i = 1_pInt,myNtwin ! assign twin system vectors and shears + td(1,i) = lattice_hex_systemTwin(1,i)*1.5_pReal + td(2,i) = (lattice_hex_systemTwin(1,i)+2.0_pReal*lattice_hex_systemTwin(2,i))*& + 0.5_pReal*sqrt(3.0_pReal) + td(3,i) = lattice_hex_systemTwin(4,i)*CoverA + tn(1,i) = lattice_hex_systemTwin(5,i) + tn(2,i) = (lattice_hex_systemTwin(5,i)+2.0_pReal*lattice_hex_systemTwin(6,i))/sqrt(3.0_pReal) + tn(3,i) = lattice_hex_systemTwin(8,i)/CoverA + select case(lattice_hex_shearTwin(i)) ! from Christian & Mahajan 1995 p.29 + case (1_pInt) ! <-10.1>{10.2} + ts(i) = (3.0_pReal-CoverA*CoverA)/sqrt(3.0_pReal)/CoverA + case (2_pInt) ! <11.6>{-1-1.1} + ts(i) = 1.0_pReal/CoverA + case (3_pInt) ! <10.-2>{10.1} + ts(i) = (4.0_pReal*CoverA*CoverA-9.0_pReal)/4.0_pReal/sqrt(3.0_pReal)/CoverA + case (4_pInt) ! <11.-3>{11.2} + ts(i) = 2.0_pReal*(CoverA*CoverA-2.0_pReal)/3.0_pReal/CoverA + end select + enddo + do i = 1_pInt, myNcleavage ! cleavage system vectors + cd(1,i) = lattice_hex_systemCleavage(1,i)*1.5_pReal ! direction [uvtw]->[3u/2 (u+2v)*sqrt(3)/2 w*(c/a)] + cd(2,i) = (lattice_hex_systemCleavage(1,i)+2.0_pReal*lattice_hex_systemCleavage(2,i))*& + 0.5_pReal*sqrt(3.0_pReal) + cd(3,i) = lattice_hex_systemCleavage(4,i)*CoverA + cd(1:3,1) = cd(1:3,i)/norm2(cd(1:3,i)) + cn(1,i) = lattice_hex_systemCleavage(5,i) ! plane (hkil)->(h (h+2k)/sqrt(3) l/(c/a)) + cn(2,i) = (lattice_hex_systemCleavage(5,i)+2.0_pReal*lattice_hex_systemCleavage(6,i))/sqrt(3.0_pReal) + cn(3,i) = lattice_hex_systemCleavage(8,i)/CoverA + cn(1:3,1) = cn(1:3,i)/norm2(cn(1:3,i)) + ct(1:3,i) = math_crossproduct(cd(1:3,i),cn(1:3,i)) + enddo + lattice_NslipSystem(1:lattice_maxNslipFamily,myPhase) = lattice_hex_NslipSystem + lattice_NtwinSystem(1:lattice_maxNtwinFamily,myPhase) = lattice_hex_NtwinSystem + lattice_NtransSystem(1:lattice_maxNtransFamily,myPhase) = lattice_hex_NtransSystem + lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_hex_NcleavageSystem + lattice_NnonSchmid(myPhase) = lattice_hex_NnonSchmid + lattice_interactionSlipSlip(1:myNslip,1:myNslip,myPhase) = lattice_hex_interactionSlipSlip + lattice_interactionSlipTwin(1:myNslip,1:myNtwin,myPhase) = lattice_hex_interactionSlipTwin + lattice_interactionTwinSlip(1:myNtwin,1:myNslip,myPhase) = lattice_hex_interactionTwinSlip + lattice_interactionTwinTwin(1:myNtwin,1:myNtwin,myPhase) = lattice_hex_interactionTwinTwin + +!-------------------------------------------------------------------------------------------------- +! bct + case (LATTICE_bct_ID) + myNslip = lattice_bct_Nslip + myNtwin = lattice_bct_Ntwin + myNcleavage = lattice_bct_Ncleavage + do i = 1_pInt,myNslip ! assign slip system vectors + sd(1:2,i) = lattice_bct_systemSlip(1:2,i) + sd(3,i) = lattice_bct_systemSlip(3,i)*CoverA + sn(1:2,i) = lattice_bct_systemSlip(4:5,i) + sn(3,i) = lattice_bct_systemSlip(6,i)/CoverA + sdU = sd(1:3,i) / norm2(sd(1:3,i)) + snU = sn(1:3,i) / norm2(sn(1:3,i)) + enddo + lattice_NslipSystem(1:lattice_maxNslipFamily,myPhase) = lattice_bct_NslipSystem + lattice_NtwinSystem(1:lattice_maxNtwinFamily,myPhase) = lattice_bct_NtwinSystem + lattice_NtransSystem(1:lattice_maxNtransFamily,myPhase) = lattice_bct_NtransSystem + lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_bct_NcleavageSystem + lattice_NnonSchmid(myPhase) = lattice_bct_NnonSchmid + lattice_interactionSlipSlip(1:myNslip,1:myNslip,myPhase) = lattice_bct_interactionSlipSlip + +!-------------------------------------------------------------------------------------------------- +! orthorhombic (no crystal plasticity) + case (LATTICE_ort_ID) + myNslip = 0_pInt + myNtwin = 0_pInt + myNtrans = 0_pInt + myNcleavage = lattice_ortho_Ncleavage + do i = 1_pInt, myNcleavage ! assign cleavage system vectors + cd(1:3,i) = lattice_iso_systemCleavage(1:3,i)/norm2(LATTICE_ortho_systemCleavage(1:3,i)) + cn(1:3,i) = lattice_iso_systemCleavage(4:6,i)/norm2(LATTICE_ortho_systemCleavage(4:6,i)) + ct(1:3,i) = math_crossproduct(cd(1:3,i),cn(1:3,i)) + enddo + lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_iso_NcleavageSystem + +!-------------------------------------------------------------------------------------------------- +! isotropic (no crystal plasticity) + case (LATTICE_iso_ID) + myNslip = 0_pInt + myNtwin = 0_pInt + myNtrans = 0_pInt + myNcleavage = lattice_iso_Ncleavage + do i = 1_pInt, myNcleavage ! assign cleavage system vectors + cd(1:3,i) = lattice_iso_systemCleavage(1:3,i)/norm2(lattice_iso_systemCleavage(1:3,i)) + cn(1:3,i) = lattice_iso_systemCleavage(4:6,i)/norm2(lattice_iso_systemCleavage(4:6,i)) + ct(1:3,i) = math_crossproduct(cd(1:3,i),cn(1:3,i)) + enddo + lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,myPhase) = lattice_iso_NcleavageSystem + +!-------------------------------------------------------------------------------------------------- +! something went wrong + case default + call IO_error(130_pInt,ext_msg='lattice_initializeStructure') + end select + + + do i = 1_pInt,myNslip ! store slip system vectors and Schmid matrix for my structure + lattice_sd(1:3,i,myPhase) = sd(1:3,i)/norm2(sd(1:3,i)) ! make unit vector + lattice_sn(1:3,i,myPhase) = sn(1:3,i)/norm2(sn(1:3,i)) ! make unit vector + lattice_st(1:3,i,myPhase) = math_crossproduct(lattice_sd(1:3,i,myPhase), & + lattice_sn(1:3,i,myPhase)) + lattice_Sslip(1:3,1:3,1,i,myPhase) = math_tensorproduct33(lattice_sd(1:3,i,myPhase), & + lattice_sn(1:3,i,myPhase)) ! calculate Schmid matrix d \otimes n + do j = 1_pInt,lattice_NnonSchmid(myPhase) + lattice_Sslip(1:3,1:3,2*j ,i,myPhase) = sns(1:3,1:3,1,j,i) + lattice_Sslip(1:3,1:3,2*j+1,i,myPhase) = sns(1:3,1:3,2,j,i) + enddo + do j = 1_pInt,1_pInt+2_pInt*lattice_NnonSchmid(myPhase) + lattice_Sslip_v(1:6,j,i,myPhase) = & + math_Mandel33to6(math_symmetric33(lattice_Sslip(1:3,1:3,j,i,myPhase))) + enddo + if (abs(math_trace33(lattice_Sslip(1:3,1:3,1,i,myPhase))) > tol_math_check) & + call IO_error(0_pInt,myPhase,i,0_pInt,ext_msg = 'dilatational slip Schmid matrix') + enddo + do i = 1_pInt,myNtwin ! store twin system vectors and Schmid plus rotation matrix for my structure + lattice_td(1:3,i,myPhase) = td(1:3,i)/norm2(td(1:3,i)) ! make unit vector + lattice_tn(1:3,i,myPhase) = tn(1:3,i)/norm2(tn(1:3,i)) ! make unit vector + lattice_tt(1:3,i,myPhase) = math_crossproduct(lattice_td(1:3,i,myPhase), & + lattice_tn(1:3,i,myPhase)) + lattice_Stwin(1:3,1:3,i,myPhase) = math_tensorproduct33(lattice_td(1:3,i,myPhase), & + lattice_tn(1:3,i,myPhase)) + lattice_Stwin_v(1:6,i,myPhase) = math_Mandel33to6(math_symmetric33(lattice_Stwin(1:3,1:3,i,myPhase))) + lattice_Qtwin(1:3,1:3,i,myPhase) = math_axisAngleToR(tn(1:3,i),180.0_pReal*INRAD) + lattice_shearTwin(i,myPhase) = ts(i) + if (abs(math_trace33(lattice_Stwin(1:3,1:3,i,myPhase))) > tol_math_check) & + call IO_error(301_pInt,myPhase,ext_msg = 'dilatational twin Schmid matrix') + enddo + do i = 1_pInt,myNtrans + lattice_Qtrans(1:3,1:3,i,myPhase) = Qtr(1:3,1:3,i) + lattice_Strans(1:3,1:3,i,myPhase) = Str(1:3,1:3,i) + lattice_Strans_v(1:6,i,myPhase) = math_Mandel33to6(math_symmetric33(lattice_Strans(1:3,1:3,i,myPhase))) + lattice_shearTrans(i,myPhase) = trs(i) + enddo + do i = 1_pInt,myNcleavage ! store slip system vectors and Schmid matrix for my structure + lattice_Scleavage(1:3,1:3,1,i,myPhase) = math_tensorproduct33(cd(1:3,i),cn(1:3,i)) + lattice_Scleavage(1:3,1:3,2,i,myPhase) = math_tensorproduct33(ct(1:3,i),cn(1:3,i)) + lattice_Scleavage(1:3,1:3,3,i,myPhase) = math_tensorproduct33(cn(1:3,i),cn(1:3,i)) + do j = 1_pInt,3_pInt + lattice_Scleavage_v(1:6,j,i,myPhase) = & + math_Mandel33to6(math_symmetric33(lattice_Scleavage(1:3,1:3,j,i,myPhase))) + enddo + enddo + +end subroutine lattice_initializeStructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief Symmetrizes stiffness matrix according to lattice type +!-------------------------------------------------------------------------------------------------- +pure function lattice_symmetrizeC66(struct,C66) + + implicit none + integer(kind(LATTICE_undefined_ID)), intent(in) :: struct + real(pReal), dimension(6,6), intent(in) :: C66 + real(pReal), dimension(6,6) :: lattice_symmetrizeC66 + integer(pInt) :: j,k + + lattice_symmetrizeC66 = 0.0_pReal + + select case(struct) + case (LATTICE_iso_ID) + forall(k=1_pInt:3_pInt) + forall(j=1_pInt:3_pInt) lattice_symmetrizeC66(k,j) = C66(1,2) + lattice_symmetrizeC66(k,k) = C66(1,1) + lattice_symmetrizeC66(k+3,k+3) = 0.5_pReal*(C66(1,1)-C66(1,2)) + end forall + case (LATTICE_fcc_ID,LATTICE_bcc_ID) + forall(k=1_pInt:3_pInt) + forall(j=1_pInt:3_pInt) lattice_symmetrizeC66(k,j) = C66(1,2) + lattice_symmetrizeC66(k,k) = C66(1,1) + lattice_symmetrizeC66(k+3_pInt,k+3_pInt) = C66(4,4) + end forall + case (LATTICE_hex_ID) + lattice_symmetrizeC66(1,1) = C66(1,1) + lattice_symmetrizeC66(2,2) = C66(1,1) + lattice_symmetrizeC66(3,3) = C66(3,3) + lattice_symmetrizeC66(1,2) = C66(1,2) + lattice_symmetrizeC66(2,1) = C66(1,2) + lattice_symmetrizeC66(1,3) = C66(1,3) + lattice_symmetrizeC66(3,1) = C66(1,3) + lattice_symmetrizeC66(2,3) = C66(1,3) + lattice_symmetrizeC66(3,2) = C66(1,3) + lattice_symmetrizeC66(4,4) = C66(4,4) + lattice_symmetrizeC66(5,5) = C66(4,4) + lattice_symmetrizeC66(6,6) = 0.5_pReal*(C66(1,1)-C66(1,2)) + case (LATTICE_ort_ID) + lattice_symmetrizeC66(1,1) = C66(1,1) + lattice_symmetrizeC66(2,2) = C66(2,2) + lattice_symmetrizeC66(3,3) = C66(3,3) + lattice_symmetrizeC66(1,2) = C66(1,2) + lattice_symmetrizeC66(2,1) = C66(1,2) + lattice_symmetrizeC66(1,3) = C66(1,3) + lattice_symmetrizeC66(3,1) = C66(1,3) + lattice_symmetrizeC66(2,3) = C66(2,3) + lattice_symmetrizeC66(3,2) = C66(2,3) + lattice_symmetrizeC66(4,4) = C66(4,4) + lattice_symmetrizeC66(5,5) = C66(5,5) + lattice_symmetrizeC66(6,6) = C66(6,6) + case (LATTICE_bct_ID) + lattice_symmetrizeC66(1,1) = C66(1,1) + lattice_symmetrizeC66(2,2) = C66(1,1) + lattice_symmetrizeC66(3,3) = C66(3,3) + lattice_symmetrizeC66(1,2) = C66(1,2) + lattice_symmetrizeC66(2,1) = C66(1,2) + lattice_symmetrizeC66(1,3) = C66(1,3) + lattice_symmetrizeC66(3,1) = C66(1,3) + lattice_symmetrizeC66(2,3) = C66(1,3) + lattice_symmetrizeC66(3,2) = C66(1,3) + lattice_symmetrizeC66(4,4) = C66(4,4) + lattice_symmetrizeC66(5,5) = C66(4,4) + lattice_symmetrizeC66(6,6) = C66(6,6) !J. A. Rayne and B. S. Chandrasekhar Phys. Rev. 120, 1658 Erratum Phys. Rev. 122, 1962 + case default + lattice_symmetrizeC66 = C66 + end select + + end function lattice_symmetrizeC66 + +!-------------------------------------------------------------------------------------------------- +!> @brief Symmetrizes 2nd order tensor according to lattice type +!-------------------------------------------------------------------------------------------------- +pure function lattice_symmetrize33(struct,T33) + + implicit none + integer(kind(LATTICE_undefined_ID)), intent(in) :: struct + real(pReal), dimension(3,3), intent(in) :: T33 + real(pReal), dimension(3,3) :: lattice_symmetrize33 + integer(pInt) :: k + + lattice_symmetrize33 = 0.0_pReal + + select case(struct) + case (LATTICE_iso_ID,LATTICE_fcc_ID,LATTICE_bcc_ID) + forall(k=1_pInt:3_pInt) lattice_symmetrize33(k,k) = T33(1,1) + case (LATTICE_hex_ID) + lattice_symmetrize33(1,1) = T33(1,1) + lattice_symmetrize33(2,2) = T33(1,1) + lattice_symmetrize33(3,3) = T33(3,3) + case (LATTICE_ort_ID,lattice_bct_ID) + lattice_symmetrize33(1,1) = T33(1,1) + lattice_symmetrize33(2,2) = T33(2,2) + lattice_symmetrize33(3,3) = T33(3,3) + case default + lattice_symmetrize33 = T33 + end select + + end function lattice_symmetrize33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief figures whether unit quat falls into stereographic standard triangle +!-------------------------------------------------------------------------------------------------- +logical pure function lattice_qInSST(Q, struct) + use prec, only: & + prec_isNaN + use math, only: & + math_qToRodrig + + implicit none + real(pReal), dimension(4), intent(in) :: Q ! orientation + integer(kind(LATTICE_undefined_ID)), intent(in) :: struct ! lattice structure + real(pReal), dimension(3) :: Rodrig ! Rodrigues vector of Q + + Rodrig = math_qToRodrig(Q) + if (any(prec_isNaN(Rodrig))) then + lattice_qInSST = .false. + else + select case (struct) + case (LATTICE_bcc_ID,LATTICE_fcc_ID) + lattice_qInSST = Rodrig(1) > Rodrig(2) .and. & + Rodrig(2) > Rodrig(3) .and. & + Rodrig(3) > 0.0_pReal + case (LATTICE_hex_ID) + lattice_qInSST = Rodrig(1) > sqrt(3.0_pReal)*Rodrig(2) .and. & + Rodrig(2) > 0.0_pReal .and. & + Rodrig(3) > 0.0_pReal + case default + lattice_qInSST = .true. + end select + endif + +end function lattice_qInSST + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the disorientation for 2 unit quaternions +!-------------------------------------------------------------------------------------------------- +pure function lattice_qDisorientation(Q1, Q2, struct) + use prec, only: & + tol_math_check + use math, only: & + math_qMul, & + math_qConj + + implicit none + real(pReal), dimension(4) :: lattice_qDisorientation + real(pReal), dimension(4), intent(in) :: & + Q1, & ! 1st orientation + Q2 ! 2nd orientation + integer(kind(LATTICE_undefined_ID)), optional, intent(in) :: & ! if given, symmetries between the two orientation will be considered + struct + + real(pReal), dimension(4) :: dQ,dQsymA,mis + integer(pInt) :: i,j,k,s,symmetry + integer(kind(LATTICE_undefined_ID)) :: myStruct + +!-------------------------------------------------------------------------------------------------- +! check if a structure with known symmetries is given + if (present(struct)) then + myStruct = struct + select case (struct) + case(LATTICE_fcc_ID,LATTICE_bcc_ID) + symmetry = 1_pInt + case(LATTICE_hex_ID) + symmetry = 2_pInt + case default + symmetry = 0_pInt + end select + else + symmetry = 0_pInt + myStruct = LATTICE_undefined_ID + endif + + +!-------------------------------------------------------------------------------------------------- +! calculate misorientation, for cubic and hexagonal structure find symmetries + dQ = math_qMul(math_qConj(Q1),Q2) + lattice_qDisorientation = dQ + + select case(symmetry) + + case (1_pInt,2_pInt) + s = sum(lattice_NsymOperations(1:symmetry-1_pInt)) + do i = 1_pInt,2_pInt + dQ = math_qConj(dQ) ! switch order of "from -- to" + do j = 1_pInt,lattice_NsymOperations(symmetry) ! run through first crystal's symmetries + dQsymA = math_qMul(lattice_symOperations(1:4,s+j),dQ) ! apply sym + do k = 1_pInt,lattice_NsymOperations(symmetry) ! run through 2nd crystal's symmetries + mis = math_qMul(dQsymA,lattice_symOperations(1:4,s+k)) ! apply sym + if (mis(1) < 0.0_pReal) & ! want positive angle + mis = -mis + if (mis(1)-lattice_qDisorientation(1) > -tol_math_check & + .and. lattice_qInSST(mis,LATTICE_undefined_ID)) lattice_qDisorientation = mis ! found better one + enddo; enddo; enddo + case (0_pInt) + if (lattice_qDisorientation(1) < 0.0_pReal) lattice_qDisorientation = -lattice_qDisorientation ! keep omega within 0 to 180 deg + end select + +end function lattice_qDisorientation + +end module lattice diff --git a/src/libs.f90 b/src/libs.f90 new file mode 100644 index 000000000..7c109cab6 --- /dev/null +++ b/src/libs.f90 @@ -0,0 +1,14 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief dummy source for inclusion of Library files +!-------------------------------------------------------------------------------------------------- +module libs +!nothing in here +end module libs + +#include "../lib/IR_Precision.f90" +#include "../lib/Lib_Base64.f90" +#include "../lib/Lib_VTK_IO.f90" + diff --git a/src/material.f90 b/src/material.f90 new file mode 100644 index 000000000..c1aacf751 --- /dev/null +++ b/src/material.f90 @@ -0,0 +1,1615 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Parses material config file, either solverJobName.materialConfig or material.config +!> @details reads the material configuration file, where solverJobName.materialConfig takes +!! precedence over material.config and parses the sections 'homogenization', 'crystallite', +!! 'phase', 'texture', and 'microstucture' +!-------------------------------------------------------------------------------------------------- +module material + use prec, only: & + pReal, & + pInt, & + tState, & + tPlasticState, & + tSourceState, & + tHomogMapping, & + tPhaseMapping, & + p_vec, & + p_intvec + + implicit none + private + character(len=*), parameter, public :: & + ELASTICITY_hooke_label = 'hooke', & + PLASTICITY_none_label = 'none', & + PLASTICITY_isotropic_label = 'isotropic', & + PLASTICITY_j2_label = 'j2', & + PLASTICITY_phenopowerlaw_label = 'phenopowerlaw', & + PLASTICITY_phenoplus_label = 'phenoplus', & + PLASTICITY_dislotwin_label = 'dislotwin', & + PLASTICITY_disloucla_label = 'disloucla', & + PLASTICITY_titanmod_label = 'titanmod', & + PLASTICITY_nonlocal_label = 'nonlocal', & + SOURCE_thermal_dissipation_label = 'thermal_dissipation', & + SOURCE_thermal_externalheat_label = 'thermal_externalheat', & + SOURCE_damage_isoBrittle_label = 'damage_isobrittle', & + SOURCE_damage_isoDuctile_label = 'damage_isoductile', & + SOURCE_damage_anisoBrittle_label = 'damage_anisobrittle', & + SOURCE_damage_anisoDuctile_label = 'damage_anisoductile', & + SOURCE_vacancy_phenoplasticity_label = 'vacancy_phenoplasticity', & + SOURCE_vacancy_irradiation_label = 'vacancy_irradiation', & + SOURCE_vacancy_thermalfluc_label = 'vacancy_thermalfluctuation', & + KINEMATICS_thermal_expansion_label = 'thermal_expansion', & + KINEMATICS_cleavage_opening_label = 'cleavage_opening', & + KINEMATICS_slipplane_opening_label = 'slipplane_opening', & + KINEMATICS_vacancy_strain_label = 'vacancy_strain', & + KINEMATICS_hydrogen_strain_label = 'hydrogen_strain', & + STIFFNESS_DEGRADATION_damage_label = 'damage', & + STIFFNESS_DEGRADATION_porosity_label = 'porosity', & + THERMAL_isothermal_label = 'isothermal', & + THERMAL_adiabatic_label = 'adiabatic', & + THERMAL_conduction_label = 'conduction', & + DAMAGE_none_label = 'none', & + DAMAGE_local_label = 'local', & + DAMAGE_nonlocal_label = 'nonlocal', & + VACANCYFLUX_isoconc_label = 'isoconcentration', & + VACANCYFLUX_isochempot_label = 'isochemicalpotential', & + VACANCYFLUX_cahnhilliard_label = 'cahnhilliard', & + POROSITY_none_label = 'none', & + POROSITY_phasefield_label = 'phasefield', & + HYDROGENFLUX_isoconc_label = 'isoconcentration', & + HYDROGENFLUX_cahnhilliard_label = 'cahnhilliard', & + HOMOGENIZATION_none_label = 'none', & + HOMOGENIZATION_isostrain_label = 'isostrain', & + HOMOGENIZATION_rgc_label = 'rgc' + + + + enum, bind(c) + enumerator :: ELASTICITY_undefined_ID, & + ELASTICITY_hooke_ID + end enum + enum, bind(c) + enumerator :: PLASTICITY_undefined_ID, & + PLASTICITY_none_ID, & + PLASTICITY_isotropic_ID, & + PLASTICITY_j2_ID, & + PLASTICITY_phenopowerlaw_ID, & + PLASTICITY_phenoplus_ID, & + PLASTICITY_dislotwin_ID, & + PLASTICITY_disloucla_ID, & + PLASTICITY_titanmod_ID, & + PLASTICITY_nonlocal_ID + end enum + + enum, bind(c) + enumerator :: 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, & + SOURCE_vacancy_phenoplasticity_ID, & + SOURCE_vacancy_irradiation_ID, & + SOURCE_vacancy_thermalfluc_ID + end enum + + enum, bind(c) + enumerator :: KINEMATICS_undefined_ID, & + KINEMATICS_cleavage_opening_ID, & + KINEMATICS_slipplane_opening_ID, & + KINEMATICS_thermal_expansion_ID, & + KINEMATICS_vacancy_strain_ID, & + KINEMATICS_hydrogen_strain_ID + end enum + + enum, bind(c) + enumerator :: STIFFNESS_DEGRADATION_undefined_ID, & + STIFFNESS_DEGRADATION_damage_ID, & + STIFFNESS_DEGRADATION_porosity_ID + end enum + + enum, bind(c) + enumerator :: THERMAL_isothermal_ID, & + THERMAL_adiabatic_ID, & + THERMAL_conduction_ID + end enum + + enum, bind(c) + enumerator :: DAMAGE_none_ID, & + DAMAGE_local_ID, & + DAMAGE_nonlocal_ID + end enum + + enum, bind(c) + enumerator :: VACANCYFLUX_isoconc_ID, & + VACANCYFLUX_isochempot_ID, & + VACANCYFLUX_cahnhilliard_ID + end enum + + enum, bind(c) + enumerator :: POROSITY_none_ID, & + POROSITY_phasefield_ID + end enum + enum, bind(c) + enumerator :: HYDROGENFLUX_isoconc_ID, & + HYDROGENFLUX_cahnhilliard_ID + end enum + + enum, bind(c) + enumerator :: HOMOGENIZATION_undefined_ID, & + HOMOGENIZATION_none_ID, & + HOMOGENIZATION_isostrain_ID, & + HOMOGENIZATION_rgc_ID + end enum + + character(len=*), parameter, public :: & + MATERIAL_configFile = 'material.config', & !< generic name for material configuration file + MATERIAL_localFileExt = 'materialConfig' !< extension of solver job name depending material configuration file + + character(len=*), parameter, public :: & + MATERIAL_partHomogenization = 'homogenization', & !< keyword for homogenization part + MATERIAL_partCrystallite = 'crystallite', & !< keyword for crystallite part + MATERIAL_partPhase = 'phase' !< keyword for phase part + + integer(kind(ELASTICITY_undefined_ID)), dimension(:), allocatable, public, protected :: & + phase_elasticity !< elasticity of each phase + integer(kind(PLASTICITY_undefined_ID)), dimension(:), allocatable, public, protected :: & + phase_plasticity !< plasticity of each phase + integer(kind(THERMAL_isothermal_ID)), dimension(:), allocatable, public, protected :: & + thermal_type !< thermal transport model + integer(kind(DAMAGE_none_ID)), dimension(:), allocatable, public, protected :: & + damage_type !< nonlocal damage model + integer(kind(VACANCYFLUX_isoconc_ID)), dimension(:), allocatable, public, protected :: & + vacancyflux_type !< vacancy transport model + integer(kind(POROSITY_none_ID)), dimension(:), allocatable, public, protected :: & + porosity_type !< porosity evolution model + integer(kind(HYDROGENFLUX_isoconc_ID)), dimension(:), allocatable, public, protected :: & + hydrogenflux_type !< hydrogen transport model + + integer(kind(SOURCE_undefined_ID)), dimension(:,:), allocatable, public, protected :: & + 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 + + integer(kind(HOMOGENIZATION_undefined_ID)), dimension(:), allocatable, public, protected :: & + homogenization_type !< type of each homogenization + + character(len=64), dimension(:), allocatable, public, protected :: & + phase_name, & !< name of each phase + homogenization_name, & !< name of each homogenization + crystallite_name !< name of each crystallite setting + + integer(pInt), public, protected :: & + homogenization_maxNgrains, & !< max number of grains in any USED homogenization + material_Nphase, & !< number of phases + material_Nhomogenization, & !< number of homogenizations + material_Nmicrostructure, & !< number of microstructures + material_Ncrystallite !< number of crystallite settings + + integer(pInt), dimension(:), allocatable, public, protected :: & + 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_Noutput, & !< number of '(output)' items per phase + phase_elasticityInstance, & !< instance of particular elasticity of each phase + phase_plasticityInstance !< instance of particular plasticity of each phase + + integer(pInt), dimension(:), allocatable, public, protected :: & + crystallite_Noutput !< number of '(output)' items per crystallite setting + + integer(pInt), dimension(:), allocatable, public, protected :: & + homogenization_Ngrains, & !< number of grains in each homogenization + homogenization_Noutput, & !< number of '(output)' items per 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 + vacancyflux_typeInstance, & !< instance of particular type of each vacancy flux + porosity_typeInstance, & !< instance of particular type of each porosity model + hydrogenflux_typeInstance, & !< instance of particular type of each hydrogen flux + microstructure_crystallite !< crystallite setting ID of each microstructure + + real(pReal), dimension(:), allocatable, public, protected :: & + thermal_initialT, & !< initial temperature per each homogenization + damage_initialPhi, & !< initial damage per each homogenization + vacancyflux_initialCv, & !< initial vacancy concentration per each homogenization + porosity_initialPhi, & !< initial posority per each homogenization + hydrogenflux_initialCh !< initial hydrogen concentration per each homogenization + + integer(pInt), dimension(:,:,:), allocatable, public :: & + material_phase !< phase (index) of each grain,IP,element + integer(pInt), dimension(:,:), allocatable, public :: & + material_homog !< homogenization (index) of each IP,element + type(tPlasticState), allocatable, dimension(:), public :: & + plasticState + type(tSourceState), allocatable, dimension(:), public :: & + sourceState + type(tState), allocatable, dimension(:), public :: & + homogState, & + thermalState, & + damageState, & + vacancyfluxState, & + porosityState, & + hydrogenfluxState + + integer(pInt), dimension(:,:,:), allocatable, public, protected :: & + material_texture !< texture (index) of each grain,IP,element + + real(pReal), dimension(:,:,:,:), allocatable, public, protected :: & + material_EulerAngles !< initial orientation of each grain,IP,element + + logical, dimension(:), allocatable, public, protected :: & + microstructure_active, & + microstructure_elemhomo, & !< flag to indicate homogeneous microstructure distribution over element's IPs + phase_localPlasticity !< flags phases with local constitutive law + + + character(len=*), parameter, private :: & + MATERIAL_partMicrostructure = 'microstructure', & !< keyword for microstructure part + MATERIAL_partTexture = 'texture' !< keyword for texture part + + character(len=64), dimension(:), allocatable, private :: & + microstructure_name, & !< name of each microstructure + texture_name !< name of each texture + + character(len=256), dimension(:), allocatable, private :: & + texture_ODFfile !< name of each ODF file + + integer(pInt), private :: & + material_Ntexture, & !< number of textures + microstructure_maxNconstituents, & !< max number of constituents in any phase + texture_maxNgauss, & !< max number of Gauss components in any texture + texture_maxNfiber !< max number of Fiber components in any texture + + integer(pInt), dimension(:), allocatable, private :: & + microstructure_Nconstituents, & !< number of constituents in each microstructure + texture_symmetry, & !< number of symmetric orientations per texture + texture_Ngauss, & !< number of Gauss components per texture + texture_Nfiber !< number of Fiber components per texture + + integer(pInt), dimension(:,:), allocatable, private :: & + microstructure_phase, & !< phase IDs of each microstructure + microstructure_texture !< texture IDs of each microstructure + + real(pReal), dimension(:,:), allocatable, private :: & + microstructure_fraction !< vol fraction of each constituent in microstructure + + real(pReal), dimension(:,:,:), allocatable, private :: & + material_volume, & !< volume of each grain,IP,element + texture_Gauss, & !< data of each Gauss component + texture_Fiber, & !< data of each Fiber component + texture_transformation !< transformation for each texture + + logical, dimension(:), allocatable, private :: & + homogenization_active + + integer(pInt), dimension(:,:,:), allocatable, public :: phaseAt !< phase ID of every material point (ipc,ip,el) + integer(pInt), dimension(:,:,:), allocatable, public :: phasememberAt !< memberID of given phase at every material point (ipc,ip,el) + integer(pInt), dimension(:,:,:), allocatable, public, target :: mappingCrystallite + integer(pInt), dimension(:,:,:), allocatable, public, target :: mappingHomogenization !< mapping from material points to offset in heterogenous state/field + integer(pInt), dimension(:,:), allocatable, public, target :: mappingHomogenizationConst !< mapping from material points to offset in constant state/field + + type(tHomogMapping), allocatable, dimension(:), public :: & + thermalMapping, & !< mapping for thermal state/fields + damageMapping, & !< mapping for damage state/fields + vacancyfluxMapping, & !< mapping for vacancy conc state/fields + porosityMapping, & !< mapping for porosity state/fields + hydrogenfluxMapping !< mapping for hydrogen conc state/fields + + type(p_vec), allocatable, dimension(:), public :: & + temperature, & !< temperature field + damage, & !< damage field + vacancyConc, & !< vacancy conc field + porosity, & !< porosity field + hydrogenConc, & !< hydrogen conc field + temperatureRate, & !< temperature change rate field + vacancyConcRate, & !< vacancy conc change field + hydrogenConcRate !< hydrogen conc change field + + public :: & + material_init, & + ELASTICITY_hooke_ID ,& + PLASTICITY_none_ID, & + PLASTICITY_isotropic_ID, & + PLASTICITY_J2_ID, & + PLASTICITY_phenopowerlaw_ID, & + PLASTICITY_phenoplus_ID, & + PLASTICITY_dislotwin_ID, & + PLASTICITY_disloucla_ID, & + PLASTICITY_titanmod_ID, & + PLASTICITY_nonlocal_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, & + SOURCE_vacancy_phenoplasticity_ID, & + SOURCE_vacancy_irradiation_ID, & + SOURCE_vacancy_thermalfluc_ID, & + KINEMATICS_cleavage_opening_ID, & + KINEMATICS_slipplane_opening_ID, & + KINEMATICS_thermal_expansion_ID, & + KINEMATICS_vacancy_strain_ID, & + KINEMATICS_hydrogen_strain_ID, & + STIFFNESS_DEGRADATION_damage_ID, & + STIFFNESS_DEGRADATION_porosity_ID, & + THERMAL_isothermal_ID, & + THERMAL_adiabatic_ID, & + THERMAL_conduction_ID, & + DAMAGE_none_ID, & + DAMAGE_local_ID, & + DAMAGE_nonlocal_ID, & + VACANCYFLUX_isoconc_ID, & + VACANCYFLUX_isochempot_ID, & + VACANCYFLUX_cahnhilliard_ID, & + POROSITY_none_ID, & + POROSITY_phasefield_ID, & + HYDROGENFLUX_isoconc_ID, & + HYDROGENFLUX_cahnhilliard_ID, & + HOMOGENIZATION_none_ID, & + HOMOGENIZATION_isostrain_ID, & +#ifdef HDF + material_NconstituentsPhase, & +#endif + HOMOGENIZATION_RGC_ID + + private :: & + material_parseHomogenization, & + material_parseMicrostructure, & + material_parseCrystallite, & + material_parsePhase, & + material_parseTexture, & + material_populateGrains + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief parses material configuration file +!> @details figures out if solverJobName.materialConfig is present, if not looks for +!> material.config +!-------------------------------------------------------------------------------------------------- +subroutine material_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_error, & + IO_open_file, & + IO_open_jobFile_stat, & + IO_timeStamp + use debug, only: & + debug_level, & + debug_material, & + debug_levelBasic, & + debug_levelExtensive + use mesh, only: & + mesh_maxNips, & + mesh_NcpElems, & + mesh_element, & + FE_Nips, & + FE_geomtype + use numerics, only: & + worldrank + + implicit none + integer(pInt), parameter :: FILEUNIT = 200_pInt + integer(pInt) :: m,c,h, myDebug, myPhase, myHomog + integer(pInt) :: & + g, & !< grain number + i, & !< integration point number + e, & !< element number + phase + integer(pInt), dimension(:), allocatable :: ConstitutivePosition + integer(pInt), dimension(:), allocatable :: CrystallitePosition + integer(pInt), dimension(:), allocatable :: HomogenizationPosition + + myDebug = debug_level(debug_material) + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- material init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + if (.not. IO_open_jobFile_stat(FILEUNIT,material_localFileExt)) & ! no local material configuration present... + call IO_open_file(FILEUNIT,material_configFile) ! ...open material.config file + call material_parseHomogenization(FILEUNIT,material_partHomogenization) + if (iand(myDebug,debug_levelBasic) /= 0_pInt) write(6,'(a)') ' Homogenization parsed'; flush(6) + call material_parseMicrostructure(FILEUNIT,material_partMicrostructure) + if (iand(myDebug,debug_levelBasic) /= 0_pInt) write(6,'(a)') ' Microstructure parsed'; flush(6) + call material_parseCrystallite(FILEUNIT,material_partCrystallite) + if (iand(myDebug,debug_levelBasic) /= 0_pInt) write(6,'(a)') ' Crystallite parsed'; flush(6) + call material_parseTexture(FILEUNIT,material_partTexture) + if (iand(myDebug,debug_levelBasic) /= 0_pInt) write(6,'(a)') ' Texture parsed'; flush(6) + call material_parsePhase(FILEUNIT,material_partPhase) + if (iand(myDebug,debug_levelBasic) /= 0_pInt) write(6,'(a)') ' Phase parsed'; flush(6) + close(FILEUNIT) + + allocate(plasticState (material_Nphase)) + allocate(sourceState (material_Nphase)) + do myPhase = 1,material_Nphase + allocate(sourceState(myPhase)%p(phase_Nsources(myPhase))) + enddo + + allocate(homogState (material_Nhomogenization)) + allocate(thermalState (material_Nhomogenization)) + allocate(damageState (material_Nhomogenization)) + allocate(vacancyfluxState (material_Nhomogenization)) + allocate(porosityState (material_Nhomogenization)) + allocate(hydrogenfluxState (material_Nhomogenization)) + + allocate(thermalMapping (material_Nhomogenization)) + allocate(damageMapping (material_Nhomogenization)) + allocate(vacancyfluxMapping (material_Nhomogenization)) + allocate(porosityMapping (material_Nhomogenization)) + allocate(hydrogenfluxMapping(material_Nhomogenization)) + + allocate(temperature (material_Nhomogenization)) + allocate(damage (material_Nhomogenization)) + allocate(vacancyConc (material_Nhomogenization)) + allocate(porosity (material_Nhomogenization)) + allocate(hydrogenConc (material_Nhomogenization)) + + allocate(temperatureRate (material_Nhomogenization)) + allocate(vacancyConcRate (material_Nhomogenization)) + allocate(hydrogenConcRate (material_Nhomogenization)) + + do m = 1_pInt,material_Nmicrostructure + if(microstructure_crystallite(m) < 1_pInt .or. & + microstructure_crystallite(m) > material_Ncrystallite) & + call IO_error(150_pInt,m,ext_msg='crystallite') + if(minval(microstructure_phase(1:microstructure_Nconstituents(m),m)) < 1_pInt .or. & + maxval(microstructure_phase(1:microstructure_Nconstituents(m),m)) > material_Nphase) & + call IO_error(150_pInt,m,ext_msg='phase') + if(minval(microstructure_texture(1:microstructure_Nconstituents(m),m)) < 1_pInt .or. & + maxval(microstructure_texture(1:microstructure_Nconstituents(m),m)) > material_Ntexture) & + call IO_error(150_pInt,m,ext_msg='texture') + if(microstructure_Nconstituents(m) < 1_pInt) & + call IO_error(151_pInt,m) + enddo + + debugOut: if (iand(myDebug,debug_levelExtensive) /= 0_pInt) then + write(6,'(/,a,/)') ' MATERIAL configuration' + write(6,'(a32,1x,a16,1x,a6)') 'homogenization ','type ','grains' + do h = 1_pInt,material_Nhomogenization + write(6,'(1x,a32,1x,a16,1x,i6)') homogenization_name(h),homogenization_type(h),homogenization_Ngrains(h) + enddo + write(6,'(/,a14,18x,1x,a11,1x,a12,1x,a13)') 'microstructure','crystallite','constituents','homogeneous' + do m = 1_pInt,material_Nmicrostructure + write(6,'(1x,a32,1x,i11,1x,i12,1x,l13)') microstructure_name(m), & + microstructure_crystallite(m), & + microstructure_Nconstituents(m), & + microstructure_elemhomo(m) + if (microstructure_Nconstituents(m) > 0_pInt) then + do c = 1_pInt,microstructure_Nconstituents(m) + write(6,'(a1,1x,a32,1x,a32,1x,f7.4)') '>',phase_name(microstructure_phase(c,m)),& + texture_name(microstructure_texture(c,m)),& + microstructure_fraction(c,m) + enddo + write(6,*) + endif + enddo + endif debugOut + + call material_populateGrains + + allocate(phaseAt ( homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems),source=0_pInt) + allocate(phasememberAt ( homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems),source=0_pInt) + allocate(mappingHomogenization (2, mesh_maxNips,mesh_NcpElems),source=0_pInt) + allocate(mappingCrystallite (2,homogenization_maxNgrains, mesh_NcpElems),source=0_pInt) + allocate(mappingHomogenizationConst( mesh_maxNips,mesh_NcpElems),source=1_pInt) + + allocate(ConstitutivePosition (material_Nphase), source=0_pInt) + allocate(HomogenizationPosition(material_Nhomogenization),source=0_pInt) + allocate(CrystallitePosition (material_Nphase), source=0_pInt) + + ElemLoop:do e = 1_pInt,mesh_NcpElems ! loop over elements + myHomog = mesh_element(3,e) + IPloop:do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) ! loop over IPs + HomogenizationPosition(myHomog) = HomogenizationPosition(myHomog) + 1_pInt + mappingHomogenization(1:2,i,e) = [HomogenizationPosition(myHomog),myHomog] + GrainLoop:do g = 1_pInt,homogenization_Ngrains(mesh_element(3,e)) ! loop over grains + phase = material_phase(g,i,e) + ConstitutivePosition(phase) = ConstitutivePosition(phase)+1_pInt ! not distinguishing between instances of same phase + phaseAt(g,i,e) = phase + phasememberAt(g,i,e) = ConstitutivePosition(phase) + enddo GrainLoop + enddo IPloop + enddo ElemLoop + +! hack needed to initialize field values used during constitutive and crystallite initializations + do myHomog = 1,material_Nhomogenization + thermalMapping (myHomog)%p => mappingHomogenizationConst + damageMapping (myHomog)%p => mappingHomogenizationConst + vacancyfluxMapping (myHomog)%p => mappingHomogenizationConst + porosityMapping (myHomog)%p => mappingHomogenizationConst + hydrogenfluxMapping(myHomog)%p => mappingHomogenizationConst + allocate(temperature (myHomog)%p(1), source=thermal_initialT(myHomog)) + allocate(damage (myHomog)%p(1), source=damage_initialPhi(myHomog)) + allocate(vacancyConc (myHomog)%p(1), source=vacancyflux_initialCv(myHomog)) + allocate(porosity (myHomog)%p(1), source=porosity_initialPhi(myHomog)) + allocate(hydrogenConc (myHomog)%p(1), source=hydrogenflux_initialCh(myHomog)) + allocate(temperatureRate (myHomog)%p(1), source=0.0_pReal) + allocate(vacancyConcRate (myHomog)%p(1), source=0.0_pReal) + allocate(hydrogenConcRate(myHomog)%p(1), source=0.0_pReal) + enddo + +end subroutine material_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief parses the homogenization part in the material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine material_parseHomogenization(fileUnit,myPart) + use IO, only: & + IO_read, & + IO_globalTagInPart, & + IO_countSections, & + IO_error, & + IO_countTagInPart, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringValue, & + IO_intValue, & + IO_floatValue, & + IO_stringPos, & + IO_EOF + use mesh, only: & + mesh_element + + implicit none + character(len=*), intent(in) :: myPart + integer(pInt), intent(in) :: fileUnit + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: Nsections, section, s, p + character(len=65536) :: & + tag, line + logical :: echo + + echo = IO_globalTagInPart(fileUnit,myPart,'/echo/') + Nsections = IO_countSections(fileUnit,myPart) + material_Nhomogenization = Nsections + if (Nsections < 1_pInt) call IO_error(160_pInt,ext_msg=myPart) + + allocate(homogenization_name(Nsections)); homogenization_name = '' + allocate(homogenization_type(Nsections), source=HOMOGENIZATION_undefined_ID) + allocate(thermal_type(Nsections), source=THERMAL_isothermal_ID) + allocate(damage_type (Nsections), source=DAMAGE_none_ID) + allocate(vacancyflux_type(Nsections), source=VACANCYFLUX_isoconc_ID) + allocate(porosity_type (Nsections), source=POROSITY_none_ID) + allocate(hydrogenflux_type(Nsections), source=HYDROGENFLUX_isoconc_ID) + allocate(homogenization_typeInstance(Nsections), source=0_pInt) + allocate(thermal_typeInstance(Nsections), source=0_pInt) + allocate(damage_typeInstance(Nsections), source=0_pInt) + allocate(vacancyflux_typeInstance(Nsections), source=0_pInt) + allocate(porosity_typeInstance(Nsections), source=0_pInt) + allocate(hydrogenflux_typeInstance(Nsections), source=0_pInt) + allocate(homogenization_Ngrains(Nsections), source=0_pInt) + allocate(homogenization_Noutput(Nsections), source=0_pInt) + allocate(homogenization_active(Nsections), source=.false.) !!!!!!!!!!!!!!! + allocate(thermal_initialT(Nsections), source=300.0_pReal) + allocate(damage_initialPhi(Nsections), source=1.0_pReal) + allocate(vacancyflux_initialCv(Nsections), source=0.0_pReal) + allocate(porosity_initialPhi(Nsections), source=1.0_pReal) + allocate(hydrogenflux_initialCh(Nsections), source=0.0_pReal) + + forall (s = 1_pInt:Nsections) homogenization_active(s) = any(mesh_element(3,:) == s) ! current homogenization used in model? Homogenization view, maximum operations depend on maximum number of homog schemes + homogenization_Noutput = IO_countTagInPart(fileUnit,myPart,'(output)',Nsections) + + rewind(fileUnit) + line = '' ! to have it initialized + section = 0_pInt ! - " - + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= myPart) ! wind forward to + line = IO_read(fileUnit) + enddo + if (echo) write(6,'(/,1x,a)') trim(line) ! echo part header + + do while (trim(line) /= IO_EOF) ! read through sections of material part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (echo) write(6,'(2x,a)') trim(line) ! echo back read lines + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + homogenization_name(section) = IO_getTag(line,'[',']') + endif + if (section > 0_pInt) then + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('type') + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case(HOMOGENIZATION_NONE_label) + homogenization_type(section) = HOMOGENIZATION_NONE_ID + homogenization_Ngrains(section) = 1_pInt + case(HOMOGENIZATION_ISOSTRAIN_label) + homogenization_type(section) = HOMOGENIZATION_ISOSTRAIN_ID + case(HOMOGENIZATION_RGC_label) + homogenization_type(section) = HOMOGENIZATION_RGC_ID + case default + call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) + end select + homogenization_typeInstance(section) = & + count(homogenization_type==homogenization_type(section)) ! count instances + case ('thermal') + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case(THERMAL_isothermal_label) + thermal_type(section) = THERMAL_isothermal_ID + case(THERMAL_adiabatic_label) + thermal_type(section) = THERMAL_adiabatic_ID + case(THERMAL_conduction_label) + thermal_type(section) = THERMAL_conduction_ID + case default + call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) + end select + + case ('damage') + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case(DAMAGE_NONE_label) + damage_type(section) = DAMAGE_none_ID + case(DAMAGE_LOCAL_label) + damage_type(section) = DAMAGE_local_ID + case(DAMAGE_NONLOCAL_label) + damage_type(section) = DAMAGE_nonlocal_ID + case default + call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) + end select + + case ('vacancyflux') + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case(VACANCYFLUX_isoconc_label) + vacancyflux_type(section) = VACANCYFLUX_isoconc_ID + case(VACANCYFLUX_isochempot_label) + vacancyflux_type(section) = VACANCYFLUX_isochempot_ID + case(VACANCYFLUX_cahnhilliard_label) + vacancyflux_type(section) = VACANCYFLUX_cahnhilliard_ID + case default + call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) + end select + + case ('porosity') + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case(POROSITY_NONE_label) + porosity_type(section) = POROSITY_none_ID + case(POROSITY_phasefield_label) + porosity_type(section) = POROSITY_phasefield_ID + case default + call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) + end select + + case ('hydrogenflux') + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case(HYDROGENFLUX_isoconc_label) + hydrogenflux_type(section) = HYDROGENFLUX_isoconc_ID + case(HYDROGENFLUX_cahnhilliard_label) + hydrogenflux_type(section) = HYDROGENFLUX_cahnhilliard_ID + case default + call IO_error(500_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) + end select + + case ('nconstituents','ngrains') + homogenization_Ngrains(section) = IO_intValue(line,chunkPos,2_pInt) + + case ('initialtemperature','initialt') + thermal_initialT(section) = IO_floatValue(line,chunkPos,2_pInt) + + case ('initialdamage') + damage_initialPhi(section) = IO_floatValue(line,chunkPos,2_pInt) + + case ('initialvacancyconc','initialcv') + vacancyflux_initialCv(section) = IO_floatValue(line,chunkPos,2_pInt) + + case ('initialporosity') + porosity_initialPhi(section) = IO_floatValue(line,chunkPos,2_pInt) + + case ('initialhydrogenconc','initialch') + hydrogenflux_initialCh(section) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif + enddo + + do p=1_pInt, Nsections + homogenization_typeInstance(p) = count(homogenization_type(1:p) == homogenization_type(p)) + thermal_typeInstance(p) = count(thermal_type (1:p) == thermal_type (p)) + damage_typeInstance(p) = count(damage_type (1:p) == damage_type (p)) + vacancyflux_typeInstance(p) = count(vacancyflux_type (1:p) == vacancyflux_type (p)) + porosity_typeInstance(p) = count(porosity_type (1:p) == porosity_type (p)) + hydrogenflux_typeInstance(p) = count(hydrogenflux_type (1:p) == hydrogenflux_type (p)) + enddo + + homogenization_maxNgrains = maxval(homogenization_Ngrains,homogenization_active) + +end subroutine material_parseHomogenization + + +!-------------------------------------------------------------------------------------------------- +!> @brief parses the microstructure part in the material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine material_parseMicrostructure(fileUnit,myPart) + use IO + use mesh, only: & + mesh_element, & + mesh_NcpElems + + implicit none + character(len=*), intent(in) :: myPart + integer(pInt), intent(in) :: fileUnit + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: Nsections, section, constituent, e, i + character(len=65536) :: & + tag, line + logical :: echo + + echo = IO_globalTagInPart(fileUnit,myPart,'/echo/') + + Nsections = IO_countSections(fileUnit,myPart) + material_Nmicrostructure = Nsections + if (Nsections < 1_pInt) call IO_error(160_pInt,ext_msg=myPart) + + allocate(microstructure_name(Nsections)); microstructure_name = '' + allocate(microstructure_crystallite(Nsections), source=0_pInt) + allocate(microstructure_Nconstituents(Nsections), source=0_pInt) + allocate(microstructure_active(Nsections), source=.false.) + allocate(microstructure_elemhomo(Nsections), source=.false.) + + if(any(mesh_element(4,1:mesh_NcpElems) > Nsections)) & + call IO_error(155_pInt,ext_msg='Microstructure in geometry > Sections in material.config') + + forall (e = 1_pInt:mesh_NcpElems) microstructure_active(mesh_element(4,e)) = .true. ! current microstructure used in model? Elementwise view, maximum N operations for N elements + + microstructure_Nconstituents = IO_countTagInPart(fileUnit,myPart,'(constituent)',Nsections) + microstructure_maxNconstituents = maxval(microstructure_Nconstituents) + microstructure_elemhomo = IO_spotTagInPart(fileUnit,myPart,'/elementhomogeneous/',Nsections) + + allocate(microstructure_phase (microstructure_maxNconstituents,Nsections),source=0_pInt) + allocate(microstructure_texture (microstructure_maxNconstituents,Nsections),source=0_pInt) + allocate(microstructure_fraction(microstructure_maxNconstituents,Nsections),source=0.0_pReal) + + rewind(fileUnit) + line = '' ! to have it initialized + section = 0_pInt ! - " - + constituent = 0_pInt ! - " - + + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= myPart) ! wind forward to + line = IO_read(fileUnit) + enddo + if (echo) write(6,'(/,1x,a)') trim(line) ! echo part header + + do while (trim(line) /= IO_EOF) ! read through sections of material part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (echo) write(6,'(2x,a)') trim(line) ! echo back read lines + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + constituent = 0_pInt + microstructure_name(section) = IO_getTag(line,'[',']') + endif + if (section > 0_pInt) then + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('crystallite') + microstructure_crystallite(section) = IO_intValue(line,chunkPos,2_pInt) + case ('(constituent)') + constituent = constituent + 1_pInt + do i=2_pInt,6_pInt,2_pInt + tag = IO_lc(IO_stringValue(line,chunkPos,i)) + select case (tag) + case('phase') + microstructure_phase(constituent,section) = IO_intValue(line,chunkPos,i+1_pInt) + case('texture') + microstructure_texture(constituent,section) = IO_intValue(line,chunkPos,i+1_pInt) + case('fraction') + microstructure_fraction(constituent,section) = IO_floatValue(line,chunkPos,i+1_pInt) + end select + enddo + end select + endif + enddo + +end subroutine material_parseMicrostructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief parses the crystallite part in the material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine material_parseCrystallite(fileUnit,myPart) + use IO, only: & + IO_read, & + IO_countSections, & + IO_error, & + IO_countTagInPart, & + IO_globalTagInPart, & + IO_getTag, & + IO_lc, & + IO_isBlank, & + IO_EOF + + implicit none + character(len=*), intent(in) :: myPart + integer(pInt), intent(in) :: fileUnit + + integer(pInt) :: Nsections, & + section + character(len=65536) :: line + logical :: echo + + echo = IO_globalTagInPart(fileUnit,myPart,'/echo/') + + Nsections = IO_countSections(fileUnit,myPart) + material_Ncrystallite = Nsections + if (Nsections < 1_pInt) call IO_error(160_pInt,ext_msg=myPart) + + allocate(crystallite_name(Nsections)); crystallite_name = '' + allocate(crystallite_Noutput(Nsections), source=0_pInt) + + crystallite_Noutput = IO_countTagInPart(fileUnit,myPart,'(output)',Nsections) + + rewind(fileUnit) + line = '' ! to have it initialized + section = 0_pInt ! - " - + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= myPart) ! wind forward to + line = IO_read(fileUnit) + enddo + if (echo) write(6,'(/,1x,a)') trim(line) ! echo part header + + do while (trim(line) /= IO_EOF) ! read through sections of material part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (echo) write(6,'(2x,a)') trim(line) ! echo back read lines + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + crystallite_name(section) = IO_getTag(line,'[',']') + endif + enddo + +end subroutine material_parseCrystallite + + +!-------------------------------------------------------------------------------------------------- +!> @brief parses the phase part in the material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine material_parsePhase(fileUnit,myPart) + use IO, only: & + IO_read, & + IO_globalTagInPart, & + IO_countSections, & + IO_error, & + IO_countTagInPart, & + IO_getTag, & + IO_spotTagInPart, & + IO_lc, & + IO_isBlank, & + IO_stringValue, & + IO_stringPos, & + IO_EOF + + implicit none + character(len=*), intent(in) :: myPart + integer(pInt), intent(in) :: fileUnit + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: Nsections, section, sourceCtr, kinematicsCtr, stiffDegradationCtr, p + character(len=65536) :: & + tag,line + logical :: echo + + echo = IO_globalTagInPart(fileUnit,myPart,'/echo/') + + Nsections = IO_countSections(fileUnit,myPart) + material_Nphase = Nsections + if (Nsections < 1_pInt) call IO_error(160_pInt,ext_msg=myPart) + + allocate(phase_name(Nsections)); phase_name = '' + allocate(phase_elasticity(Nsections), source=ELASTICITY_undefined_ID) + allocate(phase_elasticityInstance(Nsections), source=0_pInt) + allocate(phase_plasticity(Nsections) , source=PLASTICITY_undefined_ID) + allocate(phase_plasticityInstance(Nsections), source=0_pInt) + allocate(phase_Nsources(Nsections), source=0_pInt) + allocate(phase_Nkinematics(Nsections), source=0_pInt) + allocate(phase_NstiffnessDegradations(Nsections),source=0_pInt) + allocate(phase_Noutput(Nsections), source=0_pInt) + allocate(phase_localPlasticity(Nsections), source=.false.) + + phase_Noutput = IO_countTagInPart(fileUnit,myPart,'(output)',Nsections) + phase_Nsources = IO_countTagInPart(fileUnit,myPart,'(source)',Nsections) + phase_Nkinematics = IO_countTagInPart(fileUnit,myPart,'(kinematics)',Nsections) + phase_NstiffnessDegradations = IO_countTagInPart(fileUnit,myPart,'(stiffness_degradation)',Nsections) + phase_localPlasticity = .not. IO_spotTagInPart(fileUnit,myPart,'/nonlocal/',Nsections) + + allocate(phase_source(maxval(phase_Nsources),Nsections), source=SOURCE_undefined_ID) + allocate(phase_kinematics(maxval(phase_Nkinematics),Nsections), source=KINEMATICS_undefined_ID) + allocate(phase_stiffnessDegradation(maxval(phase_NstiffnessDegradations),Nsections), & + source=STIFFNESS_DEGRADATION_undefined_ID) + + rewind(fileUnit) + line = '' ! to have it initialized + section = 0_pInt ! - " - + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= myPart) ! wind forward to + line = IO_read(fileUnit) + enddo + if (echo) write(6,'(/,1x,a)') trim(line) ! echo part header + + do while (trim(line) /= IO_EOF) ! read through sections of material part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (echo) write(6,'(2x,a)') trim(line) ! echo back read lines + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + sourceCtr = 0_pInt + kinematicsCtr = 0_pInt + stiffDegradationCtr = 0_pInt + phase_name(section) = IO_getTag(line,'[',']') + endif + if (section > 0_pInt) then + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('elasticity') + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case (ELASTICITY_HOOKE_label) + phase_elasticity(section) = ELASTICITY_HOOKE_ID + case default + call IO_error(200_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) + end select + case ('plasticity') + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case (PLASTICITY_NONE_label) + phase_plasticity(section) = PLASTICITY_NONE_ID + case (PLASTICITY_ISOTROPIC_label) + phase_plasticity(section) = PLASTICITY_ISOTROPIC_ID + case (PLASTICITY_J2_label) + phase_plasticity(section) = PLASTICITY_J2_ID + case (PLASTICITY_PHENOPOWERLAW_label) + phase_plasticity(section) = PLASTICITY_PHENOPOWERLAW_ID + case (PLASTICITY_PHENOPLUS_label) + phase_plasticity(section) = PLASTICITY_PHENOPLUS_ID + case (PLASTICITY_DISLOTWIN_label) + phase_plasticity(section) = PLASTICITY_DISLOTWIN_ID + case (PLASTICITY_DISLOUCLA_label) + phase_plasticity(section) = PLASTICITY_DISLOUCLA_ID + case (PLASTICITY_TITANMOD_label) + phase_plasticity(section) = PLASTICITY_TITANMOD_ID + case (PLASTICITY_NONLOCAL_label) + phase_plasticity(section) = PLASTICITY_NONLOCAL_ID + case default + call IO_error(201_pInt,ext_msg=trim(IO_stringValue(line,chunkPos,2_pInt))) + end select + case ('(source)') + sourceCtr = sourceCtr + 1_pInt + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case (SOURCE_thermal_dissipation_label) + phase_source(sourceCtr,section) = SOURCE_thermal_dissipation_ID + case (SOURCE_thermal_externalheat_label) + phase_source(sourceCtr,section) = SOURCE_thermal_externalheat_ID + case (SOURCE_damage_isoBrittle_label) + phase_source(sourceCtr,section) = SOURCE_damage_isoBrittle_ID + case (SOURCE_damage_isoDuctile_label) + phase_source(sourceCtr,section) = SOURCE_damage_isoDuctile_ID + case (SOURCE_damage_anisoBrittle_label) + phase_source(sourceCtr,section) = SOURCE_damage_anisoBrittle_ID + case (SOURCE_damage_anisoDuctile_label) + phase_source(sourceCtr,section) = SOURCE_damage_anisoDuctile_ID + case (SOURCE_vacancy_phenoplasticity_label) + phase_source(sourceCtr,section) = SOURCE_vacancy_phenoplasticity_ID + case (SOURCE_vacancy_irradiation_label) + phase_source(sourceCtr,section) = SOURCE_vacancy_irradiation_ID + case (SOURCE_vacancy_thermalfluc_label) + phase_source(sourceCtr,section) = SOURCE_vacancy_thermalfluc_ID + end select + case ('(kinematics)') + kinematicsCtr = kinematicsCtr + 1_pInt + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case (KINEMATICS_cleavage_opening_label) + phase_kinematics(kinematicsCtr,section) = KINEMATICS_cleavage_opening_ID + case (KINEMATICS_slipplane_opening_label) + phase_kinematics(kinematicsCtr,section) = KINEMATICS_slipplane_opening_ID + case (KINEMATICS_thermal_expansion_label) + phase_kinematics(kinematicsCtr,section) = KINEMATICS_thermal_expansion_ID + case (KINEMATICS_vacancy_strain_label) + phase_kinematics(kinematicsCtr,section) = KINEMATICS_vacancy_strain_ID + case (KINEMATICS_hydrogen_strain_label) + phase_kinematics(kinematicsCtr,section) = KINEMATICS_hydrogen_strain_ID + end select + case ('(stiffness_degradation)') + stiffDegradationCtr = stiffDegradationCtr + 1_pInt + select case (IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case (STIFFNESS_DEGRADATION_damage_label) + phase_stiffnessDegradation(stiffDegradationCtr,section) = STIFFNESS_DEGRADATION_damage_ID + case (STIFFNESS_DEGRADATION_porosity_label) + phase_stiffnessDegradation(stiffDegradationCtr,section) = STIFFNESS_DEGRADATION_porosity_ID + end select + + end select + endif + enddo + + do p=1_pInt, Nsections + phase_elasticityInstance(p) = count(phase_elasticity(1:p) == phase_elasticity(p)) + phase_plasticityInstance(p) = count(phase_plasticity(1:p) == phase_plasticity(p)) + enddo + +end subroutine material_parsePhase + +!-------------------------------------------------------------------------------------------------- +!> @brief parses the texture part in the material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine material_parseTexture(fileUnit,myPart) + use IO, only: & + IO_read, & + IO_globalTagInPart, & + IO_countSections, & + IO_error, & + IO_countTagInPart, & + IO_getTag, & + IO_spotTagInPart, & + IO_lc, & + IO_isBlank, & + IO_floatValue, & + IO_stringValue, & + IO_stringPos, & + IO_EOF + use math, only: & + inRad, & + math_sampleRandomOri, & + math_I3, & + math_inv33 + + implicit none + character(len=*), intent(in) :: myPart + integer(pInt), intent(in) :: fileUnit + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: Nsections, section, gauss, fiber, j + character(len=65536) :: tag + character(len=65536) :: line + logical :: echo + + echo = IO_globalTagInPart(fileUnit,myPart,'/echo/') + + Nsections = IO_countSections(fileUnit,myPart) + material_Ntexture = Nsections + if (Nsections < 1_pInt) call IO_error(160_pInt,ext_msg=myPart) + + allocate(texture_name(Nsections)); texture_name='' + allocate(texture_ODFfile(Nsections)); texture_ODFfile='' + allocate(texture_symmetry(Nsections), source=1_pInt) + allocate(texture_Ngauss(Nsections), source=0_pInt) + allocate(texture_Nfiber(Nsections), source=0_pInt) + + texture_Ngauss = IO_countTagInPart(fileUnit,myPart,'(gauss)', Nsections) + & + IO_countTagInPart(fileUnit,myPart,'(random)',Nsections) + texture_Nfiber = IO_countTagInPart(fileUnit,myPart,'(fiber)', Nsections) + texture_maxNgauss = maxval(texture_Ngauss) + texture_maxNfiber = maxval(texture_Nfiber) + allocate(texture_Gauss (5,texture_maxNgauss,Nsections), source=0.0_pReal) + allocate(texture_Fiber (6,texture_maxNfiber,Nsections), source=0.0_pReal) + allocate(texture_transformation(3,3,Nsections), source=0.0_pReal) + texture_transformation = spread(math_I3,3,Nsections) + + rewind(fileUnit) + line = '' ! to have in initialized + section = 0_pInt ! - " - + gauss = 0_pInt ! - " - + fiber = 0_pInt ! - " - + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= myPart) ! wind forward to + line = IO_read(fileUnit) + enddo + if (echo) write(6,'(/,1x,a)') trim(line) ! echo part header + + do while (trim(line) /= IO_EOF) + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (echo) write(6,'(2x,a)') trim(line) ! echo back read lines + if (IO_getTag(line,'[',']') /= '') then ! next section + section = section + 1_pInt + gauss = 0_pInt + fiber = 0_pInt + texture_name(section) = IO_getTag(line,'[',']') + endif + if (section > 0_pInt) then + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + textureType: select case(tag) + + case ('axes', 'rotation') textureType + do j = 1_pInt, 3_pInt ! look for "x", "y", and "z" entries + tag = IO_lc(IO_stringValue(line,chunkPos,j+1_pInt)) + select case (tag) + case('x', '+x') + texture_transformation(j,1:3,section) = [ 1.0_pReal, 0.0_pReal, 0.0_pReal] ! original axis is now +x-axis + case('-x') + texture_transformation(j,1:3,section) = [-1.0_pReal, 0.0_pReal, 0.0_pReal] ! original axis is now -x-axis + case('y', '+y') + texture_transformation(j,1:3,section) = [ 0.0_pReal, 1.0_pReal, 0.0_pReal] ! original axis is now +y-axis + case('-y') + texture_transformation(j,1:3,section) = [ 0.0_pReal,-1.0_pReal, 0.0_pReal] ! original axis is now -y-axis + case('z', '+z') + texture_transformation(j,1:3,section) = [ 0.0_pReal, 0.0_pReal, 1.0_pReal] ! original axis is now +z-axis + case('-z') + texture_transformation(j,1:3,section) = [ 0.0_pReal, 0.0_pReal,-1.0_pReal] ! original axis is now -z-axis + case default + call IO_error(157_pInt,section) + end select + enddo + + case ('hybridia') textureType + texture_ODFfile(section) = IO_stringValue(line,chunkPos,2_pInt) + + case ('symmetry') textureType + tag = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + select case (tag) + case('orthotropic') + texture_symmetry(section) = 4_pInt + case('monoclinic') + texture_symmetry(section) = 2_pInt + case default + texture_symmetry(section) = 1_pInt + end select + + case ('(random)') textureType + gauss = gauss + 1_pInt + texture_Gauss(1:3,gauss,section) = math_sampleRandomOri() + do j = 2_pInt,4_pInt,2_pInt + tag = IO_lc(IO_stringValue(line,chunkPos,j)) + select case (tag) + case('scatter') + texture_Gauss(4,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad + case('fraction') + texture_Gauss(5,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt) + end select + enddo + + case ('(gauss)') textureType + gauss = gauss + 1_pInt + do j = 2_pInt,10_pInt,2_pInt + tag = IO_lc(IO_stringValue(line,chunkPos,j)) + select case (tag) + case('phi1') + texture_Gauss(1,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad + case('phi') + texture_Gauss(2,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad + case('phi2') + texture_Gauss(3,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad + case('scatter') + texture_Gauss(4,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad + case('fraction') + texture_Gauss(5,gauss,section) = IO_floatValue(line,chunkPos,j+1_pInt) + end select + enddo + + case ('(fiber)') textureType + fiber = fiber + 1_pInt + do j = 2_pInt,12_pInt,2_pInt + tag = IO_lc(IO_stringValue(line,chunkPos,j)) + select case (tag) + case('alpha1') + texture_Fiber(1,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad + case('alpha2') + texture_Fiber(2,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad + case('beta1') + texture_Fiber(3,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad + case('beta2') + texture_Fiber(4,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad + case('scatter') + texture_Fiber(5,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt)*inRad + case('fraction') + texture_Fiber(6,fiber,section) = IO_floatValue(line,chunkPos,j+1_pInt) + end select + enddo + + end select textureType + endif + enddo + +end subroutine material_parseTexture + + +!-------------------------------------------------------------------------------------------------- +!> @brief populates the grains +!> @details populates the grains by identifying active microstructure/homogenization pairs, +!! calculates the volume of the grains and deals with texture components and hybridIA +!-------------------------------------------------------------------------------------------------- +subroutine material_populateGrains + use math, only: & + math_RtoEuler, & + math_EulerToR, & + math_mul33x33, & + math_range, & + math_sampleRandomOri, & + math_sampleGaussOri, & + math_sampleFiberOri, & + math_symmetricEulers + use mesh, only: & + mesh_element, & + mesh_maxNips, & + mesh_NcpElems, & + mesh_ipVolume, & + FE_Nips, & + FE_geomtype + use IO, only: & + IO_error, & + IO_hybridIA + use debug, only: & + debug_level, & + debug_material, & + debug_levelBasic + + implicit none + integer(pInt), dimension (:,:), allocatable :: Ngrains + integer(pInt), dimension (microstructure_maxNconstituents) :: & + NgrainsOfConstituent, & + currentGrainOfConstituent, & + randomOrder + real(pReal), dimension (microstructure_maxNconstituents) :: & + rndArray + real(pReal), dimension (:), allocatable :: volumeOfGrain + real(pReal), dimension (:,:), allocatable :: orientationOfGrain + real(pReal), dimension (3) :: orientation + real(pReal), dimension (3,3) :: symOrientation + integer(pInt), dimension (:), allocatable :: phaseOfGrain, textureOfGrain + integer(pInt) :: t,e,i,g,j,m,c,r,homog,micro,sgn,hme, myDebug, & + phaseID,textureID,dGrains,myNgrains,myNorientations,myNconstituents, & + grain,constituentGrain,ipGrain,symExtension, ip + real(pReal) :: extreme,rnd + integer(pInt), dimension (:,:), allocatable :: Nelems ! counts number of elements in homog, micro array + type(p_intvec), dimension (:,:), allocatable :: elemsOfHomogMicro ! lists element number in homog, micro array + + myDebug = debug_level(debug_material) + + allocate(material_volume(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(material_phase(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source=0_pInt) + allocate(material_homog(mesh_maxNips,mesh_NcpElems), source=0_pInt) + allocate(material_texture(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), source=0_pInt) + allocate(material_EulerAngles(3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems),source=0.0_pReal) + + allocate(Ngrains(material_Nhomogenization,material_Nmicrostructure), source=0_pInt) + allocate(Nelems(material_Nhomogenization,material_Nmicrostructure), source=0_pInt) + +! populating homogenization schemes in each +!-------------------------------------------------------------------------------------------------- + do e = 1_pInt, mesh_NcpElems + material_homog(1_pInt:FE_Nips(FE_geomtype(mesh_element(2,e))),e) = mesh_element(3,e) + enddo + +!-------------------------------------------------------------------------------------------------- +! precounting of elements for each homog/micro pair + do e = 1_pInt, mesh_NcpElems + homog = mesh_element(3,e) + micro = mesh_element(4,e) + Nelems(homog,micro) = Nelems(homog,micro) + 1_pInt + enddo + allocate(elemsOfHomogMicro(material_Nhomogenization,material_Nmicrostructure)) + do homog = 1,material_Nhomogenization + do micro = 1,material_Nmicrostructure + if (Nelems(homog,micro) > 0_pInt) then + allocate(elemsOfHomogMicro(homog,micro)%p(Nelems(homog,micro))) + elemsOfHomogMicro(homog,micro)%p = 0_pInt + endif + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! identify maximum grain count per IP (from element) and find grains per homog/micro pair + Nelems = 0_pInt ! reuse as counter + elementLooping: do e = 1_pInt,mesh_NcpElems + t = FE_geomtype(mesh_element(2,e)) + homog = mesh_element(3,e) + micro = mesh_element(4,e) + if (homog < 1_pInt .or. homog > material_Nhomogenization) & ! out of bounds + call IO_error(154_pInt,e,0_pInt,0_pInt) + if (micro < 1_pInt .or. micro > material_Nmicrostructure) & ! out of bounds + call IO_error(155_pInt,e,0_pInt,0_pInt) + if (microstructure_elemhomo(micro)) then ! how many grains are needed at this element? + dGrains = homogenization_Ngrains(homog) ! only one set of Ngrains (other IPs are plain copies) + else + dGrains = homogenization_Ngrains(homog) * FE_Nips(t) ! each IP has Ngrains + endif + Ngrains(homog,micro) = Ngrains(homog,micro) + dGrains ! total grain count + Nelems(homog,micro) = Nelems(homog,micro) + 1_pInt ! total element count + elemsOfHomogMicro(homog,micro)%p(Nelems(homog,micro)) = e ! remember elements active in this homog/micro pair + enddo elementLooping + + allocate(volumeOfGrain(maxval(Ngrains)), source=0.0_pReal) ! reserve memory for maximum case + allocate(phaseOfGrain(maxval(Ngrains)), source=0_pInt) ! reserve memory for maximum case + allocate(textureOfGrain(maxval(Ngrains)), source=0_pInt) ! reserve memory for maximum case + allocate(orientationOfGrain(3,maxval(Ngrains)),source=0.0_pReal) ! reserve memory for maximum case + + if (iand(myDebug,debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(/,a/)') ' MATERIAL grain population' + write(6,'(a32,1x,a32,1x,a6)') 'homogenization_name','microstructure_name','grain#' + !$OMP END CRITICAL (write2out) + endif + do homog = 1_pInt,material_Nhomogenization ! loop over homogenizations + dGrains = homogenization_Ngrains(homog) ! grain number per material point + do micro = 1_pInt,material_Nmicrostructure ! all pairs of homog and micro + if (Ngrains(homog,micro) > 0_pInt) then ! an active pair of homog and micro + myNgrains = Ngrains(homog,micro) ! assign short name for total number of grains to populate + myNconstituents = microstructure_Nconstituents(micro) ! assign short name for number of constituents + if (iand(myDebug,debug_levelBasic) /= 0_pInt) then + !$OMP CRITICAL (write2out) + write(6,'(/,a32,1x,a32,1x,i6)') homogenization_name(homog),microstructure_name(micro),myNgrains + !$OMP END CRITICAL (write2out) + endif + + +!-------------------------------------------------------------------------------------------------- +! calculate volume of each grain + + volumeOfGrain = 0.0_pReal + grain = 0_pInt + + do hme = 1_pInt, Nelems(homog,micro) + e = elemsOfHomogMicro(homog,micro)%p(hme) ! my combination of homog and micro, only perform calculations for elements with homog, micro combinations which is indexed in cpElemsindex + t = FE_geomtype(mesh_element(2,e)) + if (microstructure_elemhomo(micro)) then ! homogeneous distribution of grains over each element's IPs + volumeOfGrain(grain+1_pInt:grain+dGrains) = sum(mesh_ipVolume(1:FE_Nips(t),e))/& + real(dGrains,pReal) ! each grain combines size of all IPs in that element + grain = grain + dGrains ! wind forward by Ngrains@IP + else + forall (i = 1_pInt:FE_Nips(t)) & ! loop over IPs + volumeOfGrain(grain+(i-1)*dGrains+1_pInt:grain+i*dGrains) = & + mesh_ipVolume(i,e)/dGrains ! assign IPvolume/Ngrains@IP to all grains of IP + grain = grain + FE_Nips(t) * dGrains ! wind forward by Nips*Ngrains@IP + endif + enddo + + if (grain /= myNgrains) & + call IO_error(0,el = homog,ip = micro,ext_msg = 'inconsistent grain count after volume calc') + +!-------------------------------------------------------------------------------------------------- +! divide myNgrains as best over constituents +! +! example: three constituents with fractions of 0.25, 0.25, and 0.5 distributed over 20 (microstructure) grains +! +! ***** ***** ********** +! NgrainsOfConstituent: 5, 5, 10 +! counters: +! |-----> grain (if constituent == 2) +! |--> constituentGrain (of constituent 2) +! + + NgrainsOfConstituent = 0_pInt ! reset counter of grains per constituent + forall (i = 1_pInt:myNconstituents) & + NgrainsOfConstituent(i) = nint(microstructure_fraction(i,micro) * myNgrains, pInt) ! do rounding integer conversion + do while (sum(NgrainsOfConstituent) /= myNgrains) ! total grain count over constituents wrong? + sgn = sign(1_pInt, myNgrains - sum(NgrainsOfConstituent)) ! direction of required change + extreme = 0.0_pReal + t = 0_pInt + do i = 1_pInt,myNconstituents ! find largest deviator + if (real(sgn,pReal)*log(NgrainsOfConstituent(i)/myNgrains/microstructure_fraction(i,micro)) > extreme) then + extreme = real(sgn,pReal)*log(NgrainsOfConstituent(i)/myNgrains/microstructure_fraction(i,micro)) + t = i + endif + enddo + NgrainsOfConstituent(t) = NgrainsOfConstituent(t) + sgn ! change that by one + enddo + +!-------------------------------------------------------------------------------------------------- +! assign phase and texture info + + phaseOfGrain = 0_pInt + textureOfGrain = 0_pInt + orientationOfGrain = 0.0_pReal + + texture: do i = 1_pInt,myNconstituents ! loop over constituents + grain = sum(NgrainsOfConstituent(1_pInt:i-1_pInt)) ! set microstructure grain index of current constituent + ! "grain" points to start of this constituent's grain population + constituentGrain = 0_pInt ! constituent grain index + + phaseID = microstructure_phase(i,micro) + textureID = microstructure_texture(i,micro) + phaseOfGrain (grain+1_pInt:grain+NgrainsOfConstituent(i)) = phaseID ! assign resp. phase + textureOfGrain(grain+1_pInt:grain+NgrainsOfConstituent(i)) = textureID ! assign resp. texture + + myNorientations = ceiling(real(NgrainsOfConstituent(i),pReal)/& + real(texture_symmetry(textureID),pReal),pInt) ! max number of unique orientations (excl. symmetry) + +!-------------------------------------------------------------------------------------------------- +! ...has texture components + if (texture_ODFfile(textureID) == '') then + gauss: do t = 1_pInt,texture_Ngauss(textureID) ! loop over Gauss components + do g = 1_pInt,int(myNorientations*texture_Gauss(5,t,textureID),pInt) ! loop over required grain count + orientationOfGrain(:,grain+constituentGrain+g) = & + math_sampleGaussOri(texture_Gauss(1:3,t,textureID),& + texture_Gauss( 4,t,textureID)) + enddo + constituentGrain = & + constituentGrain + int(myNorientations*texture_Gauss(5,t,textureID)) ! advance counter for grains of current constituent + enddo gauss + + fiber: do t = 1_pInt,texture_Nfiber(textureID) ! loop over fiber components + do g = 1_pInt,int(myNorientations*texture_Fiber(6,t,textureID),pInt) ! loop over required grain count + orientationOfGrain(:,grain+constituentGrain+g) = & + math_sampleFiberOri(texture_Fiber(1:2,t,textureID),& + texture_Fiber(3:4,t,textureID),& + texture_Fiber( 5,t,textureID)) + enddo + constituentGrain = & + constituentGrain + int(myNorientations*texture_fiber(6,t,textureID),pInt) ! advance counter for grains of current constituent + enddo fiber + + random: do constituentGrain = constituentGrain+1_pInt,myNorientations ! fill remainder with random + orientationOfGrain(:,grain+constituentGrain) = math_sampleRandomOri() + enddo random +!-------------------------------------------------------------------------------------------------- +! ...has hybrid IA + else + orientationOfGrain(1:3,grain+1_pInt:grain+myNorientations) = & + IO_hybridIA(myNorientations,texture_ODFfile(textureID)) + if (all(orientationOfGrain(1:3,grain+1_pInt) == -1.0_pReal)) call IO_error(156_pInt) + endif + +!-------------------------------------------------------------------------------------------------- +! ...texture transformation + + do j = 1_pInt,myNorientations ! loop over each "real" orientation + orientationOfGrain(1:3,grain+j) = math_RtoEuler( & ! translate back to Euler angles + math_mul33x33( & ! pre-multiply + math_EulertoR(orientationOfGrain(1:3,grain+j)), & ! face-value orientation + texture_transformation(1:3,1:3,textureID) & ! and transformation matrix + ) & + ) + enddo + +!-------------------------------------------------------------------------------------------------- +! ...sample symmetry + + symExtension = texture_symmetry(textureID) - 1_pInt + if (symExtension > 0_pInt) then ! sample symmetry (number of additional equivalent orientations) + constituentGrain = myNorientations ! start right after "real" orientations + do j = 1_pInt,myNorientations ! loop over each "real" orientation + symOrientation = math_symmetricEulers(texture_symmetry(textureID), & + orientationOfGrain(1:3,grain+j)) ! get symmetric equivalents + e = min(symExtension,NgrainsOfConstituent(i)-constituentGrain) ! do not overshoot end of constituent grain array + if (e > 0_pInt) then + orientationOfGrain(1:3,grain+constituentGrain+1: & + grain+constituentGrain+e) = & + symOrientation(1:3,1:e) + constituentGrain = constituentGrain + e ! remainder shrinks by e + endif + enddo + endif + +!-------------------------------------------------------------------------------------------------- +! shuffle grains within current constituent + + do j = 1_pInt,NgrainsOfConstituent(i)-1_pInt ! walk thru grains of current constituent + call random_number(rnd) + t = nint(rnd*(NgrainsOfConstituent(i)-j)+j+0.5_pReal,pInt) ! select a grain in remaining list + m = phaseOfGrain(grain+t) ! exchange current with random + phaseOfGrain(grain+t) = phaseOfGrain(grain+j) + phaseOfGrain(grain+j) = m + m = textureOfGrain(grain+t) ! exchange current with random + textureOfGrain(grain+t) = textureOfGrain(grain+j) + textureOfGrain(grain+j) = m + orientation = orientationOfGrain(1:3,grain+t) ! exchange current with random + orientationOfGrain(1:3,grain+t) = orientationOfGrain(1:3,grain+j) + orientationOfGrain(1:3,grain+j) = orientation + enddo + + enddo texture +!< @todo calc fraction after weighing with volumePerGrain, exchange in MC steps to improve result (humbug at the moment) + + + +!-------------------------------------------------------------------------------------------------- +! distribute grains of all constituents as accurately as possible to given constituent fractions + + ip = 0_pInt + currentGrainOfConstituent = 0_pInt + + do hme = 1_pInt, Nelems(homog,micro) + e = elemsOfHomogMicro(homog,micro)%p(hme) ! only perform calculations for elements with homog, micro combinations which is indexed in cpElemsindex + t = FE_geomtype(mesh_element(2,e)) + if (microstructure_elemhomo(micro)) then ! homogeneous distribution of grains over each element's IPs + m = 1_pInt ! process only first IP + else + m = FE_Nips(t) ! process all IPs + endif + + do i = 1_pInt, m ! loop over necessary IPs + ip = ip + 1_pInt ! keep track of total ip count + ipGrain = 0_pInt ! count number of grains assigned at this IP + randomOrder = math_range(microstructure_maxNconstituents) ! start out with ordered sequence of constituents + call random_number(rndArray) ! as many rnd numbers as (max) constituents + do j = 1_pInt, myNconstituents - 1_pInt ! loop over constituents ... + r = nint(rndArray(j)*(myNconstituents-j)+j+0.5_pReal,pInt) ! ... select one in remaining list + c = randomOrder(r) ! ... call it "c" + randomOrder(r) = randomOrder(j) ! ... and exchange with present position in constituent list + grain = sum(NgrainsOfConstituent(1:c-1_pInt)) ! figure out actual starting index in overall/consecutive grain population + do g = 1_pInt, min(dGrains-ipGrain, & ! leftover number of grains at this IP + max(0_pInt, & ! no negative values + nint(real(ip * dGrains * NgrainsOfConstituent(c)) / & ! fraction of grains scaled to this constituent... + real(myNgrains),pInt) - & ! ...minus those already distributed + currentGrainOfConstituent(c))) + ipGrain = ipGrain + 1_pInt ! advance IP grain counter + currentGrainOfConstituent(c) = currentGrainOfConstituent(c) + 1_pInt ! advance index of grain population for constituent c + material_volume(ipGrain,i,e) = volumeOfGrain(grain+currentGrainOfConstituent(c)) ! assign properties + material_phase(ipGrain,i,e) = phaseOfGrain(grain+currentGrainOfConstituent(c)) + material_texture(ipGrain,i,e) = textureOfGrain(grain+currentGrainOfConstituent(c)) + material_EulerAngles(1:3,ipGrain,i,e) = orientationOfGrain(1:3,grain+currentGrainOfConstituent(c)) + enddo; enddo + + c = randomOrder(microstructure_Nconstituents(micro)) ! look up constituent remaining after random shuffling + grain = sum(NgrainsOfConstituent(1:c-1_pInt)) ! figure out actual starting index in overall/consecutive grain population + do ipGrain = ipGrain + 1_pInt, dGrains ! ensure last constituent fills up to dGrains + currentGrainOfConstituent(c) = currentGrainOfConstituent(c) + 1_pInt + material_volume(ipGrain,i,e) = volumeOfGrain(grain+currentGrainOfConstituent(c)) + material_phase(ipGrain,i,e) = phaseOfGrain(grain+currentGrainOfConstituent(c)) + material_texture(ipGrain,i,e) = textureOfGrain(grain+currentGrainOfConstituent(c)) + material_EulerAngles(1:3,ipGrain,i,e) = orientationOfGrain(1:3,grain+currentGrainOfConstituent(c)) + enddo + + enddo + + do i = i, FE_Nips(t) ! loop over IPs to (possibly) distribute copies from first IP + material_volume (1_pInt:dGrains,i,e) = material_volume (1_pInt:dGrains,1,e) + material_phase (1_pInt:dGrains,i,e) = material_phase (1_pInt:dGrains,1,e) + material_texture(1_pInt:dGrains,i,e) = material_texture(1_pInt:dGrains,1,e) + material_EulerAngles(1:3,1_pInt:dGrains,i,e) = material_EulerAngles(1:3,1_pInt:dGrains,1,e) + enddo + + enddo + endif ! active homog,micro pair + enddo + enddo + + deallocate(volumeOfGrain) + deallocate(phaseOfGrain) + deallocate(textureOfGrain) + deallocate(orientationOfGrain) + deallocate(Nelems) + !> @todo - causing segmentation fault: needs looking into + !do homog = 1,material_Nhomogenization + ! do micro = 1,material_Nmicrostructure + ! if (Nelems(homog,micro) > 0_pInt) deallocate(elemsOfHomogMicro(homog,micro)%p) + ! enddo + !enddo + deallocate(elemsOfHomogMicro) + +end subroutine material_populateGrains + +#ifdef HDF +integer(pInt) pure function material_NconstituentsPhase(matID) + + implicit none + integer(pInt), intent(in) :: matID + + material_NconstituentsPhase = count(microstructure_phase == matID) +end function +#endif + +end module material diff --git a/src/math.f90 b/src/math.f90 new file mode 100644 index 000000000..8636ad6bc --- /dev/null +++ b/src/math.f90 @@ -0,0 +1,2678 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @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 Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Mathematical library, including random number generation and tensor represenations +!-------------------------------------------------------------------------------------------------- +module math + use, intrinsic :: iso_c_binding + use prec, only: & + pReal, & + pInt + + implicit none + private + real(pReal), parameter, public :: PI = 3.14159265358979323846264338327950288419716939937510_pReal !< ratio of a circle's circumference to its diameter + real(pReal), parameter, public :: INDEG = 180.0_pReal/PI !< conversion from radian into degree + real(pReal), parameter, public :: INRAD = PI/180.0_pReal !< conversion from degree into radian + complex(pReal), parameter, public :: TWOPIIMG = (0.0_pReal,2.0_pReal)* PI !< Re(0.0), Im(2xPi) + + real(pReal), dimension(3,3), parameter, public :: & + MATH_I3 = reshape([& + 1.0_pReal,0.0_pReal,0.0_pReal, & + 0.0_pReal,1.0_pReal,0.0_pReal, & + 0.0_pReal,0.0_pReal,1.0_pReal & + ],[3,3]) !< 3x3 Identity + + integer(pInt), dimension (2,6), parameter, private :: & + mapMandel = reshape([& + 1_pInt,1_pInt, & + 2_pInt,2_pInt, & + 3_pInt,3_pInt, & + 1_pInt,2_pInt, & + 2_pInt,3_pInt, & + 1_pInt,3_pInt & + ],[2,6]) !< arrangement in Mandel notation + + real(pReal), dimension(6), parameter, private :: & + nrmMandel = [& + 1.0_pReal, 1.0_pReal, 1.0_pReal,& + 1.414213562373095_pReal, 1.414213562373095_pReal, 1.414213562373095_pReal ] !< weighting for Mandel notation (forward) + + real(pReal), dimension(6), parameter , public :: & + invnrmMandel = [& + 1.0_pReal, 1.0_pReal, 1.0_pReal,& + 0.7071067811865476_pReal, 0.7071067811865476_pReal, 0.7071067811865476_pReal ] !< weighting for Mandel notation (backward) + + integer(pInt), dimension (2,6), parameter, private :: & + mapVoigt = reshape([& + 1_pInt,1_pInt, & + 2_pInt,2_pInt, & + 3_pInt,3_pInt, & + 2_pInt,3_pInt, & + 1_pInt,3_pInt, & + 1_pInt,2_pInt & + ],[2,6]) !< arrangement in Voigt notation + + real(pReal), dimension(6), parameter, private :: & + nrmVoigt = 1.0_pReal, & !< weighting for Voigt notation (forward) + invnrmVoigt = 1.0_pReal !< weighting for Voigt notation (backward) + + integer(pInt), dimension (2,9), parameter, private :: & + mapPlain = reshape([& + 1_pInt,1_pInt, & + 1_pInt,2_pInt, & + 1_pInt,3_pInt, & + 2_pInt,1_pInt, & + 2_pInt,2_pInt, & + 2_pInt,3_pInt, & + 3_pInt,1_pInt, & + 3_pInt,2_pInt, & + 3_pInt,3_pInt & + ],[2,9]) !< arrangement in Plain notation + +#ifdef Spectral + include 'fftw3.f03' +#endif + + public :: & + math_init, & + math_qsort, & + math_range, & + math_identity2nd, & + math_identity4th, & + math_civita, & + math_delta, & + math_crossproduct, & + math_tensorproduct33, & + math_mul3x3, & + math_mul6x6, & + math_mul33xx33, & + math_mul3333xx33, & + math_mul3333xx3333, & + math_mul33x33, & + math_mul66x66, & + math_mul99x99, & + math_mul33x3, & + math_mul33x3_complex, & + math_mul66x6 , & + math_exp33 , & + math_transpose33, & + math_inv33, & + math_invert33, & + math_invSym3333, & + math_invert, & + math_symmetric33, & + math_symmetric66, & + math_skew33, & + math_spherical33, & + math_deviatoric33, & + math_equivStrain33, & + math_equivStress33, & + math_trace33, & + math_det33, & + math_Plain33to9, & + math_Plain9to33, & + math_Mandel33to6, & + math_Mandel6to33, & + math_Plain3333to99, & + math_Plain99to3333, & + math_Mandel66toPlain66, & + math_Plain66toMandel66, & + math_Mandel3333to66, & + math_Mandel66to3333, & + math_Voigt66to3333, & + math_qRand, & + math_qMul, & + math_qDot, & + math_qConj, & + math_qInv, & + math_qRot, & + math_RtoEuler, & + math_RtoQ, & + math_EulerToR, & + math_EulerToQ, & + math_EulerAxisAngleToR, & + math_axisAngleToR, & + math_EulerAxisAngleToQ, & + math_axisAngleToQ, & + math_qToRodrig, & + math_qToEuler, & + math_qToEulerAxisAngle, & + math_qToAxisAngle, & + math_qToR, & + math_EulerMisorientation, & + math_sampleRandomOri, & + math_sampleGaussOri, & + math_sampleFiberOri, & + math_sampleGaussVar, & + math_symmetricEulers, & + math_spectralDecompositionSym33, & + math_spectralDecompositionSym, & + math_rotationalPart33, & + math_invariantsSym33, & + math_eigenvaluesSym33, & + math_factorial, & + math_binomial, & + math_multinomial, & + math_volTetrahedron, & + math_areaTriangle, & + math_rotate_forward33, & + math_rotate_backward33, & + math_rotate_forward3333 +#ifdef Spectral + public :: & + fftw_set_timelimit, & + fftw_plan_dft_3d, & + fftw_plan_many_dft_r2c, & + fftw_plan_many_dft_c2r, & + fftw_plan_with_nthreads, & + fftw_init_threads, & + fftw_alloc_complex, & + fftw_execute_dft, & + fftw_execute_dft_r2c, & + fftw_execute_dft_c2r, & + fftw_destroy_plan, & + math_tensorAvg +#endif + private :: & + math_partition, & + halton, & + halton_memory, & + halton_ndim_set, & + halton_seed_set, & + i_to_halton, & + prime + external :: & + dsyev, & + dgetrf, & + dgetri + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief initialization of random seed generator +!-------------------------------------------------------------------------------------------------- +subroutine math_init + + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: tol_math_check + use numerics, only: & + worldrank, & + fixedSeed + use IO, only: IO_error, IO_timeStamp + + implicit none + integer(pInt) :: i + real(pReal), dimension(3,3) :: R,R2 + real(pReal), dimension(3) :: Eulers,v + real(pReal), dimension(4) :: q,q2,axisangle,randTest +! the following variables are system dependend and shound NOT be pInt + integer :: randSize ! gfortran requires a variable length to compile + integer, dimension(:), allocatable :: randInit ! if recalculations of former randomness (with given seed) is necessary + ! comment the first random_seed call out, set randSize to 1, and use ifort + character(len=64) :: error_msg + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- math init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + call random_seed(size=randSize) + if (allocated(randInit)) deallocate(randInit) + allocate(randInit(randSize)) + if (fixedSeed > 0_pInt) then + randInit(1:randSize) = int(fixedSeed) ! fixedSeed is of type pInt, randInit not + call random_seed(put=randInit) + else + call random_seed() + call random_seed(get = randInit) + randInit(2:randSize) = randInit(1) + call random_seed(put = randInit) + endif + + do i = 1_pInt, 4_pInt + call random_number(randTest(i)) + enddo + + mainProcess2: if (worldrank == 0) then + write(6,*) 'size of random seed: ', randSize + do i =1, randSize + write(6,*) 'value of random seed: ', i, randInit(i) + enddo + write(6,'(a,4(/,26x,f17.14),/)') ' start of random sequence: ', randTest + endif mainProcess2 + + call random_seed(put = randInit) + + call halton_seed_set(int(randInit(1), pInt)) + call halton_ndim_set(3_pInt) + + ! --- check rotation dictionary --- + + q = math_qRand() ! random quaternion + + ! +++ q -> a -> q +++ + axisangle = math_qToAxisAngle(q) + q2 = math_axisAngleToQ(axisangle(1:3),axisangle(4)) + if ( any(abs( q-q2) > tol_math_check) .and. & + any(abs(-q-q2) > tol_math_check) ) then + write (error_msg, '(a,e14.6)' ) 'maximum deviation ',min(maxval(abs( q-q2)),maxval(abs(-q-q2))) + call IO_error(401_pInt,ext_msg=error_msg) + endif + + ! +++ q -> R -> q +++ + R = math_qToR(q) + q2 = math_RtoQ(R) + if ( any(abs( q-q2) > tol_math_check) .and. & + any(abs(-q-q2) > tol_math_check) ) then + write (error_msg, '(a,e14.6)' ) 'maximum deviation ',min(maxval(abs( q-q2)),maxval(abs(-q-q2))) + call IO_error(402_pInt,ext_msg=error_msg) + endif + + ! +++ q -> euler -> q +++ + Eulers = math_qToEuler(q) + q2 = math_EulerToQ(Eulers) + if ( any(abs( q-q2) > tol_math_check) .and. & + any(abs(-q-q2) > tol_math_check) ) then + write (error_msg, '(a,e14.6)' ) 'maximum deviation ',min(maxval(abs( q-q2)),maxval(abs(-q-q2))) + call IO_error(403_pInt,ext_msg=error_msg) + endif + + ! +++ R -> euler -> R +++ + Eulers = math_RtoEuler(R) + R2 = math_EulerToR(Eulers) + if ( any(abs( R-R2) > tol_math_check) ) then + write (error_msg, '(a,e14.6)' ) 'maximum deviation ',maxval(abs( R-R2)) + call IO_error(404_pInt,ext_msg=error_msg) + endif + + ! +++ check rotation sense of q and R +++ + q = math_qRand() ! random quaternion + call halton(3_pInt,v) ! random vector + R = math_qToR(q) + if (any(abs(math_mul33x3(R,v) - math_qRot(q,v)) > tol_math_check)) then + write(6,'(a,4(f8.3,1x))') 'q',q + call IO_error(409_pInt) + endif + +end subroutine math_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief Quicksort algorithm for two-dimensional integer arrays +! Sorting is done with respect to array(1,:) +! and keeps array(2:N,:) linked to it. +!-------------------------------------------------------------------------------------------------- +recursive subroutine math_qsort(a, istart, iend) + + implicit none + integer(pInt), dimension(:,:), intent(inout) :: a + integer(pInt), intent(in) :: istart,iend + integer(pInt) :: ipivot + + if (istart < iend) then + ipivot = math_partition(a,istart, iend) + call math_qsort(a, istart, ipivot-1_pInt) + call math_qsort(a, ipivot+1_pInt, iend) + endif + +end subroutine math_qsort + + +!-------------------------------------------------------------------------------------------------- +!> @brief Partitioning required for quicksort +!-------------------------------------------------------------------------------------------------- +integer(pInt) function math_partition(a, istart, iend) + + implicit none + integer(pInt), dimension(:,:), intent(inout) :: a + integer(pInt), intent(in) :: istart,iend + integer(pInt) :: d,i,j,k,x,tmp + + d = int(size(a,1_pInt), pInt) ! number of linked data +! set the starting and ending points, and the pivot point + + i = istart + + j = iend + x = a(1,istart) + do +! find the first element on the right side less than or equal to the pivot point + do j = j, istart, -1_pInt + if (a(1,j) <= x) exit + enddo +! find the first element on the left side greater than the pivot point + do i = i, iend + if (a(1,i) > x) exit + enddo + if (i < j) then ! if the indexes do not cross, exchange values + do k = 1_pInt,d + tmp = a(k,i) + a(k,i) = a(k,j) + a(k,j) = tmp + enddo + else ! if they do cross, exchange left value with pivot and return with the partition index + do k = 1_pInt,d + tmp = a(k,istart) + a(k,istart) = a(k,j) + a(k,j) = tmp + enddo + math_partition = j + return + endif + enddo + +end function math_partition + + +!-------------------------------------------------------------------------------------------------- +!> @brief range of integers starting at one +!-------------------------------------------------------------------------------------------------- +pure function math_range(N) + + implicit none + integer(pInt), intent(in) :: N !< length of range + integer(pInt) :: i + integer(pInt), dimension(N) :: math_range + + math_range = [(i,i=1_pInt,N)] + +end function math_range + + +!-------------------------------------------------------------------------------------------------- +!> @brief second rank identity tensor of specified dimension +!-------------------------------------------------------------------------------------------------- +pure function math_identity2nd(dimen) + + implicit none + integer(pInt), intent(in) :: dimen !< tensor dimension + integer(pInt) :: i + real(pReal), dimension(dimen,dimen) :: math_identity2nd + + math_identity2nd = 0.0_pReal + forall (i=1_pInt:dimen) math_identity2nd(i,i) = 1.0_pReal + +end function math_identity2nd + +!-------------------------------------------------------------------------------------------------- +!> @brief symmetric fourth rank identity tensor of specified dimension +! from http://en.wikipedia.org/wiki/Tensor_derivative_(continuum_mechanics)#Derivative_of_a_second-order_tensor_with_respect_to_itself +!-------------------------------------------------------------------------------------------------- +pure function math_identity4th(dimen) + + implicit none + integer(pInt), intent(in) :: dimen !< tensor dimension + integer(pInt) :: i,j,k,l + real(pReal), dimension(dimen,dimen,dimen,dimen) :: math_identity4th + + forall (i=1_pInt:dimen,j=1_pInt:dimen,k=1_pInt:dimen,l=1_pInt:dimen) math_identity4th(i,j,k,l) = & + 0.5_pReal*(math_I3(i,k)*math_I3(j,l)+math_I3(i,l)*math_I3(j,k)) + +end function math_identity4th + + +!-------------------------------------------------------------------------------------------------- +!> @brief permutation tensor e_ijk used for computing cross product of two tensors +! e_ijk = 1 if even permutation of ijk +! e_ijk = -1 if odd permutation of ijk +! e_ijk = 0 otherwise +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_civita(i,j,k) + + implicit none + integer(pInt), intent(in) :: i,j,k + + math_civita = 0.0_pReal + if (((i == 1_pInt).and.(j == 2_pInt).and.(k == 3_pInt)) .or. & + ((i == 2_pInt).and.(j == 3_pInt).and.(k == 1_pInt)) .or. & + ((i == 3_pInt).and.(j == 1_pInt).and.(k == 2_pInt))) math_civita = 1.0_pReal + if (((i == 1_pInt).and.(j == 3_pInt).and.(k == 2_pInt)) .or. & + ((i == 2_pInt).and.(j == 1_pInt).and.(k == 3_pInt)) .or. & + ((i == 3_pInt).and.(j == 2_pInt).and.(k == 1_pInt))) math_civita = -1.0_pReal + +end function math_civita + + +!-------------------------------------------------------------------------------------------------- +!> @brief kronecker delta function d_ij +! d_ij = 1 if i = j +! d_ij = 0 otherwise +! inspired by http://fortraninacworld.blogspot.de/2012/12/ternary-operator.html +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_delta(i,j) + + implicit none + integer(pInt), intent (in) :: i,j + + math_delta = merge(0.0_pReal, 1.0_pReal, i /= j) + +end function math_delta + + +!-------------------------------------------------------------------------------------------------- +!> @brief cross product a x b +!-------------------------------------------------------------------------------------------------- +pure function math_crossproduct(A,B) + + implicit none + real(pReal), dimension(3), intent(in) :: A,B + real(pReal), dimension(3) :: math_crossproduct + + math_crossproduct = [ A(2)*B(3) -A(3)*B(2), & + A(3)*B(1) -A(1)*B(3), & + A(1)*B(2) -A(2)*B(1) ] + +end function math_crossproduct + + +!-------------------------------------------------------------------------------------------------- +!> @brief tensor product a \otimes b +!-------------------------------------------------------------------------------------------------- +pure function math_tensorproduct33(A,B) + + implicit none + real(pReal), dimension(3,3) :: math_tensorproduct33 + real(pReal), dimension(3), intent(in) :: A,B + integer(pInt) :: i,j + + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) math_tensorproduct33(i,j) = A(i)*B(j) + +end function math_tensorproduct33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication 3x3 = 1 +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_mul3x3(A,B) + + implicit none + real(pReal), dimension(3), intent(in) :: A,B + + math_mul3x3 = sum(A*B) + +end function math_mul3x3 + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication 6x6 = 1 +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_mul6x6(A,B) + + implicit none + real(pReal), dimension(6), intent(in) :: A,B + + math_mul6x6 = sum(A*B) + +end function math_mul6x6 + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication 33xx33 = 1 (double contraction --> ij * ij) +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_mul33xx33(A,B) + + implicit none + real(pReal), dimension(3,3), intent(in) :: A,B + integer(pInt) :: i,j + real(pReal), dimension(3,3) :: C + + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) C(i,j) = A(i,j) * B(i,j) + math_mul33xx33 = sum(C) + +end function math_mul33xx33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication 3333x33 = 33 (double contraction --> ijkl *kl = ij) +!-------------------------------------------------------------------------------------------------- +pure function math_mul3333xx33(A,B) + + implicit none + real(pReal), dimension(3,3) :: math_mul3333xx33 + real(pReal), dimension(3,3,3,3), intent(in) :: A + real(pReal), dimension(3,3), intent(in) :: B + integer(pInt) :: i,j + + forall(i = 1_pInt:3_pInt,j = 1_pInt:3_pInt) & + math_mul3333xx33(i,j) = sum(A(i,j,1:3,1:3)*B(1:3,1:3)) + +end function math_mul3333xx33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication 3333x3333 = 3333 (ijkl *klmn = ijmn) +!-------------------------------------------------------------------------------------------------- +pure function math_mul3333xx3333(A,B) + + implicit none + integer(pInt) :: i,j,k,l + real(pReal), dimension(3,3,3,3), intent(in) :: A + real(pReal), dimension(3,3,3,3), intent(in) :: B + real(pReal), dimension(3,3,3,3) :: math_mul3333xx3333 + + forall(i = 1_pInt:3_pInt,j = 1_pInt:3_pInt, k = 1_pInt:3_pInt, l= 1_pInt:3_pInt) & + math_mul3333xx3333(i,j,k,l) = sum(A(i,j,1:3,1:3)*B(1:3,1:3,k,l)) + +end function math_mul3333xx3333 + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication 33x33 = 33 +!-------------------------------------------------------------------------------------------------- +pure function math_mul33x33(A,B) + + implicit none + real(pReal), dimension(3,3) :: math_mul33x33 + real(pReal), dimension(3,3), intent(in) :: A,B + integer(pInt) :: i,j + + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) & + math_mul33x33(i,j) = A(i,1)*B(1,j) + A(i,2)*B(2,j) + A(i,3)*B(3,j) + +end function math_mul33x33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication 66x66 = 66 +!-------------------------------------------------------------------------------------------------- +pure function math_mul66x66(A,B) + + implicit none + real(pReal), dimension(6,6) :: math_mul66x66 + real(pReal), dimension(6,6), intent(in) :: A,B + integer(pInt) :: i,j + + forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) math_mul66x66(i,j) = & + A(i,1)*B(1,j) + A(i,2)*B(2,j) + A(i,3)*B(3,j) + & + A(i,4)*B(4,j) + A(i,5)*B(5,j) + A(i,6)*B(6,j) + +end function math_mul66x66 + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication 99x99 = 99 +!-------------------------------------------------------------------------------------------------- +pure function math_mul99x99(A,B) + + implicit none + real(pReal), dimension(9,9) :: math_mul99x99 + real(pReal), dimension(9,9), intent(in) :: A,B + integer(pInt) i,j + + forall (i=1_pInt:9_pInt,j=1_pInt:9_pInt) math_mul99x99(i,j) = & + A(i,1)*B(1,j) + A(i,2)*B(2,j) + A(i,3)*B(3,j) + & + A(i,4)*B(4,j) + A(i,5)*B(5,j) + A(i,6)*B(6,j) + & + A(i,7)*B(7,j) + A(i,8)*B(8,j) + A(i,9)*B(9,j) + +end function math_mul99x99 + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication 33x3 = 3 +!-------------------------------------------------------------------------------------------------- +pure function math_mul33x3(A,B) + + implicit none + real(pReal), dimension(3) :: math_mul33x3 + real(pReal), dimension(3,3), intent(in) :: A + real(pReal), dimension(3), intent(in) :: B + integer(pInt) :: i + + forall (i=1_pInt:3_pInt) math_mul33x3(i) = sum(A(i,1:3)*B) + +end function math_mul33x3 + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication complex(33) x real(3) = complex(3) +!-------------------------------------------------------------------------------------------------- +pure function math_mul33x3_complex(A,B) + + implicit none + complex(pReal), dimension(3) :: math_mul33x3_complex + complex(pReal), dimension(3,3), intent(in) :: A + real(pReal), dimension(3), intent(in) :: B + integer(pInt) :: i + + forall (i=1_pInt:3_pInt) math_mul33x3_complex(i) = sum(A(i,1:3)*cmplx(B,0.0_pReal,pReal)) + +end function math_mul33x3_complex + + +!-------------------------------------------------------------------------------------------------- +!> @brief matrix multiplication 66x6 = 6 +!-------------------------------------------------------------------------------------------------- +pure function math_mul66x6(A,B) + + implicit none + real(pReal), dimension(6) :: math_mul66x6 + real(pReal), dimension(6,6), intent(in) :: A + real(pReal), dimension(6), intent(in) :: B + integer(pInt) :: i + + forall (i=1_pInt:6_pInt) math_mul66x6(i) = & + A(i,1)*B(1) + A(i,2)*B(2) + A(i,3)*B(3) + & + A(i,4)*B(4) + A(i,5)*B(5) + A(i,6)*B(6) + +end function math_mul66x6 + + +!-------------------------------------------------------------------------------------------------- +!> @brief 3x3 matrix exponential up to series approximation order n (default 5) +!-------------------------------------------------------------------------------------------------- +pure function math_exp33(A,n) + + implicit none + integer(pInt) :: i,order + integer(pInt), intent(in), optional :: n + real(pReal), dimension(3,3), intent(in) :: A + real(pReal), dimension(3,3) :: B,math_exp33 + real(pReal) :: invfac + + order = merge(n,5_pInt,present(n)) + + B = math_I3 ! init + invfac = 1.0_pReal ! 0! + math_exp33 = B ! A^0 = eye2 + + do i = 1_pInt,n + invfac = invfac/real(i) ! invfac = 1/i! + B = math_mul33x33(B,A) + math_exp33 = math_exp33 + invfac*B ! exp = SUM (A^i)/i! + enddo + +end function math_exp33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief transposition of a 33 matrix +!-------------------------------------------------------------------------------------------------- +pure function math_transpose33(A) + + implicit none + real(pReal),dimension(3,3) :: math_transpose33 + real(pReal),dimension(3,3),intent(in) :: A + integer(pInt) :: i,j + + forall(i=1_pInt:3_pInt, j=1_pInt:3_pInt) math_transpose33(i,j) = A(j,i) + +end function math_transpose33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief Cramer inversion of 33 matrix (function) +! direct Cramer inversion of matrix A. +! returns all zeroes if not possible, i.e. if det close to zero +!-------------------------------------------------------------------------------------------------- +pure function math_inv33(A) + + implicit none + real(pReal),dimension(3,3),intent(in) :: A + real(pReal) :: DetA + real(pReal),dimension(3,3) :: math_inv33 + + math_inv33(1,1) = A(2,2) * A(3,3) - A(2,3) * A(3,2) + math_inv33(2,1) = -A(2,1) * A(3,3) + A(2,3) * A(3,1) + math_inv33(3,1) = A(2,1) * A(3,2) - A(2,2) * A(3,1) + + DetA = A(1,1) * math_inv33(1,1) + A(1,2) * math_inv33(2,1) + A(1,3) * math_inv33(3,1) + + if (abs(DetA) > tiny(DetA)) then ! use a real threshold here + math_inv33(1,2) = -A(1,2) * A(3,3) + A(1,3) * A(3,2) + math_inv33(2,2) = A(1,1) * A(3,3) - A(1,3) * A(3,1) + math_inv33(3,2) = -A(1,1) * A(3,2) + A(1,2) * A(3,1) + + math_inv33(1,3) = A(1,2) * A(2,3) - A(1,3) * A(2,2) + math_inv33(2,3) = -A(1,1) * A(2,3) + A(1,3) * A(2,1) + math_inv33(3,3) = A(1,1) * A(2,2) - A(1,2) * A(2,1) + + math_inv33 = math_inv33/DetA + else + math_inv33 = 0.0_pReal + endif + +end function math_inv33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief Cramer inversion of 33 matrix (subroutine) +! direct Cramer inversion of matrix A. +! also returns determinant +! returns error if not possible, i.e. if det close to zero +!-------------------------------------------------------------------------------------------------- +pure subroutine math_invert33(A, InvA, DetA, error) + + implicit none + logical, intent(out) :: error + real(pReal),dimension(3,3),intent(in) :: A + real(pReal),dimension(3,3),intent(out) :: InvA + real(pReal), intent(out) :: DetA + + InvA(1,1) = A(2,2) * A(3,3) - A(2,3) * A(3,2) + InvA(2,1) = -A(2,1) * A(3,3) + A(2,3) * A(3,1) + InvA(3,1) = A(2,1) * A(3,2) - A(2,2) * A(3,1) + + DetA = A(1,1) * InvA(1,1) + A(1,2) * InvA(2,1) + A(1,3) * InvA(3,1) + + if (abs(DetA) <= tiny(DetA)) then + error = .true. + else + InvA(1,2) = -A(1,2) * A(3,3) + A(1,3) * A(3,2) + InvA(2,2) = A(1,1) * A(3,3) - A(1,3) * A(3,1) + InvA(3,2) = -A(1,1) * A(3,2) + A(1,2) * A(3,1) + + InvA(1,3) = A(1,2) * A(2,3) - A(1,3) * A(2,2) + InvA(2,3) = -A(1,1) * A(2,3) + A(1,3) * A(2,1) + InvA(3,3) = A(1,1) * A(2,2) - A(1,2) * A(2,1) + + InvA = InvA/DetA + error = .false. + endif + +end subroutine math_invert33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief Inversion of symmetriced 3x3x3x3 tensor. +!-------------------------------------------------------------------------------------------------- +function math_invSym3333(A) + use IO, only: & + IO_error + + implicit none + real(pReal),dimension(3,3,3,3) :: math_invSym3333 + + real(pReal),dimension(3,3,3,3),intent(in) :: A + + integer(pInt) :: ierr + integer(pInt), dimension(6) :: ipiv6 + real(pReal), dimension(6,6) :: temp66_Real + real(pReal), dimension(6) :: work6 + + temp66_real = math_Mandel3333to66(A) +#if(FLOAT==8) + call dgetrf(6,6,temp66_real,6,ipiv6,ierr) + call dgetri(6,temp66_real,6,ipiv6,work6,6,ierr) +#elif(FLOAT==4) + call sgetrf(6,6,temp66_real,6,ipiv6,ierr) + call sgetri(6,temp66_real,6,ipiv6,work6,6,ierr) +#endif + if (ierr == 0_pInt) then + math_invSym3333 = math_Mandel66to3333(temp66_real) + else + call IO_error(400_pInt, ext_msg = 'math_invSym3333') + endif + +end function math_invSym3333 + + +!-------------------------------------------------------------------------------------------------- +!> @brief invert matrix of arbitrary dimension +!-------------------------------------------------------------------------------------------------- +subroutine math_invert(myDim,A, InvA, error) + + implicit none + integer(pInt), intent(in) :: myDim + real(pReal), dimension(myDim,myDim), intent(in) :: A + + + integer(pInt) :: ierr + integer(pInt), dimension(myDim) :: ipiv + real(pReal), dimension(myDim) :: work + + real(pReal), dimension(myDim,myDim), intent(out) :: invA + logical, intent(out) :: error + + invA = A +#if(FLOAT==8) + call dgetrf(myDim,myDim,invA,myDim,ipiv,ierr) + call dgetri(myDim,InvA,myDim,ipiv,work,myDim,ierr) +#elif(FLOAT==4) + call sgetrf(myDim,myDim,invA,myDim,ipiv,ierr) + call sgetri(myDim,InvA,myDim,ipiv,work,myDim,ierr) +#endif + error = merge(.true.,.false., ierr /= 0_pInt) ! http://fortraninacworld.blogspot.de/2012/12/ternary-operator.html + +end subroutine math_invert + + +!-------------------------------------------------------------------------------------------------- +!> @brief symmetrize a 33 matrix +!-------------------------------------------------------------------------------------------------- +pure function math_symmetric33(m) + + implicit none + real(pReal), dimension(3,3) :: math_symmetric33 + real(pReal), dimension(3,3), intent(in) :: m + + math_symmetric33 = 0.5_pReal * (m + transpose(m)) + +end function math_symmetric33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief symmetrize a 66 matrix +!-------------------------------------------------------------------------------------------------- +pure function math_symmetric66(m) + + implicit none + real(pReal), dimension(6,6) :: math_symmetric66 + real(pReal), dimension(6,6), intent(in) :: m + + math_symmetric66 = 0.5_pReal * (m + transpose(m)) + +end function math_symmetric66 + + +!-------------------------------------------------------------------------------------------------- +!> @brief skew part of a 33 matrix +!-------------------------------------------------------------------------------------------------- +pure function math_skew33(m) + + implicit none + real(pReal), dimension(3,3) :: math_skew33 + real(pReal), dimension(3,3), intent(in) :: m + + math_skew33 = m - math_symmetric33(m) + +end function math_skew33 + +!-------------------------------------------------------------------------------------------------- +!> @brief hydrostatic part of a 33 matrix +!-------------------------------------------------------------------------------------------------- +pure function math_spherical33(m) + + implicit none + real(pReal), dimension(3,3) :: math_spherical33 + real(pReal), dimension(3,3), intent(in) :: m + + math_spherical33 = math_I3 * math_trace33(m)/3.0_pReal + +end function math_spherical33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief deviatoric part of a 33 matrix +!-------------------------------------------------------------------------------------------------- +pure function math_deviatoric33(m) + + implicit none + real(pReal), dimension(3,3) :: math_deviatoric33 + real(pReal), dimension(3,3), intent(in) :: m + + math_deviatoric33 = m - math_spherical33(m) + +end function math_deviatoric33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief equivalent scalar quantity of a full symmetric strain tensor +!-------------------------------------------------------------------------------------------------- +pure function math_equivStrain33(m) + + implicit none + real(pReal), dimension(3,3), intent(in) :: m + real(pReal), dimension(3) :: e,s + real(pReal) :: math_equivStrain33 + real(pReal), parameter :: TWOTHIRD = 2.0_pReal/3.0_pReal + + e = [2.0_pReal*m(1,1)-m(2,2)-m(3,3), & + 2.0_pReal*m(2,2)-m(3,3)-m(1,1), & + 2.0_pReal*m(3,3)-m(1,1)-m(2,2)]/3.0_pReal + s = [m(1,2),m(2,3),m(1,3)]*2.0_pReal + + math_equivStrain33 = TWOTHIRD*(1.50_pReal*(sum(e**2.0_pReal)) + & + 0.75_pReal*(sum(s**2.0_pReal)))**(0.5_pReal) + +end function math_equivStrain33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief von Mises equivalent of a full symmetric stress tensor +!-------------------------------------------------------------------------------------------------- +pure function math_equivStress33(m) + + implicit none + real(pReal), dimension(3,3), intent(in) :: m + real(pReal) :: math_equivStress33 + + math_equivStress33 =( ( (m(1,1)-m(2,2))**2.0_pReal + & + (m(2,2)-m(3,3))**2.0_pReal + & + (m(3,3)-m(1,1))**2.0_pReal + & + 6.0_pReal*( m(1,2)**2.0_pReal + & + m(2,3)**2.0_pReal + & + m(1,3)**2.0_pReal & + ) & + )**0.5_pReal & + )/sqrt(2.0_pReal) + +end function math_equivStress33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief trace of a 33 matrix +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_trace33(m) + + implicit none + real(pReal), dimension(3,3), intent(in) :: m + + math_trace33 = m(1,1) + m(2,2) + m(3,3) + +end function math_trace33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief determinant of a 33 matrix +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_det33(m) + + implicit none + real(pReal), dimension(3,3), intent(in) :: m + + math_det33 = m(1,1)* (m(2,2)*m(3,3)-m(2,3)*m(3,2)) & + - m(1,2)* (m(2,1)*m(3,3)-m(2,3)*m(3,1)) & + + m(1,3)* (m(2,1)*m(3,2)-m(2,2)*m(3,1)) + +end function math_det33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief determinant of a symmetric 33 matrix +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_detSym33(m) + + implicit none + real(pReal), dimension(3,3), intent(in) :: m + + math_detSym33 = -(m(1,1)*m(2,3)**2_pInt + m(2,2)*m(1,3)**2_pInt + m(3,3)*m(1,2)**2_pInt) & + + m(1,1)*m(2,2)*m(3,3) - 2.0_pReal * m(1,2)*m(1,3)*m(2,3) + +end function math_detSym33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief convert 33 matrix into vector 9 +!-------------------------------------------------------------------------------------------------- +pure function math_Plain33to9(m33) + + implicit none + real(pReal), dimension(9) :: math_Plain33to9 + real(pReal), dimension(3,3), intent(in) :: m33 + integer(pInt) :: i + + forall (i=1_pInt:9_pInt) math_Plain33to9(i) = m33(mapPlain(1,i),mapPlain(2,i)) + +end function math_Plain33to9 + + +!-------------------------------------------------------------------------------------------------- +!> @brief convert Plain 9 back to 33 matrix +!-------------------------------------------------------------------------------------------------- +pure function math_Plain9to33(v9) + + implicit none + real(pReal), dimension(3,3) :: math_Plain9to33 + real(pReal), dimension(9), intent(in) :: v9 + integer(pInt) :: i + + forall (i=1_pInt:9_pInt) math_Plain9to33(mapPlain(1,i),mapPlain(2,i)) = v9(i) + +end function math_Plain9to33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief convert symmetric 33 matrix into Mandel vector 6 +!-------------------------------------------------------------------------------------------------- +pure function math_Mandel33to6(m33) + + implicit none + real(pReal), dimension(6) :: math_Mandel33to6 + real(pReal), dimension(3,3), intent(in) :: m33 + + integer(pInt) :: i + + forall (i=1_pInt:6_pInt) math_Mandel33to6(i) = nrmMandel(i)*m33(mapMandel(1,i),mapMandel(2,i)) + +end function math_Mandel33to6 + + +!-------------------------------------------------------------------------------------------------- +!> @brief convert Mandel 6 back to symmetric 33 matrix +!-------------------------------------------------------------------------------------------------- +pure function math_Mandel6to33(v6) + + implicit none + real(pReal), dimension(6), intent(in) :: v6 + real(pReal), dimension(3,3) :: math_Mandel6to33 + integer(pInt) :: i + + forall (i=1_pInt:6_pInt) + math_Mandel6to33(mapMandel(1,i),mapMandel(2,i)) = invnrmMandel(i)*v6(i) + math_Mandel6to33(mapMandel(2,i),mapMandel(1,i)) = invnrmMandel(i)*v6(i) + end forall + +end function math_Mandel6to33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief convert 3333 tensor into plain matrix 99 +!-------------------------------------------------------------------------------------------------- +pure function math_Plain3333to99(m3333) + + implicit none + real(pReal), dimension(3,3,3,3), intent(in) :: m3333 + real(pReal), dimension(9,9) :: math_Plain3333to99 + integer(pInt) :: i,j + + forall (i=1_pInt:9_pInt,j=1_pInt:9_pInt) math_Plain3333to99(i,j) = & + m3333(mapPlain(1,i),mapPlain(2,i),mapPlain(1,j),mapPlain(2,j)) + +end function math_Plain3333to99 + +!-------------------------------------------------------------------------------------------------- +!> @brief plain matrix 99 into 3333 tensor +!-------------------------------------------------------------------------------------------------- +pure function math_Plain99to3333(m99) + + implicit none + real(pReal), dimension(9,9), intent(in) :: m99 + real(pReal), dimension(3,3,3,3) :: math_Plain99to3333 + integer(pInt) :: i,j + + forall (i=1_pInt:9_pInt,j=1_pInt:9_pInt) math_Plain99to3333(mapPlain(1,i),mapPlain(2,i),& + mapPlain(1,j),mapPlain(2,j)) = m99(i,j) + +end function math_Plain99to3333 + + +!-------------------------------------------------------------------------------------------------- +!> @brief convert Mandel matrix 66 into Plain matrix 66 +!-------------------------------------------------------------------------------------------------- +pure function math_Mandel66toPlain66(m66) + + implicit none + real(pReal), dimension(6,6), intent(in) :: m66 + real(pReal), dimension(6,6) :: math_Mandel66toPlain66 + integer(pInt) :: i,j + + forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) & + math_Mandel66toPlain66(i,j) = invnrmMandel(i) * invnrmMandel(j) * m66(i,j) + +end function math_Mandel66toPlain66 + + +!-------------------------------------------------------------------------------------------------- +!> @brief convert Plain matrix 66 into Mandel matrix 66 +!-------------------------------------------------------------------------------------------------- +pure function math_Plain66toMandel66(m66) + + implicit none + real(pReal), dimension(6,6), intent(in) :: m66 + real(pReal), dimension(6,6) :: math_Plain66toMandel66 + integer(pInt) :: i,j + + forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) & + math_Plain66toMandel66(i,j) = nrmMandel(i) * nrmMandel(j) * m66(i,j) + +end function math_Plain66toMandel66 + + +!-------------------------------------------------------------------------------------------------- +!> @brief convert symmetric 3333 tensor into Mandel matrix 66 +!-------------------------------------------------------------------------------------------------- +pure function math_Mandel3333to66(m3333) + + implicit none + + real(pReal), dimension(3,3,3,3), intent(in) :: m3333 + real(pReal), dimension(6,6) :: math_Mandel3333to66 + integer(pInt) :: i,j + + forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) math_Mandel3333to66(i,j) = & + nrmMandel(i)*nrmMandel(j)*m3333(mapMandel(1,i),mapMandel(2,i),mapMandel(1,j),mapMandel(2,j)) + +end function math_Mandel3333to66 + + +!-------------------------------------------------------------------------------------------------- +!> @brief convert Mandel matrix 66 back to symmetric 3333 tensor +!-------------------------------------------------------------------------------------------------- +pure function math_Mandel66to3333(m66) + + implicit none + real(pReal), dimension(3,3,3,3) :: math_Mandel66to3333 + real(pReal), dimension(6,6), intent(in) :: m66 + integer(pInt) :: i,j + + forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) + math_Mandel66to3333(mapMandel(1,i),mapMandel(2,i),mapMandel(1,j),mapMandel(2,j)) = & + invnrmMandel(i)*invnrmMandel(j)*m66(i,j) + math_Mandel66to3333(mapMandel(2,i),mapMandel(1,i),mapMandel(1,j),mapMandel(2,j)) = & + invnrmMandel(i)*invnrmMandel(j)*m66(i,j) + math_Mandel66to3333(mapMandel(1,i),mapMandel(2,i),mapMandel(2,j),mapMandel(1,j)) = & + invnrmMandel(i)*invnrmMandel(j)*m66(i,j) + math_Mandel66to3333(mapMandel(2,i),mapMandel(1,i),mapMandel(2,j),mapMandel(1,j)) = & + invnrmMandel(i)*invnrmMandel(j)*m66(i,j) + end forall + +end function math_Mandel66to3333 + + +!-------------------------------------------------------------------------------------------------- +!> @brief convert Voigt matrix 66 back to symmetric 3333 tensor +!-------------------------------------------------------------------------------------------------- +pure function math_Voigt66to3333(m66) + + implicit none + real(pReal), dimension(3,3,3,3) :: math_Voigt66to3333 + real(pReal), dimension(6,6), intent(in) :: m66 + integer(pInt) :: i,j + + forall (i=1_pInt:6_pInt,j=1_pInt:6_pInt) + math_Voigt66to3333(mapVoigt(1,i),mapVoigt(2,i),mapVoigt(1,j),mapVoigt(2,j)) = & + invnrmVoigt(i)*invnrmVoigt(j)*m66(i,j) + math_Voigt66to3333(mapVoigt(2,i),mapVoigt(1,i),mapVoigt(1,j),mapVoigt(2,j)) = & + invnrmVoigt(i)*invnrmVoigt(j)*m66(i,j) + math_Voigt66to3333(mapVoigt(1,i),mapVoigt(2,i),mapVoigt(2,j),mapVoigt(1,j)) = & + invnrmVoigt(i)*invnrmVoigt(j)*m66(i,j) + math_Voigt66to3333(mapVoigt(2,i),mapVoigt(1,i),mapVoigt(2,j),mapVoigt(1,j)) = & + invnrmVoigt(i)*invnrmVoigt(j)*m66(i,j) + end forall + +end function math_Voigt66to3333 + + +!-------------------------------------------------------------------------------------------------- +!> @brief random quaternion +!-------------------------------------------------------------------------------------------------- +function math_qRand() + + implicit none + real(pReal), dimension(4) :: math_qRand + real(pReal), dimension(3) :: rnd + + call halton(3_pInt,rnd) + math_qRand(1) = cos(2.0_pReal*PI*rnd(1))*sqrt(rnd(3)) + math_qRand(2) = sin(2.0_pReal*PI*rnd(2))*sqrt(1.0_pReal-rnd(3)) + math_qRand(3) = cos(2.0_pReal*PI*rnd(2))*sqrt(1.0_pReal-rnd(3)) + math_qRand(4) = sin(2.0_pReal*PI*rnd(1))*sqrt(rnd(3)) + +end function math_qRand + + +!-------------------------------------------------------------------------------------------------- +!> @brief quaternion multiplication q1xq2 = q12 +!-------------------------------------------------------------------------------------------------- +pure function math_qMul(A,B) + + implicit none + real(pReal), dimension(4) :: math_qMul + real(pReal), dimension(4), intent(in) :: A, B + + math_qMul = [ A(1)*B(1) - A(2)*B(2) - A(3)*B(3) - A(4)*B(4), & + A(1)*B(2) + A(2)*B(1) + A(3)*B(4) - A(4)*B(3), & + A(1)*B(3) - A(2)*B(4) + A(3)*B(1) + A(4)*B(2), & + A(1)*B(4) + A(2)*B(3) - A(3)*B(2) + A(4)*B(1) ] + +end function math_qMul + + +!-------------------------------------------------------------------------------------------------- +!> @brief quaternion dotproduct +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_qDot(A,B) + + implicit none + real(pReal), dimension(4), intent(in) :: A, B + + math_qDot = sum(A*B) + +end function math_qDot + + +!-------------------------------------------------------------------------------------------------- +!> @brief quaternion conjugation +!-------------------------------------------------------------------------------------------------- +pure function math_qConj(Q) + + implicit none + real(pReal), dimension(4) :: math_qConj + real(pReal), dimension(4), intent(in) :: Q + + math_qConj = [Q(1), -Q(2:4)] + +end function math_qConj + + +!-------------------------------------------------------------------------------------------------- +!> @brief quaternion norm +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_qNorm(Q) + + implicit none + real(pReal), dimension(4), intent(in) :: Q + + math_qNorm = norm2(Q) + +end function math_qNorm + + +!-------------------------------------------------------------------------------------------------- +!> @brief quaternion inversion +!-------------------------------------------------------------------------------------------------- +pure function math_qInv(Q) + + implicit none + real(pReal), dimension(4), intent(in) :: Q + real(pReal), dimension(4) :: math_qInv + real(pReal) :: squareNorm + + math_qInv = 0.0_pReal + + squareNorm = math_qDot(Q,Q) + if (abs(squareNorm) > tiny(squareNorm)) & + math_qInv = math_qConj(Q) / squareNorm + +end function math_qInv + + +!-------------------------------------------------------------------------------------------------- +!> @brief action of a quaternion on a vector (rotate vector v with Q) +!-------------------------------------------------------------------------------------------------- +pure function math_qRot(Q,v) + + implicit none + real(pReal), dimension(4), intent(in) :: Q + real(pReal), dimension(3), intent(in) :: v + real(pReal), dimension(3) :: math_qRot + real(pReal), dimension(4,4) :: T + integer(pInt) :: i, j + + do i = 1_pInt,4_pInt + do j = 1_pInt,i + T(i,j) = Q(i) * Q(j) + enddo + enddo + + math_qRot = [-v(1)*(T(3,3)+T(4,4)) + v(2)*(T(3,2)-T(4,1)) + v(3)*(T(4,2)+T(3,1)), & + v(1)*(T(3,2)+T(4,1)) - v(2)*(T(2,2)+T(4,4)) + v(3)*(T(4,3)-T(2,1)), & + v(1)*(T(4,2)-T(3,1)) + v(2)*(T(4,3)+T(2,1)) - v(3)*(T(2,2)+T(3,3))] + + math_qRot = 2.0_pReal * math_qRot + v + +end function math_qRot + + +!-------------------------------------------------------------------------------------------------- +!> @brief Euler angles (in radians) from rotation matrix +!> @details rotation matrix is meant to represent a PASSIVE rotation, +!> composed of INTRINSIC rotations around the axes of the +!> rotating reference frame +!> (see http://en.wikipedia.org/wiki/Euler_angles for definitions) +!-------------------------------------------------------------------------------------------------- +pure function math_RtoEuler(R) + + implicit none + real(pReal), dimension (3,3), intent(in) :: R + real(pReal), dimension(3) :: math_RtoEuler + real(pReal) :: sqhkl, squvw, sqhk + + sqhkl=sqrt(R(1,3)*R(1,3)+R(2,3)*R(2,3)+R(3,3)*R(3,3)) + squvw=sqrt(R(1,1)*R(1,1)+R(2,1)*R(2,1)+R(3,1)*R(3,1)) + sqhk =sqrt(R(1,3)*R(1,3)+R(2,3)*R(2,3)) + +! calculate PHI + math_RtoEuler(2) = acos(math_limit(R(3,3)/sqhkl,-1.0_pReal, 1.0_pReal)) + + if((math_RtoEuler(2) < 1.0e-8_pReal) .or. (pi-math_RtoEuler(2) < 1.0e-8_pReal)) then + math_RtoEuler(3) = 0.0_pReal + math_RtoEuler(1) = acos(math_limit(R(1,1)/squvw, -1.0_pReal, 1.0_pReal)) + if(R(2,1) > 0.0_pReal) math_RtoEuler(1) = 2.0_pReal*pi-math_RtoEuler(1) + else + math_RtoEuler(3) = acos(math_limit(R(2,3)/sqhk, -1.0_pReal, 1.0_pReal)) + if(R(1,3) < 0.0) math_RtoEuler(3) = 2.0_pReal*pi-math_RtoEuler(3) + math_RtoEuler(1) = acos(math_limit(-R(3,2)/sin(math_RtoEuler(2)), -1.0_pReal, 1.0_pReal)) + if(R(3,1) < 0.0) math_RtoEuler(1) = 2.0_pReal*pi-math_RtoEuler(1) + end if + +end function math_RtoEuler + + +!-------------------------------------------------------------------------------------------------- +!> @brief converts a rotation matrix into a quaternion (w+ix+jy+kz) +!> @details math adopted from http://arxiv.org/pdf/math/0701759v1.pdf +!-------------------------------------------------------------------------------------------------- +pure function math_RtoQ(R) + + implicit none + real(pReal), dimension(3,3), intent(in) :: R + real(pReal), dimension(4) :: absQ, math_RtoQ + real(pReal) :: max_absQ + integer, dimension(1) :: largest !no pInt, maxloc returns integer default + + math_RtoQ = 0.0_pReal + + absQ = [+ R(1,1) + R(2,2) + R(3,3), & + + R(1,1) - R(2,2) - R(3,3), & + - R(1,1) + R(2,2) - R(3,3), & + - R(1,1) - R(2,2) + R(3,3)] + 1.0_pReal + + largest = maxloc(absQ) + + largestComponent: select case(largest(1)) + case (1) largestComponent + !1---------------------------------- + math_RtoQ(2) = R(3,2) - R(2,3) + math_RtoQ(3) = R(1,3) - R(3,1) + math_RtoQ(4) = R(2,1) - R(1,2) + + case (2) largestComponent + math_RtoQ(1) = R(3,2) - R(2,3) + !2---------------------------------- + math_RtoQ(3) = R(2,1) + R(1,2) + math_RtoQ(4) = R(1,3) + R(3,1) + + case (3) largestComponent + math_RtoQ(1) = R(1,3) - R(3,1) + math_RtoQ(2) = R(2,1) + R(1,2) + !3---------------------------------- + math_RtoQ(4) = R(3,2) + R(2,3) + + case (4) largestComponent + math_RtoQ(1) = R(2,1) - R(1,2) + math_RtoQ(2) = R(1,3) + R(3,1) + math_RtoQ(3) = R(2,3) + R(3,2) + !4---------------------------------- + end select largestComponent + + max_absQ = 0.5_pReal * sqrt(absQ(largest(1))) + math_RtoQ = math_RtoQ * 0.25_pReal / max_absQ + math_RtoQ(largest(1)) = max_absQ + +end function math_RtoQ + + +!-------------------------------------------------------------------------------------------------- +!> @brief rotation matrix from Euler angles (in radians) +!> @details rotation matrix is meant to represent a PASSIVE rotation, +!> @details composed of INTRINSIC rotations around the axes of the +!> @details rotating reference frame +!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) +!-------------------------------------------------------------------------------------------------- +pure function math_EulerToR(Euler) + + implicit none + real(pReal), dimension(3), intent(in) :: Euler + real(pReal), dimension(3,3) :: math_EulerToR + real(pReal) c1, c, c2, s1, s, s2 + + C1 = cos(Euler(1)) + C = cos(Euler(2)) + C2 = cos(Euler(3)) + S1 = sin(Euler(1)) + S = sin(Euler(2)) + S2 = sin(Euler(3)) + + math_EulerToR(1,1)=C1*C2-S1*S2*C + math_EulerToR(1,2)=-C1*S2-S1*C2*C + math_EulerToR(1,3)=S1*S + math_EulerToR(2,1)=S1*C2+C1*S2*C + math_EulerToR(2,2)=-S1*S2+C1*C2*C + math_EulerToR(2,3)=-C1*S + math_EulerToR(3,1)=S2*S + math_EulerToR(3,2)=C2*S + math_EulerToR(3,3)=C + + math_EulerToR = transpose(math_EulerToR) ! convert to passive rotation + +end function math_EulerToR + + +!-------------------------------------------------------------------------------------------------- +!> @brief quaternion (w+ix+jy+kz) from 3-1-3 Euler angles (in radians) +!> @details quaternion is meant to represent a PASSIVE rotation, +!> @details composed of INTRINSIC rotations around the axes of the +!> @details rotating reference frame +!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) +!-------------------------------------------------------------------------------------------------- +pure function math_EulerToQ(eulerangles) + + implicit none + real(pReal), dimension(3), intent(in) :: eulerangles + real(pReal), dimension(4) :: math_EulerToQ + real(pReal), dimension(3) :: halfangles + real(pReal) :: c, s + + halfangles = 0.5_pReal * eulerangles + + c = cos(halfangles(2)) + s = sin(halfangles(2)) + + math_EulerToQ= [cos(halfangles(1)+halfangles(3)) * c, & + cos(halfangles(1)-halfangles(3)) * s, & + sin(halfangles(1)-halfangles(3)) * s, & + sin(halfangles(1)+halfangles(3)) * c ] + math_EulerToQ = math_qConj(math_EulerToQ) ! convert to passive rotation + +end function math_EulerToQ + + +!-------------------------------------------------------------------------------------------------- +!> @brief rotation matrix from axis and angle (in radians) +!> @details rotation matrix is meant to represent a ACTIVE rotation +!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) +!> @details formula for active rotation taken from http://mathworld.wolfram.com/RodriguesRotationFormula.html +!-------------------------------------------------------------------------------------------------- +pure function math_axisAngleToR(axis,omega) + + implicit none + real(pReal), dimension(3,3) :: math_axisAngleToR + real(pReal), dimension(3), intent(in) :: axis + real(pReal), intent(in) :: omega + real(pReal), dimension(3) :: axisNrm + real(pReal) :: norm,s,c,c1 + + norm = sqrt(math_mul3x3(axis,axis)) + if (norm > 1.0e-8_pReal) then ! non-zero rotation + axisNrm = axis/norm ! normalize axis to be sure + + s = sin(omega) + c = cos(omega) + c1 = 1.0_pReal - c + + math_axisAngleToR(1,1) = c + c1*axisNrm(1)**2.0_pReal + math_axisAngleToR(1,2) = -s*axisNrm(3) + c1*axisNrm(1)*axisNrm(2) + math_axisAngleToR(1,3) = s*axisNrm(2) + c1*axisNrm(1)*axisNrm(3) + + math_axisAngleToR(2,1) = s*axisNrm(3) + c1*axisNrm(2)*axisNrm(1) + math_axisAngleToR(2,2) = c + c1*axisNrm(2)**2.0_pReal + math_axisAngleToR(2,3) = -s*axisNrm(1) + c1*axisNrm(2)*axisNrm(3) + + math_axisAngleToR(3,1) = -s*axisNrm(2) + c1*axisNrm(3)*axisNrm(1) + math_axisAngleToR(3,2) = s*axisNrm(1) + c1*axisNrm(3)*axisNrm(2) + math_axisAngleToR(3,3) = c + c1*axisNrm(3)**2.0_pReal + else + math_axisAngleToR = math_I3 + endif + +end function math_axisAngleToR + + +!-------------------------------------------------------------------------------------------------- +!> @brief rotation matrix from axis and angle (in radians) +!> @details rotation matrix is meant to represent a PASSIVE rotation +!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) +!-------------------------------------------------------------------------------------------------- +pure function math_EulerAxisAngleToR(axis,omega) + + implicit none + real(pReal), dimension(3,3) :: math_EulerAxisAngleToR + real(pReal), dimension(3), intent(in) :: axis + real(pReal), intent(in) :: omega + + math_EulerAxisAngleToR = transpose(math_axisAngleToR(axis,omega)) ! convert to passive rotation + +end function math_EulerAxisAngleToR + + +!-------------------------------------------------------------------------------------------------- +!> @brief quaternion (w+ix+jy+kz) from Euler axis and angle (in radians) +!> @details quaternion is meant to represent a PASSIVE rotation +!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) +!> @details formula for active rotation taken from +!> @details http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29#Rodrigues_parameters +!-------------------------------------------------------------------------------------------------- +pure function math_EulerAxisAngleToQ(axis,omega) + + implicit none + real(pReal), dimension(4) :: math_EulerAxisAngleToQ + real(pReal), dimension(3), intent(in) :: axis + real(pReal), intent(in) :: omega + + math_EulerAxisAngleToQ = math_qConj(math_axisAngleToQ(axis,omega)) ! convert to passive rotation + +end function math_EulerAxisAngleToQ + + +!-------------------------------------------------------------------------------------------------- +!> @brief quaternion (w+ix+jy+kz) from axis and angle (in radians) +!> @details quaternion is meant to represent an ACTIVE rotation +!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) +!> @details formula for active rotation taken from +!> @details http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29#Rodrigues_parameters +!-------------------------------------------------------------------------------------------------- +pure function math_axisAngleToQ(axis,omega) + + implicit none + real(pReal), dimension(4) :: math_axisAngleToQ + real(pReal), dimension(3), intent(in) :: axis + real(pReal), intent(in) :: omega + real(pReal), dimension(3) :: axisNrm + real(pReal) :: norm + + norm = sqrt(math_mul3x3(axis,axis)) + rotation: if (norm > 1.0e-8_pReal) then + axisNrm = axis/norm ! normalize axis to be sure + math_axisAngleToQ = [cos(0.5_pReal*omega), sin(0.5_pReal*omega) * axisNrm(1:3)] + else rotation + math_axisAngleToQ = [1.0_pReal,0.0_pReal,0.0_pReal,0.0_pReal] + endif rotation + +end function math_axisAngleToQ + + +!-------------------------------------------------------------------------------------------------- +!> @brief orientation matrix from quaternion (w+ix+jy+kz) +!> @details taken from http://arxiv.org/pdf/math/0701759v1.pdf +!> @details see also http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions +!-------------------------------------------------------------------------------------------------- +pure function math_qToR(q) + + implicit none + real(pReal), dimension(4), intent(in) :: q + real(pReal), dimension(3,3) :: math_qToR, T,S + integer(pInt) :: i, j + + forall (i = 1_pInt:3_pInt, j = 1_pInt:3_pInt) & + T(i,j) = q(i+1_pInt) * q(j+1_pInt) + + S = reshape( [0.0_pReal, -q(4), q(3), & + q(4), 0.0_pReal, -q(2), & + -q(3), q(2), 0.0_pReal],[3,3]) ! notation is transposed + + math_qToR = (2.0_pReal * q(1)*q(1) - 1.0_pReal) * math_I3 & + + 2.0_pReal * T - 2.0_pReal * q(1) * S + +end function math_qToR + + +!-------------------------------------------------------------------------------------------------- +!> @brief 3-1-3 Euler angles (in radians) from quaternion (w+ix+jy+kz) +!> @details quaternion is meant to represent a PASSIVE rotation, +!> @details composed of INTRINSIC rotations around the axes of the +!> @details rotating reference frame +!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) +!-------------------------------------------------------------------------------------------------- +pure function math_qToEuler(qPassive) + + implicit none + real(pReal), dimension(4), intent(in) :: qPassive + real(pReal), dimension(4) :: q + real(pReal), dimension(3) :: math_qToEuler + + q = math_qConj(qPassive) ! convert to active rotation, since formulas are defined for active rotations + + math_qToEuler(2) = acos(1.0_pReal-2.0_pReal*(q(2)*q(2)+q(3)*q(3))) + + if (abs(math_qToEuler(2)) < 1.0e-6_pReal) then + math_qToEuler(1) = sign(2.0_pReal*acos(math_limit(q(1),-1.0_pReal, 1.0_pReal)),q(4)) + math_qToEuler(3) = 0.0_pReal + else + math_qToEuler(1) = atan2(q(1)*q(3)+q(2)*q(4), q(1)*q(2)-q(3)*q(4)) + math_qToEuler(3) = atan2(-q(1)*q(3)+q(2)*q(4), q(1)*q(2)+q(3)*q(4)) + endif + + math_qToEuler = merge(math_qToEuler + [2.0_pReal*PI, PI, 2.0_pReal*PI], & ! ensure correct range + math_qToEuler, math_qToEuler<0.0_pReal) + +end function math_qToEuler + + +!-------------------------------------------------------------------------------------------------- +!> @brief axis-angle (x, y, z, ang in radians) from quaternion (w+ix+jy+kz) +!> @details quaternion is meant to represent an ACTIVE rotation +!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) +!> @details formula for active rotation taken from +!> @details http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29#Rodrigues_parameters +!-------------------------------------------------------------------------------------------------- +pure function math_qToAxisAngle(Q) + + implicit none + real(pReal), dimension(4), intent(in) :: Q + real(pReal) :: halfAngle, sinHalfAngle + real(pReal), dimension(4) :: math_qToAxisAngle + + halfAngle = acos(max(-1.0_pReal, min(1.0_pReal, Q(1)))) ! limit to [-1,1] --> 0 to 180 deg + sinHalfAngle = sin(halfAngle) + + if (sinHalfAngle <= 1.0e-4_pReal) then ! very small rotation angle? + math_qToAxisAngle = 0.0_pReal + else + math_qToAxisAngle= [ Q(2:4)/sinHalfAngle, halfAngle*2.0_pReal] + endif + +end function math_qToAxisAngle + + +!-------------------------------------------------------------------------------------------------- +!> @brief Euler axis-angle (x, y, z, ang in radians) from quaternion (w+ix+jy+kz) +!> @details quaternion is meant to represent a PASSIVE rotation +!> @details (see http://en.wikipedia.org/wiki/Euler_angles for definitions) +!-------------------------------------------------------------------------------------------------- +pure function math_qToEulerAxisAngle(qPassive) + + implicit none + real(pReal), dimension(4), intent(in) :: qPassive + real(pReal), dimension(4) :: q + real(pReal), dimension(4) :: math_qToEulerAxisAngle + + q = math_qConj(qPassive) ! convert to active rotation + math_qToEulerAxisAngle = math_qToAxisAngle(q) + +end function math_qToEulerAxisAngle + + +!-------------------------------------------------------------------------------------------------- +!> @brief Rodrigues vector (x, y, z) from unit quaternion (w+ix+jy+kz) +!-------------------------------------------------------------------------------------------------- +pure function math_qToRodrig(Q) + use prec, only: & + DAMASK_NaN, & + tol_math_check + + implicit none + real(pReal), dimension(4), intent(in) :: Q + real(pReal), dimension(3) :: math_qToRodrig + + math_qToRodrig = merge(Q(2:4)/Q(1),DAMASK_NaN,abs(Q(1)) > tol_math_check) ! NaN for 180 deg since Rodrig is unbound + +end function math_qToRodrig + + +!-------------------------------------------------------------------------------------------------- +!> @brief misorientation angle between two sets of Euler angles +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_EulerMisorientation(EulerA,EulerB) + + implicit none + real(pReal), dimension(3), intent(in) :: EulerA,EulerB + real(pReal), dimension(3,3) :: r + real(pReal) :: tr + + r = math_mul33x33(math_EulerToR(EulerB),transpose(math_EulerToR(EulerA))) + + tr = (math_trace33(r)-1.0_pReal)*0.4999999_pReal + math_EulerMisorientation = abs(0.5_pReal*PI-asin(tr)) + +end function math_EulerMisorientation + + +!-------------------------------------------------------------------------------------------------- +!> @brief draw a random sample from Euler space +!-------------------------------------------------------------------------------------------------- +function math_sampleRandomOri() + + implicit none + real(pReal), dimension(3) :: math_sampleRandomOri, rnd + + call halton(3_pInt,rnd) + math_sampleRandomOri = [rnd(1)*2.0_pReal*PI, & + acos(2.0_pReal*rnd(2)-1.0_pReal), & + rnd(3)*2.0_pReal*PI] + +end function math_sampleRandomOri + + +!-------------------------------------------------------------------------------------------------- +!> @brief draw a random sample from Gauss component with noise (in radians) half-width +!-------------------------------------------------------------------------------------------------- +function math_sampleGaussOri(center,noise) + use prec, only: & + tol_math_check + + implicit none + real(pReal), intent(in) :: noise + real(pReal), dimension(3), intent(in) :: center + real(pReal) :: cosScatter,scatter + real(pReal), dimension(3) :: math_sampleGaussOri, disturb + real(pReal), dimension(3), parameter :: ORIGIN = [0.0_pReal,0.0_pReal,0.0_pReal] + real(pReal), dimension(5) :: rnd + integer(pInt) :: i + + if (abs(noise) < tol_math_check) then + math_sampleGaussOri = center + return + endif + +! Helming uses different distribution with Bessel functions +! therefore the gauss scatter width has to be scaled differently + scatter = 0.95_pReal * noise + cosScatter = cos(scatter) + + do + call halton(5_pInt,rnd) + forall (i=1_pInt:3_pInt) rnd(i) = 2.0_pReal*rnd(i)-1.0_pReal ! expand 1:3 to range [-1,+1] + disturb = [ scatter * rnd(1), & ! phi1 + sign(1.0_pReal,rnd(2))*acos(cosScatter+(1.0_pReal-cosScatter)*rnd(4)), & ! Phi + scatter * rnd(2)] ! phi2 + if (rnd(5) <= exp(-1.0_pReal*(math_EulerMisorientation(ORIGIN,disturb)/scatter)**2_pReal)) exit + enddo + + math_sampleGaussOri = math_RtoEuler(math_mul33x33(math_EulerToR(disturb),math_EulerToR(center))) + +end function math_sampleGaussOri + + +!-------------------------------------------------------------------------------------------------- +!> @brief draw a random sample from Fiber component with noise (in radians) +!-------------------------------------------------------------------------------------------------- +function math_sampleFiberOri(alpha,beta,noise) + use prec, only: & + tol_math_check + + implicit none + real(pReal), dimension(3) :: math_sampleFiberOri, fiberInC,fiberInS,axis + real(pReal), dimension(2), intent(in) :: alpha,beta + real(pReal), dimension(6) :: rnd + real(pReal), dimension(3,3) :: oRot,fRot,pRot + real(pReal) :: noise, scatter, cos2Scatter, angle + integer(pInt), dimension(2,3), parameter :: ROTMAP = reshape([2_pInt,3_pInt,& + 3_pInt,1_pInt,& + 1_pInt,2_pInt],[2,3]) + integer(pInt) :: i + +! Helming uses different distribution with Bessel functions +! therefore the gauss scatter width has to be scaled differently + scatter = 0.95_pReal * noise + cos2Scatter = cos(2.0_pReal*scatter) + +! fiber axis in crystal coordinate system + fiberInC = [ sin(alpha(1))*cos(alpha(2)) , & + sin(alpha(1))*sin(alpha(2)), & + cos(alpha(1))] +! fiber axis in sample coordinate system + fiberInS = [ sin(beta(1))*cos(beta(2)), & + sin(beta(1))*sin(beta(2)), & + cos(beta(1))] + +! ---# rotation matrix from sample to crystal system #--- + angle = -acos(dot_product(fiberInC,fiberInS)) + if(abs(angle) > tol_math_check) then +! rotation axis between sample and crystal system (cross product) + forall(i=1_pInt:3_pInt) axis(i) = fiberInC(ROTMAP(1,i))*fiberInS(ROTMAP(2,i))-fiberInC(ROTMAP(2,i))*fiberInS(ROTMAP(1,i)) + oRot = math_EulerAxisAngleToR(math_crossproduct(fiberInC,fiberInS),angle) + else + oRot = math_I3 + end if + +! ---# rotation matrix about fiber axis (random angle) #--- + do + call halton(6_pInt,rnd) + fRot = math_EulerAxisAngleToR(fiberInS,rnd(1)*2.0_pReal*pi) + +! ---# rotation about random axis perpend to fiber #--- +! random axis pependicular to fiber axis + axis(1:2) = rnd(2:3) + if (abs(fiberInS(3)) > tol_math_check) then + axis(3)=-(axis(1)*fiberInS(1)+axis(2)*fiberInS(2))/fiberInS(3) + else if(abs(fiberInS(2)) > tol_math_check) then + axis(3)=axis(2) + axis(2)=-(axis(1)*fiberInS(1)+axis(3)*fiberInS(3))/fiberInS(2) + else if(abs(fiberInS(1)) > tol_math_check) then + axis(3)=axis(1) + axis(1)=-(axis(2)*fiberInS(2)+axis(3)*fiberInS(3))/fiberInS(1) + end if + +! scattered rotation angle + if (noise > 0.0_pReal) then + angle = acos(cos2Scatter+(1.0_pReal-cos2Scatter)*rnd(4)) + if (rnd(5) <= exp(-1.0_pReal*(angle/scatter)**2.0_pReal)) exit + else + angle = 0.0_pReal + exit + end if + enddo + if (rnd(6) <= 0.5) angle = -angle + + pRot = math_EulerAxisAngleToR(axis,angle) + +! ---# apply the three rotations #--- + math_sampleFiberOri = math_RtoEuler(math_mul33x33(pRot,math_mul33x33(fRot,oRot))) + +end function math_sampleFiberOri + + +!-------------------------------------------------------------------------------------------------- +!> @brief draw a random sample from Gauss variable +!-------------------------------------------------------------------------------------------------- +real(pReal) function math_sampleGaussVar(meanvalue, stddev, width) + use prec, only: & + tol_math_check + + implicit none + real(pReal), intent(in) :: meanvalue, & ! meanvalue of gauss distribution + stddev ! standard deviation of gauss distribution + real(pReal), intent(in), optional :: width ! width of considered values as multiples of standard deviation + real(pReal), dimension(2) :: rnd ! random numbers + real(pReal) :: scatter, & ! normalized scatter around meanvalue + myWidth + + if (abs(stddev) < tol_math_check) then + math_sampleGaussVar = meanvalue + return + endif + + myWidth = merge(width,3.0_pReal,present(width)) ! use +-3*sigma as default value for scatter if not given + + do + call halton(2_pInt, rnd) + scatter = myWidth * (2.0_pReal * rnd(1) - 1.0_pReal) + if (rnd(2) <= exp(-0.5_pReal * scatter ** 2.0_pReal)) exit ! test if scattered value is drawn + enddo + + math_sampleGaussVar = scatter * stddev + +end function math_sampleGaussVar + + +!-------------------------------------------------------------------------------------------------- +!> @brief symmetrically equivalent Euler angles for given sample symmetry 1:triclinic, 2:monoclinic, 4:orthotropic +!-------------------------------------------------------------------------------------------------- +pure function math_symmetricEulers(sym,Euler) + + implicit none + integer(pInt), intent(in) :: sym + real(pReal), dimension(3), intent(in) :: Euler + real(pReal), dimension(3,3) :: math_symmetricEulers + integer(pInt) :: i,j + + math_symmetricEulers(1,1) = PI+Euler(1) + math_symmetricEulers(2,1) = Euler(2) + math_symmetricEulers(3,1) = Euler(3) + + math_symmetricEulers(1,2) = PI-Euler(1) + math_symmetricEulers(2,2) = PI-Euler(2) + math_symmetricEulers(3,2) = PI+Euler(3) + + math_symmetricEulers(1,3) = 2.0_pReal*PI-Euler(1) + math_symmetricEulers(2,3) = PI-Euler(2) + math_symmetricEulers(3,3) = PI+Euler(3) + + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt) math_symmetricEulers(j,i) = modulo(math_symmetricEulers(j,i),2.0_pReal*pi) + + select case (sym) + case (4_pInt) ! all done + + case (2_pInt) ! return only first + math_symmetricEulers(1:3,2:3) = 0.0_pReal + + case default ! return blank + math_symmetricEulers = 0.0_pReal + end select + +end function math_symmetricEulers + + +!-------------------------------------------------------------------------------------------------- +!> @brief eigenvalues and eigenvectors of symmetric matrix m +!-------------------------------------------------------------------------------------------------- +subroutine math_spectralDecompositionSym(m,values,vectors,error) + + implicit none + real(pReal), dimension(:,:), intent(in) :: m + real(pReal), dimension(size(m,1)), intent(out) :: values + real(pReal), dimension(size(m,1),size(m,1)), intent(out) :: vectors + logical, intent(out) :: error + + integer(pInt) :: info + real(pReal), dimension((64+2)*size(m,1)) :: work ! block size of 64 taken from http://www.netlib.org/lapack/double/dsyev.f + + vectors = M ! copy matrix to input (doubles as output) array +#if(FLOAT==8) + call dsyev('V','U',size(m,1),vectors,size(m,1),values,work,(64+2)*size(m,1),info) +#elif(FLOAT==4) + call ssyev('V','U',size(m,1),vectors,size(m,1),values,work,(64+2)*size(m,1),info) +#endif + error = (info == 0_pInt) + +end subroutine math_spectralDecompositionSym + + +!-------------------------------------------------------------------------------------------------- +!> @brief eigenvalues and eigenvectors of symmetric 33 matrix m using an analytical expression +!> and the general LAPACK powered version for arbritrary sized matrices as fallback +!> @author Joachim Kopp, Max–Planck–Institut für Kernphysik, Heidelberg (Copyright (C) 2006) +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @details See http://arxiv.org/abs/physics/0610206 (DSYEVH3) +!-------------------------------------------------------------------------------------------------- +subroutine math_spectralDecompositionSym33(m,values,vectors) + + implicit none + real(pReal), dimension(3,3),intent(in) :: m + real(pReal), dimension(3), intent(out) :: values + real(pReal), dimension(3,3),intent(out) :: vectors + real(pReal) :: T, U, norm, threshold + logical :: error + + values = math_eigenvaluesSym33(m) + + vectors(1:3,2) = [ m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2), & + m(1, 3) * m(1, 2) - m(2, 3) * m(1, 1), & + m(1, 2)**2_pInt] + + T = maxval(abs(values)) + U = max(T, T**2_pInt) + threshold = sqrt(5.0e-14_pReal * U**2_pInt) + +! Calculate first eigenvector by the formula v[0] = (m - lambda[0]).e1 x (m - lambda[0]).e2 + vectors(1:3,1) = [ vectors(1,2) + m(1, 3) * values(1), & + vectors(2,2) + m(2, 3) * values(1), & + (m(1,1) - values(1)) * (m(2,2) - values(1)) - vectors(3,2)] + norm = norm2(vectors(1:3, 1)) + + fallback1: if(norm < threshold) then + call math_spectralDecompositionSym(m,values,vectors,error) + return + endif fallback1 + + vectors(1:3,1) = vectors(1:3, 1) / norm + +! Calculate second eigenvector by the formula v[1] = (m - lambda[1]).e1 x (m - lambda[1]).e2 + vectors(1:3,2) = [ vectors(1,2) + m(1, 3) * values(2), & + vectors(2,2) + m(2, 3) * values(2), & + (m(1,1) - values(2)) * (m(2,2) - values(2)) - vectors(3,2)] + norm = norm2(vectors(1:3, 2)) + + fallback2: if(norm < threshold) then + call math_spectralDecompositionSym(m,values,vectors,error) + return + endif fallback2 + vectors(1:3,2) = vectors(1:3, 2) / norm + +! Calculate third eigenvector according to v[2] = v[0] x v[1] + vectors(1:3,3) = math_crossproduct(vectors(1:3,1),vectors(1:3,2)) + +end subroutine math_spectralDecompositionSym33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief rotational part from polar decomposition of tensor m +!-------------------------------------------------------------------------------------------------- +function math_rotationalPart33(m) + use IO, only: & + IO_warning + + implicit none + real(pReal), intent(in), dimension(3,3) :: m + real(pReal), dimension(3,3) :: math_rotationalPart33 + real(pReal), dimension(3,3) :: U, mTm , Uinv, EB + real(pReal), dimension(3) :: EV + + mTm = math_mul33x33(math_transpose33(m),m) + call math_spectralDecompositionSym33(mTm,EV,EB) + + U = sqrt(EV(1)) * math_tensorproduct33(EB(1:3,1),EB(1:3,1)) & + + sqrt(EV(2)) * math_tensorproduct33(EB(1:3,2),EB(1:3,2)) & + + sqrt(EV(3)) * math_tensorproduct33(EB(1:3,3),EB(1:3,3)) + + Uinv = math_inv33(U) + if (all(abs(Uinv) <= tiny(Uinv))) then ! math_inv33 returns zero when failed, avoid floating point equality comparison + math_rotationalPart33 = math_I3 + call IO_warning(650_pInt) + else + math_rotationalPart33 = math_mul33x33(m,Uinv) + endif + +end function math_rotationalPart33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief Eigenvalues of symmetric matrix m +! will return NaN on error +!-------------------------------------------------------------------------------------------------- +function math_eigenvaluesSym(m) + use prec, only: & + DAMASK_NaN + + implicit none + real(pReal), dimension(:,:), intent(in) :: m + real(pReal), dimension(size(m,1)) :: math_eigenvaluesSym + real(pReal), dimension(size(m,1),size(m,1)) :: vectors + + integer(pInt) :: info + real(pReal), dimension((64+2)*size(m,1)) :: work ! block size of 64 taken from http://www.netlib.org/lapack/double/dsyev.f + + vectors = m ! copy matrix to input (doubles as output) array +#if(FLOAT==8) + call dsyev('N','U',size(m,1),vectors,size(m,1),math_eigenvaluesSym,work,(64+2)*size(m,1),info) +#elif(FLOAT==4) + call ssyev('N','U',size(m,1),vectors,size(m,1),math_eigenvaluesSym,work,(64+2)*size(m,1),info) +#endif + if (info /= 0_pInt) math_eigenvaluesSym = DAMASK_NaN + +end function math_eigenvaluesSym + + +!-------------------------------------------------------------------------------------------------- +!> @brief eigenvalues of symmetric 33 matrix m using an analytical expression +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @details similar to http://arxiv.org/abs/physics/0610206 (DSYEVC3) +!> but apparently more stable solution and has general LAPACK powered version for arbritrary sized +!> matrices as fallback +!-------------------------------------------------------------------------------------------------- +function math_eigenvaluesSym33(m) + + implicit none + real(pReal), intent(in), dimension(3,3) :: m + real(pReal), dimension(3) :: math_eigenvaluesSym33,invariants + real(pReal) :: P, Q, rho, phi + real(pReal), parameter :: TOL=1.e-14_pReal + + invariants = math_invariantsSym33(m) ! invariants are coefficients in characteristic polynomial apart for the sign of c0 and c2 in http://arxiv.org/abs/physics/0610206 + + P = invariants(2)-invariants(1)**2.0_pReal/3.0_pReal ! different from http://arxiv.org/abs/physics/0610206 (this formulation was in DAMASK) + Q = -2.0_pReal/27.0_pReal*invariants(1)**3.0_pReal+product(invariants(1:2))/3.0_pReal-invariants(3)! different from http://arxiv.org/abs/physics/0610206 (this formulation was in DAMASK) + + if(any(abs([p,q]) < TOL)) then + math_eigenvaluesSym33 = math_eigenvaluesSym(m) + else + rho=sqrt(-3.0_pReal*P**3.0_pReal)/9.0_pReal + phi=acos(math_limit(-Q/rho*0.5_pReal,-1.0_pReal,1.0_pReal)) + math_eigenvaluesSym33 = 2.0_pReal*rho**(1.0_pReal/3.0_pReal)* & + [cos(phi/3.0_pReal), & + cos((phi+2.0_pReal*PI)/3.0_pReal), & + cos((phi+4.0_pReal*PI)/3.0_pReal) & + ] + invariants(1)/3.0_pReal + endif +end function math_eigenvaluesSym33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief invariants of symmetrix 33 matrix m +!-------------------------------------------------------------------------------------------------- +pure function math_invariantsSym33(m) + + implicit none + real(pReal), dimension(3,3), intent(in) :: m + real(pReal), dimension(3) :: math_invariantsSym33 + + math_invariantsSym33(1) = math_trace33(m) + math_invariantsSym33(2) = m(1,1)*m(2,2) + m(1,1)*m(3,3) + m(2,2)*m(3,3) & + -(m(1,2)**2 + m(1,3)**2 + m(2,3)**2) + math_invariantsSym33(3) = math_detSym33(m) + +end function math_invariantsSym33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief computes the next element in the Halton sequence. +!> @author John Burkardt +!-------------------------------------------------------------------------------------------------- +subroutine halton(ndim, r) + + implicit none + integer(pInt), intent(in) :: ndim !< dimension of the element + real(pReal), intent(out), dimension(ndim) :: r !< next element of the current Halton sequence + integer(pInt), dimension(ndim) :: base + integer(pInt) :: seed + integer(pInt), dimension(1) :: value_halton + + call halton_memory ('GET', 'SEED', 1_pInt, value_halton) + seed = value_halton(1) + + call halton_memory ('GET', 'BASE', ndim, base) + + call i_to_halton (seed, base, ndim, r) + + value_halton(1) = 1_pInt + call halton_memory ('INC', 'SEED', 1_pInt, value_halton) + +end subroutine halton + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets or returns quantities associated with the Halton sequence. +!> @details If action_halton is 'SET' and action_halton is 'BASE', then NDIM is input, and +!> @details is the number of entries in value_halton to be put into BASE. +!> @details If action_halton is 'SET', then on input, value_halton contains values to be assigned +!> @details to the internal variable. +!> @details If action_halton is 'GET', then on output, value_halton contains the values of +!> @details the specified internal variable. +!> @details If action_halton is 'INC', then on input, value_halton contains the increment to +!> @details be added to the specified internal variable. +!> @author John Burkardt +!-------------------------------------------------------------------------------------------------- +subroutine halton_memory (action_halton, name_halton, ndim, value_halton) + + implicit none + character(len = *), intent(in) :: & + action_halton, & !< desired action: GET the value of a particular quantity, SET the value of a particular quantity, INC the value of a particular quantity (only for SEED) + name_halton !< name of the quantity: BASE: Halton base(s), NDIM: spatial dimension, SEED: current Halton seed + integer(pInt), dimension(*), intent(inout) :: value_halton + integer(pInt), allocatable, save, dimension(:) :: base + logical, save :: first_call = .true. + integer(pInt), intent(in) :: ndim !< dimension of the quantity + integer(pInt):: i + integer(pInt), save :: ndim_save = 0_pInt, seed = 1_pInt + + if (first_call) then + ndim_save = 1_pInt + allocate(base(ndim_save)) + base(1) = 2_pInt + first_call = .false. + endif + +!-------------------------------------------------------------------------------------------------- +! Set + if(action_halton(1:1) == 'S' .or. action_halton(1:1) == 's') then + + if(name_halton(1:1) == 'B' .or. name_halton(1:1) == 'b') then + + if(ndim_save /= ndim) then + deallocate(base) + ndim_save = ndim + allocate(base(ndim_save)) + endif + + base(1:ndim) = value_halton(1:ndim) + + elseif(name_halton(1:1) == 'N' .or. name_halton(1:1) == 'n') then + + if(ndim_save /= value_halton(1)) then + deallocate(base) + ndim_save = value_halton(1) + allocate(base(ndim_save)) + do i = 1_pInt, ndim_save + base(i) = prime (i) + enddo + else + ndim_save = value_halton(1) + endif + elseif(name_halton(1:1) == 'S' .or. name_halton(1:1) == 's') then + seed = value_halton(1) + endif + +!-------------------------------------------------------------------------------------------------- +! Get + elseif(action_halton(1:1) == 'G' .or. action_halton(1:1) == 'g') then + if(name_halton(1:1) == 'B' .or. name_halton(1:1) == 'b') then + if(ndim /= ndim_save) then + deallocate(base) + ndim_save = ndim + allocate(base(ndim_save)) + do i = 1_pInt, ndim_save + base(i) = prime(i) + enddo + endif + value_halton(1:ndim_save) = base(1:ndim_save) + elseif(name_halton(1:1) == 'N' .or. name_halton(1:1) == 'n') then + value_halton(1) = ndim_save + elseif(name_halton(1:1) == 'S' .or. name_halton(1:1) == 's') then + value_halton(1) = seed + endif + +!-------------------------------------------------------------------------------------------------- +! Increment + elseif(action_halton(1:1) == 'I' .or. action_halton(1:1) == 'i') then + if(name_halton(1:1) == 'S' .or. name_halton(1:1) == 's') then + seed = seed + value_halton(1) + end if + endif + +end subroutine halton_memory + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the dimension for a Halton sequence +!> @author John Burkardt +!-------------------------------------------------------------------------------------------------- +subroutine halton_ndim_set (ndim) + + implicit none + integer(pInt), intent(in) :: ndim !< dimension of the Halton vectors + integer(pInt) :: value_halton(1) + + value_halton(1) = ndim + call halton_memory ('SET', 'NDIM', 1_pInt, value_halton) + +end subroutine halton_ndim_set + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the seed for the Halton sequence. +!> @details Calling HALTON repeatedly returns the elements of the Halton sequence in order, +!> @details starting with element number 1. +!> @details An internal counter, called SEED, keeps track of the next element to return. Each time +!> @details is computed, and then SEED is incremented by 1. +!> @details To restart the Halton sequence, it is only necessary to reset SEED to 1. It might also +!> @details be desirable to reset SEED to some other value. This routine allows the user to specify +!> @details any value of SEED. +!> @details The default value of SEED is 1, which restarts the Halton sequence. +!> @author John Burkardt +!-------------------------------------------------------------------------------------------------- +subroutine halton_seed_set(seed) + implicit none + + integer(pInt), parameter :: NDIM = 1_pInt + integer(pInt), intent(in) :: seed !< seed for the Halton sequence. + integer(pInt) :: value_halton(ndim) + + value_halton(1) = seed + call halton_memory ('SET', 'SEED', NDIM, value_halton) + +end subroutine halton_seed_set + + +!-------------------------------------------------------------------------------------------------- +!> @brief computes an element of a Halton sequence. +!> @details Only the absolute value of SEED is considered. SEED = 0 is allowed, and returns R = 0. +!> @details Halton Bases should be distinct prime numbers. This routine only checks that each base +!> @details is greater than 1. +!> @details Reference: +!> @details J.H. Halton: On the efficiency of certain quasi-random sequences of points in evaluating +!> @details multi-dimensional integrals, Numerische Mathematik, Volume 2, pages 84-90, 1960. +!> @author John Burkardt +!-------------------------------------------------------------------------------------------------- +subroutine i_to_halton (seed, base, ndim, r) + use IO, only: & + IO_error + + implicit none + integer(pInt), intent(in) :: ndim !< dimension of the sequence + integer(pInt), intent(in), dimension(ndim) :: base !< Halton bases + real(pReal), dimension(ndim) :: base_inv + integer(pInt), dimension(ndim) :: digit + real(pReal), dimension(ndim), intent(out) ::r !< the SEED-th element of the Halton sequence for the given bases + integer(pInt) , intent(in):: seed !< index of the desired element + integer(pInt), dimension(ndim) :: seed2 + + seed2(1:ndim) = abs(seed) + + r(1:ndim) = 0.0_pReal + + if (any (base(1:ndim) <= 1_pInt)) call IO_error(error_ID=405_pInt) + + base_inv(1:ndim) = 1.0_pReal / real (base(1:ndim), pReal) + + do while ( any ( seed2(1:ndim) /= 0_pInt) ) + digit(1:ndim) = mod ( seed2(1:ndim), base(1:ndim)) + r(1:ndim) = r(1:ndim) + real ( digit(1:ndim), pReal) * base_inv(1:ndim) + base_inv(1:ndim) = base_inv(1:ndim) / real ( base(1:ndim), pReal) + seed2(1:ndim) = seed2(1:ndim) / base(1:ndim) + enddo + +end subroutine i_to_halton + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns any of the first 1500 prime numbers. +!> @details n <= 0 returns 1500, the index of the largest prime (12553) available. +!> @details n = 0 is legal, returning PRIME = 1. +!> @details Reference: +!> @details Milton Abramowitz and Irene Stegun: Handbook of Mathematical Functions, +!> @details US Department of Commerce, 1964, pages 870-873. +!> @details Daniel Zwillinger: CRC Standard Mathematical Tables and Formulae, +!> @details 30th Edition, CRC Press, 1996, pages 95-98. +!> @author John Burkardt +!-------------------------------------------------------------------------------------------------- +integer(pInt) function prime(n) + use IO, only: & + IO_error + + implicit none + integer(pInt), intent(in) :: n !< index of the desired prime number + integer(pInt), parameter :: PRIME_MAX = 1500_pInt + integer(pInt), save :: icall = 0_pInt + integer(pInt), save, dimension(PRIME_MAX) :: npvec + + if (icall == 0_pInt) then + icall = 1_pInt + + npvec = [& + 2_pInt, 3_pInt, 5_pInt, 7_pInt, 11_pInt, 13_pInt, 17_pInt, 19_pInt, 23_pInt, 29_pInt, & + 31_pInt, 37_pInt, 41_pInt, 43_pInt, 47_pInt, 53_pInt, 59_pInt, 61_pInt, 67_pInt, 71_pInt, & + 73_pInt, 79_pInt, 83_pInt, 89_pInt, 97_pInt, 101_pInt, 103_pInt, 107_pInt, 109_pInt, 113_pInt, & + 127_pInt, 131_pInt, 137_pInt, 139_pInt, 149_pInt, 151_pInt, 157_pInt, 163_pInt, 167_pInt, 173_pInt, & + 179_pInt, 181_pInt, 191_pInt, 193_pInt, 197_pInt, 199_pInt, 211_pInt, 223_pInt, 227_pInt, 229_pInt, & + 233_pInt, 239_pInt, 241_pInt, 251_pInt, 257_pInt, 263_pInt, 269_pInt, 271_pInt, 277_pInt, 281_pInt, & + 283_pInt, 293_pInt, 307_pInt, 311_pInt, 313_pInt, 317_pInt, 331_pInt, 337_pInt, 347_pInt, 349_pInt, & + 353_pInt, 359_pInt, 367_pInt, 373_pInt, 379_pInt, 383_pInt, 389_pInt, 397_pInt, 401_pInt, 409_pInt, & + 419_pInt, 421_pInt, 431_pInt, 433_pInt, 439_pInt, 443_pInt, 449_pInt, 457_pInt, 461_pInt, 463_pInt, & + 467_pInt, 479_pInt, 487_pInt, 491_pInt, 499_pInt, 503_pInt, 509_pInt, 521_pInt, 523_pInt, 541_pInt, & + ! 101:200 + 547_pInt, 557_pInt, 563_pInt, 569_pInt, 571_pInt, 577_pInt, 587_pInt, 593_pInt, 599_pInt, 601_pInt, & + 607_pInt, 613_pInt, 617_pInt, 619_pInt, 631_pInt, 641_pInt, 643_pInt, 647_pInt, 653_pInt, 659_pInt, & + 661_pInt, 673_pInt, 677_pInt, 683_pInt, 691_pInt, 701_pInt, 709_pInt, 719_pInt, 727_pInt, 733_pInt, & + 739_pInt, 743_pInt, 751_pInt, 757_pInt, 761_pInt, 769_pInt, 773_pInt, 787_pInt, 797_pInt, 809_pInt, & + 811_pInt, 821_pInt, 823_pInt, 827_pInt, 829_pInt, 839_pInt, 853_pInt, 857_pInt, 859_pInt, 863_pInt, & + 877_pInt, 881_pInt, 883_pInt, 887_pInt, 907_pInt, 911_pInt, 919_pInt, 929_pInt, 937_pInt, 941_pInt, & + 947_pInt, 953_pInt, 967_pInt, 971_pInt, 977_pInt, 983_pInt, 991_pInt, 997_pInt, 1009_pInt, 1013_pInt, & + 1019_pInt, 1021_pInt, 1031_pInt, 1033_pInt, 1039_pInt, 1049_pInt, 1051_pInt, 1061_pInt, 1063_pInt, 1069_pInt, & + 1087_pInt, 1091_pInt, 1093_pInt, 1097_pInt, 1103_pInt, 1109_pInt, 1117_pInt, 1123_pInt, 1129_pInt, 1151_pInt, & + 1153_pInt, 1163_pInt, 1171_pInt, 1181_pInt, 1187_pInt, 1193_pInt, 1201_pInt, 1213_pInt, 1217_pInt, 1223_pInt, & + ! 201:300 + 1229_pInt, 1231_pInt, 1237_pInt, 1249_pInt, 1259_pInt, 1277_pInt, 1279_pInt, 1283_pInt, 1289_pInt, 1291_pInt, & + 1297_pInt, 1301_pInt, 1303_pInt, 1307_pInt, 1319_pInt, 1321_pInt, 1327_pInt, 1361_pInt, 1367_pInt, 1373_pInt, & + 1381_pInt, 1399_pInt, 1409_pInt, 1423_pInt, 1427_pInt, 1429_pInt, 1433_pInt, 1439_pInt, 1447_pInt, 1451_pInt, & + 1453_pInt, 1459_pInt, 1471_pInt, 1481_pInt, 1483_pInt, 1487_pInt, 1489_pInt, 1493_pInt, 1499_pInt, 1511_pInt, & + 1523_pInt, 1531_pInt, 1543_pInt, 1549_pInt, 1553_pInt, 1559_pInt, 1567_pInt, 1571_pInt, 1579_pInt, 1583_pInt, & + 1597_pInt, 1601_pInt, 1607_pInt, 1609_pInt, 1613_pInt, 1619_pInt, 1621_pInt, 1627_pInt, 1637_pInt, 1657_pInt, & + 1663_pInt, 1667_pInt, 1669_pInt, 1693_pInt, 1697_pInt, 1699_pInt, 1709_pInt, 1721_pInt, 1723_pInt, 1733_pInt, & + 1741_pInt, 1747_pInt, 1753_pInt, 1759_pInt, 1777_pInt, 1783_pInt, 1787_pInt, 1789_pInt, 1801_pInt, 1811_pInt, & + 1823_pInt, 1831_pInt, 1847_pInt, 1861_pInt, 1867_pInt, 1871_pInt, 1873_pInt, 1877_pInt, 1879_pInt, 1889_pInt, & + 1901_pInt, 1907_pInt, 1913_pInt, 1931_pInt, 1933_pInt, 1949_pInt, 1951_pInt, 1973_pInt, 1979_pInt, 1987_pInt, & + ! 301:400 + 1993_pInt, 1997_pInt, 1999_pInt, 2003_pInt, 2011_pInt, 2017_pInt, 2027_pInt, 2029_pInt, 2039_pInt, 2053_pInt, & + 2063_pInt, 2069_pInt, 2081_pInt, 2083_pInt, 2087_pInt, 2089_pInt, 2099_pInt, 2111_pInt, 2113_pInt, 2129_pInt, & + 2131_pInt, 2137_pInt, 2141_pInt, 2143_pInt, 2153_pInt, 2161_pInt, 2179_pInt, 2203_pInt, 2207_pInt, 2213_pInt, & + 2221_pInt, 2237_pInt, 2239_pInt, 2243_pInt, 2251_pInt, 2267_pInt, 2269_pInt, 2273_pInt, 2281_pInt, 2287_pInt, & + 2293_pInt, 2297_pInt, 2309_pInt, 2311_pInt, 2333_pInt, 2339_pInt, 2341_pInt, 2347_pInt, 2351_pInt, 2357_pInt, & + 2371_pInt, 2377_pInt, 2381_pInt, 2383_pInt, 2389_pInt, 2393_pInt, 2399_pInt, 2411_pInt, 2417_pInt, 2423_pInt, & + 2437_pInt, 2441_pInt, 2447_pInt, 2459_pInt, 2467_pInt, 2473_pInt, 2477_pInt, 2503_pInt, 2521_pInt, 2531_pInt, & + 2539_pInt, 2543_pInt, 2549_pInt, 2551_pInt, 2557_pInt, 2579_pInt, 2591_pInt, 2593_pInt, 2609_pInt, 2617_pInt, & + 2621_pInt, 2633_pInt, 2647_pInt, 2657_pInt, 2659_pInt, 2663_pInt, 2671_pInt, 2677_pInt, 2683_pInt, 2687_pInt, & + 2689_pInt, 2693_pInt, 2699_pInt, 2707_pInt, 2711_pInt, 2713_pInt, 2719_pInt, 2729_pInt, 2731_pInt, 2741_pInt, & + ! 401:500 + 2749_pInt, 2753_pInt, 2767_pInt, 2777_pInt, 2789_pInt, 2791_pInt, 2797_pInt, 2801_pInt, 2803_pInt, 2819_pInt, & + 2833_pInt, 2837_pInt, 2843_pInt, 2851_pInt, 2857_pInt, 2861_pInt, 2879_pInt, 2887_pInt, 2897_pInt, 2903_pInt, & + 2909_pInt, 2917_pInt, 2927_pInt, 2939_pInt, 2953_pInt, 2957_pInt, 2963_pInt, 2969_pInt, 2971_pInt, 2999_pInt, & + 3001_pInt, 3011_pInt, 3019_pInt, 3023_pInt, 3037_pInt, 3041_pInt, 3049_pInt, 3061_pInt, 3067_pInt, 3079_pInt, & + 3083_pInt, 3089_pInt, 3109_pInt, 3119_pInt, 3121_pInt, 3137_pInt, 3163_pInt, 3167_pInt, 3169_pInt, 3181_pInt, & + 3187_pInt, 3191_pInt, 3203_pInt, 3209_pInt, 3217_pInt, 3221_pInt, 3229_pInt, 3251_pInt, 3253_pInt, 3257_pInt, & + 3259_pInt, 3271_pInt, 3299_pInt, 3301_pInt, 3307_pInt, 3313_pInt, 3319_pInt, 3323_pInt, 3329_pInt, 3331_pInt, & + 3343_pInt, 3347_pInt, 3359_pInt, 3361_pInt, 3371_pInt, 3373_pInt, 3389_pInt, 3391_pInt, 3407_pInt, 3413_pInt, & + 3433_pInt, 3449_pInt, 3457_pInt, 3461_pInt, 3463_pInt, 3467_pInt, 3469_pInt, 3491_pInt, 3499_pInt, 3511_pInt, & + 3517_pInt, 3527_pInt, 3529_pInt, 3533_pInt, 3539_pInt, 3541_pInt, 3547_pInt, 3557_pInt, 3559_pInt, 3571_pInt, & + ! 501:600 + 3581_pInt, 3583_pInt, 3593_pInt, 3607_pInt, 3613_pInt, 3617_pInt, 3623_pInt, 3631_pInt, 3637_pInt, 3643_pInt, & + 3659_pInt, 3671_pInt, 3673_pInt, 3677_pInt, 3691_pInt, 3697_pInt, 3701_pInt, 3709_pInt, 3719_pInt, 3727_pInt, & + 3733_pInt, 3739_pInt, 3761_pInt, 3767_pInt, 3769_pInt, 3779_pInt, 3793_pInt, 3797_pInt, 3803_pInt, 3821_pInt, & + 3823_pInt, 3833_pInt, 3847_pInt, 3851_pInt, 3853_pInt, 3863_pInt, 3877_pInt, 3881_pInt, 3889_pInt, 3907_pInt, & + 3911_pInt, 3917_pInt, 3919_pInt, 3923_pInt, 3929_pInt, 3931_pInt, 3943_pInt, 3947_pInt, 3967_pInt, 3989_pInt, & + 4001_pInt, 4003_pInt, 4007_pInt, 4013_pInt, 4019_pInt, 4021_pInt, 4027_pInt, 4049_pInt, 4051_pInt, 4057_pInt, & + 4073_pInt, 4079_pInt, 4091_pInt, 4093_pInt, 4099_pInt, 4111_pInt, 4127_pInt, 4129_pInt, 4133_pInt, 4139_pInt, & + 4153_pInt, 4157_pInt, 4159_pInt, 4177_pInt, 4201_pInt, 4211_pInt, 4217_pInt, 4219_pInt, 4229_pInt, 4231_pInt, & + 4241_pInt, 4243_pInt, 4253_pInt, 4259_pInt, 4261_pInt, 4271_pInt, 4273_pInt, 4283_pInt, 4289_pInt, 4297_pInt, & + 4327_pInt, 4337_pInt, 4339_pInt, 4349_pInt, 4357_pInt, 4363_pInt, 4373_pInt, 4391_pInt, 4397_pInt, 4409_pInt, & + ! 601:700 + 4421_pInt, 4423_pInt, 4441_pInt, 4447_pInt, 4451_pInt, 4457_pInt, 4463_pInt, 4481_pInt, 4483_pInt, 4493_pInt, & + 4507_pInt, 4513_pInt, 4517_pInt, 4519_pInt, 4523_pInt, 4547_pInt, 4549_pInt, 4561_pInt, 4567_pInt, 4583_pInt, & + 4591_pInt, 4597_pInt, 4603_pInt, 4621_pInt, 4637_pInt, 4639_pInt, 4643_pInt, 4649_pInt, 4651_pInt, 4657_pInt, & + 4663_pInt, 4673_pInt, 4679_pInt, 4691_pInt, 4703_pInt, 4721_pInt, 4723_pInt, 4729_pInt, 4733_pInt, 4751_pInt, & + 4759_pInt, 4783_pInt, 4787_pInt, 4789_pInt, 4793_pInt, 4799_pInt, 4801_pInt, 4813_pInt, 4817_pInt, 4831_pInt, & + 4861_pInt, 4871_pInt, 4877_pInt, 4889_pInt, 4903_pInt, 4909_pInt, 4919_pInt, 4931_pInt, 4933_pInt, 4937_pInt, & + 4943_pInt, 4951_pInt, 4957_pInt, 4967_pInt, 4969_pInt, 4973_pInt, 4987_pInt, 4993_pInt, 4999_pInt, 5003_pInt, & + 5009_pInt, 5011_pInt, 5021_pInt, 5023_pInt, 5039_pInt, 5051_pInt, 5059_pInt, 5077_pInt, 5081_pInt, 5087_pInt, & + 5099_pInt, 5101_pInt, 5107_pInt, 5113_pInt, 5119_pInt, 5147_pInt, 5153_pInt, 5167_pInt, 5171_pInt, 5179_pInt, & + 5189_pInt, 5197_pInt, 5209_pInt, 5227_pInt, 5231_pInt, 5233_pInt, 5237_pInt, 5261_pInt, 5273_pInt, 5279_pInt, & + ! 701:800 + 5281_pInt, 5297_pInt, 5303_pInt, 5309_pInt, 5323_pInt, 5333_pInt, 5347_pInt, 5351_pInt, 5381_pInt, 5387_pInt, & + 5393_pInt, 5399_pInt, 5407_pInt, 5413_pInt, 5417_pInt, 5419_pInt, 5431_pInt, 5437_pInt, 5441_pInt, 5443_pInt, & + 5449_pInt, 5471_pInt, 5477_pInt, 5479_pInt, 5483_pInt, 5501_pInt, 5503_pInt, 5507_pInt, 5519_pInt, 5521_pInt, & + 5527_pInt, 5531_pInt, 5557_pInt, 5563_pInt, 5569_pInt, 5573_pInt, 5581_pInt, 5591_pInt, 5623_pInt, 5639_pInt, & + 5641_pInt, 5647_pInt, 5651_pInt, 5653_pInt, 5657_pInt, 5659_pInt, 5669_pInt, 5683_pInt, 5689_pInt, 5693_pInt, & + 5701_pInt, 5711_pInt, 5717_pInt, 5737_pInt, 5741_pInt, 5743_pInt, 5749_pInt, 5779_pInt, 5783_pInt, 5791_pInt, & + 5801_pInt, 5807_pInt, 5813_pInt, 5821_pInt, 5827_pInt, 5839_pInt, 5843_pInt, 5849_pInt, 5851_pInt, 5857_pInt, & + 5861_pInt, 5867_pInt, 5869_pInt, 5879_pInt, 5881_pInt, 5897_pInt, 5903_pInt, 5923_pInt, 5927_pInt, 5939_pInt, & + 5953_pInt, 5981_pInt, 5987_pInt, 6007_pInt, 6011_pInt, 6029_pInt, 6037_pInt, 6043_pInt, 6047_pInt, 6053_pInt, & + 6067_pInt, 6073_pInt, 6079_pInt, 6089_pInt, 6091_pInt, 6101_pInt, 6113_pInt, 6121_pInt, 6131_pInt, 6133_pInt, & + ! 801:900 + 6143_pInt, 6151_pInt, 6163_pInt, 6173_pInt, 6197_pInt, 6199_pInt, 6203_pInt, 6211_pInt, 6217_pInt, 6221_pInt, & + 6229_pInt, 6247_pInt, 6257_pInt, 6263_pInt, 6269_pInt, 6271_pInt, 6277_pInt, 6287_pInt, 6299_pInt, 6301_pInt, & + 6311_pInt, 6317_pInt, 6323_pInt, 6329_pInt, 6337_pInt, 6343_pInt, 6353_pInt, 6359_pInt, 6361_pInt, 6367_pInt, & + 6373_pInt, 6379_pInt, 6389_pInt, 6397_pInt, 6421_pInt, 6427_pInt, 6449_pInt, 6451_pInt, 6469_pInt, 6473_pInt, & + 6481_pInt, 6491_pInt, 6521_pInt, 6529_pInt, 6547_pInt, 6551_pInt, 6553_pInt, 6563_pInt, 6569_pInt, 6571_pInt, & + 6577_pInt, 6581_pInt, 6599_pInt, 6607_pInt, 6619_pInt, 6637_pInt, 6653_pInt, 6659_pInt, 6661_pInt, 6673_pInt, & + 6679_pInt, 6689_pInt, 6691_pInt, 6701_pInt, 6703_pInt, 6709_pInt, 6719_pInt, 6733_pInt, 6737_pInt, 6761_pInt, & + 6763_pInt, 6779_pInt, 6781_pInt, 6791_pInt, 6793_pInt, 6803_pInt, 6823_pInt, 6827_pInt, 6829_pInt, 6833_pInt, & + 6841_pInt, 6857_pInt, 6863_pInt, 6869_pInt, 6871_pInt, 6883_pInt, 6899_pInt, 6907_pInt, 6911_pInt, 6917_pInt, & + 6947_pInt, 6949_pInt, 6959_pInt, 6961_pInt, 6967_pInt, 6971_pInt, 6977_pInt, 6983_pInt, 6991_pInt, 6997_pInt, & + ! 901:1000 + 7001_pInt, 7013_pInt, 7019_pInt, 7027_pInt, 7039_pInt, 7043_pInt, 7057_pInt, 7069_pInt, 7079_pInt, 7103_pInt, & + 7109_pInt, 7121_pInt, 7127_pInt, 7129_pInt, 7151_pInt, 7159_pInt, 7177_pInt, 7187_pInt, 7193_pInt, 7207_pInt, & + 7211_pInt, 7213_pInt, 7219_pInt, 7229_pInt, 7237_pInt, 7243_pInt, 7247_pInt, 7253_pInt, 7283_pInt, 7297_pInt, & + 7307_pInt, 7309_pInt, 7321_pInt, 7331_pInt, 7333_pInt, 7349_pInt, 7351_pInt, 7369_pInt, 7393_pInt, 7411_pInt, & + 7417_pInt, 7433_pInt, 7451_pInt, 7457_pInt, 7459_pInt, 7477_pInt, 7481_pInt, 7487_pInt, 7489_pInt, 7499_pInt, & + 7507_pInt, 7517_pInt, 7523_pInt, 7529_pInt, 7537_pInt, 7541_pInt, 7547_pInt, 7549_pInt, 7559_pInt, 7561_pInt, & + 7573_pInt, 7577_pInt, 7583_pInt, 7589_pInt, 7591_pInt, 7603_pInt, 7607_pInt, 7621_pInt, 7639_pInt, 7643_pInt, & + 7649_pInt, 7669_pInt, 7673_pInt, 7681_pInt, 7687_pInt, 7691_pInt, 7699_pInt, 7703_pInt, 7717_pInt, 7723_pInt, & + 7727_pInt, 7741_pInt, 7753_pInt, 7757_pInt, 7759_pInt, 7789_pInt, 7793_pInt, 7817_pInt, 7823_pInt, 7829_pInt, & + 7841_pInt, 7853_pInt, 7867_pInt, 7873_pInt, 7877_pInt, 7879_pInt, 7883_pInt, 7901_pInt, 7907_pInt, 7919_pInt, & + ! 1001:1100 + 7927_pInt, 7933_pInt, 7937_pInt, 7949_pInt, 7951_pInt, 7963_pInt, 7993_pInt, 8009_pInt, 8011_pInt, 8017_pInt, & + 8039_pInt, 8053_pInt, 8059_pInt, 8069_pInt, 8081_pInt, 8087_pInt, 8089_pInt, 8093_pInt, 8101_pInt, 8111_pInt, & + 8117_pInt, 8123_pInt, 8147_pInt, 8161_pInt, 8167_pInt, 8171_pInt, 8179_pInt, 8191_pInt, 8209_pInt, 8219_pInt, & + 8221_pInt, 8231_pInt, 8233_pInt, 8237_pInt, 8243_pInt, 8263_pInt, 8269_pInt, 8273_pInt, 8287_pInt, 8291_pInt, & + 8293_pInt, 8297_pInt, 8311_pInt, 8317_pInt, 8329_pInt, 8353_pInt, 8363_pInt, 8369_pInt, 8377_pInt, 8387_pInt, & + 8389_pInt, 8419_pInt, 8423_pInt, 8429_pInt, 8431_pInt, 8443_pInt, 8447_pInt, 8461_pInt, 8467_pInt, 8501_pInt, & + 8513_pInt, 8521_pInt, 8527_pInt, 8537_pInt, 8539_pInt, 8543_pInt, 8563_pInt, 8573_pInt, 8581_pInt, 8597_pInt, & + 8599_pInt, 8609_pInt, 8623_pInt, 8627_pInt, 8629_pInt, 8641_pInt, 8647_pInt, 8663_pInt, 8669_pInt, 8677_pInt, & + 8681_pInt, 8689_pInt, 8693_pInt, 8699_pInt, 8707_pInt, 8713_pInt, 8719_pInt, 8731_pInt, 8737_pInt, 8741_pInt, & + 8747_pInt, 8753_pInt, 8761_pInt, 8779_pInt, 8783_pInt, 8803_pInt, 8807_pInt, 8819_pInt, 8821_pInt, 8831_pInt, & + ! 1101:1200 + 8837_pInt, 8839_pInt, 8849_pInt, 8861_pInt, 8863_pInt, 8867_pInt, 8887_pInt, 8893_pInt, 8923_pInt, 8929_pInt, & + 8933_pInt, 8941_pInt, 8951_pInt, 8963_pInt, 8969_pInt, 8971_pInt, 8999_pInt, 9001_pInt, 9007_pInt, 9011_pInt, & + 9013_pInt, 9029_pInt, 9041_pInt, 9043_pInt, 9049_pInt, 9059_pInt, 9067_pInt, 9091_pInt, 9103_pInt, 9109_pInt, & + 9127_pInt, 9133_pInt, 9137_pInt, 9151_pInt, 9157_pInt, 9161_pInt, 9173_pInt, 9181_pInt, 9187_pInt, 9199_pInt, & + 9203_pInt, 9209_pInt, 9221_pInt, 9227_pInt, 9239_pInt, 9241_pInt, 9257_pInt, 9277_pInt, 9281_pInt, 9283_pInt, & + 9293_pInt, 9311_pInt, 9319_pInt, 9323_pInt, 9337_pInt, 9341_pInt, 9343_pInt, 9349_pInt, 9371_pInt, 9377_pInt, & + 9391_pInt, 9397_pInt, 9403_pInt, 9413_pInt, 9419_pInt, 9421_pInt, 9431_pInt, 9433_pInt, 9437_pInt, 9439_pInt, & + 9461_pInt, 9463_pInt, 9467_pInt, 9473_pInt, 9479_pInt, 9491_pInt, 9497_pInt, 9511_pInt, 9521_pInt, 9533_pInt, & + 9539_pInt, 9547_pInt, 9551_pInt, 9587_pInt, 9601_pInt, 9613_pInt, 9619_pInt, 9623_pInt, 9629_pInt, 9631_pInt, & + 9643_pInt, 9649_pInt, 9661_pInt, 9677_pInt, 9679_pInt, 9689_pInt, 9697_pInt, 9719_pInt, 9721_pInt, 9733_pInt, & + ! 1201:1300 + 9739_pInt, 9743_pInt, 9749_pInt, 9767_pInt, 9769_pInt, 9781_pInt, 9787_pInt, 9791_pInt, 9803_pInt, 9811_pInt, & + 9817_pInt, 9829_pInt, 9833_pInt, 9839_pInt, 9851_pInt, 9857_pInt, 9859_pInt, 9871_pInt, 9883_pInt, 9887_pInt, & + 9901_pInt, 9907_pInt, 9923_pInt, 9929_pInt, 9931_pInt, 9941_pInt, 9949_pInt, 9967_pInt, 9973_pInt,10007_pInt, & + 10009_pInt,10037_pInt,10039_pInt,10061_pInt,10067_pInt,10069_pInt,10079_pInt,10091_pInt,10093_pInt,10099_pInt, & + 10103_pInt,10111_pInt,10133_pInt,10139_pInt,10141_pInt,10151_pInt,10159_pInt,10163_pInt,10169_pInt,10177_pInt, & + 10181_pInt,10193_pInt,10211_pInt,10223_pInt,10243_pInt,10247_pInt,10253_pInt,10259_pInt,10267_pInt,10271_pInt, & + 10273_pInt,10289_pInt,10301_pInt,10303_pInt,10313_pInt,10321_pInt,10331_pInt,10333_pInt,10337_pInt,10343_pInt, & + 10357_pInt,10369_pInt,10391_pInt,10399_pInt,10427_pInt,10429_pInt,10433_pInt,10453_pInt,10457_pInt,10459_pInt, & + 10463_pInt,10477_pInt,10487_pInt,10499_pInt,10501_pInt,10513_pInt,10529_pInt,10531_pInt,10559_pInt,10567_pInt, & + 10589_pInt,10597_pInt,10601_pInt,10607_pInt,10613_pInt,10627_pInt,10631_pInt,10639_pInt,10651_pInt,10657_pInt, & + ! 1301:1400 + 10663_pInt,10667_pInt,10687_pInt,10691_pInt,10709_pInt,10711_pInt,10723_pInt,10729_pInt,10733_pInt,10739_pInt, & + 10753_pInt,10771_pInt,10781_pInt,10789_pInt,10799_pInt,10831_pInt,10837_pInt,10847_pInt,10853_pInt,10859_pInt, & + 10861_pInt,10867_pInt,10883_pInt,10889_pInt,10891_pInt,10903_pInt,10909_pInt,19037_pInt,10939_pInt,10949_pInt, & + 10957_pInt,10973_pInt,10979_pInt,10987_pInt,10993_pInt,11003_pInt,11027_pInt,11047_pInt,11057_pInt,11059_pInt, & + 11069_pInt,11071_pInt,11083_pInt,11087_pInt,11093_pInt,11113_pInt,11117_pInt,11119_pInt,11131_pInt,11149_pInt, & + 11159_pInt,11161_pInt,11171_pInt,11173_pInt,11177_pInt,11197_pInt,11213_pInt,11239_pInt,11243_pInt,11251_pInt, & + 11257_pInt,11261_pInt,11273_pInt,11279_pInt,11287_pInt,11299_pInt,11311_pInt,11317_pInt,11321_pInt,11329_pInt, & + 11351_pInt,11353_pInt,11369_pInt,11383_pInt,11393_pInt,11399_pInt,11411_pInt,11423_pInt,11437_pInt,11443_pInt, & + 11447_pInt,11467_pInt,11471_pInt,11483_pInt,11489_pInt,11491_pInt,11497_pInt,11503_pInt,11519_pInt,11527_pInt, & + 11549_pInt,11551_pInt,11579_pInt,11587_pInt,11593_pInt,11597_pInt,11617_pInt,11621_pInt,11633_pInt,11657_pInt, & + ! 1401:1500 + 11677_pInt,11681_pInt,11689_pInt,11699_pInt,11701_pInt,11717_pInt,11719_pInt,11731_pInt,11743_pInt,11777_pInt, & + 11779_pInt,11783_pInt,11789_pInt,11801_pInt,11807_pInt,11813_pInt,11821_pInt,11827_pInt,11831_pInt,11833_pInt, & + 11839_pInt,11863_pInt,11867_pInt,11887_pInt,11897_pInt,11903_pInt,11909_pInt,11923_pInt,11927_pInt,11933_pInt, & + 11939_pInt,11941_pInt,11953_pInt,11959_pInt,11969_pInt,11971_pInt,11981_pInt,11987_pInt,12007_pInt,12011_pInt, & + 12037_pInt,12041_pInt,12043_pInt,12049_pInt,12071_pInt,12073_pInt,12097_pInt,12101_pInt,12107_pInt,12109_pInt, & + 12113_pInt,12119_pInt,12143_pInt,12149_pInt,12157_pInt,12161_pInt,12163_pInt,12197_pInt,12203_pInt,12211_pInt, & + 12227_pInt,12239_pInt,12241_pInt,12251_pInt,12253_pInt,12263_pInt,12269_pInt,12277_pInt,12281_pInt,12289_pInt, & + 12301_pInt,12323_pInt,12329_pInt,12343_pInt,12347_pInt,12373_pInt,12377_pInt,12379_pInt,12391_pInt,12401_pInt, & + 12409_pInt,12413_pInt,12421_pInt,12433_pInt,12437_pInt,12451_pInt,12457_pInt,12473_pInt,12479_pInt,12487_pInt, & + 12491_pInt,12497_pInt,12503_pInt,12511_pInt,12517_pInt,12527_pInt,12539_pInt,12541_pInt,12547_pInt,12553_pInt] + endif + + if(n < 0_pInt) then + prime = PRIME_MAX + else if (n == 0_pInt) then + prime = 1_pInt + else if (n <= PRIME_MAX) then + prime = npvec(n) + else + prime = -1_pInt + call IO_error(error_ID=406_pInt) + end if + +end function prime + + +!-------------------------------------------------------------------------------------------------- +!> @brief factorial +!-------------------------------------------------------------------------------------------------- +integer(pInt) pure function math_factorial(n) + + implicit none + integer(pInt), intent(in) :: n + integer(pInt) :: i + + math_factorial = product([(i, i=1,n)]) + +end function math_factorial + + +!-------------------------------------------------------------------------------------------------- +!> @brief binomial coefficient +!-------------------------------------------------------------------------------------------------- +integer(pInt) pure function math_binomial(n,k) + + implicit none + integer(pInt), intent(in) :: n, k + integer(pInt) :: i, j + + j = min(k,n-k) + math_binomial = product([(i, i=n, n-j+1, -1)])/math_factorial(j) + +end function math_binomial + + +!-------------------------------------------------------------------------------------------------- +!> @brief multinomial coefficient +!-------------------------------------------------------------------------------------------------- +integer(pInt) pure function math_multinomial(alpha) + + implicit none + integer(pInt), intent(in), dimension(:) :: alpha + integer(pInt) :: i + + math_multinomial = 1_pInt + do i = 1, size(alpha) + math_multinomial = math_multinomial*math_binomial(sum(alpha(1:i)),alpha(i)) + enddo + +end function math_multinomial + + +!-------------------------------------------------------------------------------------------------- +!> @brief volume of tetrahedron given by four vertices +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_volTetrahedron(v1,v2,v3,v4) + + implicit none + real(pReal), dimension (3), intent(in) :: v1,v2,v3,v4 + real(pReal), dimension (3,3) :: m + + m(1:3,1) = v1-v2 + m(1:3,2) = v2-v3 + m(1:3,3) = v3-v4 + + math_volTetrahedron = math_det33(m)/6.0_pReal + +end function math_volTetrahedron + + +!-------------------------------------------------------------------------------------------------- +!> @brief area of triangle given by three vertices +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_areaTriangle(v1,v2,v3) + + implicit none + real(pReal), dimension (3), intent(in) :: v1,v2,v3 + + math_areaTriangle = 0.5_pReal * norm2(math_crossproduct(v1-v2,v1-v3)) + +end function math_areaTriangle + + +!-------------------------------------------------------------------------------------------------- +!> @brief rotate 33 tensor forward +!-------------------------------------------------------------------------------------------------- +pure function math_rotate_forward33(tensor,rot_tensor) + + implicit none + + real(pReal), dimension(3,3) :: math_rotate_forward33 + real(pReal), dimension(3,3), intent(in) :: tensor, rot_tensor + + math_rotate_forward33 = math_mul33x33(rot_tensor,& + math_mul33x33(tensor,math_transpose33(rot_tensor))) + +end function math_rotate_forward33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief rotate 33 tensor backward +!-------------------------------------------------------------------------------------------------- +pure function math_rotate_backward33(tensor,rot_tensor) + + implicit none + real(pReal), dimension(3,3) :: math_rotate_backward33 + real(pReal), dimension(3,3), intent(in) :: tensor, rot_tensor + + math_rotate_backward33 = math_mul33x33(math_transpose33(rot_tensor),& + math_mul33x33(tensor,rot_tensor)) + +end function math_rotate_backward33 + + +!-------------------------------------------------------------------------------------------------- +!> @brief rotate 3333 tensor C'_ijkl=g_im*g_jn*g_ko*g_lp*C_mnop +!-------------------------------------------------------------------------------------------------- +pure function math_rotate_forward3333(tensor,rot_tensor) + + implicit none + real(pReal), dimension(3,3,3,3) :: math_rotate_forward3333 + real(pReal), dimension(3,3), intent(in) :: rot_tensor + real(pReal), dimension(3,3,3,3), intent(in) :: tensor + integer(pInt) :: i,j,k,l,m,n,o,p + + math_rotate_forward3333= 0.0_pReal + + do i = 1_pInt,3_pInt; do j = 1_pInt,3_pInt; do k = 1_pInt,3_pInt; do l = 1_pInt,3_pInt + do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt; do p = 1_pInt,3_pInt + math_rotate_forward3333(i,j,k,l) = math_rotate_forward3333(i,j,k,l) & + + rot_tensor(m,i) * rot_tensor(n,j) & + * rot_tensor(o,k) * rot_tensor(p,l) * tensor(m,n,o,p) + enddo; enddo; enddo; enddo; enddo; enddo; enddo; enddo + +end function math_rotate_forward3333 + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate average of tensor field +!-------------------------------------------------------------------------------------------------- +function math_tensorAvg(field) + + implicit none + real(pReal), dimension(3,3) :: math_tensorAvg + real(pReal), intent(in), dimension(:,:,:,:,:) :: field + real(pReal) :: wgt + + wgt = 1.0_pReal/real(size(field,3)*size(field,4)*size(field,5), pReal) + math_tensorAvg = sum(sum(sum(field,dim=5),dim=4),dim=3)*wgt + +end function math_tensorAvg + + +!-------------------------------------------------------------------------------------------------- +!> @brief limits a scalar value to a certain range (either one or two sided) +! Will return NaN if left > right +!-------------------------------------------------------------------------------------------------- +real(pReal) pure function math_limit(a, left, right) + use prec, only: & + DAMASK_NaN + + implicit none + real(pReal), intent(in) :: a + real(pReal), intent(in), optional :: left, right + + + math_limit = min ( & + max (merge(left, -huge(a), present(left)), a), & + merge(right, huge(a), present(right)) & + ) + + if (present(left) .and. present(right)) math_limit = merge (DAMASK_NaN,math_limit, left>right) + +end function math_limit + +end module math diff --git a/src/mesh.f90 b/src/mesh.f90 new file mode 100644 index 000000000..1cd80a625 --- /dev/null +++ b/src/mesh.f90 @@ -0,0 +1,4784 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Christoph Koords, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Krishna Komerla, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Sets up the mesh for the solvers MSC.Marc, Abaqus and the spectral solver +!-------------------------------------------------------------------------------------------------- +module mesh + use, intrinsic :: iso_c_binding + use prec, only: pReal, pInt + + implicit none + private + integer(pInt), public, protected :: & + mesh_NcpElems, & !< total number of CP elements in local mesh + mesh_NelemSets, & + mesh_maxNelemInSet, & + mesh_Nmaterials, & + mesh_Nnodes, & !< total number of nodes in mesh + mesh_Ncellnodes, & !< total number of cell nodes in mesh (including duplicates) + mesh_Ncells, & !< total number of cells in mesh + mesh_maxNnodes, & !< max number of nodes in any CP element + mesh_maxNips, & !< max number of IPs in any CP element + mesh_maxNipNeighbors, & !< max number of IP neighbors in any CP element + mesh_maxNsharedElems, & !< max number of CP elements sharing a node + mesh_maxNcellnodes, & !< max number of cell nodes in any CP element + mesh_Nelems !< total number of elements in mesh + +#ifdef Spectral + integer(pInt), dimension(3), public, protected :: & + grid !< (global) grid + integer(pInt), public, protected :: & + mesh_NcpElemsGlobal, & !< total number of CP elements in global mesh + grid3, & !< (local) grid in 3rd direction + grid3Offset !< (local) grid offset in 3rd direction + real(pReal), dimension(3), public, protected :: & + geomSize + real(pReal), public, protected :: & + size3, & !< (local) size in 3rd direction + size3offset !< (local) size offset in 3rd direction +#endif + + integer(pInt), dimension(:,:), allocatable, public, protected :: & + mesh_element, & !< FEid, type(internal representation), material, texture, node indices as CP IDs + mesh_sharedElem, & !< entryCount and list of elements containing node + mesh_nodeTwins !< node twins are surface nodes that lie exactly on opposite sides of the mesh (surfaces nodes with equal coordinate values in two dimensions) + + integer(pInt), dimension(:,:,:,:), allocatable, public, protected :: & + mesh_ipNeighborhood !< 6 or less neighboring IPs as [element_num, IP_index, neighbor_index that points to me] + + real(pReal), public, protected :: & + mesh_unitlength !< physical length of one unit in mesh + + real(pReal), dimension(:,:), allocatable, public :: & + mesh_node, & !< node x,y,z coordinates (after deformation! ONLY FOR MARC!!!) + mesh_cellnode !< cell node x,y,z coordinates (after deformation! ONLY FOR MARC!!!) + + real(pReal), dimension(:,:), allocatable, public, protected :: & + mesh_ipVolume, & !< volume associated with IP (initially!) + mesh_node0 !< node x,y,z coordinates (initially!) + + real(pReal), dimension(:,:,:), allocatable, public, protected :: & + mesh_ipArea !< area of interface to neighboring IP (initially!) + + real(pReal), dimension(:,:,:), allocatable, public :: & + mesh_ipCoordinates !< IP x,y,z coordinates (after deformation!) + + real(pReal),dimension(:,:,:,:), allocatable, public, protected :: & + mesh_ipAreaNormal !< area normal of interface to neighboring IP (initially!) + + logical, dimension(3), public, protected :: mesh_periodicSurface !< flag indicating periodic outer surfaces (used for fluxes) + +#ifdef Marc4DAMASK + integer(pInt), private :: & + hypoelasticTableStyle, & !< Table style (Marc only) + initialcondTableStyle !< Table style (Marc only) +#endif + + integer(pInt), dimension(2), private :: & + mesh_maxValStateVar = 0_pInt + +#ifndef Spectral + character(len=64), dimension(:), allocatable, private :: & + mesh_nameElemSet, & !< names of elementSet + mesh_nameMaterial, & !< names of material in solid section + mesh_mapMaterial !< name of elementSet for material + + integer(pInt), dimension(:,:), allocatable, private :: & + mesh_mapElemSet !< list of elements in elementSet +#endif + integer(pInt), dimension(:,:), allocatable, private :: & + mesh_cellnodeParent !< cellnode's parent element ID, cellnode's intra-element ID + + integer(pInt), dimension(:,:), allocatable, target, private :: & + mesh_mapFEtoCPelem, & !< [sorted FEid, corresponding CPid] + mesh_mapFEtoCPnode !< [sorted FEid, corresponding CPid] + + integer(pInt),dimension(:,:,:), allocatable, private :: & + mesh_cell !< cell connectivity for each element,ip/cell + + integer(pInt), dimension(:,:,:), allocatable, private :: & + FE_nodesAtIP, & !< map IP index to node indices in a specific type of element + FE_ipNeighbor, & !< +x,-x,+y,-y,+z,-z list of intra-element IPs and(negative) neighbor faces per own IP in a specific type of element + FE_cell, & !< list of intra-element cell node IDs that constitute the cells in a specific type of element geometry + FE_cellface !< list of intra-cell cell node IDs that constitute the cell faces of a specific type of cell + + real(pReal), dimension(:,:,:), allocatable, private :: & + FE_cellnodeParentnodeWeights !< list of node weights for the generation of cell nodes + + integer(pInt), dimension(:,:,:,:), allocatable, private :: & + FE_subNodeOnIPFace + +#ifdef Abaqus + logical, private :: noPart !< for cases where the ABAQUS input file does not use part/assembly information +#endif + +#ifdef Spectral +#ifdef PETSc +#include + include 'fftw3-mpi.f03' +#else + include 'fftw3.f03' +#endif +#endif + +! These definitions should actually reside in the FE-solver specific part (different for MARC/ABAQUS) +! Hence, I suggest to prefix with "FE_" + + integer(pInt), parameter, public :: & + FE_Nelemtypes = 13_pInt, & + FE_Ngeomtypes = 10_pInt, & + FE_Ncelltypes = 4_pInt, & + FE_maxNnodes = 20_pInt, & + FE_maxNips = 27_pInt, & + FE_maxNipNeighbors = 6_pInt, & + FE_maxmaxNnodesAtIP = 8_pInt, & !< max number of (equivalent) nodes attached to an IP + FE_maxNmatchingNodesPerFace = 4_pInt, & + FE_maxNfaces = 6_pInt, & + FE_maxNcellnodes = 64_pInt, & + FE_maxNcellnodesPerCell = 8_pInt, & + FE_maxNcellfaces = 6_pInt, & + FE_maxNcellnodesPerCellface = 4_pInt + + integer(pInt), dimension(FE_Nelemtypes), parameter, public :: FE_geomtype = & !< geometry type of particular element type + int([ & + 1, & ! element 6 (2D 3node 1ip) + 2, & ! element 125 (2D 6node 3ip) + 3, & ! element 11 (2D 4node 4ip) + 4, & ! element 27 (2D 8node 9ip) + 3, & ! element 54 (2D 8node 4ip) + 5, & ! element 134 (3D 4node 1ip) + 6, & ! element 157 (3D 5node 4ip) + 6, & ! element 127 (3D 10node 4ip) + 7, & ! element 136 (3D 6node 6ip) + 8, & ! element 117 (3D 8node 1ip) + 9, & ! element 7 (3D 8node 8ip) + 9, & ! element 57 (3D 20node 8ip) + 10 & ! element 21 (3D 20node 27ip) + ],pInt) + + integer(pInt), dimension(FE_Ngeomtypes), parameter, public :: FE_celltype = & !< cell type that is used by each geometry type + int([ & + 1, & ! element 6 (2D 3node 1ip) + 2, & ! element 125 (2D 6node 3ip) + 2, & ! element 11 (2D 4node 4ip) + 2, & ! element 27 (2D 8node 9ip) + 3, & ! element 134 (3D 4node 1ip) + 4, & ! element 127 (3D 10node 4ip) + 4, & ! element 136 (3D 6node 6ip) + 4, & ! element 117 (3D 8node 1ip) + 4, & ! element 7 (3D 8node 8ip) + 4 & ! element 21 (3D 20node 27ip) + ],pInt) + + integer(pInt), dimension(FE_Ngeomtypes), parameter, public :: FE_dimension = & !< dimension of geometry type + int([ & + 2, & ! element 6 (2D 3node 1ip) + 2, & ! element 125 (2D 6node 3ip) + 2, & ! element 11 (2D 4node 4ip) + 2, & ! element 27 (2D 8node 9ip) + 3, & ! element 134 (3D 4node 1ip) + 3, & ! element 127 (3D 10node 4ip) + 3, & ! element 136 (3D 6node 6ip) + 3, & ! element 117 (3D 8node 1ip) + 3, & ! element 7 (3D 8node 8ip) + 3 & ! element 21 (3D 20node 27ip) + ],pInt) + + integer(pInt), dimension(FE_Nelemtypes), parameter, public :: FE_Nnodes = & !< number of nodes that constitute a specific type of element + int([ & + 3, & ! element 6 (2D 3node 1ip) + 6, & ! element 125 (2D 6node 3ip) + 4, & ! element 11 (2D 4node 4ip) + 8, & ! element 27 (2D 8node 9ip) + 8, & ! element 54 (2D 8node 4ip) + 4, & ! element 134 (3D 4node 1ip) + 5, & ! element 157 (3D 5node 4ip) + 10, & ! element 127 (3D 10node 4ip) + 6, & ! element 136 (3D 6node 6ip) + 8, & ! element 117 (3D 8node 1ip) + 8, & ! element 7 (3D 8node 8ip) + 20, & ! element 57 (3D 20node 8ip) + 20 & ! element 21 (3D 20node 27ip) + ],pInt) + + integer(pInt), dimension(FE_Ngeomtypes), parameter, public :: FE_Nfaces = & !< number of faces of a specific type of element geometry + int([ & + 3, & ! element 6 (2D 3node 1ip) + 3, & ! element 125 (2D 6node 3ip) + 4, & ! element 11 (2D 4node 4ip) + 4, & ! element 27 (2D 8node 9ip) + 4, & ! element 134 (3D 4node 1ip) + 4, & ! element 127 (3D 10node 4ip) + 5, & ! element 136 (3D 6node 6ip) + 6, & ! element 117 (3D 8node 1ip) + 6, & ! element 7 (3D 8node 8ip) + 6 & ! element 21 (3D 20node 27ip) + ],pInt) + + integer(pInt), dimension(FE_Ngeomtypes), parameter, private :: FE_NmatchingNodes = & !< number of nodes that are needed for face matching in a specific type of element geometry + int([ & + 3, & ! element 6 (2D 3node 1ip) + 3, & ! element 125 (2D 6node 3ip) + 4, & ! element 11 (2D 4node 4ip) + 4, & ! element 27 (2D 8node 9ip) + 4, & ! element 134 (3D 4node 1ip) + 4, & ! element 127 (3D 10node 4ip) + 6, & ! element 136 (3D 6node 6ip) + 8, & ! element 117 (3D 8node 1ip) + 8, & ! element 7 (3D 8node 8ip) + 8 & ! element 21 (3D 20node 27ip) + ],pInt) + + integer(pInt), dimension(FE_maxNfaces,FE_Ngeomtypes), parameter, private :: & + FE_NmatchingNodesPerFace = & !< number of matching nodes per face in a specific type of element geometry + reshape(int([ & + 2,2,2,0,0,0, & ! element 6 (2D 3node 1ip) + 2,2,2,0,0,0, & ! element 125 (2D 6node 3ip) + 2,2,2,2,0,0, & ! element 11 (2D 4node 4ip) + 2,2,2,2,0,0, & ! element 27 (2D 8node 9ip) + 3,3,3,3,0,0, & ! element 134 (3D 4node 1ip) + 3,3,3,3,0,0, & ! element 127 (3D 10node 4ip) + 3,4,4,4,3,0, & ! element 136 (3D 6node 6ip) + 4,4,4,4,4,4, & ! element 117 (3D 8node 1ip) + 4,4,4,4,4,4, & ! element 7 (3D 8node 8ip) + 4,4,4,4,4,4 & ! element 21 (3D 20node 27ip) + ],pInt),[FE_maxNipNeighbors,FE_Ngeomtypes]) + + integer(pInt), dimension(FE_maxNmatchingNodesPerFace,FE_maxNfaces,FE_Ngeomtypes), & + parameter, private :: FE_face = & !< List of node indices on each face of a specific type of element geometry + reshape(int([& + 1,2,0,0 , & ! element 6 (2D 3node 1ip) + 2,3,0,0 , & + 3,1,0,0 , & + 0,0,0,0 , & + 0,0,0,0 , & + 0,0,0,0 , & + 1,2,0,0 , & ! element 125 (2D 6node 3ip) + 2,3,0,0 , & + 3,1,0,0 , & + 0,0,0,0 , & + 0,0,0,0 , & + 0,0,0,0 , & + 1,2,0,0 , & ! element 11 (2D 4node 4ip) + 2,3,0,0 , & + 3,4,0,0 , & + 4,1,0,0 , & + 0,0,0,0 , & + 0,0,0,0 , & + 1,2,0,0 , & ! element 27 (2D 8node 9ip) + 2,3,0,0 , & + 3,4,0,0 , & + 4,1,0,0 , & + 0,0,0,0 , & + 0,0,0,0 , & + 1,2,3,0 , & ! element 134 (3D 4node 1ip) + 1,4,2,0 , & + 2,3,4,0 , & + 1,3,4,0 , & + 0,0,0,0 , & + 0,0,0,0 , & + 1,2,3,0 , & ! element 127 (3D 10node 4ip) + 1,4,2,0 , & + 2,4,3,0 , & + 1,3,4,0 , & + 0,0,0,0 , & + 0,0,0,0 , & + 1,2,3,0 , & ! element 136 (3D 6node 6ip) + 1,4,5,2 , & + 2,5,6,3 , & + 1,3,6,4 , & + 4,6,5,0 , & + 0,0,0,0 , & + 1,2,3,4 , & ! element 117 (3D 8node 1ip) + 2,1,5,6 , & + 3,2,6,7 , & + 4,3,7,8 , & + 4,1,5,8 , & + 8,7,6,5 , & + 1,2,3,4 , & ! element 7 (3D 8node 8ip) + 2,1,5,6 , & + 3,2,6,7 , & + 4,3,7,8 , & + 4,1,5,8 , & + 8,7,6,5 , & + 1,2,3,4 , & ! element 21 (3D 20node 27ip) + 2,1,5,6 , & + 3,2,6,7 , & + 4,3,7,8 , & + 4,1,5,8 , & + 8,7,6,5 & + ],pInt),[FE_maxNmatchingNodesPerFace,FE_maxNfaces,FE_Ngeomtypes]) + + integer(pInt), dimension(FE_Ngeomtypes), parameter, private :: FE_Ncellnodes = & !< number of cell nodes in a specific geometry type + int([ & + 3, & ! element 6 (2D 3node 1ip) + 7, & ! element 125 (2D 6node 3ip) + 9, & ! element 11 (2D 4node 4ip) + 16, & ! element 27 (2D 8node 9ip) + 4, & ! element 134 (3D 4node 1ip) + 15, & ! element 127 (3D 10node 4ip) + 21, & ! element 136 (3D 6node 6ip) + 8, & ! element 117 (3D 8node 1ip) + 27, & ! element 7 (3D 8node 8ip) + 64 & ! element 21 (3D 20node 27ip) + ],pInt) + + integer(pInt), dimension(FE_Ncelltypes), parameter, private :: FE_NcellnodesPerCell = & !< number of cell nodes in a specific cell type + int([ & + 3, & ! (2D 3node) + 4, & ! (2D 4node) + 4, & ! (3D 4node) + 8 & ! (3D 8node) + ],pInt) + + integer(pInt), dimension(FE_Ncelltypes), parameter, private :: FE_NcellnodesPerCellface = & !< number of cell nodes per cell face in a specific cell type + int([& + 2, & ! (2D 3node) + 2, & ! (2D 4node) + 3, & ! (3D 4node) + 4 & ! (3D 8node) + ],pInt) + + integer(pInt), dimension(FE_Ngeomtypes), parameter, public :: FE_Nips = & !< number of IPs in a specific type of element + int([ & + 1, & ! element 6 (2D 3node 1ip) + 3, & ! element 125 (2D 6node 3ip) + 4, & ! element 11 (2D 4node 4ip) + 9, & ! element 27 (2D 8node 9ip) + 1, & ! element 134 (3D 4node 1ip) + 4, & ! element 127 (3D 10node 4ip) + 6, & ! element 136 (3D 6node 6ip) + 1, & ! element 117 (3D 8node 1ip) + 8, & ! element 7 (3D 8node 8ip) + 27 & ! element 21 (3D 20node 27ip) + ],pInt) + + integer(pInt), dimension(FE_Ncelltypes), parameter, public :: FE_NipNeighbors = & !< number of ip neighbors / cell faces in a specific cell type + int([& + 3, & ! (2D 3node) + 4, & ! (2D 4node) + 4, & ! (3D 4node) + 6 & ! (3D 8node) + ],pInt) + + + integer(pInt), dimension(FE_Ngeomtypes), parameter, private :: FE_maxNnodesAtIP = & !< maximum number of parent nodes that belong to an IP for a specific type of element + int([ & + 3, & ! element 6 (2D 3node 1ip) + 1, & ! element 125 (2D 6node 3ip) + 1, & ! element 11 (2D 4node 4ip) + 2, & ! element 27 (2D 8node 9ip) + 4, & ! element 134 (3D 4node 1ip) + 1, & ! element 127 (3D 10node 4ip) + 1, & ! element 136 (3D 6node 6ip) + 8, & ! element 117 (3D 8node 1ip) + 1, & ! element 7 (3D 8node 8ip) + 4 & ! element 21 (3D 20node 27ip) + ],pInt) + + + integer(pInt), dimension(FE_Nelemtypes), parameter, private :: MESH_VTKELEMTYPE = & + int([ & + 5, & ! element 6 (2D 3node 1ip) + 22, & ! element 125 (2D 6node 3ip) + 9, & ! element 11 (2D 4node 4ip) + 23, & ! element 27 (2D 8node 9ip) + 23, & ! element 54 (2D 8node 4ip) + 10, & ! element 134 (3D 4node 1ip) + 10, & ! element 157 (3D 5node 4ip) + 24, & ! element 127 (3D 10node 4ip) + 13, & ! element 136 (3D 6node 6ip) + 12, & ! element 117 (3D 8node 1ip) + 12, & ! element 7 (3D 8node 8ip) + 25, & ! element 57 (3D 20node 8ip) + 25 & ! element 21 (3D 20node 27ip) + ],pInt) + + integer(pInt), dimension(FE_Ncelltypes), parameter, private :: MESH_VTKCELLTYPE = & + int([ & + 5, & ! (2D 3node) + 9, & ! (2D 4node) + 10, & ! (3D 4node) + 12 & ! (3D 8node) + ],pInt) + + + public :: & + mesh_init, & + mesh_FEasCP, & + mesh_build_cellnodes, & + mesh_build_ipVolumes, & + mesh_build_ipCoordinates, & + mesh_cellCenterCoordinates, & + mesh_init_postprocessing, & + mesh_get_Ncellnodes, & + mesh_get_unitlength, & + mesh_get_nodeAtIP +#ifdef Spectral + public :: & + mesh_spectral_getGrid, & + mesh_spectral_getSize, & + mesh_nodesAroundCentres, & + mesh_deformedCoordsFFT, & + mesh_volumeMismatch, & + mesh_shapeMismatch +#endif + + private :: & +#ifdef Spectral + mesh_spectral_getHomogenization, & + mesh_spectral_count, & + mesh_spectral_mapNodesAndElems, & + mesh_spectral_count_cpSizes, & + mesh_spectral_build_nodes, & + mesh_spectral_build_elements, & + mesh_spectral_build_ipNeighborhood, & +#endif +#ifdef Marc4DAMASK + mesh_marc_get_tableStyles, & + mesh_marc_count_nodesAndElements, & + mesh_marc_count_elementSets, & + mesh_marc_map_elementSets, & + mesh_marc_count_cpElements, & + mesh_marc_map_Elements, & + mesh_marc_map_nodes, & + mesh_marc_build_nodes, & + mesh_marc_count_cpSizes, & + mesh_marc_build_elements, & +#endif +#ifdef Abaqus + mesh_abaqus_count_nodesAndElements, & + mesh_abaqus_count_elementSets, & + mesh_abaqus_count_materials, & + mesh_abaqus_map_elementSets, & + mesh_abaqus_map_materials, & + mesh_abaqus_count_cpElements, & + mesh_abaqus_map_elements, & + mesh_abaqus_map_nodes, & + mesh_abaqus_build_nodes, & + mesh_abaqus_count_cpSizes, & + mesh_abaqus_build_elements, & +#endif +#ifndef Spectral + mesh_build_nodeTwins, & + mesh_build_sharedElems, & + mesh_build_ipNeighborhood, & +#endif + mesh_get_damaskOptions, & + mesh_build_cellconnectivity, & + mesh_build_ipAreas, & + mesh_tell_statistics, & + FE_mapElemtype, & + mesh_faceMatch, & + mesh_build_FEdata, & + mesh_write_cellGeom, & + mesh_write_elemGeom, & + mesh_write_meshfile, & + mesh_read_meshfile + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief initializes the mesh by calling all necessary private routines the mesh module +!! Order and routines strongly depend on type of solver +!-------------------------------------------------------------------------------------------------- +subroutine mesh_init(ip,el) +#ifdef Spectral + use, intrinsic :: iso_c_binding +#endif + use DAMASK_interface + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & +#ifdef Abaqus + IO_abaqus_hasNoPart, & +#endif +#ifdef Spectral + IO_open_file, & +#else + IO_open_InputFile, & +#endif + IO_timeStamp, & + IO_error, & + IO_write_jobFile + use debug, only: & + debug_e, & + debug_i, & + debug_level, & + debug_mesh, & + debug_levelBasic + use numerics, only: & + usePingPong, & + numerics_unitlength, & + worldrank + use FEsolving, only: & + FEsolving_execElem, & +#ifndef Spectral + modelName, & +#endif + FEsolving_execIP, & + calcMode + + implicit none +#ifdef Spectral + integer(C_INTPTR_T) :: gridMPI(3), alloc_local, local_K, local_K_offset +#endif + integer(pInt), parameter :: FILEUNIT = 222_pInt + integer(pInt), intent(in) :: el, ip + integer(pInt) :: j + logical :: myDebug + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- mesh init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + if (allocated(mesh_mapFEtoCPelem)) deallocate(mesh_mapFEtoCPelem) + if (allocated(mesh_mapFEtoCPnode)) deallocate(mesh_mapFEtoCPnode) + if (allocated(mesh_node0)) deallocate(mesh_node0) + if (allocated(mesh_node)) deallocate(mesh_node) + if (allocated(mesh_element)) deallocate(mesh_element) + if (allocated(mesh_cell)) deallocate(mesh_cell) + if (allocated(mesh_cellnode)) deallocate(mesh_cellnode) + if (allocated(mesh_cellnodeParent)) deallocate(mesh_cellnodeParent) + if (allocated(mesh_ipCoordinates)) deallocate(mesh_ipCoordinates) + if (allocated(mesh_ipArea)) deallocate(mesh_ipArea) + if (allocated(mesh_ipAreaNormal)) deallocate(mesh_ipAreaNormal) + if (allocated(mesh_sharedElem)) deallocate(mesh_sharedElem) + if (allocated(mesh_ipNeighborhood)) deallocate(mesh_ipNeighborhood) + if (allocated(mesh_ipVolume)) deallocate(mesh_ipVolume) + if (allocated(mesh_nodeTwins)) deallocate(mesh_nodeTwins) + if (allocated(FE_nodesAtIP)) deallocate(FE_nodesAtIP) + if (allocated(FE_ipNeighbor)) deallocate(FE_ipNeighbor) + if (allocated(FE_cellnodeParentnodeWeights)) deallocate(FE_cellnodeParentnodeWeights) + if (allocated(FE_subNodeOnIPFace)) deallocate(FE_subNodeOnIPFace) + call mesh_build_FEdata ! get properties of the different types of elements + mesh_unitlength = numerics_unitlength ! set physical extent of a length unit in mesh + + myDebug = (iand(debug_level(debug_mesh),debug_levelBasic) /= 0_pInt) + +#ifdef Spectral +#ifdef PETSc + call fftw_mpi_init() +#endif + call IO_open_file(FILEUNIT,geometryFile) ! parse info from geometry file... + if (myDebug) write(6,'(a)') ' Opened geometry file'; flush(6) + grid = mesh_spectral_getGrid(fileUnit) + geomSize = mesh_spectral_getSize(fileUnit) + +#ifdef PETSc + gridMPI = int(grid,C_INTPTR_T) + alloc_local = fftw_mpi_local_size_3d(gridMPI(3), gridMPI(2), gridMPI(1)/2 +1, & + MPI_COMM_WORLD, local_K, local_K_offset) + grid3 = int(local_K,pInt) + grid3Offset = int(local_K_offset,pInt) + + size3 = geomSize(3)*real(grid3,pReal) /real(grid(3),pReal) + size3Offset = geomSize(3)*real(grid3Offset,pReal)/real(grid(3),pReal) +#endif + + if (myDebug) write(6,'(a)') ' Grid partitioned'; flush(6) + call mesh_spectral_count() + if (myDebug) write(6,'(a)') ' Counted nodes/elements'; flush(6) + call mesh_spectral_mapNodesAndElems + if (myDebug) write(6,'(a)') ' Mapped nodes and elements'; flush(6) + call mesh_spectral_count_cpSizes + if (myDebug) write(6,'(a)') ' Built CP statistics'; flush(6) + call mesh_spectral_build_nodes() + if (myDebug) write(6,'(a)') ' Built nodes'; flush(6) + call mesh_spectral_build_elements(FILEUNIT) + if (myDebug) write(6,'(a)') ' Built elements'; flush(6) +#endif +#ifdef Marc4DAMASK + call IO_open_inputFile(FILEUNIT,modelName) ! parse info from input file... + if (myDebug) write(6,'(a)') ' Opened input file'; flush(6) + call mesh_marc_get_tableStyles(FILEUNIT) + if (myDebug) write(6,'(a)') ' Got table styles'; flush(6) + call mesh_marc_count_nodesAndElements(FILEUNIT) + if (myDebug) write(6,'(a)') ' Counted nodes/elements'; flush(6) + call mesh_marc_count_elementSets(FILEUNIT) + if (myDebug) write(6,'(a)') ' Counted element sets'; flush(6) + call mesh_marc_map_elementSets(FILEUNIT) + if (myDebug) write(6,'(a)') ' Mapped element sets'; flush(6) + call mesh_marc_count_cpElements(FILEUNIT) + if (myDebug) write(6,'(a)') ' Counted CP elements'; flush(6) + call mesh_marc_map_elements(FILEUNIT) + if (myDebug) write(6,'(a)') ' Mapped elements'; flush(6) + call mesh_marc_map_nodes(FILEUNIT) + if (myDebug) write(6,'(a)') ' Mapped nodes'; flush(6) + call mesh_marc_build_nodes(FILEUNIT) + if (myDebug) write(6,'(a)') ' Built nodes'; flush(6) + call mesh_marc_count_cpSizes(FILEUNIT) + if (myDebug) write(6,'(a)') ' Counted CP sizes'; flush(6) + call mesh_marc_build_elements(FILEUNIT) + if (myDebug) write(6,'(a)') ' Built elements'; flush(6) +#endif +#ifdef Abaqus + call IO_open_inputFile(FILEUNIT,modelName) ! parse info from input file... + if (myDebug) write(6,'(a)') ' Opened input file'; flush(6) + noPart = IO_abaqus_hasNoPart(FILEUNIT) + call mesh_abaqus_count_nodesAndElements(FILEUNIT) + if (myDebug) write(6,'(a)') ' Counted nodes/elements'; flush(6) + call mesh_abaqus_count_elementSets(FILEUNIT) + if (myDebug) write(6,'(a)') ' Counted element sets'; flush(6) + call mesh_abaqus_count_materials(FILEUNIT) + if (myDebug) write(6,'(a)') ' Counted materials'; flush(6) + call mesh_abaqus_map_elementSets(FILEUNIT) + if (myDebug) write(6,'(a)') ' Mapped element sets'; flush(6) + call mesh_abaqus_map_materials(FILEUNIT) + if (myDebug) write(6,'(a)') ' Mapped materials'; flush(6) + call mesh_abaqus_count_cpElements(FILEUNIT) + if (myDebug) write(6,'(a)') ' Counted CP elements'; flush(6) + call mesh_abaqus_map_elements(FILEUNIT) + if (myDebug) write(6,'(a)') ' Mapped elements'; flush(6) + call mesh_abaqus_map_nodes(FILEUNIT) + if (myDebug) write(6,'(a)') ' Mapped nodes'; flush(6) + call mesh_abaqus_build_nodes(FILEUNIT) + if (myDebug) write(6,'(a)') ' Built nodes'; flush(6) + call mesh_abaqus_count_cpSizes(FILEUNIT) + if (myDebug) write(6,'(a)') ' Counted CP sizes'; flush(6) + call mesh_abaqus_build_elements(FILEUNIT) + if (myDebug) write(6,'(a)') ' Built elements'; flush(6) +#endif + + call mesh_get_damaskOptions(FILEUNIT) + if (myDebug) write(6,'(a)') ' Got DAMASK options'; flush(6) + call mesh_build_cellconnectivity + if (myDebug) write(6,'(a)') ' Built cell connectivity'; flush(6) + mesh_cellnode = mesh_build_cellnodes(mesh_node,mesh_Ncellnodes) + if (myDebug) write(6,'(a)') ' Built cell nodes'; flush(6) + call mesh_build_ipCoordinates + if (myDebug) write(6,'(a)') ' Built IP coordinates'; flush(6) + call mesh_build_ipVolumes + if (myDebug) write(6,'(a)') ' Built IP volumes'; flush(6) + call mesh_build_ipAreas + if (myDebug) write(6,'(a)') ' Built IP areas'; flush(6) + close (FILEUNIT) + +#if defined(Marc4DAMASK) || defined(Abaqus) + call mesh_build_nodeTwins + if (myDebug) write(6,'(a)') ' Built node twins'; flush(6) + call mesh_build_sharedElems + if (myDebug) write(6,'(a)') ' Built shared elements'; flush(6) + call mesh_build_ipNeighborhood +#else + call mesh_spectral_build_ipNeighborhood(FILEUNIT) +#endif + if (myDebug) write(6,'(a)') ' Built IP neighborhood'; flush(6) + + if (worldrank == 0_pInt) then + call mesh_tell_statistics + call mesh_write_meshfile + call mesh_write_cellGeom + call mesh_write_elemGeom + endif + + if (usePingPong .and. (mesh_Nelems /= mesh_NcpElems)) & + call IO_error(600_pInt) ! ping-pong must be disabled when having non-DAMASK elements + if (debug_e < 1 .or. debug_e > mesh_NcpElems) & + call IO_error(602_pInt,ext_msg='element') ! selected element does not exist + if (debug_i < 1 .or. debug_i > FE_Nips(FE_geomtype(mesh_element(2_pInt,debug_e)))) & + call IO_error(602_pInt,ext_msg='IP') ! selected element does not have requested IP + + FEsolving_execElem = [ 1_pInt,mesh_NcpElems ] ! parallel loop bounds set to comprise all DAMASK elements + if (allocated(FEsolving_execIP)) deallocate(FEsolving_execIP) + allocate(FEsolving_execIP(2_pInt,mesh_NcpElems)); FEsolving_execIP = 1_pInt ! parallel loop bounds set to comprise from first IP... + forall (j = 1_pInt:mesh_NcpElems) FEsolving_execIP(2,j) = FE_Nips(FE_geomtype(mesh_element(2,j))) ! ...up to own IP count for each element + + if (allocated(calcMode)) deallocate(calcMode) + allocate(calcMode(mesh_maxNips,mesh_NcpElems)) + calcMode = .false. ! pretend to have collected what first call is asking (F = I) + calcMode(ip,mesh_FEasCP('elem',el)) = .true. ! first ip,el needs to be already pingponged to "calc" + + +end subroutine mesh_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief Gives the FE to CP ID mapping by binary search through lookup array +!! valid questions (what) are 'elem', 'node' +!-------------------------------------------------------------------------------------------------- +integer(pInt) function mesh_FEasCP(what,myID) + use IO, only: & + IO_lc + + implicit none + character(len=*), intent(in) :: what + integer(pInt), intent(in) :: myID + + integer(pInt), dimension(:,:), pointer :: lookupMap + integer(pInt) :: lower,upper,center + + mesh_FEasCP = 0_pInt + select case(IO_lc(what(1:4))) + case('elem') + lookupMap => mesh_mapFEtoCPelem + case('node') + lookupMap => mesh_mapFEtoCPnode + case default + return + endselect + + lower = 1_pInt + upper = int(size(lookupMap,2_pInt),pInt) + + if (lookupMap(1_pInt,lower) == myID) then ! check at bounds QUESTION is it valid to extend bounds by 1 and just do binary search w/o init check at bounds? + mesh_FEasCP = lookupMap(2_pInt,lower) + return + elseif (lookupMap(1_pInt,upper) == myID) then + mesh_FEasCP = lookupMap(2_pInt,upper) + return + endif + ! this might be the reason for the heap problems + binarySearch: do while (upper-lower > 1_pInt) + center = (lower+upper)/2_pInt + if (lookupMap(1_pInt,center) < myID) then + lower = center + elseif (lookupMap(1_pInt,center) > myID) then + upper = center + else + mesh_FEasCP = lookupMap(2_pInt,center) + exit + endif + enddo binarySearch + +end function mesh_FEasCP + + +!-------------------------------------------------------------------------------------------------- +!> @brief Split CP elements into cells. +!> @details Build a mapping between cells and the corresponding cell nodes ('mesh_cell'). +!> Cell nodes that are also matching nodes are unique in the list of cell nodes, +!> all others (currently) might be stored more than once. +!> Also allocates the 'mesh_node' array. +!-------------------------------------------------------------------------------------------------- +subroutine mesh_build_cellconnectivity + + implicit none + integer(pInt), dimension(:), allocatable :: & + matchingNode2cellnode + integer(pInt), dimension(:,:), allocatable :: & + cellnodeParent + integer(pInt), dimension(mesh_maxNcellnodes) :: & + localCellnode2globalCellnode + integer(pInt) :: & + e,t,g,c,n,i, & + matchingNodeID, & + localCellnodeID + + allocate(mesh_cell(FE_maxNcellnodesPerCell,mesh_maxNips,mesh_NcpElems), source=0_pInt) + allocate(matchingNode2cellnode(mesh_Nnodes), source=0_pInt) + allocate(cellnodeParent(2_pInt,mesh_maxNcellnodes*mesh_NcpElems), source=0_pInt) + +!-------------------------------------------------------------------------------------------------- +! Count cell nodes (including duplicates) and generate cell connectivity list + mesh_Ncellnodes = 0_pInt + mesh_Ncells = 0_pInt + do e = 1_pInt,mesh_NcpElems ! loop over cpElems + t = mesh_element(2_pInt,e) ! get element type + g = FE_geomtype(t) ! get geometry type + c = FE_celltype(g) ! get cell type + localCellnode2globalCellnode = 0_pInt + mesh_Ncells = mesh_Ncells + FE_Nips(g) + do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element + do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in this cell + localCellnodeID = FE_cell(n,i,g) + if (localCellnodeID <= FE_NmatchingNodes(g)) then ! this cell node is a matching node + matchingNodeID = mesh_element(4_pInt+localCellnodeID,e) + if (matchingNode2cellnode(matchingNodeID) == 0_pInt) then ! if this matching node does not yet exist in the glbal cell node list ... + mesh_Ncellnodes = mesh_Ncellnodes + 1_pInt ! ... count it as cell node ... + matchingNode2cellnode(matchingNodeID) = mesh_Ncellnodes ! ... and remember its global ID + cellnodeParent(1_pInt,mesh_Ncellnodes) = e ! ... and where it belongs to + cellnodeParent(2_pInt,mesh_Ncellnodes) = localCellnodeID + endif + mesh_cell(n,i,e) = matchingNode2cellnode(matchingNodeID) + else ! this cell node is no matching node + if (localCellnode2globalCellnode(localCellnodeID) == 0_pInt) then ! if this local cell node does not yet exist in the global cell node list ... + mesh_Ncellnodes = mesh_Ncellnodes + 1_pInt ! ... count it as cell node ... + localCellnode2globalCellnode(localCellnodeID) = mesh_Ncellnodes ! ... and remember its global ID ... + cellnodeParent(1_pInt,mesh_Ncellnodes) = e ! ... and it belongs to + cellnodeParent(2_pInt,mesh_Ncellnodes) = localCellnodeID + endif + mesh_cell(n,i,e) = localCellnode2globalCellnode(localCellnodeID) + endif + enddo + enddo + enddo + + allocate(mesh_cellnodeParent(2_pInt,mesh_Ncellnodes)) + allocate(mesh_cellnode(3_pInt,mesh_Ncellnodes)) + forall(n = 1_pInt:mesh_Ncellnodes) + mesh_cellnodeParent(1,n) = cellnodeParent(1,n) + mesh_cellnodeParent(2,n) = cellnodeParent(2,n) + endforall + + deallocate(matchingNode2cellnode) + deallocate(cellnodeParent) + +end subroutine mesh_build_cellconnectivity + + +!-------------------------------------------------------------------------------------------------- +!> @brief Calculate position of cellnodes from the given position of nodes +!> Build list of cellnodes' coordinates. +!> Cellnode coordinates are calculated from a weighted sum of node coordinates. +!-------------------------------------------------------------------------------------------------- +function mesh_build_cellnodes(nodes,Ncellnodes) + + implicit none + integer(pInt), intent(in) :: Ncellnodes !< requested number of cellnodes + real(pReal), dimension(3,mesh_Nnodes), intent(in) :: nodes + real(pReal), dimension(3,Ncellnodes) :: mesh_build_cellnodes + + integer(pInt) :: & + e,t,n,m, & + localCellnodeID + real(pReal), dimension(3) :: & + myCoords + + mesh_build_cellnodes = 0.0_pReal +!$OMP PARALLEL DO PRIVATE(e,localCellnodeID,t,myCoords) + do n = 1_pInt,Ncellnodes ! loop over cell nodes + e = mesh_cellnodeParent(1,n) + localCellnodeID = mesh_cellnodeParent(2,n) + t = mesh_element(2,e) ! get element type + myCoords = 0.0_pReal + do m = 1_pInt,FE_Nnodes(t) + myCoords = myCoords + nodes(1:3,mesh_element(4_pInt+m,e)) & + * FE_cellnodeParentnodeWeights(m,localCellnodeID,t) + enddo + mesh_build_cellnodes(1:3,n) = myCoords / sum(FE_cellnodeParentnodeWeights(:,localCellnodeID,t)) + enddo +!$OMP END PARALLEL DO + +end function mesh_build_cellnodes + + +!-------------------------------------------------------------------------------------------------- +!> @brief Calculates IP volume. Allocates global array 'mesh_ipVolume' +!> @details The IP volume is calculated differently depending on the cell type. +!> 2D cells assume an element depth of one in order to calculate the volume. +!> For the hexahedral cell we subdivide the cell into subvolumes of pyramidal +!> shape with a cell face as basis and the central ip at the tip. This subvolume is +!> calculated as an average of four tetrahedals with three corners on the cell face +!> and one corner at the central ip. +!-------------------------------------------------------------------------------------------------- +subroutine mesh_build_ipVolumes + use math, only: & + math_volTetrahedron, & + math_areaTriangle + + implicit none + integer(pInt) :: e,t,g,c,i,m,f,n + real(pReal), dimension(FE_maxNcellnodesPerCellface,FE_maxNcellfaces) :: subvolume + + if (.not. allocated(mesh_ipVolume)) then + allocate(mesh_ipVolume(mesh_maxNips,mesh_NcpElems)) + mesh_ipVolume = 0.0_pReal + endif + + !$OMP PARALLEL DO PRIVATE(t,g,c,m,subvolume) + do e = 1_pInt,mesh_NcpElems ! loop over cpElems + t = mesh_element(2_pInt,e) ! get element type + g = FE_geomtype(t) ! get geometry type + c = FE_celltype(g) ! get cell type + select case (c) + + case (1_pInt) ! 2D 3node + forall (i = 1_pInt:FE_Nips(g)) & ! loop over ips=cells in this element + mesh_ipVolume(i,e) = math_areaTriangle(mesh_cellnode(1:3,mesh_cell(1,i,e)), & + mesh_cellnode(1:3,mesh_cell(2,i,e)), & + mesh_cellnode(1:3,mesh_cell(3,i,e))) + + case (2_pInt) ! 2D 4node + forall (i = 1_pInt:FE_Nips(g)) & ! loop over ips=cells in this element + mesh_ipVolume(i,e) = math_areaTriangle(mesh_cellnode(1:3,mesh_cell(1,i,e)), & ! here we assume a planar shape, so division in two triangles suffices + mesh_cellnode(1:3,mesh_cell(2,i,e)), & + mesh_cellnode(1:3,mesh_cell(3,i,e))) & + + math_areaTriangle(mesh_cellnode(1:3,mesh_cell(3,i,e)), & + mesh_cellnode(1:3,mesh_cell(4,i,e)), & + mesh_cellnode(1:3,mesh_cell(1,i,e))) + + case (3_pInt) ! 3D 4node + forall (i = 1_pInt:FE_Nips(g)) & ! loop over ips=cells in this element + mesh_ipVolume(i,e) = math_volTetrahedron(mesh_cellnode(1:3,mesh_cell(1,i,e)), & + mesh_cellnode(1:3,mesh_cell(2,i,e)), & + mesh_cellnode(1:3,mesh_cell(3,i,e)), & + mesh_cellnode(1:3,mesh_cell(4,i,e))) + + case (4_pInt) ! 3D 8node + m = FE_NcellnodesPerCellface(c) + do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element + subvolume = 0.0_pReal + forall(f = 1_pInt:FE_NipNeighbors(c), n = 1_pInt:FE_NcellnodesPerCellface(c)) & + subvolume(n,f) = math_volTetrahedron(& + mesh_cellnode(1:3,mesh_cell(FE_cellface( n ,f,c),i,e)), & + mesh_cellnode(1:3,mesh_cell(FE_cellface(1+mod(n ,m),f,c),i,e)), & + mesh_cellnode(1:3,mesh_cell(FE_cellface(1+mod(n+1,m),f,c),i,e)), & + mesh_ipCoordinates(1:3,i,e)) + mesh_ipVolume(i,e) = 0.5_pReal * sum(subvolume) ! each subvolume is based on four tetrahedrons, altough the face consists of only two triangles -> averaging factor two + enddo + + end select + enddo + !$OMP END PARALLEL DO + +end subroutine mesh_build_ipVolumes + + +!-------------------------------------------------------------------------------------------------- +!> @brief Calculates IP Coordinates. Allocates global array 'mesh_ipCoordinates' +! Called by all solvers in mesh_init in order to initialize the ip coordinates. +! Later on the current ip coordinates are directly prvided by the spectral solver and by Abaqus, +! so no need to use this subroutine anymore; Marc however only provides nodal displacements, +! so in this case the ip coordinates are always calculated on the basis of this subroutine. +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! FOR THE MOMENT THIS SUBROUTINE ACTUALLY CALCULATES THE CELL CENTER AND NOT THE IP COORDINATES, +! AS THE IP IS NOT (ALWAYS) LOCATED IN THE CENTER OF THE IP VOLUME. +! HAS TO BE CHANGED IN A LATER VERSION. +! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!-------------------------------------------------------------------------------------------------- +subroutine mesh_build_ipCoordinates + + implicit none + integer(pInt) :: e,t,g,c,i,n + real(pReal), dimension(3) :: myCoords + + if (.not. allocated(mesh_ipCoordinates)) then + allocate(mesh_ipCoordinates(3,mesh_maxNips,mesh_NcpElems)) + mesh_ipCoordinates = 0.0_pReal + endif + + !$OMP PARALLEL DO PRIVATE(t,g,c,myCoords) + do e = 1_pInt,mesh_NcpElems ! loop over cpElems + t = mesh_element(2_pInt,e) ! get element type + g = FE_geomtype(t) ! get geometry type + c = FE_celltype(g) ! get cell type + do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element + myCoords = 0.0_pReal + do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in this cell + myCoords = myCoords + mesh_cellnode(1:3,mesh_cell(n,i,e)) + enddo + mesh_ipCoordinates(1:3,i,e) = myCoords / FE_NcellnodesPerCell(c) + enddo + enddo + !$OMP END PARALLEL DO + +end subroutine mesh_build_ipCoordinates + + +!-------------------------------------------------------------------------------------------------- +!> @brief Calculates cell center coordinates. +!-------------------------------------------------------------------------------------------------- +pure function mesh_cellCenterCoordinates(ip,el) + + implicit none + integer(pInt), intent(in) :: el, & !< element number + ip !< integration point number + real(pReal), dimension(3) :: mesh_cellCenterCoordinates !< x,y,z coordinates of the cell center of the requested IP cell + integer(pInt) :: t,g,c,n + + + t = mesh_element(2_pInt,el) ! get element type + g = FE_geomtype(t) ! get geometry type + c = FE_celltype(g) ! get cell type + mesh_cellCenterCoordinates = 0.0_pReal + do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in this cell + mesh_cellCenterCoordinates = mesh_cellCenterCoordinates + mesh_cellnode(1:3,mesh_cell(n,ip,el)) + enddo + mesh_cellCenterCoordinates = mesh_cellCenterCoordinates / FE_NcellnodesPerCell(c) + + end function mesh_cellCenterCoordinates + + +#ifdef Spectral +!-------------------------------------------------------------------------------------------------- +!> @brief Reads grid information from geometry file. If fileUnit is given, +!! assumes an opened file, otherwise tries to open the one specified in geometryFile +!-------------------------------------------------------------------------------------------------- +function mesh_spectral_getGrid(fileUnit) + use IO, only: & + IO_checkAndRewind, & + IO_open_file, & + IO_stringPos, & + IO_lc, & + IO_stringValue, & + IO_intValue, & + IO_floatValue, & + IO_error + use DAMASK_interface, only: & + geometryFile + + implicit none + integer(pInt), dimension(3) :: mesh_spectral_getGrid + integer(pInt), intent(in), optional :: fileUnit + integer(pInt), allocatable, dimension(:) :: chunkPos + + integer(pInt) :: headerLength = 0_pInt + character(len=1024) :: line, & + keyword + integer(pInt) :: i, j, myFileUnit + logical :: gotGrid = .false. + + mesh_spectral_getGrid = -1_pInt + if(.not. present(fileUnit)) then + myFileUnit = 289_pInt + call IO_open_file(myFileUnit,trim(geometryFile)) + else + myFileUnit = fileUnit + endif + + call IO_checkAndRewind(myFileUnit) + + read(myFileUnit,'(a1024)') line + chunkPos = IO_stringPos(line) + keyword = IO_lc(IO_StringValue(line,chunkPos,2_pInt,.true.)) + if (keyword(1:4) == 'head') then + headerLength = IO_intValue(line,chunkPos,1_pInt) + 1_pInt + else + call IO_error(error_ID=841_pInt, ext_msg='mesh_spectral_getGrid') + endif + rewind(myFileUnit) + do i = 1_pInt, headerLength + read(myFileUnit,'(a1024)') line + chunkPos = IO_stringPos(line) + select case ( IO_lc(IO_StringValue(line,chunkPos,1_pInt,.true.)) ) + case ('grid') + gotGrid = .true. + do j = 2_pInt,6_pInt,2_pInt + select case (IO_lc(IO_stringValue(line,chunkPos,j))) + case('a') + mesh_spectral_getGrid(1) = IO_intValue(line,chunkPos,j+1_pInt) + case('b') + mesh_spectral_getGrid(2) = IO_intValue(line,chunkPos,j+1_pInt) + case('c') + mesh_spectral_getGrid(3) = IO_intValue(line,chunkPos,j+1_pInt) + end select + enddo + end select + enddo + + if(.not. present(fileUnit)) close(myFileUnit) + + if (.not. gotGrid) & + call IO_error(error_ID = 845_pInt, ext_msg='grid') + if(any(mesh_spectral_getGrid < 1_pInt)) & + call IO_error(error_ID = 843_pInt, ext_msg='mesh_spectral_getGrid') + +end function mesh_spectral_getGrid + + +!-------------------------------------------------------------------------------------------------- +!> @brief Reads size information from geometry file. If fileUnit is given, +!! assumes an opened file, otherwise tries to open the one specified in geometryFile +!-------------------------------------------------------------------------------------------------- +function mesh_spectral_getSize(fileUnit) + use IO, only: & + IO_checkAndRewind, & + IO_open_file, & + IO_stringPos, & + IO_lc, & + IO_stringValue, & + IO_intValue, & + IO_floatValue, & + IO_error + use DAMASK_interface, only: & + geometryFile + + implicit none + real(pReal), dimension(3) :: mesh_spectral_getSize + integer(pInt), intent(in), optional :: fileUnit + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: headerLength = 0_pInt + character(len=1024) :: line, & + keyword + integer(pInt) :: i, j, myFileUnit + logical :: gotSize = .false. + + mesh_spectral_getSize = -1.0_pReal + if(.not. present(fileUnit)) then + myFileUnit = 289_pInt + call IO_open_file(myFileUnit,trim(geometryFile)) + else + myFileUnit = fileUnit + endif + + call IO_checkAndRewind(myFileUnit) + + read(myFileUnit,'(a1024)') line + chunkPos = IO_stringPos(line) + keyword = IO_lc(IO_StringValue(line,chunkPos,2_pInt,.true.)) + if (keyword(1:4) == 'head') then + headerLength = IO_intValue(line,chunkPos,1_pInt) + 1_pInt + else + call IO_error(error_ID=841_pInt, ext_msg='mesh_spectral_getSize') + endif + rewind(myFileUnit) + do i = 1_pInt, headerLength + read(myFileUnit,'(a1024)') line + chunkPos = IO_stringPos(line) + select case ( IO_lc(IO_StringValue(line,chunkPos,1,.true.)) ) + case ('size') + gotSize = .true. + do j = 2_pInt,6_pInt,2_pInt + select case (IO_lc(IO_stringValue(line,chunkPos,j))) + case('x') + mesh_spectral_getSize(1) = IO_floatValue(line,chunkPos,j+1_pInt) + case('y') + mesh_spectral_getSize(2) = IO_floatValue(line,chunkPos,j+1_pInt) + case('z') + mesh_spectral_getSize(3) = IO_floatValue(line,chunkPos,j+1_pInt) + end select + enddo + end select + enddo + + if(.not. present(fileUnit)) close(myFileUnit) + + if (.not. gotSize) & + call IO_error(error_ID = 845_pInt, ext_msg='size') + if (any(mesh_spectral_getSize<=0.0_pReal)) & + call IO_error(error_ID = 844_pInt, ext_msg='mesh_spectral_getSize') + +end function mesh_spectral_getSize + + +!-------------------------------------------------------------------------------------------------- +!> @brief Reads homogenization information from geometry file. If fileUnit is given, +!! assumes an opened file, otherwise tries to open the one specified in geometryFile +!-------------------------------------------------------------------------------------------------- +integer(pInt) function mesh_spectral_getHomogenization(fileUnit) + use IO, only: & + IO_checkAndRewind, & + IO_open_file, & + IO_stringPos, & + IO_lc, & + IO_stringValue, & + IO_intValue, & + IO_error + use DAMASK_interface, only: & + geometryFile + + implicit none + integer(pInt), intent(in), optional :: fileUnit + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: headerLength = 0_pInt + character(len=1024) :: line, & + keyword + integer(pInt) :: i, myFileUnit + logical :: gotHomogenization = .false. + + mesh_spectral_getHomogenization = -1_pInt + if(.not. present(fileUnit)) then + myFileUnit = 289_pInt + call IO_open_file(myFileUnit,trim(geometryFile)) + else + myFileUnit = fileUnit + endif + + call IO_checkAndRewind(myFileUnit) + + read(myFileUnit,'(a1024)') line + chunkPos = IO_stringPos(line) + keyword = IO_lc(IO_StringValue(line,chunkPos,2_pInt,.true.)) + if (keyword(1:4) == 'head') then + headerLength = IO_intValue(line,chunkPos,1_pInt) + 1_pInt + else + call IO_error(error_ID=841_pInt, ext_msg='mesh_spectral_getHomogenization') + endif + rewind(myFileUnit) + do i = 1_pInt, headerLength + read(myFileUnit,'(a1024)') line + chunkPos = IO_stringPos(line) + select case ( IO_lc(IO_StringValue(line,chunkPos,1,.true.)) ) + case ('homogenization') + gotHomogenization = .true. + mesh_spectral_getHomogenization = IO_intValue(line,chunkPos,2_pInt) + end select + enddo + + if(.not. present(fileUnit)) close(myFileUnit) + + if (.not. gotHomogenization ) & + call IO_error(error_ID = 845_pInt, ext_msg='homogenization') + if (mesh_spectral_getHomogenization<1_pInt) & + call IO_error(error_ID = 842_pInt, ext_msg='mesh_spectral_getHomogenization') + +end function mesh_spectral_getHomogenization + + +!-------------------------------------------------------------------------------------------------- +!> @brief Count overall number of nodes and elements in mesh and stores them in +!! 'mesh_Nelems', 'mesh_Nnodes' and 'mesh_NcpElems' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_spectral_count() + + implicit none + + mesh_Nelems = product(grid(1:2))*grid3 + mesh_NcpElems= mesh_Nelems + mesh_Nnodes = product(grid(1:2) + 1_pInt)*(grid3 + 1_pInt) + + mesh_NcpElemsGlobal = product(grid) + +end subroutine mesh_spectral_count + + +!-------------------------------------------------------------------------------------------------- +!> @brief fake map node from FE ID to internal (consecutive) representation for node and element +!! Allocates global array 'mesh_mapFEtoCPnode' and 'mesh_mapFEtoCPelem' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_spectral_mapNodesAndElems + use math, only: & + math_range + + implicit none + allocate (mesh_mapFEtoCPnode(2_pInt,mesh_Nnodes), source = 0_pInt) + allocate (mesh_mapFEtoCPelem(2_pInt,mesh_NcpElems), source = 0_pInt) + + mesh_mapFEtoCPnode = spread(math_range(mesh_Nnodes),1,2) + mesh_mapFEtoCPelem = spread(math_range(mesh_NcpElems),1,2) + +end subroutine mesh_spectral_mapNodesAndElems + + +!-------------------------------------------------------------------------------------------------- +!> @brief Gets maximum count of nodes, IPs, IP neighbors, and subNodes among cpElements. +!! Sets global values 'mesh_maxNnodes', 'mesh_maxNips', 'mesh_maxNipNeighbors', +!! and 'mesh_maxNcellnodes' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_spectral_count_cpSizes + + implicit none + integer(pInt) :: t,g,c + + t = FE_mapElemtype('C3D8R') ! fake 3D hexahedral 8 node 1 IP element + g = FE_geomtype(t) + c = FE_celltype(g) + + mesh_maxNnodes = FE_Nnodes(t) + mesh_maxNips = FE_Nips(g) + mesh_maxNipNeighbors = FE_NipNeighbors(c) + mesh_maxNcellnodes = FE_Ncellnodes(g) + +end subroutine mesh_spectral_count_cpSizes + + +!-------------------------------------------------------------------------------------------------- +!> @brief Store x,y,z coordinates of all nodes in mesh. +!! Allocates global arrays 'mesh_node0' and 'mesh_node' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_spectral_build_nodes() + + implicit none + integer(pInt) :: n + + allocate (mesh_node0 (3,mesh_Nnodes), source = 0.0_pReal) + allocate (mesh_node (3,mesh_Nnodes), source = 0.0_pReal) + + forall (n = 0_pInt:mesh_Nnodes-1_pInt) + mesh_node0(1,n+1_pInt) = mesh_unitlength * & + geomSize(1)*real(mod(n,(grid(1)+1_pInt) ),pReal) & + / real(grid(1),pReal) + mesh_node0(2,n+1_pInt) = mesh_unitlength * & + geomSize(2)*real(mod(n/(grid(1)+1_pInt),(grid(2)+1_pInt)),pReal) & + / real(grid(2),pReal) + mesh_node0(3,n+1_pInt) = mesh_unitlength * & + size3*real(mod(n/(grid(1)+1_pInt)/(grid(2)+1_pInt),(grid3+1_pInt)),pReal) & + / real(grid3,pReal) + & + size3offset + end forall + + mesh_node = mesh_node0 + +end subroutine mesh_spectral_build_nodes + + +!-------------------------------------------------------------------------------------------------- +!> @brief Store FEid, type, material, texture, and node list per element. +!! Allocates global array 'mesh_element' +!> @todo does the IO_error makes sense? +!-------------------------------------------------------------------------------------------------- +subroutine mesh_spectral_build_elements(fileUnit) + use IO, only: & + IO_checkAndRewind, & + IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_error, & + IO_continuousIntValues, & + IO_intValue, & + IO_countContinuousIntValues + + implicit none + integer(pInt), intent(in) :: & + fileUnit + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + e, i, & + headerLength = 0_pInt, & + maxIntCount, & + homog, & + elemType, & + elemOffset + integer(pInt), dimension(:), allocatable :: & + microstructures, & + mesh_microGlobal + integer(pInt), dimension(1,1) :: & + dummySet = 0_pInt + character(len=65536) :: & + line, & + keyword + character(len=64), dimension(1) :: & + dummyName = '' + + homog = mesh_spectral_getHomogenization(fileUnit) + +!-------------------------------------------------------------------------------------------------- +! get header length + call IO_checkAndRewind(fileUnit) + read(fileUnit,'(a65536)') line + chunkPos = IO_stringPos(line) + keyword = IO_lc(IO_StringValue(line,chunkPos,2_pInt,.true.)) + if (keyword(1:4) == 'head') then + headerLength = IO_intValue(line,chunkPos,1_pInt) + 1_pInt + else + call IO_error(error_ID=841_pInt, ext_msg='mesh_spectral_build_elements') + endif + +!-------------------------------------------------------------------------------------------------- +! get maximum microstructure index + call IO_checkAndRewind(fileUnit) + do i = 1_pInt, headerLength + read(fileUnit,'(a65536)') line + enddo + + maxIntCount = 0_pInt + i = 1_pInt + + do while (i > 0_pInt) + i = IO_countContinuousIntValues(fileUnit) + maxIntCount = max(maxIntCount, i) + enddo + allocate (mesh_element (4_pInt+mesh_maxNnodes,mesh_NcpElems), source = 0_pInt) + allocate (microstructures (1_pInt+maxIntCount), source = 1_pInt) + allocate (mesh_microGlobal(mesh_NcpElemsGlobal), source = 1_pInt) + +!-------------------------------------------------------------------------------------------------- +! read in microstructures + call IO_checkAndRewind(fileUnit) + do i=1_pInt,headerLength + read(fileUnit,'(a65536)') line + enddo + + e = 0_pInt + do while (e < mesh_NcpElemsGlobal .and. microstructures(1) > 0_pInt) ! fill expected number of elements, stop at end of data (or blank line!) + microstructures = IO_continuousIntValues(fileUnit,maxIntCount,dummyName,dummySet,0_pInt) ! get affected elements + do i = 1_pInt,microstructures(1_pInt) + e = e+1_pInt ! valid element entry + mesh_microGlobal(e) = microstructures(1_pInt+i) + enddo + enddo + + elemType = FE_mapElemtype('C3D8R') + elemOffset = product(grid(1:2))*grid3Offset + e = 0_pInt + do while (e < mesh_NcpElems) ! fill expected number of elements, stop at end of data (or blank line!) + e = e+1_pInt ! valid element entry + mesh_element( 1,e) = e ! FE id + mesh_element( 2,e) = elemType ! elem type + mesh_element( 3,e) = homog ! homogenization + mesh_element( 4,e) = mesh_microGlobal(e+elemOffset) ! microstructure + mesh_element( 5,e) = e + (e-1_pInt)/grid(1) + & + ((e-1_pInt)/(grid(1)*grid(2)))*(grid(1)+1_pInt) ! base node + mesh_element( 6,e) = mesh_element(5,e) + 1_pInt + mesh_element( 7,e) = mesh_element(5,e) + grid(1) + 2_pInt + mesh_element( 8,e) = mesh_element(5,e) + grid(1) + 1_pInt + mesh_element( 9,e) = mesh_element(5,e) +(grid(1) + 1_pInt) * (grid(2) + 1_pInt) ! second floor base node + mesh_element(10,e) = mesh_element(9,e) + 1_pInt + mesh_element(11,e) = mesh_element(9,e) + grid(1) + 2_pInt + mesh_element(12,e) = mesh_element(9,e) + grid(1) + 1_pInt + mesh_maxValStateVar(1) = max(mesh_maxValStateVar(1),mesh_element(3,e)) ! needed for statistics + mesh_maxValStateVar(2) = max(mesh_maxValStateVar(2),mesh_element(4,e)) + enddo + + deallocate(microstructures) + deallocate(mesh_microGlobal) + if (e /= mesh_NcpElems) call IO_error(880_pInt,e) + +end subroutine mesh_spectral_build_elements + + +!-------------------------------------------------------------------------------------------------- +!> @brief build neighborhood relations for spectral +!> @details assign globals: mesh_ipNeighborhood +!-------------------------------------------------------------------------------------------------- +subroutine mesh_spectral_build_ipNeighborhood(fileUnit) + + implicit none + integer(pInt), intent(in) :: & + fileUnit + integer(pInt) :: & + x,y,z, & + e + allocate(mesh_ipNeighborhood(3,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems),source=0_pInt) + + e = 0_pInt + do z = 0_pInt,grid3-1_pInt + do y = 0_pInt,grid(2)-1_pInt + do x = 0_pInt,grid(1)-1_pInt + e = e + 1_pInt + mesh_ipNeighborhood(1,1,1,e) = z * grid(1) * grid(2) & + + y * grid(1) & + + modulo(x+1_pInt,grid(1)) & + + 1_pInt + mesh_ipNeighborhood(1,2,1,e) = z * grid(1) * grid(2) & + + y * grid(1) & + + modulo(x-1_pInt,grid(1)) & + + 1_pInt + mesh_ipNeighborhood(1,3,1,e) = z * grid(1) * grid(2) & + + modulo(y+1_pInt,grid(2)) * grid(1) & + + x & + + 1_pInt + mesh_ipNeighborhood(1,4,1,e) = z * grid(1) * grid(2) & + + modulo(y-1_pInt,grid(2)) * grid(1) & + + x & + + 1_pInt + mesh_ipNeighborhood(1,5,1,e) = modulo(z+1_pInt,grid3) * grid(1) * grid(2) & + + y * grid(1) & + + x & + + 1_pInt + mesh_ipNeighborhood(1,6,1,e) = modulo(z-1_pInt,grid3) * grid(1) * grid(2) & + + y * grid(1) & + + x & + + 1_pInt + mesh_ipNeighborhood(2,1:6,1,e) = 1_pInt + mesh_ipNeighborhood(3,1,1,e) = 2_pInt + mesh_ipNeighborhood(3,2,1,e) = 1_pInt + mesh_ipNeighborhood(3,3,1,e) = 4_pInt + mesh_ipNeighborhood(3,4,1,e) = 3_pInt + mesh_ipNeighborhood(3,5,1,e) = 6_pInt + mesh_ipNeighborhood(3,6,1,e) = 5_pInt + enddo + enddo + enddo + +end subroutine mesh_spectral_build_ipNeighborhood + + +!-------------------------------------------------------------------------------------------------- +!> @brief builds mesh of (distorted) cubes for given coordinates (= center of the cubes) +!-------------------------------------------------------------------------------------------------- +function mesh_nodesAroundCentres(gDim,Favg,centres) result(nodes) + use debug, only: & + debug_mesh, & + debug_level, & + debug_levelBasic + use math, only: & + math_mul33x3 + + implicit none + real(pReal), intent(in), dimension(:,:,:,:) :: & + centres + real(pReal), dimension(3,size(centres,2)+1,size(centres,3)+1,size(centres,4)+1) :: & + nodes + real(pReal), intent(in), dimension(3) :: & + gDim + real(pReal), intent(in), dimension(3,3) :: & + Favg + real(pReal), dimension(3,size(centres,2)+2,size(centres,3)+2,size(centres,4)+2) :: & + wrappedCentres + + integer(pInt) :: & + i,j,k,n + integer(pInt), dimension(3), parameter :: & + diag = 1_pInt + integer(pInt), dimension(3) :: & + shift = 0_pInt, & + lookup = 0_pInt, & + me = 0_pInt, & + iRes = 0_pInt + integer(pInt), dimension(3,8) :: & + neighbor = reshape([ & + 0_pInt, 0_pInt, 0_pInt, & + 1_pInt, 0_pInt, 0_pInt, & + 1_pInt, 1_pInt, 0_pInt, & + 0_pInt, 1_pInt, 0_pInt, & + 0_pInt, 0_pInt, 1_pInt, & + 1_pInt, 0_pInt, 1_pInt, & + 1_pInt, 1_pInt, 1_pInt, & + 0_pInt, 1_pInt, 1_pInt ], [3,8]) + +!-------------------------------------------------------------------------------------------------- +! initializing variables + iRes = [size(centres,2),size(centres,3),size(centres,4)] + nodes = 0.0_pReal + wrappedCentres = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! report + if (iand(debug_level(debug_mesh),debug_levelBasic) /= 0_pInt) then + write(6,'(a)') ' Meshing cubes around centroids' + write(6,'(a,3(e12.5))') ' Dimension: ', gDim + write(6,'(a,3(i5))') ' Resolution:', iRes + endif + +!-------------------------------------------------------------------------------------------------- +! building wrappedCentres = centroids + ghosts + wrappedCentres(1:3,2_pInt:iRes(1)+1_pInt,2_pInt:iRes(2)+1_pInt,2_pInt:iRes(3)+1_pInt) = centres + do k = 0_pInt,iRes(3)+1_pInt + do j = 0_pInt,iRes(2)+1_pInt + do i = 0_pInt,iRes(1)+1_pInt + if (k==0_pInt .or. k==iRes(3)+1_pInt .or. & ! z skin + j==0_pInt .or. j==iRes(2)+1_pInt .or. & ! y skin + i==0_pInt .or. i==iRes(1)+1_pInt ) then ! x skin + me = [i,j,k] ! me on skin + shift = sign(abs(iRes+diag-2_pInt*me)/(iRes+diag),iRes+diag-2_pInt*me) + lookup = me-diag+shift*iRes + wrappedCentres(1:3,i+1_pInt, j+1_pInt, k+1_pInt) = & + centres(1:3,lookup(1)+1_pInt,lookup(2)+1_pInt,lookup(3)+1_pInt) - & + math_mul33x3(Favg, shift*gDim) + endif + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! averaging + do k = 0_pInt,iRes(3); do j = 0_pInt,iRes(2); do i = 0_pInt,iRes(1) + do n = 1_pInt,8_pInt + nodes(1:3,i+1_pInt,j+1_pInt,k+1_pInt) = & + nodes(1:3,i+1_pInt,j+1_pInt,k+1_pInt) + wrappedCentres(1:3,i+1_pInt+neighbor(1,n), & + j+1_pInt+neighbor(2,n), & + k+1_pInt+neighbor(3,n) ) + enddo + enddo; enddo; enddo + nodes = nodes/8.0_pReal + +end function mesh_nodesAroundCentres + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate coordinates in current configuration for given defgrad +! using integration in Fourier space +!-------------------------------------------------------------------------------------------------- +function mesh_deformedCoordsFFT(gDim,F,FavgIn,scalingIn) result(coords) + use IO, only: & + IO_error + use numerics, only: & + fftw_timelimit, & + fftw_planner_flag + use debug, only: & + debug_mesh, & + debug_level, & + debug_levelBasic + use math, only: & + PI, & + math_mul33x3 + + implicit none + real(pReal), intent(in), dimension(:,:,:,:,:) :: F + real(pReal), dimension(3,size(F,3),size(F,4),size(F,5)) :: coords + real(pReal), intent(in), dimension(3) :: gDim + real(pReal), intent(in), dimension(3,3), optional :: FavgIn + real(pReal), intent(in), dimension(3), optional :: scalingIn + +! allocatable arrays for fftw c routines + type(C_PTR) :: planForth, planBack + type(C_PTR) :: coords_fftw, defgrad_fftw + real(pReal), dimension(:,:,:,:,:), pointer :: F_real + complex(pReal), dimension(:,:,:,:,:), pointer :: F_fourier + real(pReal), dimension(:,:,:,:), pointer :: coords_real + complex(pReal), dimension(:,:,:,:), pointer :: coords_fourier + ! other variables + integer(pInt) :: i, j, k, m, res1Red + integer(pInt), dimension(3) :: k_s, iRes + real(pReal), dimension(3) :: scaling, step, offset_coords, integrator + real(pReal), dimension(3,3) :: Favg + integer(pInt), dimension(2:3,2) :: Nyquist ! highest frequencies to be removed (1 if even, 2 if odd) + + if (present(scalingIn)) then + where (scalingIn < 0.0_pReal) ! invalid values. in case of f2py -1 if not present + scaling = [1.0_pReal,1.0_pReal,1.0_pReal] + elsewhere + scaling = scalingIn + end where + else + scaling = 1.0_pReal + endif + + iRes = [size(F,3),size(F,4),size(F,5)] + integrator = gDim / 2.0_pReal / PI ! see notes where it is used + res1Red = iRes(1)/2_pInt + 1_pInt ! size of complex array in first dimension (c2r, r2c) + step = gDim/real(iRes, pReal) + Nyquist(2,1:2) = [iRes(2)/2_pInt + 1_pInt, iRes(2)/2_pInt + 1_pInt + mod(iRes(2),2_pInt)] + Nyquist(3,1:2) = [iRes(3)/2_pInt + 1_pInt, iRes(3)/2_pInt + 1_pInt + mod(iRes(3),2_pInt)] + +!-------------------------------------------------------------------------------------------------- +! report + if (iand(debug_level(debug_mesh),debug_levelBasic) /= 0_pInt) then + write(6,'(a)') ' Restore geometry using FFT-based integration' + write(6,'(a,3(i12 ))') ' grid a b c: ', iRes + write(6,'(a,3(es12.5))') ' size x y z: ', gDim + endif + +!-------------------------------------------------------------------------------------------------- +! sanity check + if (pReal /= C_DOUBLE .or. pInt /= C_INT) & + call IO_error(0_pInt,ext_msg='Fortran to C in mesh_deformedCoordsFFT') + +!-------------------------------------------------------------------------------------------------- +! allocation and FFTW initialization + defgrad_fftw = fftw_alloc_complex(int(res1Red *iRes(2)*iRes(3)*9_pInt,C_SIZE_T)) ! C_SIZE_T is of type integer(8) + coords_fftw = fftw_alloc_complex(int(res1Red *iRes(2)*iRes(3)*3_pInt,C_SIZE_T)) ! C_SIZE_T is of type integer(8) + call c_f_pointer(defgrad_fftw, F_real, & + [iRes(1)+2_pInt-mod(iRes(1),2_pInt),iRes(2),iRes(3),3_pInt,3_pInt]) + call c_f_pointer(defgrad_fftw, F_fourier, & + [res1Red, iRes(2),iRes(3),3_pInt,3_pInt]) + call c_f_pointer(coords_fftw, coords_real, & + [iRes(1)+2_pInt-mod(iRes(1),2_pInt),iRes(2),iRes(3),3_pInt]) + call c_f_pointer(coords_fftw, coords_fourier, & + [res1Red, iRes(2),iRes(3),3_pInt]) + + call fftw_set_timelimit(fftw_timelimit) + planForth = fftw_plan_many_dft_r2c(3_pInt,[iRes(3),iRes(2) ,iRes(1)],9_pInt,& ! dimensions , length in each dimension in reversed order + F_real,[iRes(3),iRes(2) ,iRes(1)+2_pInt-mod(iRes(1),2_pInt)],& ! input data , physical length in each dimension in reversed order + 1_pInt, iRes(3)*iRes(2)*(iRes(1)+2_pInt-mod(iRes(1),2_pInt)),& ! striding , product of physical lenght in the 3 dimensions + F_fourier,[iRes(3),iRes(2) ,res1Red],& + 1_pInt, iRes(3)*iRes(2)* res1Red,fftw_planner_flag) + + planBack = fftw_plan_many_dft_c2r(3_pInt,[iRes(3),iRes(2) ,iRes(1)],3_pInt,& + coords_fourier,[iRes(3),iRes(2) ,res1Red],& + 1_pInt, iRes(3)*iRes(2)* res1Red,& + coords_real,[iRes(3),iRes(2) ,iRes(1)+2_pInt-mod(iRes(1),2_pInt)],& + 1_pInt, iRes(3)*iRes(2)*(iRes(1)+2_pInt-mod(iRes(1),2_pInt)),& + fftw_planner_flag) + F_real(1:iRes(1),1:iRes(2),1:iRes(3),1:3,1:3) = & + reshape(F,[iRes(1),iRes(2),iRes(3),3,3], order = [4,5,1,2,3]) ! F_real is overwritten during plan creatio, is larger (padding) and has different order + +!-------------------------------------------------------------------------------------------------- +! FFT + call fftw_execute_dft_r2c(planForth, F_real, F_fourier) + +!-------------------------------------------------------------------------------------------------- +! if no average F is given, compute it in Fourier space + if (present(FavgIn)) then + if (all(FavgIn < 0.0_pReal)) then + Favg = real(F_fourier(1,1,1,1:3,1:3),pReal)/real(product(iRes),pReal) !the f2py way to tell it is not present + else + Favg = FavgIn + endif + else + Favg = real(F_fourier(1,1,1,1:3,1:3),pReal)/real(product(iRes),pReal) + endif + +!-------------------------------------------------------------------------------------------------- +! remove highest frequency in each direction, in third direction only if not 2D + + if(iRes(1)/=1_pInt) & ! do not delete the whole slice in case of 2D calculation + F_fourier (res1Red, 1:iRes(2), 1:iRes(3), 1:3,1:3) & + = cmplx(0.0_pReal,0.0_pReal,pReal) + if(iRes(2)/=1_pInt) & ! do not delete the whole slice in case of 2D calculation + F_fourier (1:res1Red,Nyquist(2,1):Nyquist(2,2),1:iRes(3), 1:3,1:3) & + = cmplx(0.0_pReal,0.0_pReal,pReal) + if(iRes(3)/=1_pInt) & ! do not delete the whole slice in case of 2D calculation + F_fourier (1:res1Red,1:iRes(2), Nyquist(3,1):Nyquist(3,2),1:3,1:3) & + = cmplx(0.0_pReal,0.0_pReal,pReal) + +!-------------------------------------------------------------------------------------------------- +! integration in Fourier space + coords_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) + do k = 1_pInt, iRes(3) + k_s(3) = k-1_pInt + if(k > iRes(3)/2_pInt+1_pInt) k_s(3) = k_s(3)-iRes(3) + do j = 1_pInt, iRes(2) + k_s(2) = j-1_pInt + if(j > iRes(2)/2_pInt+1_pInt) k_s(2) = k_s(2)-iRes(2) + do i = 1_pInt, res1Red + k_s(1) = i-1_pInt + do m = 1_pInt,3_pInt + coords_fourier(i,j,k,m) = sum(F_fourier(i,j,k,m,1:3)*& + cmplx(0.0_pReal,real(k_s,pReal)*integrator,pReal)) + enddo + if (any(k_s /= 0_pInt)) coords_fourier(i,j,k,1:3) = & + coords_fourier(i,j,k,1:3) / cmplx(-sum(k_s*k_s),0.0_pReal,pReal) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! iFFT and freeing memory + call fftw_execute_dft_c2r(planBack,coords_fourier,coords_real) + coords = reshape(coords_real(1:iRes(1),1:iRes(2),1:iRes(3),1:3), [3,iRes(1),iRes(2),iRes(3)], & + order = [2,3,4,1])/real(product(iRes),pReal) ! weight and change order + call fftw_destroy_plan(planForth) + call fftw_destroy_plan(planBack) + call fftw_free(defgrad_fftw) + call fftw_free(coords_fftw) + +!-------------------------------------------------------------------------------------------------- +! add average to scaled fluctuation and put (0,0,0) on (0,0,0) + offset_coords = math_mul33x3(F(1:3,1:3,1,1,1),step/2.0_pReal) - scaling*coords(1:3,1,1,1) + forall(k = 1_pInt:iRes(3), j = 1_pInt:iRes(2), i = 1_pInt:iRes(1)) & + coords(1:3,i,j,k) = scaling(1:3)*coords(1:3,i,j,k) & + + offset_coords & + + math_mul33x3(Favg,step*real([i,j,k]-1_pInt,pReal)) + +end function mesh_deformedCoordsFFT + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the mismatch between volume of reconstructed (compatible) cube and +! determinant of defgrad at the FP +!-------------------------------------------------------------------------------------------------- +function mesh_volumeMismatch(gDim,F,nodes) result(vMismatch) + use IO, only: & + IO_error + use debug, only: & + debug_mesh, & + debug_level, & + debug_levelBasic + use math, only: & + math_det33, & + math_volTetrahedron + + implicit none + real(pReal), intent(in), dimension(:,:,:,:,:) :: & + F + real(pReal), dimension(size(F,3),size(F,4),size(F,5)) :: & + vMismatch + real(pReal), intent(in), dimension(:,:,:,:) :: & + nodes + real(pReal), dimension(3) :: & + gDim + integer(pInt), dimension(3) :: & + iRes + real(pReal), dimension(3,8) :: coords + integer(pInt) :: i,j,k + real(pReal) :: volInitial + + iRes = [size(F,3),size(F,4),size(F,5)] + volInitial = product(gDim)/real(product(iRes), pReal) + +!-------------------------------------------------------------------------------------------------- +! report and check + if (iand(debug_level(debug_mesh),debug_levelBasic) /= 0_pInt) then + write(6,'(a)') ' Calculating volume mismatch' + write(6,'(a,3(i12 ))') ' grid a b c: ', iRes + write(6,'(a,3(es12.5))') ' size x y z: ', gDim + endif + + if (any([iRes/=size(nodes,2)-1_pInt,iRes/=size(nodes,3)-1_pInt,iRes/=size(nodes,4)-1_pInt]))& + call IO_error(0_pInt,ext_msg='Arrays F and nodes in mesh_volumeMismatch') + +!-------------------------------------------------------------------------------------------------- +! calculate actual volume and volume resulting from deformation gradient + do k = 1_pInt,iRes(3) + do j = 1_pInt,iRes(2) + do i = 1_pInt,iRes(1) + coords(1:3,1) = nodes(1:3,i, j, k ) + coords(1:3,2) = nodes(1:3,i+1_pInt,j, k ) + coords(1:3,3) = nodes(1:3,i+1_pInt,j+1_pInt,k ) + coords(1:3,4) = nodes(1:3,i, j+1_pInt,k ) + coords(1:3,5) = nodes(1:3,i, j, k+1_pInt) + coords(1:3,6) = nodes(1:3,i+1_pInt,j, k+1_pInt) + coords(1:3,7) = nodes(1:3,i+1_pInt,j+1_pInt,k+1_pInt) + coords(1:3,8) = nodes(1:3,i, j+1_pInt,k+1_pInt) + vMismatch(i,j,k) = & + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,1),coords(1:3,8),coords(1:3,4))) & + + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,1),coords(1:3,8),coords(1:3,5))) & + + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,1),coords(1:3,3),coords(1:3,4))) & + + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,1),coords(1:3,3),coords(1:3,2))) & + + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,5),coords(1:3,2),coords(1:3,6))) & + + abs(math_volTetrahedron(coords(1:3,7),coords(1:3,5),coords(1:3,2),coords(1:3,1))) + vMismatch(i,j,k) = vMismatch(i,j,k)/math_det33(F(1:3,1:3,i,j,k)) + enddo; enddo; enddo + vMismatch = vMismatch/volInitial + +end function mesh_volumeMismatch + + +!-------------------------------------------------------------------------------------------------- +!> @brief Routine to calculate the mismatch between the vectors from the central point to +! the corners of reconstructed (combatible) volume element and the vectors calculated by deforming +! the initial volume element with the current deformation gradient +!-------------------------------------------------------------------------------------------------- +function mesh_shapeMismatch(gDim,F,nodes,centres) result(sMismatch) + use IO, only: & + IO_error + use debug, only: & + debug_mesh, & + debug_level, & + debug_levelBasic + use math, only: & + math_mul33x3 + + implicit none + real(pReal), intent(in), dimension(:,:,:,:,:) :: & + F + real(pReal), dimension(size(F,3),size(F,4),size(F,5)) :: & + sMismatch + real(pReal), intent(in), dimension(:,:,:,:) :: & + nodes, & + centres + real(pReal), dimension(3) :: & + gDim, & + fRes + integer(pInt), dimension(3) :: & + iRes + real(pReal), dimension(3,8) :: coordsInitial + integer(pInt) i,j,k + + iRes = [size(F,3),size(F,4),size(F,5)] + fRes = real(iRes,pReal) + +!-------------------------------------------------------------------------------------------------- +! report and check + if (iand(debug_level(debug_mesh),debug_levelBasic) /= 0_pInt) then + write(6,'(a)') ' Calculating shape mismatch' + write(6,'(a,3(i12 ))') ' grid a b c: ', iRes + write(6,'(a,3(es12.5))') ' size x y z: ', gDim + endif + + if(any([iRes/=size(nodes,2)-1_pInt,iRes/=size(nodes,3)-1_pInt,iRes/=size(nodes,4)-1_pInt]) .or.& + any([iRes/=size(centres,2), iRes/=size(centres,3), iRes/=size(centres,4)]))& + call IO_error(0_pInt,ext_msg='Arrays F and nodes/centres in mesh_shapeMismatch') + +!-------------------------------------------------------------------------------------------------- +! initial positions + coordsInitial(1:3,1) = [-gDim(1)/fRes(1),-gDim(2)/fRes(2),-gDim(3)/fRes(3)] + coordsInitial(1:3,2) = [+gDim(1)/fRes(1),-gDim(2)/fRes(2),-gDim(3)/fRes(3)] + coordsInitial(1:3,3) = [+gDim(1)/fRes(1),+gDim(2)/fRes(2),-gDim(3)/fRes(3)] + coordsInitial(1:3,4) = [-gDim(1)/fRes(1),+gDim(2)/fRes(2),-gDim(3)/fRes(3)] + coordsInitial(1:3,5) = [-gDim(1)/fRes(1),-gDim(2)/fRes(2),+gDim(3)/fRes(3)] + coordsInitial(1:3,6) = [+gDim(1)/fRes(1),-gDim(2)/fRes(2),+gDim(3)/fRes(3)] + coordsInitial(1:3,7) = [+gDim(1)/fRes(1),+gDim(2)/fRes(2),+gDim(3)/fRes(3)] + coordsInitial(1:3,8) = [-gDim(1)/fRes(1),+gDim(2)/fRes(2),+gDim(3)/fRes(3)] + coordsInitial = coordsInitial/2.0_pReal + +!-------------------------------------------------------------------------------------------------- +! compare deformed original and deformed positions to actual positions + do k = 1_pInt,iRes(3) + do j = 1_pInt,iRes(2) + do i = 1_pInt,iRes(1) + sMismatch(i,j,k) = & + sqrt(sum((nodes(1:3,i, j, k ) - centres(1:3,i,j,k)& + - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,1)))**2.0_pReal))& + + sqrt(sum((nodes(1:3,i+1_pInt,j, k ) - centres(1:3,i,j,k)& + - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,2)))**2.0_pReal))& + + sqrt(sum((nodes(1:3,i+1_pInt,j+1_pInt,k ) - centres(1:3,i,j,k)& + - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,3)))**2.0_pReal))& + + sqrt(sum((nodes(1:3,i, j+1_pInt,k ) - centres(1:3,i,j,k)& + - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,4)))**2.0_pReal))& + + sqrt(sum((nodes(1:3,i, j, k+1_pInt) - centres(1:3,i,j,k)& + - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,5)))**2.0_pReal))& + + sqrt(sum((nodes(1:3,i+1_pInt,j, k+1_pInt) - centres(1:3,i,j,k)& + - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,6)))**2.0_pReal))& + + sqrt(sum((nodes(1:3,i+1_pInt,j+1_pInt,k+1_pInt) - centres(1:3,i,j,k)& + - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,7)))**2.0_pReal))& + + sqrt(sum((nodes(1:3,i, j+1_pInt,k+1_pInt) - centres(1:3,i,j,k)& + - math_mul33x3(F(1:3,1:3,i,j,k), coordsInitial(1:3,8)))**2.0_pReal)) + enddo; enddo; enddo + +end function mesh_shapeMismatch +#endif + + +#ifdef Marc4DAMASK +!-------------------------------------------------------------------------------------------------- +!> @brief Figures out table styles (Marc only) and stores to 'initialcondTableStyle' and +!! 'hypoelasticTableStyle' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_marc_get_tableStyles(fileUnit) + use IO, only: & + IO_lc, & + IO_intValue, & + IO_stringValue, & + IO_stringPos + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) line + + initialcondTableStyle = 0_pInt + hypoelasticTableStyle = 0_pInt + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'table' .and. chunkPos(1_pInt) > 5) then + initialcondTableStyle = IO_intValue(line,chunkPos,4_pInt) + hypoelasticTableStyle = IO_intValue(line,chunkPos,5_pInt) + exit + endif + enddo + +620 end subroutine mesh_marc_get_tableStyles + + +!-------------------------------------------------------------------------------------------------- +!> @brief Count overall number of nodes and elements in mesh and stores the numbers in +!! 'mesh_Nelems' and 'mesh_Nnodes' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_marc_count_nodesAndElements(fileUnit) + use IO, only: & + IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_IntValue + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) line + + mesh_Nnodes = 0_pInt + mesh_Nelems = 0_pInt + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + + if ( IO_lc(IO_StringValue(line,chunkPos,1_pInt)) == 'sizing') & + mesh_Nelems = IO_IntValue (line,chunkPos,3_pInt) + if ( IO_lc(IO_StringValue(line,chunkPos,1_pInt)) == 'coordinates') then + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + mesh_Nnodes = IO_IntValue (line,chunkPos,2_pInt) + exit ! assumes that "coordinates" comes later in file + endif + enddo + +620 end subroutine mesh_marc_count_nodesAndElements + + +!-------------------------------------------------------------------------------------------------- +!> @brief Count overall number of element sets in mesh. Stores to 'mesh_NelemSets', and +!! 'mesh_maxNelemInSet' +!-------------------------------------------------------------------------------------------------- + subroutine mesh_marc_count_elementSets(fileUnit) + use IO, only: & + IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_countContinuousIntValues + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) line + + mesh_NelemSets = 0_pInt + mesh_maxNelemInSet = 0_pInt + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + + if ( IO_lc(IO_StringValue(line,chunkPos,1_pInt)) == 'define' .and. & + IO_lc(IO_StringValue(line,chunkPos,2_pInt)) == 'element' ) then + mesh_NelemSets = mesh_NelemSets + 1_pInt + mesh_maxNelemInSet = max(mesh_maxNelemInSet, & + IO_countContinuousIntValues(fileUnit)) + endif + enddo + +620 end subroutine mesh_marc_count_elementSets + + +!******************************************************************** +! map element sets +! +! allocate globals: mesh_nameElemSet, mesh_mapElemSet +!******************************************************************** +subroutine mesh_marc_map_elementSets(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_continuousIntValues + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + integer(pInt) :: elemSet = 0_pInt + + allocate (mesh_nameElemSet(mesh_NelemSets)) ; mesh_nameElemSet = '' + allocate (mesh_mapElemSet(1_pInt+mesh_maxNelemInSet,mesh_NelemSets)) ; mesh_mapElemSet = 0_pInt + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=640) line + chunkPos = IO_stringPos(line) + if( (IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'define' ) .and. & + (IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'element' ) ) then + elemSet = elemSet+1_pInt + mesh_nameElemSet(elemSet) = trim(IO_stringValue(line,chunkPos,4_pInt)) + mesh_mapElemSet(:,elemSet) = & + IO_continuousIntValues(fileUnit,mesh_maxNelemInSet,mesh_nameElemSet,mesh_mapElemSet,mesh_NelemSets) + endif + enddo + +640 end subroutine mesh_marc_map_elementSets + + +!-------------------------------------------------------------------------------------------------- +!> @brief Count overall number of CP elements in mesh and stores them in 'mesh_NcpElems' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_marc_count_cpElements(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_countContinuousIntValues + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: i + character(len=300):: line + + mesh_NcpElems = 0_pInt + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'hypoelastic') then + do i=1_pInt,3_pInt+hypoelasticTableStyle ! Skip 3 or 4 lines + read (fileUnit,610,END=620) line + enddo + mesh_NcpElems = mesh_NcpElems + IO_countContinuousIntValues(fileUnit) ! why not simply mesh_NcpElems = IO_countContinuousIntValues(fileUnit)? + exit + endif + enddo + +620 end subroutine mesh_marc_count_cpElements + + +!-------------------------------------------------------------------------------------------------- +!> @brief Maps elements from FE ID to internal (consecutive) representation. +!! Allocates global array 'mesh_mapFEtoCPelem' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_marc_map_elements(fileUnit) + + use math, only: math_qsort + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_continuousIntValues + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + + integer(pInt), dimension (1_pInt+mesh_NcpElems) :: contInts + integer(pInt) :: i,cpElem = 0_pInt + + allocate (mesh_mapFEtoCPelem(2,mesh_NcpElems)) ; mesh_mapFEtoCPelem = 0_pInt + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=660) line + chunkPos = IO_stringPos(line) + if( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'hypoelastic' ) then + do i=1_pInt,3_pInt+hypoelasticTableStyle ! skip three (or four if new table style!) lines + read (fileUnit,610,END=660) line + enddo + contInts = IO_continuousIntValues(fileUnit,mesh_NcpElems,mesh_nameElemSet,& + mesh_mapElemSet,mesh_NelemSets) + do i = 1_pInt,contInts(1) + cpElem = cpElem+1_pInt + mesh_mapFEtoCPelem(1,cpElem) = contInts(1_pInt+i) + mesh_mapFEtoCPelem(2,cpElem) = cpElem + enddo + endif + enddo + +660 call math_qsort(mesh_mapFEtoCPelem,1_pInt,int(size(mesh_mapFEtoCPelem,2_pInt),pInt)) ! should be mesh_NcpElems + +end subroutine mesh_marc_map_elements + + +!-------------------------------------------------------------------------------------------------- +!> @brief Maps node from FE ID to internal (consecutive) representation. +!! Allocates global array 'mesh_mapFEtoCPnode' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_marc_map_nodes(fileUnit) + + use math, only: math_qsort + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_fixedIntValue + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) line + + integer(pInt), dimension (mesh_Nnodes) :: node_count + integer(pInt) :: i + + allocate (mesh_mapFEtoCPnode(2_pInt,mesh_Nnodes)) ; mesh_mapFEtoCPnode = 0_pInt + +610 FORMAT(A300) + + node_count = 0_pInt + + rewind(fileUnit) + do + read (fileUnit,610,END=650) line + chunkPos = IO_stringPos(line) + if( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'coordinates' ) then + read (fileUnit,610,END=650) line ! skip crap line + do i = 1_pInt,mesh_Nnodes + read (fileUnit,610,END=650) line + mesh_mapFEtoCPnode(1_pInt,i) = IO_fixedIntValue (line,[ 0_pInt,10_pInt],1_pInt) + mesh_mapFEtoCPnode(2_pInt,i) = i + enddo + exit + endif + enddo + +650 call math_qsort(mesh_mapFEtoCPnode,1_pInt,int(size(mesh_mapFEtoCPnode,2_pInt),pInt)) + +end subroutine mesh_marc_map_nodes + + +!-------------------------------------------------------------------------------------------------- +!> @brief store x,y,z coordinates of all nodes in mesh. +!! Allocates global arrays 'mesh_node0' and 'mesh_node' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_marc_build_nodes(fileUnit) + + use IO, only: & + IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_fixedIntValue, & + IO_fixedNoEFloatValue + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), dimension(5), parameter :: node_ends = int([0,10,30,50,70],pInt) + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + integer(pInt) :: i,j,m + + allocate ( mesh_node0 (3,mesh_Nnodes) ); mesh_node0 = 0.0_pReal + allocate ( mesh_node (3,mesh_Nnodes) ); mesh_node = 0.0_pReal + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=670) line + chunkPos = IO_stringPos(line) + if( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'coordinates' ) then + read (fileUnit,610,END=670) line ! skip crap line + do i=1_pInt,mesh_Nnodes + read (fileUnit,610,END=670) line + m = mesh_FEasCP('node',IO_fixedIntValue(line,node_ends,1_pInt)) + do j = 1_pInt,3_pInt + mesh_node0(j,m) = mesh_unitlength * IO_fixedNoEFloatValue(line,node_ends,j+1_pInt) + enddo + enddo + exit + endif + enddo + +670 mesh_node = mesh_node0 + +end subroutine mesh_marc_build_nodes + + +!-------------------------------------------------------------------------------------------------- +!> @brief Gets maximum count of nodes, IPs, IP neighbors, and cellnodes among cpElements. +!! Sets global values 'mesh_maxNnodes', 'mesh_maxNips', 'mesh_maxNipNeighbors', +!! and 'mesh_maxNcellnodes' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_marc_count_cpSizes(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_intValue, & + IO_skipChunks + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + integer(pInt) :: i,t,g,e,c + + mesh_maxNnodes = 0_pInt + mesh_maxNips = 0_pInt + mesh_maxNipNeighbors = 0_pInt + mesh_maxNcellnodes = 0_pInt + +610 FORMAT(A300) + rewind(fileUnit) + do + read (fileUnit,610,END=630) line + chunkPos = IO_stringPos(line) + if( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'connectivity' ) then + read (fileUnit,610,END=630) line ! Garbage line + do i=1_pInt,mesh_Nelems ! read all elements + read (fileUnit,610,END=630) line + chunkPos = IO_stringPos(line) ! limit to id and type + e = mesh_FEasCP('elem',IO_intValue(line,chunkPos,1_pInt)) + if (e /= 0_pInt) then + t = FE_mapElemtype(IO_stringValue(line,chunkPos,2_pInt)) + g = FE_geomtype(t) + c = FE_celltype(g) + mesh_maxNnodes = max(mesh_maxNnodes,FE_Nnodes(t)) + mesh_maxNips = max(mesh_maxNips,FE_Nips(g)) + mesh_maxNipNeighbors = max(mesh_maxNipNeighbors,FE_NipNeighbors(c)) + mesh_maxNcellnodes = max(mesh_maxNcellnodes,FE_Ncellnodes(g)) + call IO_skipChunks(fileUnit,FE_Nnodes(t)-(chunkPos(1_pInt)-2_pInt)) ! read on if FE_Nnodes exceeds node count present on current line + endif + enddo + exit + endif + enddo + +630 end subroutine mesh_marc_count_cpSizes + + +!-------------------------------------------------------------------------------------------------- +!> @brief Store FEid, type, mat, tex, and node list per element. +!! Allocates global array 'mesh_element' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_marc_build_elements(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_fixedNoEFloatValue, & + IO_skipChunks, & + IO_stringPos, & + IO_intValue, & + IO_continuousIntValues + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) line + + integer(pInt), dimension(1_pInt+mesh_NcpElems) :: contInts + integer(pInt) :: i,j,t,sv,myVal,e,nNodesAlreadyRead + + allocate (mesh_element(4_pInt+mesh_maxNnodes,mesh_NcpElems)) ; mesh_element = 0_pInt + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + if( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'connectivity' ) then + read (fileUnit,610,END=620) line ! garbage line + do i = 1_pInt,mesh_Nelems + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + e = mesh_FEasCP('elem',IO_intValue(line,chunkPos,1_pInt)) + if (e /= 0_pInt) then ! disregard non CP elems + mesh_element(1,e) = IO_IntValue (line,chunkPos,1_pInt) ! FE id + t = FE_mapElemtype(IO_StringValue(line,chunkPos,2_pInt)) ! elem type + mesh_element(2,e) = t + nNodesAlreadyRead = 0_pInt + do j = 1_pInt,chunkPos(1)-2_pInt + mesh_element(4_pInt+j,e) = mesh_FEasCP('node',IO_IntValue(line,chunkPos,j+2_pInt)) ! CP ids of nodes + enddo + nNodesAlreadyRead = chunkPos(1) - 2_pInt + do while(nNodesAlreadyRead < FE_Nnodes(t)) ! read on if not all nodes in one line + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + do j = 1_pInt,chunkPos(1) + mesh_element(4_pInt+nNodesAlreadyRead+j,e) & + = mesh_FEasCP('node',IO_IntValue(line,chunkPos,j)) ! CP ids of nodes + enddo + nNodesAlreadyRead = nNodesAlreadyRead + chunkPos(1) + enddo + endif + enddo + exit + endif + enddo + +620 rewind(fileUnit) ! just in case "initial state" appears before "connectivity" + read (fileUnit,610,END=620) line + do + chunkPos = IO_stringPos(line) + if( (IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == 'initial') .and. & + (IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'state') ) then + if (initialcondTableStyle == 2_pInt) read (fileUnit,610,END=620) line ! read extra line for new style + read (fileUnit,610,END=630) line ! read line with index of state var + chunkPos = IO_stringPos(line) + sv = IO_IntValue(line,chunkPos,1_pInt) ! figure state variable index + if( (sv == 2_pInt).or.(sv == 3_pInt) ) then ! only state vars 2 and 3 of interest + read (fileUnit,610,END=620) line ! read line with value of state var + chunkPos = IO_stringPos(line) + do while (scan(IO_stringValue(line,chunkPos,1_pInt),'+-',back=.true.)>1) ! is noEfloat value? + myVal = nint(IO_fixedNoEFloatValue(line,[0_pInt,20_pInt],1_pInt),pInt) ! state var's value + mesh_maxValStateVar(sv-1_pInt) = max(myVal,mesh_maxValStateVar(sv-1_pInt)) ! remember max val of homogenization and microstructure index + if (initialcondTableStyle == 2_pInt) then + read (fileUnit,610,END=630) line ! read extra line + read (fileUnit,610,END=630) line ! read extra line + endif + contInts = IO_continuousIntValues& ! get affected elements + (fileUnit,mesh_NcpElems,mesh_nameElemSet,mesh_mapElemSet,mesh_NelemSets) + do i = 1_pInt,contInts(1) + e = mesh_FEasCP('elem',contInts(1_pInt+i)) + mesh_element(1_pInt+sv,e) = myVal + enddo + if (initialcondTableStyle == 0_pInt) read (fileUnit,610,END=620) line ! ignore IP range for old table style + read (fileUnit,610,END=630) line + chunkPos = IO_stringPos(line) + enddo + endif + else + read (fileUnit,610,END=630) line + endif + enddo + +630 end subroutine mesh_marc_build_elements +#endif + +#ifdef Abaqus +!-------------------------------------------------------------------------------------------------- +!> @brief Count overall number of nodes and elements in mesh and stores them in +!! 'mesh_Nelems' and 'mesh_Nnodes' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_count_nodesAndElements(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_countDataLines, & + IO_error + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + logical :: inPart + + mesh_Nnodes = 0_pInt + mesh_Nelems = 0_pInt + +610 FORMAT(A300) + + inPart = .false. + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. + + if (inPart .or. noPart) then + select case ( IO_lc(IO_stringValue(line,chunkPos,1_pInt))) + case('*node') + if( & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'print' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'file' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' & + ) & + mesh_Nnodes = mesh_Nnodes + IO_countDataLines(fileUnit) + case('*element') + if( & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'matrix' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' & + ) then + mesh_Nelems = mesh_Nelems + IO_countDataLines(fileUnit) + endif + endselect + endif + enddo + +620 if (mesh_Nnodes < 2_pInt) call IO_error(error_ID=900_pInt) + if (mesh_Nelems == 0_pInt) call IO_error(error_ID=901_pInt) + +end subroutine mesh_abaqus_count_nodesAndElements + + +!-------------------------------------------------------------------------------------------------- +!> @brief count overall number of element sets in mesh and write 'mesh_NelemSets' and +!! 'mesh_maxNelemInSet' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_count_elementSets(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_error + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + logical :: inPart + + mesh_NelemSets = 0_pInt + mesh_maxNelemInSet = mesh_Nelems ! have to be conservative, since Abaqus allows for recursive definitons + +610 FORMAT(A300) + + inPart = .false. + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. + + if ( (inPart .or. noPart) .and. IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*elset' ) & + mesh_NelemSets = mesh_NelemSets + 1_pInt + enddo + +620 continue + if (mesh_NelemSets == 0) call IO_error(error_ID=902_pInt) + +end subroutine mesh_abaqus_count_elementSets + + +!-------------------------------------------------------------------------------------------------- +! count overall number of solid sections sets in mesh (Abaqus only) +! +! mesh_Nmaterials +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_count_materials(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_error + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + logical inPart + + mesh_Nmaterials = 0_pInt + +610 FORMAT(A300) + + inPart = .false. + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. + + if ( (inPart .or. noPart) .and. & + IO_lc(IO_StringValue(line,chunkPos,1_pInt)) == '*solid' .and. & + IO_lc(IO_StringValue(line,chunkPos,2_pInt)) == 'section' ) & + mesh_Nmaterials = mesh_Nmaterials + 1_pInt + enddo + +620 if (mesh_Nmaterials == 0_pInt) call IO_error(error_ID=903_pInt) + +end subroutine mesh_abaqus_count_materials + + +!-------------------------------------------------------------------------------------------------- +! Build element set mapping +! +! allocate globals: mesh_nameElemSet, mesh_mapElemSet +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_map_elementSets(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_extractValue, & + IO_continuousIntValues, & + IO_error + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + integer(pInt) :: elemSet = 0_pInt,i + logical :: inPart = .false. + + allocate (mesh_nameElemSet(mesh_NelemSets)) ; mesh_nameElemSet = '' + allocate (mesh_mapElemSet(1_pInt+mesh_maxNelemInSet,mesh_NelemSets)) ; mesh_mapElemSet = 0_pInt + +610 FORMAT(A300) + + + rewind(fileUnit) + do + read (fileUnit,610,END=640) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. + + if ( (inPart .or. noPart) .and. IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*elset' ) then + elemSet = elemSet + 1_pInt + mesh_nameElemSet(elemSet) = trim(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,2_pInt)),'elset')) + mesh_mapElemSet(:,elemSet) = IO_continuousIntValues(fileUnit,mesh_Nelems,mesh_nameElemSet,& + mesh_mapElemSet,elemSet-1_pInt) + endif + enddo + +640 do i = 1_pInt,elemSet + if (mesh_mapElemSet(1,i) == 0_pInt) call IO_error(error_ID=904_pInt,ext_msg=mesh_nameElemSet(i)) + enddo + +end subroutine mesh_abaqus_map_elementSets + + +!-------------------------------------------------------------------------------------------------- +! map solid section (Abaqus only) +! +! allocate globals: mesh_nameMaterial, mesh_mapMaterial +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_map_materials(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_extractValue, & + IO_error + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) line + + integer(pInt) :: i,c = 0_pInt + logical :: inPart = .false. + character(len=64) :: elemSetName,materialName + + allocate (mesh_nameMaterial(mesh_Nmaterials)) ; mesh_nameMaterial = '' + allocate (mesh_mapMaterial(mesh_Nmaterials)) ; mesh_mapMaterial = '' + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. + + if ( (inPart .or. noPart) .and. & + IO_lc(IO_StringValue(line,chunkPos,1_pInt)) == '*solid' .and. & + IO_lc(IO_StringValue(line,chunkPos,2_pInt)) == 'section' ) then + + elemSetName = '' + materialName = '' + + do i = 3_pInt,chunkPos(1_pInt) + if (IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,i)),'elset') /= '') & + elemSetName = trim(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,i)),'elset')) + if (IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,i)),'material') /= '') & + materialName = trim(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,i)),'material')) + enddo + + if (elemSetName /= '' .and. materialName /= '') then + c = c + 1_pInt + mesh_nameMaterial(c) = materialName ! name of material used for this section + mesh_mapMaterial(c) = elemSetName ! mapped to respective element set + endif + endif + enddo + +620 if (c==0_pInt) call IO_error(error_ID=905_pInt) + do i=1_pInt,c + if (mesh_nameMaterial(i)=='' .or. mesh_mapMaterial(i)=='') call IO_error(error_ID=905_pInt) + enddo + + end subroutine mesh_abaqus_map_materials + + +!-------------------------------------------------------------------------------------------------- +!> @brief Count overall number of CP elements in mesh and stores them in 'mesh_NcpElems' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_count_cpElements(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_error, & + IO_extractValue + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) line + integer(pInt) :: i,k + logical :: materialFound = .false. + character(len=64) ::materialName,elemSetName + + mesh_NcpElems = 0_pInt + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + select case ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ) + case('*material') + materialName = trim(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,2_pInt)),'name')) ! extract name=value + materialFound = materialName /= '' ! valid name? + case('*user') + if (IO_lc(IO_StringValue(line,chunkPos,2_pInt)) == 'material' .and. materialFound) then + do i = 1_pInt,mesh_Nmaterials ! look thru material names + if (materialName == mesh_nameMaterial(i)) then ! found one + elemSetName = mesh_mapMaterial(i) ! take corresponding elemSet + do k = 1_pInt,mesh_NelemSets ! look thru all elemSet definitions + if (elemSetName == mesh_nameElemSet(k)) & ! matched? + mesh_NcpElems = mesh_NcpElems + mesh_mapElemSet(1,k) ! add those elem count + enddo + endif + enddo + materialFound = .false. + endif + endselect + enddo + +620 if (mesh_NcpElems == 0_pInt) call IO_error(error_ID=906_pInt) + +end subroutine mesh_abaqus_count_cpElements + + +!-------------------------------------------------------------------------------------------------- +!> @brief Maps elements from FE ID to internal (consecutive) representation. +!! Allocates global array 'mesh_mapFEtoCPelem' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_map_elements(fileUnit) + + use math, only: math_qsort + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_extractValue, & + IO_error + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + integer(pInt) ::i,j,k,cpElem = 0_pInt + logical :: materialFound = .false. + character (len=64) materialName,elemSetName ! why limited to 64? ABAQUS? + + allocate (mesh_mapFEtoCPelem(2,mesh_NcpElems)) ; mesh_mapFEtoCPelem = 0_pInt + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=660) line + chunkPos = IO_stringPos(line) + select case ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ) + case('*material') + materialName = trim(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,2_pInt)),'name')) ! extract name=value + materialFound = materialName /= '' ! valid name? + case('*user') + if (IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'material' .and. materialFound) then + do i = 1_pInt,mesh_Nmaterials ! look thru material names + if (materialName == mesh_nameMaterial(i)) then ! found one + elemSetName = mesh_mapMaterial(i) ! take corresponding elemSet + do k = 1_pInt,mesh_NelemSets ! look thru all elemSet definitions + if (elemSetName == mesh_nameElemSet(k)) then ! matched? + do j = 1_pInt,mesh_mapElemSet(1,k) + cpElem = cpElem + 1_pInt + mesh_mapFEtoCPelem(1,cpElem) = mesh_mapElemSet(1_pInt+j,k) ! store FE id + mesh_mapFEtoCPelem(2,cpElem) = cpElem ! store our id + enddo + endif + enddo + endif + enddo + materialFound = .false. + endif + endselect + enddo + +660 call math_qsort(mesh_mapFEtoCPelem,1_pInt,int(size(mesh_mapFEtoCPelem,2_pInt),pInt)) ! should be mesh_NcpElems + + if (int(size(mesh_mapFEtoCPelem),pInt) < 2_pInt) call IO_error(error_ID=907_pInt) + +end subroutine mesh_abaqus_map_elements + + +!-------------------------------------------------------------------------------------------------- +!> @brief Maps node from FE ID to internal (consecutive) representation. +!! Allocates global array 'mesh_mapFEtoCPnode' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_map_nodes(fileUnit) + + use math, only: math_qsort + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_countDataLines, & + IO_intValue, & + IO_error + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) line + + integer(pInt) :: i,c,cpNode = 0_pInt + logical :: inPart = .false. + + allocate (mesh_mapFEtoCPnode(2_pInt,mesh_Nnodes)) ; mesh_mapFEtoCPnode = 0_pInt + +610 FORMAT(A300) + + rewind(fileUnit) + do + read (fileUnit,610,END=650) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. + + if( (inPart .or. noPart) .and. & + IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*node' .and. & + ( IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'print' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'file' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' ) & + ) then + c = IO_countDataLines(fileUnit) + do i = 1_pInt,c + backspace(fileUnit) + enddo + do i = 1_pInt,c + read (fileUnit,610,END=650) line + chunkPos = IO_stringPos(line) + cpNode = cpNode + 1_pInt + mesh_mapFEtoCPnode(1_pInt,cpNode) = IO_intValue(line,chunkPos,1_pInt) + mesh_mapFEtoCPnode(2_pInt,cpNode) = cpNode + enddo + endif + enddo + +650 call math_qsort(mesh_mapFEtoCPnode,1_pInt,int(size(mesh_mapFEtoCPnode,2_pInt),pInt)) + + if (int(size(mesh_mapFEtoCPnode),pInt) == 0_pInt) call IO_error(error_ID=908_pInt) + +end subroutine mesh_abaqus_map_nodes + + +!-------------------------------------------------------------------------------------------------- +!> @brief store x,y,z coordinates of all nodes in mesh. +!! Allocates global arrays 'mesh_node0' and 'mesh_node' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_build_nodes(fileUnit) + use IO, only: & + IO_lc, & + IO_stringValue, & + IO_floatValue, & + IO_stringPos, & + IO_error, & + IO_countDataLines, & + IO_intValue + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + integer(pInt) :: i,j,m,c + logical :: inPart + + allocate ( mesh_node0 (3,mesh_Nnodes) ); mesh_node0 = 0.0_pReal + allocate ( mesh_node (3,mesh_Nnodes) ); mesh_node = 0.0_pReal + +610 FORMAT(A300) + + inPart = .false. + rewind(fileUnit) + do + read (fileUnit,610,END=670) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. + + if( (inPart .or. noPart) .and. & + IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*node' .and. & + ( IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'print' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'file' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' ) & + ) then + c = IO_countDataLines(fileUnit) ! how many nodes are defined here? + do i = 1_pInt,c + backspace(fileUnit) ! rewind to first entry + enddo + do i = 1_pInt,c + read (fileUnit,610,END=670) line + chunkPos = IO_stringPos(line) + m = mesh_FEasCP('node',IO_intValue(line,chunkPos,1_pInt)) + do j=1_pInt, 3_pInt + mesh_node0(j,m) = mesh_unitlength * IO_floatValue(line,chunkPos,j+1_pInt) + enddo + enddo + endif + enddo + +670 if (int(size(mesh_node0,2_pInt),pInt) /= mesh_Nnodes) call IO_error(error_ID=909_pInt) + mesh_node = mesh_node0 + +end subroutine mesh_abaqus_build_nodes + + +!-------------------------------------------------------------------------------------------------- +!> @brief Gets maximum count of nodes, IPs, IP neighbors, and subNodes among cpElements. +!! Sets global values 'mesh_maxNnodes', 'mesh_maxNips', 'mesh_maxNipNeighbors', +!! and 'mesh_maxNcellnodes' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_count_cpSizes(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_stringPos, & + IO_extractValue ,& + IO_error, & + IO_countDataLines, & + IO_intValue + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=300) :: line + integer(pInt) :: i,c,t,g + logical :: inPart + + mesh_maxNnodes = 0_pInt + mesh_maxNips = 0_pInt + mesh_maxNipNeighbors = 0_pInt + mesh_maxNcellnodes = 0_pInt + +610 FORMAT(A300) + + inPart = .false. + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. + + if( (inPart .or. noPart) .and. & + IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*element' .and. & + ( IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'matrix' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' ) & + ) then + t = FE_mapElemtype(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,2_pInt)),'type')) ! remember elem type + g = FE_geomtype(t) + c = FE_celltype(g) + mesh_maxNnodes = max(mesh_maxNnodes,FE_Nnodes(t)) + mesh_maxNips = max(mesh_maxNips,FE_Nips(g)) + mesh_maxNipNeighbors = max(mesh_maxNipNeighbors,FE_NipNeighbors(c)) + mesh_maxNcellnodes = max(mesh_maxNcellnodes,FE_Ncellnodes(g)) + endif + enddo + +620 end subroutine mesh_abaqus_count_cpSizes + + +!-------------------------------------------------------------------------------------------------- +!> @brief Store FEid, type, mat, tex, and node list per elemen. +!! Allocates global array 'mesh_element' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_abaqus_build_elements(fileUnit) + + use IO, only: IO_lc, & + IO_stringValue, & + IO_skipChunks, & + IO_stringPos, & + IO_intValue, & + IO_extractValue, & + IO_floatValue, & + IO_error, & + IO_countDataLines + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + + integer(pInt) :: i,j,k,c,e,t,homog,micro, nNodesAlreadyRead + logical inPart,materialFound + character (len=64) :: materialName,elemSetName + character(len=300) :: line + + allocate (mesh_element (4_pInt+mesh_maxNnodes,mesh_NcpElems)) ; mesh_element = 0_pInt + +610 FORMAT(A300) + + inPart = .false. + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*part' ) inPart = .true. + if ( IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*end' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) == 'part' ) inPart = .false. + + if( (inPart .or. noPart) .and. & + IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == '*element' .and. & + ( IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'output' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'matrix' .and. & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) /= 'response' ) & + ) then + t = FE_mapElemtype(IO_extractValue(IO_lc(IO_stringValue(line,chunkPos,2_pInt)),'type')) ! remember elem type + c = IO_countDataLines(fileUnit) + do i = 1_pInt,c + backspace(fileUnit) + enddo + do i = 1_pInt,c + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) ! limit to 64 nodes max + e = mesh_FEasCP('elem',IO_intValue(line,chunkPos,1_pInt)) + if (e /= 0_pInt) then ! disregard non CP elems + mesh_element(1,e) = IO_intValue(line,chunkPos,1_pInt) ! FE id + mesh_element(2,e) = t ! elem type + nNodesAlreadyRead = 0_pInt + do j = 1_pInt,chunkPos(1)-1_pInt + mesh_element(4_pInt+j,e) = mesh_FEasCP('node',IO_intValue(line,chunkPos,1_pInt+j)) ! put CP ids of nodes to position 5: + enddo + nNodesAlreadyRead = chunkPos(1) - 1_pInt + do while(nNodesAlreadyRead < FE_Nnodes(t)) ! read on if not all nodes in one line + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + do j = 1_pInt,chunkPos(1) + mesh_element(4_pInt+nNodesAlreadyRead+j,e) & + = mesh_FEasCP('node',IO_IntValue(line,chunkPos,j)) ! CP ids of nodes + enddo + nNodesAlreadyRead = nNodesAlreadyRead + chunkPos(1) + enddo + endif + enddo + endif + enddo + + +620 rewind(fileUnit) ! just in case "*material" definitions apear before "*element" + + materialFound = .false. + do + read (fileUnit,610,END=630) line + chunkPos = IO_stringPos(line) + select case ( IO_lc(IO_StringValue(line,chunkPos,1_pInt))) + case('*material') + materialName = trim(IO_extractValue(IO_lc(IO_StringValue(line,chunkPos,2_pInt)),'name')) ! extract name=value + materialFound = materialName /= '' ! valid name? + case('*user') + if ( IO_lc(IO_StringValue(line,chunkPos,2_pInt)) == 'material' .and. & + materialFound ) then + read (fileUnit,610,END=630) line ! read homogenization and microstructure + chunkPos = IO_stringPos(line) + homog = nint(IO_floatValue(line,chunkPos,1_pInt),pInt) + micro = nint(IO_floatValue(line,chunkPos,2_pInt),pInt) + do i = 1_pInt,mesh_Nmaterials ! look thru material names + if (materialName == mesh_nameMaterial(i)) then ! found one + elemSetName = mesh_mapMaterial(i) ! take corresponding elemSet + do k = 1_pInt,mesh_NelemSets ! look thru all elemSet definitions + if (elemSetName == mesh_nameElemSet(k)) then ! matched? + do j = 1_pInt,mesh_mapElemSet(1,k) + e = mesh_FEasCP('elem',mesh_mapElemSet(1+j,k)) + mesh_element(3,e) = homog ! store homogenization + mesh_element(4,e) = micro ! store microstructure + mesh_maxValStateVar(1) = max(mesh_maxValStateVar(1),homog) + mesh_maxValStateVar(2) = max(mesh_maxValStateVar(2),micro) + enddo + endif + enddo + endif + enddo + materialFound = .false. + endif + endselect + enddo + +630 end subroutine mesh_abaqus_build_elements +#endif + + +!-------------------------------------------------------------------------------------------------- +!> @brief get any additional damask options from input file, sets mesh_periodicSurface +!-------------------------------------------------------------------------------------------------- +subroutine mesh_get_damaskOptions(fileUnit) + +use IO, only: & + IO_lc, & + IO_stringValue, & + IO_stringPos + + implicit none + integer(pInt), intent(in) :: fileUnit + +#ifndef Spectral + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) chunk, Nchunks + character(len=300) :: line, damaskOption, v + character(len=300) :: keyword +#endif + +#ifdef Spectral + mesh_periodicSurface = .true. +#else + mesh_periodicSurface = .false. +#ifdef Marc4DAMASK + keyword = '$damask' +#endif +#ifdef Abaqus + keyword = '**damask' +#endif + + rewind(fileUnit) + do + read (fileUnit,610,END=620) line + chunkPos = IO_stringPos(line) + Nchunks = chunkPos(1) + if (IO_lc(IO_stringValue(line,chunkPos,1_pInt)) == keyword .and. Nchunks > 1_pInt) then ! found keyword for damask option and there is at least one more chunk to read + damaskOption = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + select case(damaskOption) + case('periodic') ! damask Option that allows to specify periodic fluxes + do chunk = 3_pInt,Nchunks ! loop through chunks (skipping the keyword) + v = IO_lc(IO_stringValue(line,chunkPos,chunk)) ! chunk matches keyvalues x,y, or z? + mesh_periodicSurface(1) = mesh_periodicSurface(1) .or. v == 'x' + mesh_periodicSurface(2) = mesh_periodicSurface(2) .or. v == 'y' + mesh_periodicSurface(3) = mesh_periodicSurface(3) .or. v == 'z' + enddo + endselect + endif + enddo + +610 FORMAT(A300) +#endif + +620 end subroutine mesh_get_damaskOptions + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculation of IP interface areas, allocate globals '_ipArea', and '_ipAreaNormal' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_build_ipAreas + use math, only: & + math_crossproduct + + implicit none + integer(pInt) :: e,t,g,c,i,f,n,m + real(pReal), dimension (3,FE_maxNcellnodesPerCellface) :: nodePos, normals + real(pReal), dimension(3) :: normal + + allocate(mesh_ipArea(mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + allocate(mesh_ipAreaNormal(3_pInt,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems), source=0.0_pReal) + + !$OMP PARALLEL DO PRIVATE(t,g,c,nodePos,normal,normals) + do e = 1_pInt,mesh_NcpElems ! loop over cpElems + t = mesh_element(2_pInt,e) ! get element type + g = FE_geomtype(t) ! get geometry type + c = FE_celltype(g) ! get cell type + select case (c) + + case (1_pInt,2_pInt) ! 2D 3 or 4 node + do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element + do f = 1_pInt,FE_NipNeighbors(c) ! loop over cell faces + forall(n = 1_pInt:FE_NcellnodesPerCellface(c)) & + nodePos(1:3,n) = mesh_cellnode(1:3,mesh_cell(FE_cellface(n,f,c),i,e)) + normal(1) = nodePos(2,2) - nodePos(2,1) ! x_normal = y_connectingVector + normal(2) = -(nodePos(1,2) - nodePos(1,1)) ! y_normal = -x_connectingVector + normal(3) = 0.0_pReal + mesh_ipArea(f,i,e) = norm2(normal) + mesh_ipAreaNormal(1:3,f,i,e) = normal / norm2(normal) ! ensure unit length of area normal + enddo + enddo + + case (3_pInt) ! 3D 4node + do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element + do f = 1_pInt,FE_NipNeighbors(c) ! loop over cell faces + forall(n = 1_pInt:FE_NcellnodesPerCellface(c)) & + nodePos(1:3,n) = mesh_cellnode(1:3,mesh_cell(FE_cellface(n,f,c),i,e)) + normal = math_crossproduct(nodePos(1:3,2) - nodePos(1:3,1), & + nodePos(1:3,3) - nodePos(1:3,1)) + mesh_ipArea(f,i,e) = norm2(normal) + mesh_ipAreaNormal(1:3,f,i,e) = normal / norm2(normal) ! ensure unit length of area normal + enddo + enddo + + case (4_pInt) ! 3D 8node + ! for this cell type we get the normal of the quadrilateral face as an average of + ! four normals of triangular subfaces; since the face consists only of two triangles, + ! the sum has to be divided by two; this whole prcedure tries to compensate for + ! probable non-planar cell surfaces + m = FE_NcellnodesPerCellface(c) + do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element + do f = 1_pInt,FE_NipNeighbors(c) ! loop over cell faces + forall(n = 1_pInt:FE_NcellnodesPerCellface(c)) & + nodePos(1:3,n) = mesh_cellnode(1:3,mesh_cell(FE_cellface(n,f,c),i,e)) + forall(n = 1_pInt:FE_NcellnodesPerCellface(c)) & + normals(1:3,n) = 0.5_pReal & + * math_crossproduct(nodePos(1:3,1+mod(n ,m)) - nodePos(1:3,n), & + nodePos(1:3,1+mod(n+1,m)) - nodePos(1:3,n)) + normal = 0.5_pReal * sum(normals,2) + mesh_ipArea(f,i,e) = norm2(normal) + mesh_ipAreaNormal(1:3,f,i,e) = normal / norm2(normal) + enddo + enddo + + end select + enddo + !$OMP END PARALLEL DO + +end subroutine mesh_build_ipAreas + +#ifndef Spectral +!-------------------------------------------------------------------------------------------------- +!> @brief assignment of twin nodes for each cp node, allocate globals '_nodeTwins' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_build_nodeTwins + + implicit none + integer(pInt) dir, & ! direction of periodicity + node, & + minimumNode, & + maximumNode, & + n1, & + n2 + integer(pInt), dimension(mesh_Nnodes+1) :: minimumNodes, maximumNodes ! list of surface nodes (minimum and maximum coordinate value) with first entry giving the number of nodes + real(pReal) minCoord, maxCoord, & ! extreme positions in one dimension + tolerance ! tolerance below which positions are assumed identical + real(pReal), dimension(3) :: distance ! distance between two nodes in all three coordinates + logical, dimension(mesh_Nnodes) :: unpaired + + allocate(mesh_nodeTwins(3,mesh_Nnodes)) + mesh_nodeTwins = 0_pInt + + tolerance = 0.001_pReal * minval(mesh_ipVolume) ** 0.333_pReal + + do dir = 1_pInt,3_pInt ! check periodicity in directions of x,y,z + if (mesh_periodicSurface(dir)) then ! only if periodicity is requested + + + !*** find out which nodes sit on the surface + !*** and have a minimum or maximum position in this dimension + + minimumNodes = 0_pInt + maximumNodes = 0_pInt + minCoord = minval(mesh_node0(dir,:)) + maxCoord = maxval(mesh_node0(dir,:)) + do node = 1_pInt,mesh_Nnodes ! loop through all nodes and find surface nodes + if (abs(mesh_node0(dir,node) - minCoord) <= tolerance) then + minimumNodes(1) = minimumNodes(1) + 1_pInt + minimumNodes(minimumNodes(1)+1_pInt) = node + elseif (abs(mesh_node0(dir,node) - maxCoord) <= tolerance) then + maximumNodes(1) = maximumNodes(1) + 1_pInt + maximumNodes(maximumNodes(1)+1_pInt) = node + endif + enddo + + + !*** find the corresponding node on the other side with the same position in this dimension + + unpaired = .true. + do n1 = 1_pInt,minimumNodes(1) + minimumNode = minimumNodes(n1+1_pInt) + if (unpaired(minimumNode)) then + do n2 = 1_pInt,maximumNodes(1) + maximumNode = maximumNodes(n2+1_pInt) + distance = abs(mesh_node0(:,minimumNode) - mesh_node0(:,maximumNode)) + if (sum(distance) - distance(dir) <= tolerance) then ! minimum possible distance (within tolerance) + mesh_nodeTwins(dir,minimumNode) = maximumNode + mesh_nodeTwins(dir,maximumNode) = minimumNode + unpaired(maximumNode) = .false. ! remember this node, we don't have to look for his partner again + exit + endif + enddo + endif + enddo + + endif + enddo + +end subroutine mesh_build_nodeTwins + + +!-------------------------------------------------------------------------------------------------- +!> @brief get maximum count of shared elements among cpElements and build list of elements shared +!! by each node in mesh. Allocate globals '_maxNsharedElems' and '_sharedElem' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_build_sharedElems + + implicit none + integer(pint) e, & ! element index + g, & ! element type + node, & ! CP node index + n, & ! node index per element + myDim, & ! dimension index + nodeTwin ! node twin in the specified dimension + integer(pInt), dimension (mesh_Nnodes) :: node_count + integer(pInt), dimension (:), allocatable :: node_seen + + allocate(node_seen(maxval(FE_NmatchingNodes))) + + + node_count = 0_pInt + + do e = 1_pInt,mesh_NcpElems + g = FE_geomtype(mesh_element(2,e)) ! get elemGeomType + node_seen = 0_pInt ! reset node duplicates + do n = 1_pInt,FE_NmatchingNodes(g) ! check each node of element + node = mesh_element(4+n,e) + if (all(node_seen /= node)) then + node_count(node) = node_count(node) + 1_pInt ! if FE node not yet encountered -> count it + do myDim = 1_pInt,3_pInt ! check in each dimension... + nodeTwin = mesh_nodeTwins(myDim,node) + if (nodeTwin > 0_pInt) & ! if I am a twin of some node... + node_count(nodeTwin) = node_count(nodeTwin) + 1_pInt ! -> count me again for the twin node + enddo + endif + node_seen(n) = node ! remember this node to be counted already + enddo + enddo + + mesh_maxNsharedElems = int(maxval(node_count),pInt) ! most shared node + + allocate(mesh_sharedElem(1+mesh_maxNsharedElems,mesh_Nnodes)) + mesh_sharedElem = 0_pInt + + do e = 1_pInt,mesh_NcpElems + g = FE_geomtype(mesh_element(2,e)) ! get elemGeomType + node_seen = 0_pInt + do n = 1_pInt,FE_NmatchingNodes(g) + node = mesh_element(4_pInt+n,e) + if (all(node_seen /= node)) then + mesh_sharedElem(1,node) = mesh_sharedElem(1,node) + 1_pInt ! count for each node the connected elements + mesh_sharedElem(mesh_sharedElem(1,node)+1_pInt,node) = e ! store the respective element id + do myDim = 1_pInt,3_pInt ! check in each dimension... + nodeTwin = mesh_nodeTwins(myDim,node) + if (nodeTwin > 0_pInt) then ! if i am a twin of some node... + mesh_sharedElem(1,nodeTwin) = mesh_sharedElem(1,nodeTwin) + 1_pInt ! ...count me again for the twin + mesh_sharedElem(mesh_sharedElem(1,nodeTwin)+1,nodeTwin) = e ! store the respective element id + endif + enddo + endif + node_seen(n) = node + enddo + enddo + + deallocate(node_seen) + +end subroutine mesh_build_sharedElems + + +!-------------------------------------------------------------------------------------------------- +!> @brief build up of IP neighborhood, allocate globals '_ipNeighborhood' +!-------------------------------------------------------------------------------------------------- +subroutine mesh_build_ipNeighborhood + use math, only: & + math_mul3x3 + + implicit none + integer(pInt) :: myElem, & ! my CP element index + myIP, & + myType, & ! my element type + myFace, & + neighbor, & ! neighor index + neighboringIPkey, & ! positive integer indicating the neighboring IP (for intra-element) and negative integer indicating the face towards neighbor (for neighboring element) + candidateIP, & + neighboringType, & ! element type of neighbor + NlinkedNodes, & ! number of linked nodes + twin_of_linkedNode, & ! node twin of a specific linkedNode + NmatchingNodes, & ! number of matching nodes + dir, & ! direction of periodicity + matchingElem, & ! CP elem number of matching element + matchingFace, & ! face ID of matching element + a, anchor, & + neighboringIP, & + neighboringElem, & + pointingToMe + integer(pInt), dimension(FE_maxmaxNnodesAtIP) :: & + linkedNodes = 0_pInt, & + matchingNodes + logical checkTwins + + allocate(mesh_ipNeighborhood(3,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems)) + mesh_ipNeighborhood = 0_pInt + + + do myElem = 1_pInt,mesh_NcpElems ! loop over cpElems + myType = FE_geomtype(mesh_element(2,myElem)) ! get elemGeomType + do myIP = 1_pInt,FE_Nips(myType) ! loop over IPs of elem + + do neighbor = 1_pInt,FE_NipNeighbors(FE_celltype(myType)) ! loop over neighbors of IP + neighboringIPkey = FE_ipNeighbor(neighbor,myIP,myType) + + !*** if the key is positive, the neighbor is inside the element + !*** that means, we have already found our neighboring IP + + if (neighboringIPkey > 0_pInt) then + mesh_ipNeighborhood(1,neighbor,myIP,myElem) = myElem + mesh_ipNeighborhood(2,neighbor,myIP,myElem) = neighboringIPkey + + + !*** if the key is negative, the neighbor resides in a neighboring element + !*** that means, we have to look through the face indicated by the key and see which element is behind that face + + elseif (neighboringIPkey < 0_pInt) then ! neighboring element's IP + myFace = -neighboringIPkey + call mesh_faceMatch(myElem, myFace, matchingElem, matchingFace) ! get face and CP elem id of face match + if (matchingElem > 0_pInt) then ! found match? + neighboringType = FE_geomtype(mesh_element(2,matchingElem)) + + !*** trivial solution if neighbor has only one IP + + if (FE_Nips(neighboringType) == 1_pInt) then + mesh_ipNeighborhood(1,neighbor,myIP,myElem) = matchingElem + mesh_ipNeighborhood(2,neighbor,myIP,myElem) = 1_pInt + cycle + endif + + !*** find those nodes which build the link to the neighbor + + NlinkedNodes = 0_pInt + linkedNodes = 0_pInt + do a = 1_pInt,FE_maxNnodesAtIP(myType) ! figure my anchor nodes on connecting face + anchor = FE_nodesAtIP(a,myIP,myType) + if (anchor /= 0_pInt) then ! valid anchor node + if (any(FE_face(:,myFace,myType) == anchor)) then ! ip anchor sits on face? + NlinkedNodes = NlinkedNodes + 1_pInt + linkedNodes(NlinkedNodes) = mesh_element(4_pInt+anchor,myElem) ! CP id of anchor node + else ! something went wrong with the linkage, since not all anchors sit on my face + NlinkedNodes = 0_pInt + linkedNodes = 0_pInt + exit + endif + endif + enddo + + !*** loop through the ips of my neighbor + !*** and try to find an ip with matching nodes + !*** also try to match with node twins + + checkCandidateIP: do candidateIP = 1_pInt,FE_Nips(neighboringType) + NmatchingNodes = 0_pInt + matchingNodes = 0_pInt + do a = 1_pInt,FE_maxNnodesAtIP(neighboringType) ! check each anchor node of that ip + anchor = FE_nodesAtIP(a,candidateIP,neighboringType) + if (anchor /= 0_pInt) then ! valid anchor node + if (any(FE_face(:,matchingFace,neighboringType) == anchor)) then ! sits on matching face? + NmatchingNodes = NmatchingNodes + 1_pInt + matchingNodes(NmatchingNodes) = mesh_element(4+anchor,matchingElem) ! CP id of neighbor's anchor node + else ! no matching, because not all nodes sit on the matching face + NmatchingNodes = 0_pInt + matchingNodes = 0_pInt + exit + endif + endif + enddo + + if (NmatchingNodes /= NlinkedNodes) & ! this ip has wrong count of anchors on face + cycle checkCandidateIP + + !*** check "normal" nodes whether they match or not + + checkTwins = .false. + do a = 1_pInt,NlinkedNodes + if (all(matchingNodes /= linkedNodes(a))) then ! this linkedNode does not match any matchingNode + checkTwins = .true. + exit ! no need to search further + endif + enddo + + !*** if no match found, then also check node twins + + if(checkTwins) then + dir = int(maxloc(abs(mesh_ipAreaNormal(1:3,neighbor,myIP,myElem)),1),pInt) ! check for twins only in direction of the surface normal + do a = 1_pInt,NlinkedNodes + twin_of_linkedNode = mesh_nodeTwins(dir,linkedNodes(a)) + if (twin_of_linkedNode == 0_pInt .or. & ! twin of linkedNode does not exist... + all(matchingNodes /= twin_of_linkedNode)) then ! ... or it does not match any matchingNode + cycle checkCandidateIP ! ... then check next candidateIP + endif + enddo + endif + + !*** we found a match !!! + + mesh_ipNeighborhood(1,neighbor,myIP,myElem) = matchingElem + mesh_ipNeighborhood(2,neighbor,myIP,myElem) = candidateIP + exit checkCandidateIP + enddo checkCandidateIP + endif ! end of valid external matching + endif ! end of internal/external matching + enddo + enddo + enddo + do myElem = 1_pInt,mesh_NcpElems ! loop over cpElems + myType = FE_geomtype(mesh_element(2,myElem)) ! get elemGeomType + do myIP = 1_pInt,FE_Nips(myType) ! loop over IPs of elem + do neighbor = 1_pInt,FE_NipNeighbors(FE_celltype(myType)) ! loop over neighbors of IP + neighboringElem = mesh_ipNeighborhood(1,neighbor,myIP,myElem) + neighboringIP = mesh_ipNeighborhood(2,neighbor,myIP,myElem) + if (neighboringElem > 0_pInt .and. neighboringIP > 0_pInt) then ! if neighbor exists ... + neighboringType = FE_geomtype(mesh_element(2,neighboringElem)) + do pointingToMe = 1_pInt,FE_NipNeighbors(FE_celltype(neighboringType)) ! find neighboring index that points from my neighbor to myself + if ( myElem == mesh_ipNeighborhood(1,pointingToMe,neighboringIP,neighboringElem) & + .and. myIP == mesh_ipNeighborhood(2,pointingToMe,neighboringIP,neighboringElem)) then ! possible candidate + if (math_mul3x3(mesh_ipAreaNormal(1:3,neighbor,myIP,myElem),& + mesh_ipAreaNormal(1:3,pointingToMe,neighboringIP,neighboringElem)) < 0.0_pReal) then ! area normals have opposite orientation (we have to check that because of special case for single element with two ips and periodicity. In this case the neighbor is identical in two different directions.) + mesh_ipNeighborhood(3,neighbor,myIP,myElem) = pointingToMe ! found match + exit ! so no need to search further + endif + endif + enddo + endif + enddo + enddo + enddo + +end subroutine mesh_build_ipNeighborhood +#endif + + +!-------------------------------------------------------------------------------------------------- +!> @brief write statistics regarding input file parsing to the output file +!-------------------------------------------------------------------------------------------------- +subroutine mesh_tell_statistics + use math, only: & + math_range + use IO, only: & + IO_error + use debug, only: & + debug_level, & + debug_MESH, & + debug_LEVELBASIC, & + debug_LEVELEXTENSIVE, & + debug_LEVELSELECTIVE, & + debug_e, & + debug_i + + implicit none + integer(pInt), dimension (:,:), allocatable :: mesh_HomogMicro + character(len=64) :: myFmt + integer(pInt) :: i,e,n,f,t,g,c, myDebug + + myDebug = debug_level(debug_mesh) + + if (mesh_maxValStateVar(1) < 1_pInt) call IO_error(error_ID=170_pInt) ! no homogenization specified + if (mesh_maxValStateVar(2) < 1_pInt) call IO_error(error_ID=180_pInt) ! no microstructure specified + + allocate (mesh_HomogMicro(mesh_maxValStateVar(1),mesh_maxValStateVar(2))); mesh_HomogMicro = 0_pInt +do e = 1_pInt,mesh_NcpElems + if (mesh_element(3,e) < 1_pInt) call IO_error(error_ID=170_pInt,el=e) ! no homogenization specified + if (mesh_element(4,e) < 1_pInt) call IO_error(error_ID=180_pInt,el=e) ! no microstructure specified + mesh_HomogMicro(mesh_element(3,e),mesh_element(4,e)) = & + mesh_HomogMicro(mesh_element(3,e),mesh_element(4,e)) + 1_pInt ! count combinations of homogenization and microstructure +enddo +!$OMP CRITICAL (write2out) + if (iand(myDebug,debug_levelBasic) /= 0_pInt) then + write(6,'(/,a,/)') ' Input Parser: STATISTICS' + write(6,*) mesh_Nelems, ' : total number of elements in mesh' + write(6,*) mesh_NcpElems, ' : total number of CP elements in mesh' + write(6,*) mesh_Nnodes, ' : total number of nodes in mesh' + write(6,*) mesh_maxNnodes, ' : max number of nodes in any CP element' + write(6,*) mesh_maxNips, ' : max number of IPs in any CP element' + write(6,*) mesh_maxNipNeighbors, ' : max number of IP neighbors in any CP element' + write(6,*) mesh_maxNsharedElems, ' : max number of CP elements sharing a node' + write(6,'(/,a,/)') ' Input Parser: HOMOGENIZATION/MICROSTRUCTURE' + write(6,*) mesh_maxValStateVar(1), ' : maximum homogenization index' + write(6,*) mesh_maxValStateVar(2), ' : maximum microstructure index' + write(6,*) + write (myFmt,'(a,i32.32,a)') '(9x,a2,1x,',mesh_maxValStateVar(2),'(i8))' + write(6,myFmt) '+-',math_range(mesh_maxValStateVar(2)) + write (myFmt,'(a,i32.32,a)') '(i8,1x,a2,1x,',mesh_maxValStateVar(2),'(i8))' + do i=1_pInt,mesh_maxValStateVar(1) ! loop over all (possibly assigned) homogenizations + write(6,myFmt) i,'| ',mesh_HomogMicro(i,:) ! loop over all (possibly assigned) microstructures + enddo + write(6,'(/,a,/)') ' Input Parser: ADDITIONAL MPIE OPTIONS' + write(6,*) 'periodic surface : ', mesh_periodicSurface + write(6,*) + flush(6) + endif + + if (iand(myDebug,debug_levelExtensive) /= 0_pInt) then + write(6,'(/,a,/)') 'Input Parser: ELEMENT TYPE' + write(6,'(a8,3(1x,a8))') 'elem','elemtype','geomtype','celltype' + do e = 1_pInt,mesh_NcpElems + if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_e /= e) cycle + t = mesh_element(2,e) ! get elemType + g = FE_geomtype(t) ! get elemGeomType + c = FE_celltype(g) ! get cellType + write(6,'(i8,3(1x,i8))') e,t,g,c + enddo + write(6,'(/,a)') 'Input Parser: ELEMENT VOLUME' + write(6,'(/,a13,1x,e15.8)') 'total volume', sum(mesh_ipVolume) + write(6,'(/,a8,1x,a5,1x,a15,1x,a5,1x,a15,1x,a16)') 'elem','IP','volume','face','area','-- normal --' + do e = 1_pInt,mesh_NcpElems + if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_e /= e) cycle + t = mesh_element(2,e) ! get element type + g = FE_geomtype(t) ! get geometry type + c = FE_celltype(g) ! get cell type + do i = 1_pInt,FE_Nips(g) + if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_i /= i) cycle + write(6,'(i8,1x,i5,1x,e15.8)') e,i,mesh_IPvolume(i,e) + do f = 1_pInt,FE_NipNeighbors(c) + write(6,'(i33,1x,e15.8,1x,3(f6.3,1x))') f,mesh_ipArea(f,i,e),mesh_ipAreaNormal(:,f,i,e) + enddo + enddo + enddo + write(6,'(/,a,/)') 'Input Parser: CELLNODE COORDINATES' + write(6,'(a8,1x,a2,1x,a8,3(1x,a12))') 'elem','IP','cellnode','x','y','z' + do e = 1_pInt,mesh_NcpElems ! loop over cpElems + if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_e /= e) cycle + t = mesh_element(2,e) ! get element type + g = FE_geomtype(t) ! get geometry type + c = FE_celltype(g) ! get cell type + do i = 1_pInt,FE_Nips(g) ! loop over IPs of elem + if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_i /= i) cycle + write(6,'(i8,1x,i2)') e,i + do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in the cell + write(6,'(12x,i8,3(1x,f12.8))') mesh_cell(n,i,e), & + mesh_cellnode(1:3,mesh_cell(n,i,e)) + enddo + enddo + enddo + write(6,'(/,a)') 'Input Parser: IP COORDINATES' + write(6,'(a8,1x,a5,3(1x,a12))') 'elem','IP','x','y','z' + do e = 1_pInt,mesh_NcpElems + if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_e /= e) cycle + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_i /= i) cycle + write(6,'(i8,1x,i5,3(1x,f12.8))') e, i, mesh_ipCoordinates(:,i,e) + enddo + enddo +#ifndef Spectral + write(6,'(/,a,/)') 'Input Parser: NODE TWINS' + write(6,'(a6,3(3x,a6))') ' node','twin_x','twin_y','twin_z' + do n = 1_pInt,mesh_Nnodes ! loop over cpNodes + if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. .not. any(mesh_element(5:,debug_e) == n)) cycle + write(6,'(i6,3(3x,i6))') n, mesh_nodeTwins(1:3,n) + enddo +#endif + write(6,'(/,a,/)') 'Input Parser: IP NEIGHBORHOOD' + write(6,'(a8,1x,a10,1x,a10,1x,a3,1x,a13,1x,a13)') 'elem','IP','neighbor','','elemNeighbor','ipNeighbor' + do e = 1_pInt,mesh_NcpElems ! loop over cpElems + if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_e /= e) cycle + t = mesh_element(2,e) ! get element type + g = FE_geomtype(t) ! get geometry type + c = FE_celltype(g) ! get cell type + do i = 1_pInt,FE_Nips(g) ! loop over IPs of elem + if (iand(myDebug,debug_levelSelective) /= 0_pInt .and. debug_i /= i) cycle + do n = 1_pInt,FE_NipNeighbors(c) ! loop over neighbors of IP + write(6,'(i8,1x,i10,1x,i10,1x,a3,1x,i13,1x,i13)') e,i,n,'-->',mesh_ipNeighborhood(1,n,i,e),mesh_ipNeighborhood(2,n,i,e) + enddo + enddo + enddo + endif +!$OMP END CRITICAL (write2out) + + deallocate(mesh_HomogMicro) + +end subroutine mesh_tell_statistics + + +!-------------------------------------------------------------------------------------------------- +!> @brief mapping of FE element types to internal representation +!-------------------------------------------------------------------------------------------------- +integer(pInt) function FE_mapElemtype(what) + use IO, only: IO_lc, IO_error + + implicit none + character(len=*), intent(in) :: what + + select case (IO_lc(what)) + case ( '6') + FE_mapElemtype = 1_pInt ! Two-dimensional Plane Strain Triangle + case ( '155', & + '125', & + '128') + FE_mapElemtype = 2_pInt ! Two-dimensional Plane Strain triangle (155: cubic shape function, 125/128: second order isoparametric) + case ( '11', & + 'cpe4', & + 'cpe4t') + FE_mapElemtype = 3_pInt ! Arbitrary Quadrilateral Plane-strain + case ( '27', & + 'cpe8', & + 'cpe8t') + FE_mapElemtype = 4_pInt ! Plane Strain, Eight-node Distorted Quadrilateral + case ( '54') + FE_mapElemtype = 5_pInt ! Plane Strain, Eight-node Distorted Quadrilateral with reduced integration + case ( '134', & + 'c3d4', & + 'c3d4t') + FE_mapElemtype = 6_pInt ! Three-dimensional Four-node Tetrahedron + case ( '157') + FE_mapElemtype = 7_pInt ! Three-dimensional, Low-order, Tetrahedron, Herrmann Formulations + case ( '127') + FE_mapElemtype = 8_pInt ! Three-dimensional Ten-node Tetrahedron + case ( '136', & + 'c3d6', & + 'c3d6t') + FE_mapElemtype = 9_pInt ! Three-dimensional Arbitrarily Distorted Pentahedral + case ( '117', & + '123', & + 'c3d8r', & + 'c3d8rt') + FE_mapElemtype = 10_pInt ! Three-dimensional Arbitrarily Distorted linear hexahedral with reduced integration + case ( '7', & + 'c3d8', & + 'c3d8t') + FE_mapElemtype = 11_pInt ! Three-dimensional Arbitrarily Distorted Brick + case ( '57', & + 'c3d20r', & + 'c3d20rt') + FE_mapElemtype = 12_pInt ! Three-dimensional Arbitrarily Distorted quad hexahedral with reduced integration + case ( '21', & + 'c3d20', & + 'c3d20t') + FE_mapElemtype = 13_pInt ! Three-dimensional Arbitrarily Distorted quadratic hexahedral + case default + call IO_error(error_ID=190_pInt,ext_msg=IO_lc(what)) + end select + +end function FE_mapElemtype + + +!-------------------------------------------------------------------------------------------------- +!> @brief find face-matching element of same type +!-------------------------------------------------------------------------------------------------- +subroutine mesh_faceMatch(elem, face ,matchingElem, matchingFace) + +implicit none +!*** output variables +integer(pInt), intent(out) :: matchingElem, & ! matching CP element ID + matchingFace ! matching face ID + +!*** input variables +integer(pInt), intent(in) :: face, & ! face ID + elem ! CP elem ID + +!*** local variables +integer(pInt), dimension(FE_NmatchingNodesPerFace(face,FE_geomtype(mesh_element(2,elem)))) :: & + myFaceNodes ! global node ids on my face +integer(pInt) :: myType, & + candidateType, & + candidateElem, & + candidateFace, & + candidateFaceNode, & + minNsharedElems, & + NsharedElems, & + lonelyNode = 0_pInt, & + i, & + n, & + dir ! periodicity direction +integer(pInt), dimension(:), allocatable :: element_seen +logical checkTwins + +matchingElem = 0_pInt +matchingFace = 0_pInt +minNsharedElems = mesh_maxNsharedElems + 1_pInt ! init to worst case +myType = FE_geomtype(mesh_element(2_pInt,elem)) ! figure elemGeomType + +do n = 1_pInt,FE_NmatchingNodesPerFace(face,myType) ! loop over nodes on face + myFaceNodes(n) = mesh_element(4_pInt+FE_face(n,face,myType),elem) ! CP id of face node + NsharedElems = mesh_sharedElem(1_pInt,myFaceNodes(n)) ! figure # shared elements for this node + if (NsharedElems < minNsharedElems) then + minNsharedElems = NsharedElems ! remember min # shared elems + lonelyNode = n ! remember most lonely node + endif +enddo + +allocate(element_seen(minNsharedElems)) +element_seen = 0_pInt + +checkCandidate: do i = 1_pInt,minNsharedElems ! iterate over lonelyNode's shared elements + candidateElem = mesh_sharedElem(1_pInt+i,myFaceNodes(lonelyNode)) ! present candidate elem + if (all(element_seen /= candidateElem)) then ! element seen for the first time? + element_seen(i) = candidateElem + candidateType = FE_geomtype(mesh_element(2_pInt,candidateElem)) ! figure elemGeomType of candidate +checkCandidateFace: do candidateFace = 1_pInt,FE_maxNipNeighbors ! check each face of candidate + if (FE_NmatchingNodesPerFace(candidateFace,candidateType) & + /= FE_NmatchingNodesPerFace(face,myType) & ! incompatible face + .or. (candidateElem == elem .and. candidateFace == face)) then ! this is my face + cycle checkCandidateFace + endif + checkTwins = .false. + do n = 1_pInt,FE_NmatchingNodesPerFace(candidateFace,candidateType) ! loop through nodes on face + candidateFaceNode = mesh_element(4_pInt+FE_face(n,candidateFace,candidateType),candidateElem) + if (all(myFaceNodes /= candidateFaceNode)) then ! candidate node does not match any of my face nodes + checkTwins = .true. ! perhaps the twin nodes do match + exit + endif + enddo + if(checkTwins) then +checkCandidateFaceTwins: do dir = 1_pInt,3_pInt + do n = 1_pInt,FE_NmatchingNodesPerFace(candidateFace,candidateType) ! loop through nodes on face + candidateFaceNode = mesh_element(4+FE_face(n,candidateFace,candidateType),candidateElem) + if (all(myFaceNodes /= mesh_nodeTwins(dir,candidateFaceNode))) then ! node twin does not match either + if (dir == 3_pInt) then + cycle checkCandidateFace + else + cycle checkCandidateFaceTwins ! try twins in next dimension + endif + endif + enddo + exit checkCandidateFaceTwins + enddo checkCandidateFaceTwins + endif + matchingFace = candidateFace + matchingElem = candidateElem + exit checkCandidate ! found my matching candidate + enddo checkCandidateFace + endif +enddo checkCandidate + +deallocate(element_seen) + +end subroutine mesh_faceMatch + + +!-------------------------------------------------------------------------------------------------- +!> @brief get properties of different types of finite elements +!> @details assign globals: FE_nodesAtIP, FE_ipNeighbor, FE_cellnodeParentnodeWeights, FE_subNodeOnIPFace +!-------------------------------------------------------------------------------------------------- +subroutine mesh_build_FEdata + + implicit none + integer(pInt) :: me + allocate(FE_nodesAtIP(FE_maxmaxNnodesAtIP,FE_maxNips,FE_Ngeomtypes)); FE_nodesAtIP = 0_pInt + allocate(FE_ipNeighbor(FE_maxNipNeighbors,FE_maxNips,FE_Ngeomtypes)); FE_ipNeighbor = 0_pInt + allocate(FE_cell(FE_maxNcellnodesPerCell,FE_maxNips,FE_Ngeomtypes)); FE_cell = 0_pInt + allocate(FE_cellnodeParentnodeWeights(FE_maxNnodes,FE_maxNcellnodes,FE_Nelemtypes)); FE_cellnodeParentnodeWeights = 0.0_pReal + allocate(FE_cellface(FE_maxNcellnodesPerCellface,FE_maxNcellfaces,FE_Ncelltypes)); FE_cellface = 0_pInt + + + !*** fill FE_nodesAtIP with data *** + + me = 0_pInt + + me = me + 1_pInt + FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 6 (2D 3node 1ip) + reshape(int([& + 1,2,3 & + ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) + + me = me + 1_pInt + FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 125 (2D 6node 3ip) + reshape(int([& + 1, & + 2, & + 3 & + ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) + + me = me + 1_pInt + FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 11 (2D 4node 4ip) + reshape(int([& + 1, & + 2, & + 4, & + 3 & + ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) + + me = me + 1_pInt + FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 27 (2D 8node 9ip) + reshape(int([& + 1,0, & + 1,2, & + 2,0, & + 1,4, & + 0,0, & + 2,3, & + 4,0, & + 3,4, & + 3,0 & + ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) + + me = me + 1_pInt + FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 134 (3D 4node 1ip) + reshape(int([& + 1,2,3,4 & + ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) + + me = me + 1_pInt + FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 127 (3D 10node 4ip) + reshape(int([& + 1, & + 2, & + 3, & + 4 & + ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) + + me = me + 1_pInt + FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 136 (3D 6node 6ip) + reshape(int([& + 1, & + 2, & + 3, & + 4, & + 5, & + 6 & + ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) + + me = me + 1_pInt + FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 117 (3D 8node 1ip) + reshape(int([& + 1,2,3,4,5,6,7,8 & + ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) + + me = me + 1_pInt + FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 7 (3D 8node 8ip) + reshape(int([& + 1, & + 2, & + 4, & + 3, & + 5, & + 6, & + 8, & + 7 & + ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) + + me = me + 1_pInt + FE_nodesAtIP(1:FE_maxNnodesAtIP(me),1:FE_Nips(me),me) = & ! element 21 (3D 20node 27ip) + reshape(int([& + 1,0, 0,0, & + 1,2, 0,0, & + 2,0, 0,0, & + 1,4, 0,0, & + 1,3, 2,4, & + 2,3, 0,0, & + 4,0, 0,0, & + 3,4, 0,0, & + 3,0, 0,0, & + 1,5, 0,0, & + 1,6, 2,5, & + 2,6, 0,0, & + 1,8, 4,5, & + 0,0, 0,0, & + 2,7, 3,6, & + 4,8, 0,0, & + 3,8, 4,7, & + 3,7, 0,0, & + 5,0, 0,0, & + 5,6, 0,0, & + 6,0, 0,0, & + 5,8, 0,0, & + 5,7, 6,8, & + 6,7, 0,0, & + 8,0, 0,0, & + 7,8, 0,0, & + 7,0, 0,0 & + ],pInt),[FE_maxNnodesAtIP(me),FE_Nips(me)]) + + + ! *** FE_ipNeighbor *** + ! is a list of the neighborhood of each IP. + ! It is sorted in (local) +x,-x, +y,-y, +z,-z direction. + ! Positive integers denote an intra-FE IP identifier. + ! Negative integers denote the interface behind which the neighboring (extra-FE) IP will be located. + me = 0_pInt + + me = me + 1_pInt + FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 6 (2D 3node 1ip) + reshape(int([& + -2,-3,-1 & + ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 125 (2D 6node 3ip) + reshape(int([& + 2,-3, 3,-1, & + -2, 1, 3,-1, & + 2,-3,-2, 1 & + ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 11 (2D 4node 4ip) + reshape(int([& + 2,-4, 3,-1, & + -2, 1, 4,-1, & + 4,-4,-3, 1, & + -2, 3,-3, 2 & + ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 27 (2D 8node 9ip) + reshape(int([& + 2,-4, 4,-1, & + 3, 1, 5,-1, & + -2, 2, 6,-1, & + 5,-4, 7, 1, & + 6, 4, 8, 2, & + -2, 5, 9, 3, & + 8,-4,-3, 4, & + 9, 7,-3, 5, & + -2, 8,-3, 6 & + ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 134 (3D 4node 1ip) + reshape(int([& + -1,-2,-3,-4 & + ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 127 (3D 10node 4ip) + reshape(int([& + 2,-4, 3,-2, 4,-1, & + -2, 1, 3,-2, 4,-1, & + 2,-4,-3, 1, 4,-1, & + 2,-4, 3,-2,-3, 1 & + ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 136 (3D 6node 6ip) + reshape(int([& + 2,-4, 3,-2, 4,-1, & + -3, 1, 3,-2, 5,-1, & + 2,-4,-3, 1, 6,-1, & + 5,-4, 6,-2,-5, 1, & + -3, 4, 6,-2,-5, 2, & + 5,-4,-3, 4,-5, 3 & + ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 117 (3D 8node 1ip) + reshape(int([& + -3,-5,-4,-2,-6,-1 & + ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 7 (3D 8node 8ip) + reshape(int([& + 2,-5, 3,-2, 5,-1, & + -3, 1, 4,-2, 6,-1, & + 4,-5,-4, 1, 7,-1, & + -3, 3,-4, 2, 8,-1, & + 6,-5, 7,-2,-6, 1, & + -3, 5, 8,-2,-6, 2, & + 8,-5,-4, 5,-6, 3, & + -3, 7,-4, 6,-6, 4 & + ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_ipNeighbor(1:FE_NipNeighbors(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 21 (3D 20node 27ip) + reshape(int([& + 2,-5, 4,-2,10,-1, & + 3, 1, 5,-2,11,-1, & + -3, 2, 6,-2,12,-1, & + 5,-5, 7, 1,13,-1, & + 6, 4, 8, 2,14,-1, & + -3, 5, 9, 3,15,-1, & + 8,-5,-4, 4,16,-1, & + 9, 7,-4, 5,17,-1, & + -3, 8,-4, 6,18,-1, & + 11,-5,13,-2,19, 1, & + 12,10,14,-2,20, 2, & + -3,11,15,-2,21, 3, & + 14,-5,16,10,22, 4, & + 15,13,17,11,23, 5, & + -3,14,18,12,24, 6, & + 17,-5,-4,13,25, 7, & + 18,16,-4,14,26, 8, & + -3,17,-4,15,27, 9, & + 20,-5,22,-2,-6,10, & + 21,19,23,-2,-6,11, & + -3,20,24,-2,-6,12, & + 23,-5,25,19,-6,13, & + 24,22,26,20,-6,14, & + -3,23,27,21,-6,15, & + 26,-5,-4,22,-6,16, & + 27,25,-4,23,-6,17, & + -3,26,-4,24,-6,18 & + ],pInt),[FE_NipNeighbors(FE_celltype(me)),FE_Nips(me)]) + + + ! *** FE_cell *** + me = 0_pInt + + me = me + 1_pInt + FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 6 (2D 3node 1ip) + reshape(int([& + 1,2,3 & + ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 125 (2D 6node 3ip) + reshape(int([& + 1, 4, 7, 6, & + 2, 5, 7, 4, & + 3, 6, 7, 5 & + ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 11 (2D 4node 4ip) + reshape(int([& + 1, 5, 9, 8, & + 5, 2, 6, 9, & + 8, 9, 7, 4, & + 9, 6, 3, 7 & + ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 27 (2D 8node 9ip) + reshape(int([& + 1, 5,13,12, & + 5, 6,14,13, & + 6, 2, 7,14, & + 12,13,16,11, & + 13,14,15,16, & + 14, 7, 8,15, & + 11,16,10, 4, & + 16,15, 9,10, & + 15, 8, 3, 9 & + ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 134 (3D 4node 1ip) + reshape(int([& + 1, 2, 3, 4 & + ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 127 (3D 10node 4ip) + reshape(int([& + 1, 5,11, 7, 8,12,15,14, & + 5, 2, 6,11,12, 9,13,15, & + 7,11, 6, 3,14,15,13,10, & + 8,12,15, 4, 4, 9,13,10 & + ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 136 (3D 6node 6ip) + reshape(int([& + 1, 7,16, 9,10,17,21,19, & + 7, 2, 8,16,17,11,18,21, & + 9,16, 8, 3,19,21,18,12, & + 10,17,21,19, 4,13,20,15, & + 17,11,18,21,13, 5,14,20, & + 19,21,18,12,15,20,14, 6 & + ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 117 (3D 8node 1ip) + reshape(int([& + 1, 2, 3, 4, 5, 6, 7, 8 & + ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 7 (3D 8node 8ip) + reshape(int([& + 1, 9,21,12,13,22,27,25, & + 9, 2,10,21,22,14,23,27, & + 12,21,11, 4,25,27,24,16, & + 21,10, 3,11,27,23,15,24, & + 13,22,27,25, 5,17,26,20, & + 22,14,23,27,17, 6,18,26, & + 25,27,24,16,20,26,19, 8, & + 27,23,15,24,26,18, 7,19 & + ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) + + me = me + 1_pInt + FE_cell(1:FE_NcellnodesPerCell(FE_celltype(me)),1:FE_Nips(me),me) = & ! element 21 (3D 20node 27ip) + reshape(int([& + 1, 9,33,16,17,37,57,44, & + 9,10,34,33,37,38,58,57, & + 10, 2,11,34,38,18,39,58, & + 16,33,36,15,44,57,60,43, & + 33,34,35,36,57,58,59,60, & + 34,11,12,35,58,39,40,59, & + 15,36,14, 4,43,60,42,20, & + 36,35,13,14,60,59,41,42, & + 35,12, 3,13,59,40,19,41, & + 17,37,57,44,21,45,61,52, & + 37,38,58,57,45,46,62,61, & + 38,18,39,58,46,22,47,62, & + 44,57,60,43,52,61,64,51, & + 57,58,59,60,61,62,63,64, & + 58,39,40,59,62,47,48,63, & + 43,60,42,20,51,64,50,24, & + 60,59,41,42,64,63,49,50, & + 59,40,19,41,63,48,23,49, & + 21,45,61,52, 5,25,53,32, & + 45,46,62,61,25,26,54,53, & + 46,22,47,62,26, 6,27,54, & + 52,61,64,51,32,53,56,31, & + 61,62,63,64,53,54,55,56, & + 62,47,48,63,54,27,28,55, & + 51,64,50,24,31,56,30, 8, & + 64,63,49,50,56,55,29,30, & + 63,48,23,49,55,28, 7,29 & + ],pInt),[FE_NcellnodesPerCell(FE_celltype(me)),FE_Nips(me)]) + + + ! *** FE_cellnodeParentnodeWeights *** + ! center of gravity of the weighted nodes gives the position of the cell node. + ! fill with 0. + ! example: face-centered cell node with face nodes 1,2,5,6 to be used in, + ! e.g., an 8 node element, would be encoded: + ! 1, 1, 0, 0, 1, 1, 0, 0 + me = 0_pInt + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 6 (2D 3node 1ip) + reshape(real([& + 1, 0, 0, & + 0, 1, 0, & + 0, 0, 1 & + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 125 (2D 6node 3ip) + reshape(real([& + 1, 0, 0, 0, 0, 0, & + 0, 1, 0, 0, 0, 0, & + 0, 0, 1, 0, 0, 0, & + 0, 0, 0, 1, 0, 0, & + 0, 0, 0, 0, 1, 0, & + 0, 0, 0, 0, 0, 1, & + 1, 1, 1, 2, 2, 2 & + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 11 (2D 4node 4ip) + reshape(real([& + 1, 0, 0, 0, & + 0, 1, 0, 0, & + 0, 0, 1, 0, & + 0, 0, 0, 1, & + 1, 1, 0, 0, & + 0, 1, 1, 0, & + 0, 0, 1, 1, & + 1, 0, 0, 1, & + 1, 1, 1, 1 & + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 27 (2D 8node 9ip) + reshape(real([& + 1, 0, 0, 0, 0, 0, 0, 0, & + 0, 1, 0, 0, 0, 0, 0, 0, & + 0, 0, 1, 0, 0, 0, 0, 0, & + 0, 0, 0, 1, 0, 0, 0, 0, & + 1, 0, 0, 0, 2, 0, 0, 0, & + 0, 1, 0, 0, 2, 0, 0, 0, & + 0, 1, 0, 0, 0, 2, 0, 0, & + 0, 0, 1, 0, 0, 2, 0, 0, & + 0, 0, 1, 0, 0, 0, 2, 0, & + 0, 0, 0, 1, 0, 0, 2, 0, & + 0, 0, 0, 1, 0, 0, 0, 2, & + 1, 0, 0, 0, 0, 0, 0, 2, & + 4, 1, 1, 1, 8, 2, 2, 8, & + 1, 4, 1, 1, 8, 8, 2, 2, & + 1, 1, 4, 1, 2, 8, 8, 2, & + 1, 1, 1, 4, 2, 2, 8, 8 & + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 54 (2D 8node 4ip) + reshape(real([& + 1, 0, 0, 0, 0, 0, 0, 0, & + 0, 1, 0, 0, 0, 0, 0, 0, & + 0, 0, 1, 0, 0, 0, 0, 0, & + 0, 0, 0, 1, 0, 0, 0, 0, & + 0, 0, 0, 0, 1, 0, 0, 0, & + 0, 0, 0, 0, 0, 1, 0, 0, & + 0, 0, 0, 0, 0, 0, 1, 0, & + 0, 0, 0, 0, 0, 0, 0, 1, & + 1, 1, 1, 1, 2, 2, 2, 2 & + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 134 (3D 4node 1ip) + reshape(real([& + 1, 0, 0, 0, & + 0, 1, 0, 0, & + 0, 0, 1, 0, & + 0, 0, 0, 1 & + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 157 (3D 5node 4ip) + reshape(real([& + 1, 0, 0, 0, 0, & + 0, 1, 0, 0, 0, & + 0, 0, 1, 0, 0, & + 0, 0, 0, 1, 0, & + 1, 1, 0, 0, 0, & + 0, 1, 1, 0, 0, & + 1, 0, 1, 0, 0, & + 1, 0, 0, 1, 0, & + 0, 1, 0, 1, 0, & + 0, 0, 1, 1, 0, & + 1, 1, 1, 0, 0, & + 1, 1, 0, 1, 0, & + 0, 1, 1, 1, 0, & + 1, 0, 1, 1, 0, & + 0, 0, 0, 0, 1 & + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 127 (3D 10node 4ip) + reshape(real([& + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, & + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, & + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, & + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, & + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, & + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, & + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, & + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, & + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, & + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, & + 1, 1, 1, 0, 2, 2, 2, 0, 0, 0, & + 1, 1, 0, 1, 2, 0, 0, 2, 2, 0, & + 0, 1, 1, 1, 0, 2, 0, 0, 2, 2, & + 1, 0, 1, 1, 0, 0, 2, 2, 0, 2, & + 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 & + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 136 (3D 6node 6ip) + reshape(real([& + 1, 0, 0, 0, 0, 0, & + 0, 1, 0, 0, 0, 0, & + 0, 0, 1, 0, 0, 0, & + 0, 0, 0, 1, 0, 0, & + 0, 0, 0, 0, 1, 0, & + 0, 0, 0, 0, 0, 1, & + 1, 1, 0, 0, 0, 0, & + 0, 1, 1, 0, 0, 0, & + 1, 0, 1, 0, 0, 0, & + 1, 0, 0, 1, 0, 0, & + 0, 1, 0, 0, 1, 0, & + 0, 0, 1, 0, 0, 1, & + 0, 0, 0, 1, 1, 0, & + 0, 0, 0, 0, 1, 1, & + 0, 0, 0, 1, 0, 1, & + 1, 1, 1, 0, 0, 0, & + 1, 1, 0, 1, 1, 0, & + 0, 1, 1, 0, 1, 1, & + 1, 0, 1, 1, 0, 1, & + 0, 0, 0, 1, 1, 1, & + 1, 1, 1, 1, 1, 1 & + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 117 (3D 8node 1ip) + reshape(real([& + 1, 0, 0, 0, 0, 0, 0, 0, & + 0, 1, 0, 0, 0, 0, 0, 0, & + 0, 0, 1, 0, 0, 0, 0, 0, & + 0, 0, 0, 1, 0, 0, 0, 0, & + 0, 0, 0, 0, 1, 0, 0, 0, & + 0, 0, 0, 0, 0, 1, 0, 0, & + 0, 0, 0, 0, 0, 0, 1, 0, & + 0, 0, 0, 0, 0, 0, 0, 1 & + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 7 (3D 8node 8ip) + reshape(real([& + 1, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 1, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 1, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 1, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 1, 0, 0, 0, & ! 5 + 0, 0, 0, 0, 0, 1, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 1, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 1, & ! + 1, 1, 0, 0, 0, 0, 0, 0, & ! + 0, 1, 1, 0, 0, 0, 0, 0, & ! 10 + 0, 0, 1, 1, 0, 0, 0, 0, & ! + 1, 0, 0, 1, 0, 0, 0, 0, & ! + 1, 0, 0, 0, 1, 0, 0, 0, & ! + 0, 1, 0, 0, 0, 1, 0, 0, & ! + 0, 0, 1, 0, 0, 0, 1, 0, & ! 15 + 0, 0, 0, 1, 0, 0, 0, 1, & ! + 0, 0, 0, 0, 1, 1, 0, 0, & ! + 0, 0, 0, 0, 0, 1, 1, 0, & ! + 0, 0, 0, 0, 0, 0, 1, 1, & ! + 0, 0, 0, 0, 1, 0, 0, 1, & ! 20 + 1, 1, 1, 1, 0, 0, 0, 0, & ! + 1, 1, 0, 0, 1, 1, 0, 0, & ! + 0, 1, 1, 0, 0, 1, 1, 0, & ! + 0, 0, 1, 1, 0, 0, 1, 1, & ! + 1, 0, 0, 1, 1, 0, 0, 1, & ! 25 + 0, 0, 0, 0, 1, 1, 1, 1, & ! + 1, 1, 1, 1, 1, 1, 1, 1 & ! + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 57 (3D 20node 8ip) + reshape(real([& + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! 5 + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! 10 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, & ! 15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, & ! + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, & ! 20 + 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 1, 1, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 0, 0, & ! + 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 0, & ! + 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, & ! + 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 2, 2, 0, 0, 2, & ! 25 + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, & ! + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 & ! + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + me = me + 1_pInt + FE_cellnodeParentnodeWeights(1:FE_Nnodes(me),1:FE_Ncellnodes(FE_geomtype(me)),me) = & ! element 21 (3D 20node 27ip) + reshape(real([& + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! 5 + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! 10 + 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, & ! 15 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, & ! + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, & ! + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, & ! + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, & ! 20 + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, & ! + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, & ! 25 + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, & ! 30 + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, & ! + 4, 1, 1, 1, 0, 0, 0, 0, 8, 2, 2, 8, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 1, 4, 1, 1, 0, 0, 0, 0, 8, 8, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 1, 1, 4, 1, 0, 0, 0, 0, 2, 8, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, & ! 35 + 1, 1, 1, 4, 0, 0, 0, 0, 2, 2, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, & ! + 4, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 8, 2, 0, 0, & ! + 1, 4, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 2, 8, 0, 0, & ! + 0, 4, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 8, 2, 0, & ! + 0, 1, 4, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 2, 8, 0, & ! 40 + 0, 0, 4, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 8, 2, & ! + 0, 0, 1, 4, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 2, 8, & ! + 1, 0, 0, 4, 1, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 2, 2, 0, 0, 8, & ! + 4, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 2, 8, 0, 0, 2, & ! + 1, 1, 0, 0, 4, 1, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 8, 2, 0, 0, & ! 45 + 1, 1, 0, 0, 1, 4, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 2, 8, 0, 0, & ! + 0, 1, 1, 0, 0, 4, 1, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 8, 2, 0, & ! + 0, 1, 1, 0, 0, 1, 4, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 2, 8, 0, & ! + 0, 0, 1, 1, 0, 0, 4, 1, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 8, 2, & ! + 0, 0, 1, 1, 0, 0, 1, 4, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 2, 8, & ! 50 + 1, 0, 0, 1, 1, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 8, 2, 0, 0, 8, & ! + 1, 0, 0, 1, 4, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 8, 8, 0, 0, 2, & ! + 0, 0, 0, 0, 4, 1, 1, 1, 0, 0, 0, 0, 8, 2, 2, 8, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 1, 4, 1, 1, 0, 0, 0, 0, 8, 8, 2, 2, 0, 0, 0, 0, & ! + 0, 0, 0, 0, 1, 1, 4, 1, 0, 0, 0, 0, 2, 8, 8, 2, 0, 0, 0, 0, & ! 55 + 0, 0, 0, 0, 1, 1, 1, 4, 0, 0, 0, 0, 2, 2, 8, 8, 0, 0, 0, 0, & ! + 24, 8, 4, 8, 8, 4, 3, 4, 32,12,12,32, 12, 4, 4,12, 32,12, 4,12, & ! + 8,24, 8, 4, 4, 8, 4, 3, 32,32,12,12, 12,12, 4, 4, 12,32,12, 4, & ! + 4, 8,24, 8, 3, 4, 8, 4, 12,32,32,12, 4,12,12, 4, 4,12,32,12, & ! + 8, 4, 8,24, 4, 3, 4, 8, 12,12,32,32, 4, 4,12,12, 12, 4,12,32, & ! 60 + 8, 4, 3, 4, 24, 8, 4, 8, 12, 4, 4,12, 32,12,12,32, 32,12, 4,12, & ! + 4, 8, 4, 3, 8,24, 8, 4, 12,12, 4, 4, 32,32,12,12, 12,32,12, 4, & ! + 3, 4, 8, 4, 4, 8,24, 8, 4,12,12, 4, 12,32,32,12, 4,12,32,12, & ! + 4, 3, 4, 8, 8, 4, 8,24, 4, 4,12,12, 12,12,32,32, 12, 4,12,32 & ! + ],pReal),[FE_Nnodes(me),FE_Ncellnodes(FE_geomtype(me))]) + + + + ! *** FE_cellface *** + me = 0_pInt + + me = me + 1_pInt + FE_cellface(1:FE_NcellnodesPerCellface(me),1:FE_NipNeighbors(me),me) = & ! 2D 3node, VTK_TRIANGLE (5) + reshape(int([& + 2,3, & + 3,1, & + 1,2 & + ],pInt),[FE_NcellnodesPerCellface(me),FE_NipNeighbors(me)]) + + me = me + 1_pInt + FE_cellface(1:FE_NcellnodesPerCellface(me),1:FE_NipNeighbors(me),me) = & ! 2D 4node, VTK_QUAD (9) + reshape(int([& + 2,3, & + 4,1, & + 3,4, & + 1,2 & + ],pInt),[FE_NcellnodesPerCellface(me),FE_NipNeighbors(me)]) + + me = me + 1_pInt + FE_cellface(1:FE_NcellnodesPerCellface(me),1:FE_NipNeighbors(me),me) = & ! 3D 4node, VTK_TETRA (10) + reshape(int([& + 1,3,2, & + 1,2,4, & + 2,3,4, & + 1,4,3 & + ],pInt),[FE_NcellnodesPerCellface(me),FE_NipNeighbors(me)]) + + me = me + 1_pInt + FE_cellface(1:FE_NcellnodesPerCellface(me),1:FE_NipNeighbors(me),me) = & ! 3D 8node, VTK_HEXAHEDRON (12) + reshape(int([& + 2,3,7,6, & + 4,1,5,8, & + 3,4,8,7, & + 1,2,6,5, & + 5,6,7,8, & + 1,4,3,2 & + ],pInt),[FE_NcellnodesPerCellface(me),FE_NipNeighbors(me)]) + + +end subroutine mesh_build_FEdata + + +!-------------------------------------------------------------------------------------------------- +!> @brief writes out initial cell geometry +!-------------------------------------------------------------------------------------------------- +subroutine mesh_write_cellGeom + use DAMASK_interface, only: & + getSolverJobName, & + getSolverWorkingDirectoryName + use IR_Precision, only: & + I4P + use Lib_VTK_IO, only: & + VTK_ini, & + VTK_geo, & + VTK_con, & + VTK_end +#ifdef HDF + use IO, only: & + HDF5_mappingCells +#endif + implicit none + integer(I4P), dimension(1:mesh_Ncells) :: celltype + integer(I4P), dimension(mesh_Ncells*(1_pInt+FE_maxNcellnodesPerCell)) :: cellconnection +#ifdef HDF + integer(pInt), dimension(mesh_Ncells*FE_maxNcellnodesPerCell) :: cellconnectionHDF5 + integer(pInt) :: j2=0_pInt +#endif + integer(I4P):: error + integer(I4P):: g, c, e, CellID, i, j + + cellID = 0_pInt + j = 0_pInt + do e = 1_pInt, mesh_NcpElems ! loop over cpElems + g = FE_geomtype(mesh_element(2_pInt,e)) ! get geometry type + c = FE_celltype(g) ! get cell type + do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element + cellID = cellID + 1_pInt + celltype(cellID) = MESH_VTKCELLTYPE(c) + cellconnection(j+1_pInt:j+FE_NcellnodesPerCell(c)+1_pInt) & + = [FE_NcellnodesPerCell(c),mesh_cell(1:FE_NcellnodesPerCell(c),i,e)-1_pInt] ! number of cellnodes per cell & list of global cellnode IDs belnging to this cell (cellnode counting starts at 0) + j = j + FE_NcellnodesPerCell(c) + 1_pInt +#ifdef HDF + cellconnectionHDF5(j2+1_pInt:j2+FE_NcellnodesPerCell(c)) & + = mesh_cell(1:FE_NcellnodesPerCell(c),i,e)-1_pInt + j2=j2 + FE_ncellnodesPerCell(c) +#endif + enddo + enddo +#ifdef HDF + call HDF5_mappingCells(cellconnectionHDF5(1:j2)) +#endif + + error=VTK_ini(output_format = 'ASCII', & + title=trim(getSolverJobName())//' cell mesh', & + filename = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'_ipbased.vtk', & + mesh_topology = 'UNSTRUCTURED_GRID') + !ToDo: check error here + error=VTK_geo(NN = int(mesh_Ncellnodes,I4P), & + X = mesh_cellnode(1,1:mesh_Ncellnodes), & + Y = mesh_cellnode(2,1:mesh_Ncellnodes), & + Z = mesh_cellnode(3,1:mesh_Ncellnodes)) + !ToDo: check error here + error=VTK_con(NC = int(mesh_Ncells,I4P), & + connect = cellconnection(1:j), & + !ToDo: check error here + cell_type = celltype) + error=VTK_end() + !ToDo: check error here + +end subroutine mesh_write_cellGeom + + +!-------------------------------------------------------------------------------------------------- +!> @brief writes out initial element geometry +!-------------------------------------------------------------------------------------------------- +subroutine mesh_write_elemGeom + use DAMASK_interface, only: & + getSolverJobName, & + getSolverWorkingDirectoryName + use IR_Precision, only: & + I4P + use Lib_VTK_IO, only: & + VTK_ini, & + VTK_geo, & + VTK_con, & + VTK_end + + implicit none + integer(I4P), dimension(1:mesh_NcpElems) :: elemtype + integer(I4P), dimension(mesh_NcpElems*(1_pInt+FE_maxNnodes)) :: elementconnection + integer(I4P):: error + integer(pInt):: e, t, n, i + + i = 0_pInt + do e = 1_pInt, mesh_NcpElems ! loop over cpElems + t = mesh_element(2,e) ! get element type + elemtype(e) = MESH_VTKELEMTYPE(t) + elementconnection(i+1_pInt) = FE_Nnodes(t) ! number of nodes per element + do n = 1_pInt,FE_Nnodes(t) + elementconnection(i+1_pInt+n) = mesh_element(4_pInt+n,e) - 1_pInt ! global node ID of node that belongs to this element (node counting starts at 0) + enddo + i = i + 1_pInt + FE_Nnodes(t) + enddo + + error=VTK_ini(output_format = 'ASCII', & + title=trim(getSolverJobName())//' element mesh', & + filename = trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())//'_nodebased.vtk', & + mesh_topology = 'UNSTRUCTURED_GRID') + !ToDo: check error here + error=VTK_geo(NN = int(mesh_Nnodes,I4P), & + X = mesh_node0(1,1:mesh_Nnodes), & + Y = mesh_node0(2,1:mesh_Nnodes), & + Z = mesh_node0(3,1:mesh_Nnodes)) + !ToDo: check error here + error=VTK_con(NC = int(mesh_Nelems,I4P), & + connect = elementconnection(1:i), & + cell_type = elemtype) + !ToDo: check error here + error =VTK_end() + !ToDo: check error here + +end subroutine mesh_write_elemGeom + + +!-------------------------------------------------------------------------------------------------- +!> @brief writes description file for mesh +!-------------------------------------------------------------------------------------------------- +subroutine mesh_write_meshfile + use IO, only: & + IO_write_jobFile + + implicit none + integer(pInt), parameter :: fileUnit = 223_pInt + integer(pInt) :: e,i,t,g,c,n + + call IO_write_jobFile(fileUnit,'mesh') + write(fileUnit,'(A16,E10.3)') 'unitlength', mesh_unitlength + write(fileUnit,'(A16,I10)') 'maxNcellnodes', mesh_maxNcellnodes + write(fileUnit,'(A16,I10)') 'maxNips', mesh_maxNips + write(fileUnit,'(A16,I10)') 'maxNnodes', mesh_maxNnodes + write(fileUnit,'(A16,I10)') 'Nnodes', mesh_Nnodes + write(fileUnit,'(A16,I10)') 'NcpElems', mesh_NcpElems + do e = 1_pInt,mesh_NcpElems + t = mesh_element(2,e) + write(fileUnit,'(20(I10))') mesh_element(1_pInt:4_pInt+FE_Nnodes(t),e) + enddo + write(fileUnit,'(A16,I10)') 'Ncellnodes', mesh_Ncellnodes + do n = 1_pInt,mesh_Ncellnodes + write(fileUnit,'(2(I10))') mesh_cellnodeParent(1:2,n) + enddo + write(fileUnit,'(A16,I10)') 'Ncells', mesh_Ncells + do e = 1_pInt,mesh_NcpElems + t = mesh_element(2,e) + g = FE_geomtype(t) + c = FE_celltype(g) + do i = 1_pInt,FE_Nips(g) + write(fileUnit,'(8(I10))') & + mesh_cell(1_pInt:FE_NcellnodesPerCell(c),i,e) + enddo + enddo + close(fileUnit) + +end subroutine mesh_write_meshfile + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads mesh description file +!-------------------------------------------------------------------------------------------------- +integer function mesh_read_meshfile(filepath) + + implicit none + character(len=*), intent(in) :: filepath + integer(pInt), parameter :: fileUnit = 223_pInt + integer(pInt) :: e,i,t,g,n + + open(fileUnit,status='old',err=100,iostat=mesh_read_meshfile,action='read',file=filepath) + read(fileUnit,'(TR16,E10.3)',err=100,iostat=mesh_read_meshfile) mesh_unitlength + read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_maxNcellnodes + read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_maxNips + read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_maxNnodes + read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_Nnodes + read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_NcpElems + if (.not. allocated(mesh_element)) allocate(mesh_element(4_pInt+mesh_maxNnodes,mesh_NcpElems)) + mesh_element = 0_pInt + do e = 1_pInt,mesh_NcpElems + read(fileUnit,'(20(I10))',err=100,iostat=mesh_read_meshfile) & + mesh_element(:,e) + enddo + read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_Ncellnodes + if (.not. allocated(mesh_cellnodeParent)) allocate(mesh_cellnodeParent(2_pInt,mesh_Ncellnodes)) + do n = 1_pInt,mesh_Ncellnodes + read(fileUnit,'(2(I10))',err=100,iostat=mesh_read_meshfile) mesh_cellnodeParent(1:2,n) + enddo + read(fileUnit,'(TR16,I10)',err=100,iostat=mesh_read_meshfile) mesh_Ncells + if (.not. allocated(mesh_cell)) allocate(mesh_cell(FE_maxNcellnodesPerCell,mesh_maxNips,mesh_NcpElems)) + do e = 1_pInt,mesh_NcpElems + t = mesh_element(2,e) + g = FE_geomtype(t) + do i = 1_pInt,FE_Nips(g) + read(fileUnit,'(8(I10))',err=100,iostat=mesh_read_meshfile) mesh_cell(:,i,e) + enddo + enddo + close(fileUnit) + + mesh_read_meshfile = 0 ! successfully read data + +100 continue +end function mesh_read_meshfile + + +!-------------------------------------------------------------------------------------------------- +!> @brief initializes mesh data for use in post processing +!-------------------------------------------------------------------------------------------------- +integer function mesh_init_postprocessing(filepath) + + implicit none + character(len=*), intent(in) :: filepath + + call mesh_build_FEdata + mesh_init_postprocessing = mesh_read_meshfile(filepath) + +end function mesh_init_postprocessing + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns global variable mesh_Ncellnodes +!-------------------------------------------------------------------------------------------------- +integer(pInt) function mesh_get_Ncellnodes() + + implicit none + + mesh_get_Ncellnodes = mesh_Ncellnodes + +end function mesh_get_Ncellnodes + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns global variable mesh_unitlength +!-------------------------------------------------------------------------------------------------- +real(pReal) function mesh_get_unitlength() + + implicit none + + mesh_get_unitlength = mesh_unitlength + +end function mesh_get_unitlength + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns node that is located at an ip +!> @details return zero if requested ip does not exist or not available (more ips than nodes) +!-------------------------------------------------------------------------------------------------- +integer(pInt) function mesh_get_nodeAtIP(elemtypeFE,ip) + + implicit none + character(len=*), intent(in) :: elemtypeFE + integer(pInt), intent(in) :: ip + integer(pInt) :: elemtype + integer(pInt) :: geomtype + + mesh_get_nodeAtIP = 0_pInt + + elemtype = FE_mapElemtype(elemtypeFE) + geomtype = FE_geomtype(elemtype) + if (FE_Nips(geomtype) >= ip .and. FE_Nips(geomtype) <= FE_Nnodes(elemtype)) & + mesh_get_nodeAtIP = FE_nodesAtIP(1,ip,geomtype) + +end function mesh_get_nodeAtIP + + +end module mesh diff --git a/src/numerics.f90 b/src/numerics.f90 new file mode 100644 index 000000000..61f326c02 --- /dev/null +++ b/src/numerics.f90 @@ -0,0 +1,726 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Managing of parameters related to numerics +!-------------------------------------------------------------------------------------------------- +module numerics + use prec, only: & + pInt, & + pReal + + implicit none + private +#ifdef PETSc +#include +#endif + character(len=64), parameter, private :: & + numerics_CONFIGFILE = 'numerics.config' !< name of configuration file + + integer(pInt), protected, public :: & + iJacoStiffness = 1_pInt, & !< frequency of stiffness update + iJacoLpresiduum = 1_pInt, & !< frequency of Jacobian update of residuum in Lp + nHomog = 20_pInt, & !< homogenization loop limit (only for debugging info, loop limit is determined by "subStepMinHomog") + nMPstate = 10_pInt, & !< materialpoint state loop limit + nCryst = 20_pInt, & !< crystallite loop limit (only for debugging info, loop limit is determined by "subStepMinCryst") + nState = 10_pInt, & !< state loop limit + nStress = 40_pInt, & !< stress loop limit + pert_method = 1_pInt, & !< method used in perturbation technique for tangent + fixedSeed = 0_pInt, & !< fixed seeding for pseudo-random number generator, Default 0: use random seed + worldrank = 0_pInt, & !< MPI worldrank (/=0 for MPI simulations only) + worldsize = 0_pInt !< MPI worldsize (/=0 for MPI simulations only) + integer, protected, public :: & + DAMASK_NumThreadsInt = 0 !< value stored in environment variable DAMASK_NUM_THREADS, set to zero if no OpenMP directive + integer(pInt), public :: & + numerics_integrationMode = 0_pInt !< integrationMode 1 = central solution; integrationMode 2 = perturbation, Default 0: undefined, is not read from file + integer(pInt), dimension(2) , protected, public :: & + numerics_integrator = 1_pInt !< method used for state integration (central & perturbed state), Default 1: fix-point iteration for both states + real(pReal), protected, public :: & + relevantStrain = 1.0e-7_pReal, & !< strain increment considered significant (used by crystallite to determine whether strain inc is considered significant) + defgradTolerance = 1.0e-7_pReal, & !< deviation of deformation gradient that is still allowed (used by CPFEM to determine outdated ffn1) + pert_Fg = 1.0e-7_pReal, & !< strain perturbation for FEM Jacobi + subStepMinCryst = 1.0e-3_pReal, & !< minimum (relative) size of sub-step allowed during cutback in crystallite + subStepMinHomog = 1.0e-3_pReal, & !< minimum (relative) size of sub-step allowed during cutback in homogenization + subStepSizeCryst = 0.25_pReal, & !< size of first substep when cutback in crystallite + subStepSizeHomog = 0.25_pReal, & !< size of first substep when cutback in homogenization + stepIncreaseCryst = 1.5_pReal, & !< increase of next substep size when previous substep converged in crystallite + stepIncreaseHomog = 1.5_pReal, & !< increase of next substep size when previous substep converged in homogenization + rTol_crystalliteState = 1.0e-6_pReal, & !< relative tolerance in crystallite state loop + rTol_crystalliteStress = 1.0e-6_pReal, & !< relative tolerance in crystallite stress loop + aTol_crystalliteStress = 1.0e-8_pReal, & !< absolute tolerance in crystallite stress loop, Default 1.0e-8: residuum is in Lp and hence strain is on this order + numerics_unitlength = 1.0_pReal, & !< determines the physical length of one computational length unit + absTol_RGC = 1.0e+4_pReal, & !< absolute tolerance of RGC residuum + relTol_RGC = 1.0e-3_pReal, & !< relative tolerance of RGC residuum + absMax_RGC = 1.0e+10_pReal, & !< absolute maximum of RGC residuum + relMax_RGC = 1.0e+2_pReal, & !< relative maximum of RGC residuum + pPert_RGC = 1.0e-7_pReal, & !< perturbation for computing RGC penalty tangent + xSmoo_RGC = 1.0e-5_pReal, & !< RGC penalty smoothing parameter (hyperbolic tangent) + viscPower_RGC = 1.0e+0_pReal, & !< power (sensitivity rate) of numerical viscosity in RGC scheme, Default 1.0e0: Newton viscosity (linear model) + viscModus_RGC = 0.0e+0_pReal, & !< stress modulus of RGC numerical viscosity, Default 0.0e0: No viscosity is applied + refRelaxRate_RGC = 1.0e-3_pReal, & !< reference relaxation rate in RGC viscosity + maxdRelax_RGC = 1.0e+0_pReal, & !< threshold of maximum relaxation vector increment (if exceed this then cutback) + maxVolDiscr_RGC = 1.0e-5_pReal, & !< threshold of maximum volume discrepancy allowed + volDiscrMod_RGC = 1.0e+12_pReal, & !< stiffness of RGC volume discrepancy (zero = without volume discrepancy constraint) + volDiscrPow_RGC = 5.0_pReal, & !< powerlaw penalty for volume discrepancy + charLength = 1.0_pReal, & !< characteristic length scale for gradient problems + residualStiffness = 1.0e-6_pReal !< non-zero residual damage + logical, protected, public :: & + analyticJaco = .true., & !< use analytic Jacobian or perturbation, Default for Spectral solver .true.: + usePingPong = .true., & + numerics_timeSyncing = .false. !< flag indicating if time synchronization in crystallite is used for nonlocal plasticity + +!-------------------------------------------------------------------------------------------------- +! field parameters: + real(pReal), protected, public :: & + err_struct_tolAbs = 1.0e-10_pReal, & !< absolute tolerance for mechanical equilibrium + err_struct_tolRel = 1.0e-4_pReal, & !< relative tolerance for mechanical equilibrium + err_thermal_tolAbs = 1.0e-2_pReal, & !< absolute tolerance for thermal equilibrium + err_thermal_tolRel = 1.0e-6_pReal, & !< relative tolerance for thermal equilibrium + err_damage_tolAbs = 1.0e-2_pReal, & !< absolute tolerance for damage evolution + err_damage_tolRel = 1.0e-6_pReal, & !< relative tolerance for damage evolution + err_vacancyflux_tolAbs = 1.0e-8_pReal, & !< absolute tolerance for vacancy transport + err_vacancyflux_tolRel = 1.0e-6_pReal, & !< relative tolerance for vacancy transport + err_porosity_tolAbs = 1.0e-2_pReal, & !< absolute tolerance for porosity evolution + err_porosity_tolRel = 1.0e-6_pReal, & !< relative tolerance for porosity evolution + err_hydrogenflux_tolAbs = 1.0e-8_pReal, & !< absolute tolerance for hydrogen transport + err_hydrogenflux_tolRel = 1.0e-6_pReal, & !< relative tolerance for hydrogen transport + vacancyBoundPenalty = 1.0e+4_pReal, & !< penalty to enforce 0 < Cv < 1 + hydrogenBoundPenalty = 1.0e+4_pReal !< penalty to enforce 0 < Ch < 1 + integer(pInt), protected, public :: & + itmax = 250_pInt, & !< maximum number of iterations + itmin = 1_pInt, & !< minimum number of iterations + stagItMax = 10_pInt, & !< max number of field level staggered iterations + maxCutBack = 3_pInt, & !< max number of cut backs + vacancyPolyOrder = 10_pInt, & !< order of polynomial approximation of entropic contribution to vacancy chemical potential + hydrogenPolyOrder = 10_pInt !< order of polynomial approximation of entropic contribution to hydrogen chemical potential + +!-------------------------------------------------------------------------------------------------- +! spectral parameters: +#ifdef Spectral + real(pReal), protected, public :: & + err_div_tolAbs = 1.0e-10_pReal, & !< absolute tolerance for equilibrium + err_div_tolRel = 5.0e-4_pReal, & !< relative tolerance for equilibrium + err_curl_tolAbs = 1.0e-10_pReal, & !< absolute tolerance for compatibility + err_curl_tolRel = 5.0e-4_pReal, & !< relative tolerance for compatibility + err_stress_tolAbs = 1.0e3_pReal, & !< absolute tolerance for fullfillment of stress BC + err_stress_tolRel = 0.01_pReal, & !< relative tolerance for fullfillment of stress BC + fftw_timelimit = -1.0_pReal, & !< sets the timelimit of plan creation for FFTW, see manual on www.fftw.org, Default -1.0: disable timelimit + rotation_tol = 1.0e-12_pReal, & !< tolerance of rotation specified in loadcase, Default 1.0e-12: first guess + polarAlpha = 1.0_pReal, & !< polarization scheme parameter 0.0 < alpha < 2.0. alpha = 1.0 ==> AL scheme, alpha = 2.0 ==> accelerated scheme + polarBeta = 1.0_pReal !< polarization scheme parameter 0.0 < beta < 2.0. beta = 1.0 ==> AL scheme, beta = 2.0 ==> accelerated scheme + character(len=64), private :: & + fftw_plan_mode = 'FFTW_PATIENT' !< reads the planing-rigor flag, see manual on www.fftw.org, Default FFTW_PATIENT: use patient planner flag + character(len=64), protected, public :: & + spectral_solver = 'basicpetsc' , & !< spectral solution method + spectral_derivative = 'continuous' !< spectral filtering method + character(len=1024), protected, public :: & + petsc_defaultOptions = '-mech_snes_type ngmres & + &-damage_snes_type ngmres & + &-thermal_snes_type ngmres ', & + petsc_options = '' + integer(pInt), protected, public :: & + fftw_planner_flag = 32_pInt, & !< conversion of fftw_plan_mode to integer, basically what is usually done in the include file of fftw + continueCalculation = 0_pInt, & !< 0: exit if BVP solver does not converge, 1: continue calculation if BVP solver does not converge + divergence_correction = 2_pInt !< correct divergence calculation in fourier space 0: no correction, 1: size scaled to 1, 2: size scaled to Npoints + logical, protected, public :: & + memory_efficient = .true., & !< for fast execution (pre calculation of gamma_hat), Default .true.: do not precalculate + update_gamma = .false. !< update gamma operator with current stiffness, Default .false.: use initial stiffness +#endif + +!-------------------------------------------------------------------------------------------------- +! FEM parameters: +#ifdef FEM + integer(pInt), protected, public :: & + integrationOrder = 2_pInt, & !< order of quadrature rule required + structOrder = 2_pInt, & !< order of displacement shape functions + thermalOrder = 2_pInt, & !< order of temperature field shape functions + damageOrder = 2_pInt, & !< order of damage field shape functions + vacancyfluxOrder = 2_pInt, & !< order of vacancy concentration and chemical potential field shape functions + porosityOrder = 2_pInt, & !< order of porosity field shape functions + hydrogenfluxOrder = 2_pInt !< order of hydrogen concentration and chemical potential field shape functions + logical, protected, public :: & + BBarStabilisation = .false. + character(len=4096), protected, public :: & + petsc_defaultOptions = '-mech_snes_type newtonls & + &-mech_snes_linesearch_type cp & + &-mech_snes_ksp_ew & + &-mech_snes_ksp_ew_rtol0 0.01 & + &-mech_snes_ksp_ew_rtolmax 0.01 & + &-mech_ksp_type fgmres & + &-mech_ksp_max_it 25 & + &-mech_pc_type ml & + &-mech_mg_levels_ksp_type chebyshev & + &-mech_mg_levels_pc_type sor & + &-mech_pc_ml_nullspace user & + &-damage_snes_type vinewtonrsls & + &-damage_snes_atol 1e-8 & + &-damage_ksp_type preonly & + &-damage_ksp_max_it 25 & + &-damage_pc_type cholesky & + &-damage_pc_factor_mat_solver_package mumps & + &-thermal_snes_type newtonls & + &-thermal_snes_linesearch_type cp & + &-thermal_ksp_type fgmres & + &-thermal_ksp_max_it 25 & + &-thermal_snes_atol 1e-3 & + &-thermal_pc_type hypre & + &-vacancy_snes_type newtonls & + &-vacancy_snes_linesearch_type cp & + &-vacancy_snes_atol 1e-9 & + &-vacancy_ksp_type fgmres & + &-vacancy_ksp_max_it 25 & + &-vacancy_pc_type ml & + &-vacancy_mg_levels_ksp_type chebyshev & + &-vacancy_mg_levels_pc_type sor & + &-porosity_snes_type newtonls & + &-porosity_snes_atol 1e-8 & + &-porosity_ksp_type fgmres & + &-porosity_ksp_max_it 25 & + &-porosity_pc_type hypre & + &-hydrogen_snes_type newtonls & + &-hydrogen_snes_linesearch_type cp & + &-hydrogen_snes_atol 1e-9 & + &-hydrogen_ksp_type fgmres & + &-hydrogen_ksp_max_it 25 & + &-hydrogen_pc_type ml & + &-hydrogen_mg_levels_ksp_type chebyshev & + &-hydrogen_mg_levels_pc_type sor ', & + petsc_options = '' +#endif + + public :: numerics_init + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief reads in parameters from numerics.config and sets openMP related parameters. Also does +! a sanity check +!-------------------------------------------------------------------------------------------------- +subroutine numerics_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_error, & + IO_open_file_stat, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_lc, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_timeStamp, & + IO_EOF + +#if defined(Spectral) || defined(FEM) +!$ use OMP_LIB, only: omp_set_num_threads ! Use the standard conforming module file for omp if using the spectral solver + implicit none +#else + implicit none +!$ include "omp_lib.h" ! use the not F90 standard conforming include file to prevent crashes with some versions of MSC.Marc +#endif + integer(pInt), parameter :: FILEUNIT = 300_pInt +!$ integer :: gotDAMASK_NUM_THREADS = 1 + integer :: i, ierr ! no pInt + integer(pInt), allocatable, dimension(:) :: chunkPos + character(len=65536) :: & + tag ,& + line +!$ character(len=6) DAMASK_NumThreadsString ! environment variable DAMASK_NUM_THREADS + external :: & + MPI_Comm_rank, & + MPI_Comm_size, & + MPI_Abort + +#ifdef PETSc + call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) + call MPI_Comm_size(PETSC_COMM_WORLD,worldsize,ierr);CHKERRQ(ierr) +#endif + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- numerics init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!$ call GET_ENVIRONMENT_VARIABLE(NAME='DAMASK_NUM_THREADS',VALUE=DAMASK_NumThreadsString,STATUS=gotDAMASK_NUM_THREADS) ! get environment variable DAMASK_NUM_THREADS... +!$ if(gotDAMASK_NUM_THREADS /= 0) then ! could not get number of threads, set it to 1 +!$ call IO_warning(35_pInt,ext_msg='BEGIN:'//DAMASK_NumThreadsString//':END') +!$ DAMASK_NumThreadsInt = 1 +!$ else +!$ read(DAMASK_NumThreadsString,'(i6)') DAMASK_NumThreadsInt ! read as integer +!$ if (DAMASK_NumThreadsInt < 1) DAMASK_NumThreadsInt = 1 ! in case of string conversion fails, set it to one +!$ endif +!$ call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution + +!-------------------------------------------------------------------------------------------------- +! try to open the config file + fileExists: if(IO_open_file_stat(FILEUNIT,numerics_configFile)) then + mainProcess2: if (worldrank == 0) then + write(6,'(a,/)') ' using values from config file' + flush(6) + endif mainProcess2 + +!-------------------------------------------------------------------------------------------------- +! read variables from config file and overwrite default parameters if keyword is present + line = '' + do while (trim(line) /= IO_EOF) ! read thru sections of phase part + line = IO_read(FILEUNIT) + do i=1,len(line) + if(line(i:i) == '=') line(i:i) = ' ' ! also allow keyword = value version + enddo + if (IO_isBlank(line)) cycle ! skip empty lines + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + + select case(tag) + case ('relevantstrain') + relevantStrain = IO_floatValue(line,chunkPos,2_pInt) + case ('defgradtolerance') + defgradTolerance = IO_floatValue(line,chunkPos,2_pInt) + case ('ijacostiffness') + iJacoStiffness = IO_intValue(line,chunkPos,2_pInt) + case ('ijacolpresiduum') + iJacoLpresiduum = IO_intValue(line,chunkPos,2_pInt) + case ('pert_fg') + pert_Fg = IO_floatValue(line,chunkPos,2_pInt) + case ('pert_method') + pert_method = IO_intValue(line,chunkPos,2_pInt) + case ('nhomog') + nHomog = IO_intValue(line,chunkPos,2_pInt) + case ('nmpstate') + nMPstate = IO_intValue(line,chunkPos,2_pInt) + case ('ncryst') + nCryst = IO_intValue(line,chunkPos,2_pInt) + case ('nstate') + nState = IO_intValue(line,chunkPos,2_pInt) + case ('nstress') + nStress = IO_intValue(line,chunkPos,2_pInt) + case ('substepmincryst') + subStepMinCryst = IO_floatValue(line,chunkPos,2_pInt) + case ('substepsizecryst') + subStepSizeCryst = IO_floatValue(line,chunkPos,2_pInt) + case ('stepincreasecryst') + stepIncreaseCryst = IO_floatValue(line,chunkPos,2_pInt) + case ('substepminhomog') + subStepMinHomog = IO_floatValue(line,chunkPos,2_pInt) + case ('substepsizehomog') + subStepSizeHomog = IO_floatValue(line,chunkPos,2_pInt) + case ('stepincreasehomog') + stepIncreaseHomog = IO_floatValue(line,chunkPos,2_pInt) + case ('rtol_crystallitestate') + rTol_crystalliteState = IO_floatValue(line,chunkPos,2_pInt) + case ('rtol_crystallitestress') + rTol_crystalliteStress = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_crystallitestress') + aTol_crystalliteStress = IO_floatValue(line,chunkPos,2_pInt) + case ('integrator') + numerics_integrator(1) = IO_intValue(line,chunkPos,2_pInt) + case ('integratorstiffness') + numerics_integrator(2) = IO_intValue(line,chunkPos,2_pInt) + case ('analyticjaco') + analyticJaco = IO_intValue(line,chunkPos,2_pInt) > 0_pInt + case ('usepingpong') + usepingpong = IO_intValue(line,chunkPos,2_pInt) > 0_pInt + case ('timesyncing') + numerics_timeSyncing = IO_intValue(line,chunkPos,2_pInt) > 0_pInt + case ('unitlength') + numerics_unitlength = IO_floatValue(line,chunkPos,2_pInt) + +!-------------------------------------------------------------------------------------------------- +! RGC parameters + case ('atol_rgc') + absTol_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('rtol_rgc') + relTol_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('amax_rgc') + absMax_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('rmax_rgc') + relMax_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('perturbpenalty_rgc') + pPert_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('relevantmismatch_rgc') + xSmoo_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('viscositypower_rgc') + viscPower_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('viscositymodulus_rgc') + viscModus_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('refrelaxationrate_rgc') + refRelaxRate_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('maxrelaxation_rgc') + maxdRelax_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('maxvoldiscrepancy_rgc') + maxVolDiscr_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('voldiscrepancymod_rgc') + volDiscrMod_RGC = IO_floatValue(line,chunkPos,2_pInt) + case ('discrepancypower_rgc') + volDiscrPow_RGC = IO_floatValue(line,chunkPos,2_pInt) + +!-------------------------------------------------------------------------------------------------- +! random seeding parameter + case ('fixed_seed') + fixedSeed = IO_intValue(line,chunkPos,2_pInt) + +!-------------------------------------------------------------------------------------------------- +! gradient parameter + case ('charlength') + charLength = IO_floatValue(line,chunkPos,2_pInt) + case ('residualstiffness') + residualStiffness = IO_floatValue(line,chunkPos,2_pInt) + +!-------------------------------------------------------------------------------------------------- +! field parameters + case ('err_struct_tolabs') + err_struct_tolAbs = IO_floatValue(line,chunkPos,2_pInt) + case ('err_struct_tolrel') + err_struct_tolRel = IO_floatValue(line,chunkPos,2_pInt) + case ('err_thermal_tolabs') + err_thermal_tolabs = IO_floatValue(line,chunkPos,2_pInt) + case ('err_thermal_tolrel') + err_thermal_tolrel = IO_floatValue(line,chunkPos,2_pInt) + case ('err_damage_tolabs') + err_damage_tolabs = IO_floatValue(line,chunkPos,2_pInt) + case ('err_damage_tolrel') + err_damage_tolrel = IO_floatValue(line,chunkPos,2_pInt) + case ('err_vacancyflux_tolabs') + err_vacancyflux_tolabs = IO_floatValue(line,chunkPos,2_pInt) + case ('err_vacancyflux_tolrel') + err_vacancyflux_tolrel = IO_floatValue(line,chunkPos,2_pInt) + case ('err_porosity_tolabs') + err_porosity_tolabs = IO_floatValue(line,chunkPos,2_pInt) + case ('err_porosity_tolrel') + err_porosity_tolrel = IO_floatValue(line,chunkPos,2_pInt) + case ('err_hydrogenflux_tolabs') + err_hydrogenflux_tolabs = IO_floatValue(line,chunkPos,2_pInt) + case ('err_hydrogenflux_tolrel') + err_hydrogenflux_tolrel = IO_floatValue(line,chunkPos,2_pInt) + case ('vacancyboundpenalty') + vacancyBoundPenalty = IO_floatValue(line,chunkPos,2_pInt) + case ('hydrogenboundpenalty') + hydrogenBoundPenalty = IO_floatValue(line,chunkPos,2_pInt) + case ('itmax') + itmax = IO_intValue(line,chunkPos,2_pInt) + case ('itmin') + itmin = IO_intValue(line,chunkPos,2_pInt) + case ('maxcutback') + maxCutBack = IO_intValue(line,chunkPos,2_pInt) + case ('maxstaggerediter') + stagItMax = IO_intValue(line,chunkPos,2_pInt) + case ('vacancypolyorder') + vacancyPolyOrder = IO_intValue(line,chunkPos,2_pInt) + case ('hydrogenpolyorder') + hydrogenPolyOrder = IO_intValue(line,chunkPos,2_pInt) + +!-------------------------------------------------------------------------------------------------- +! spectral parameters +#ifdef Spectral + case ('err_div_tolabs') + err_div_tolAbs = IO_floatValue(line,chunkPos,2_pInt) + case ('err_div_tolrel') + err_div_tolRel = IO_floatValue(line,chunkPos,2_pInt) + case ('err_stress_tolrel') + err_stress_tolrel = IO_floatValue(line,chunkPos,2_pInt) + case ('err_stress_tolabs') + err_stress_tolabs = IO_floatValue(line,chunkPos,2_pInt) + case ('continuecalculation') + continueCalculation = IO_intValue(line,chunkPos,2_pInt) + case ('memory_efficient') + memory_efficient = IO_intValue(line,chunkPos,2_pInt) > 0_pInt + case ('fftw_timelimit') + fftw_timelimit = IO_floatValue(line,chunkPos,2_pInt) + case ('fftw_plan_mode') + fftw_plan_mode = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('spectralderivative') + spectral_derivative = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('divergence_correction') + divergence_correction = IO_intValue(line,chunkPos,2_pInt) + case ('update_gamma') + update_gamma = IO_intValue(line,chunkPos,2_pInt) > 0_pInt + case ('petsc_options') + petsc_options = trim(line(chunkPos(4):)) + case ('spectralsolver','myspectralsolver') + spectral_solver = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('err_curl_tolabs') + err_curl_tolAbs = IO_floatValue(line,chunkPos,2_pInt) + case ('err_curl_tolrel') + err_curl_tolRel = IO_floatValue(line,chunkPos,2_pInt) + case ('polaralpha') + polarAlpha = IO_floatValue(line,chunkPos,2_pInt) + case ('polarbeta') + polarBeta = IO_floatValue(line,chunkPos,2_pInt) +#else + case ('err_div_tolabs','err_div_tolrel','err_stress_tolrel','err_stress_tolabs',& ! found spectral parameter for FEM build + 'memory_efficient','fftw_timelimit','fftw_plan_mode', & + 'divergence_correction','update_gamma','spectralfilter','myfilter', & + 'err_curl_tolabs','err_curl_tolrel', & + 'polaralpha','polarbeta') + call IO_warning(40_pInt,ext_msg=tag) +#endif + +!-------------------------------------------------------------------------------------------------- +! FEM parameters +#ifdef FEM + case ('integrationorder') + integrationorder = IO_intValue(line,chunkPos,2_pInt) + case ('structorder') + structorder = IO_intValue(line,chunkPos,2_pInt) + case ('thermalorder') + thermalorder = IO_intValue(line,chunkPos,2_pInt) + case ('damageorder') + damageorder = IO_intValue(line,chunkPos,2_pInt) + case ('vacancyfluxorder') + vacancyfluxOrder = IO_intValue(line,chunkPos,2_pInt) + case ('porosityorder') + porosityOrder = IO_intValue(line,chunkPos,2_pInt) + case ('hydrogenfluxorder') + hydrogenfluxOrder = IO_intValue(line,chunkPos,2_pInt) + case ('petsc_options') + petsc_options = trim(line(chunkPos(4):)) + case ('bbarstabilisation') + BBarStabilisation = IO_intValue(line,chunkPos,2_pInt) > 0_pInt +#else + case ('integrationorder','structorder','thermalorder', 'damageorder','vacancyfluxorder', & + 'porosityorder','hydrogenfluxorder','bbarstabilisation') + call IO_warning(40_pInt,ext_msg=tag) +#endif + case default ! found unknown keyword + call IO_error(300_pInt,ext_msg=tag) + endselect + enddo + close(FILEUNIT) + + else fileExists +#ifdef FEM + if (worldrank == 0) then +#endif + write(6,'(a,/)') ' using standard values' + flush(6) +#ifdef FEM + endif +#endif + endif fileExists + +#ifdef Spectral + select case(IO_lc(fftw_plan_mode)) ! setting parameters for the plan creation of FFTW. Basically a translation from fftw3.f + case('estimate','fftw_estimate') ! ordered from slow execution (but fast plan creation) to fast execution + fftw_planner_flag = 64_pInt + case('measure','fftw_measure') + fftw_planner_flag = 0_pInt + case('patient','fftw_patient') + fftw_planner_flag= 32_pInt + case('exhaustive','fftw_exhaustive') + fftw_planner_flag = 8_pInt + case default + call IO_warning(warning_ID=47_pInt,ext_msg=trim(IO_lc(fftw_plan_mode))) + fftw_planner_flag = 32_pInt + end select +#endif + + numerics_timeSyncing = numerics_timeSyncing .and. all(numerics_integrator==2_pInt) ! timeSyncing only allowed for explicit Euler integrator + +!-------------------------------------------------------------------------------------------------- +! writing parameters to output + mainProcess3: if (worldrank == 0) then + write(6,'(a24,1x,es8.1)') ' relevantStrain: ',relevantStrain + write(6,'(a24,1x,es8.1)') ' defgradTolerance: ',defgradTolerance + write(6,'(a24,1x,i8)') ' iJacoStiffness: ',iJacoStiffness + write(6,'(a24,1x,i8)') ' iJacoLpresiduum: ',iJacoLpresiduum + write(6,'(a24,1x,es8.1)') ' pert_Fg: ',pert_Fg + write(6,'(a24,1x,i8)') ' pert_method: ',pert_method + write(6,'(a24,1x,i8)') ' nCryst: ',nCryst + write(6,'(a24,1x,es8.1)') ' subStepMinCryst: ',subStepMinCryst + write(6,'(a24,1x,es8.1)') ' subStepSizeCryst: ',subStepSizeCryst + write(6,'(a24,1x,es8.1)') ' stepIncreaseCryst: ',stepIncreaseCryst + write(6,'(a24,1x,i8)') ' nState: ',nState + write(6,'(a24,1x,i8)') ' nStress: ',nStress + write(6,'(a24,1x,es8.1)') ' rTol_crystalliteState: ',rTol_crystalliteState + write(6,'(a24,1x,es8.1)') ' rTol_crystalliteStress: ',rTol_crystalliteStress + write(6,'(a24,1x,es8.1)') ' aTol_crystalliteStress: ',aTol_crystalliteStress + write(6,'(a24,2(1x,i8))') ' integrator: ',numerics_integrator + write(6,'(a24,1x,L8)') ' timeSyncing: ',numerics_timeSyncing + write(6,'(a24,1x,L8)') ' analytic Jacobian: ',analyticJaco + write(6,'(a24,1x,L8)') ' use ping pong scheme: ',usepingpong + write(6,'(a24,1x,es8.1,/)')' unitlength: ',numerics_unitlength + + write(6,'(a24,1x,i8)') ' nHomog: ',nHomog + write(6,'(a24,1x,es8.1)') ' subStepMinHomog: ',subStepMinHomog + write(6,'(a24,1x,es8.1)') ' subStepSizeHomog: ',subStepSizeHomog + write(6,'(a24,1x,es8.1)') ' stepIncreaseHomog: ',stepIncreaseHomog + write(6,'(a24,1x,i8,/)') ' nMPstate: ',nMPstate + +!-------------------------------------------------------------------------------------------------- +! RGC parameters + write(6,'(a24,1x,es8.1)') ' aTol_RGC: ',absTol_RGC + write(6,'(a24,1x,es8.1)') ' rTol_RGC: ',relTol_RGC + write(6,'(a24,1x,es8.1)') ' aMax_RGC: ',absMax_RGC + write(6,'(a24,1x,es8.1)') ' rMax_RGC: ',relMax_RGC + write(6,'(a24,1x,es8.1)') ' perturbPenalty_RGC: ',pPert_RGC + write(6,'(a24,1x,es8.1)') ' relevantMismatch_RGC: ',xSmoo_RGC + write(6,'(a24,1x,es8.1)') ' viscosityrate_RGC: ',viscPower_RGC + write(6,'(a24,1x,es8.1)') ' viscositymodulus_RGC: ',viscModus_RGC + write(6,'(a24,1x,es8.1)') ' maxrelaxation_RGC: ',maxdRelax_RGC + write(6,'(a24,1x,es8.1)') ' maxVolDiscrepancy_RGC: ',maxVolDiscr_RGC + write(6,'(a24,1x,es8.1)') ' volDiscrepancyMod_RGC: ',volDiscrMod_RGC + write(6,'(a24,1x,es8.1,/)') ' discrepancyPower_RGC: ',volDiscrPow_RGC + +!-------------------------------------------------------------------------------------------------- +! Random seeding parameter + write(6,'(a24,1x,i16,/)') ' fixed_seed: ',fixedSeed + if (fixedSeed <= 0_pInt) & + write(6,'(a,/)') ' No fixed Seed: Random is random!' + +!-------------------------------------------------------------------------------------------------- +! gradient parameter + write(6,'(a24,1x,es8.1)') ' charLength: ',charLength + write(6,'(a24,1x,es8.1)') ' residualStiffness: ',residualStiffness + +!-------------------------------------------------------------------------------------------------- +! openMP parameter + !$ write(6,'(a24,1x,i8,/)') ' number of threads: ',DAMASK_NumThreadsInt + +!-------------------------------------------------------------------------------------------------- +! field parameters + write(6,'(a24,1x,i8)') ' itmax: ',itmax + write(6,'(a24,1x,i8)') ' itmin: ',itmin + write(6,'(a24,1x,i8)') ' maxCutBack: ',maxCutBack + write(6,'(a24,1x,i8)') ' maxStaggeredIter: ',stagItMax + write(6,'(a24,1x,i8)') ' vacancyPolyOrder: ',vacancyPolyOrder + write(6,'(a24,1x,i8)') ' hydrogenPolyOrder: ',hydrogenPolyOrder + write(6,'(a24,1x,es8.1)') ' err_struct_tolAbs: ',err_struct_tolAbs + write(6,'(a24,1x,es8.1)') ' err_struct_tolRel: ',err_struct_tolRel + write(6,'(a24,1x,es8.1)') ' err_thermal_tolabs: ',err_thermal_tolabs + write(6,'(a24,1x,es8.1)') ' err_thermal_tolrel: ',err_thermal_tolrel + write(6,'(a24,1x,es8.1)') ' err_damage_tolabs: ',err_damage_tolabs + write(6,'(a24,1x,es8.1)') ' err_damage_tolrel: ',err_damage_tolrel + write(6,'(a24,1x,es8.1)') ' err_vacancyflux_tolabs: ',err_vacancyflux_tolabs + write(6,'(a24,1x,es8.1)') ' err_vacancyflux_tolrel: ',err_vacancyflux_tolrel + write(6,'(a24,1x,es8.1)') ' err_porosity_tolabs: ',err_porosity_tolabs + write(6,'(a24,1x,es8.1)') ' err_porosity_tolrel: ',err_porosity_tolrel + write(6,'(a24,1x,es8.1)') ' err_hydrogenflux_tolabs:',err_hydrogenflux_tolabs + write(6,'(a24,1x,es8.1)') ' err_hydrogenflux_tolrel:',err_hydrogenflux_tolrel + write(6,'(a24,1x,es8.1)') ' vacancyBoundPenalty: ',vacancyBoundPenalty + write(6,'(a24,1x,es8.1)') ' hydrogenBoundPenalty: ',hydrogenBoundPenalty + +!-------------------------------------------------------------------------------------------------- +! spectral parameters +#ifdef Spectral + write(6,'(a24,1x,i8)') ' continueCalculation: ',continueCalculation + write(6,'(a24,1x,L8)') ' memory_efficient: ',memory_efficient + write(6,'(a24,1x,i8)') ' divergence_correction: ',divergence_correction + write(6,'(a24,1x,a)') ' spectral_derivative: ',trim(spectral_derivative) + if(fftw_timelimit<0.0_pReal) then + write(6,'(a24,1x,L8)') ' fftw_timelimit: ',.false. + else + write(6,'(a24,1x,es8.1)') ' fftw_timelimit: ',fftw_timelimit + endif + write(6,'(a24,1x,a)') ' fftw_plan_mode: ',trim(fftw_plan_mode) + write(6,'(a24,1x,i8)') ' fftw_planner_flag: ',fftw_planner_flag + write(6,'(a24,1x,L8,/)') ' update_gamma: ',update_gamma + write(6,'(a24,1x,es8.1)') ' err_stress_tolAbs: ',err_stress_tolAbs + write(6,'(a24,1x,es8.1)') ' err_stress_tolRel: ',err_stress_tolRel + write(6,'(a24,1x,es8.1)') ' err_div_tolAbs: ',err_div_tolAbs + write(6,'(a24,1x,es8.1)') ' err_div_tolRel: ',err_div_tolRel + write(6,'(a24,1x,es8.1)') ' err_curl_tolAbs: ',err_curl_tolAbs + write(6,'(a24,1x,es8.1)') ' err_curl_tolRel: ',err_curl_tolRel + write(6,'(a24,1x,es8.1)') ' polarAlpha: ',polarAlpha + write(6,'(a24,1x,es8.1)') ' polarBeta: ',polarBeta + write(6,'(a24,1x,a)') ' spectral solver: ',trim(spectral_solver) + write(6,'(a24,1x,a)') ' PETSc_options: ',trim(petsc_defaultOptions)//' '//trim(petsc_options) +#endif + +!-------------------------------------------------------------------------------------------------- +! spectral parameters +#ifdef FEM + write(6,'(a24,1x,i8)') ' integrationOrder: ',integrationOrder + write(6,'(a24,1x,i8)') ' structOrder: ',structOrder + write(6,'(a24,1x,i8)') ' thermalOrder: ',thermalOrder + write(6,'(a24,1x,i8)') ' damageOrder: ',damageOrder + write(6,'(a24,1x,i8)') ' vacancyfluxOrder: ',vacancyfluxOrder + write(6,'(a24,1x,i8)') ' porosityOrder: ',porosityOrder + write(6,'(a24,1x,i8)') ' hydrogenfluxOrder: ',hydrogenfluxOrder + write(6,'(a24,1x,a)') ' PETSc_options: ',trim(petsc_defaultOptions)//' '//trim(petsc_options) + write(6,'(a24,1x,L8)') ' B-Bar stabilisation: ',BBarStabilisation +#endif + endif mainProcess3 + + +!-------------------------------------------------------------------------------------------------- +! sanity checks + if (relevantStrain <= 0.0_pReal) call IO_error(301_pInt,ext_msg='relevantStrain') + if (defgradTolerance <= 0.0_pReal) call IO_error(301_pInt,ext_msg='defgradTolerance') + if (iJacoStiffness < 1_pInt) call IO_error(301_pInt,ext_msg='iJacoStiffness') + if (iJacoLpresiduum < 1_pInt) call IO_error(301_pInt,ext_msg='iJacoLpresiduum') + if (pert_Fg <= 0.0_pReal) call IO_error(301_pInt,ext_msg='pert_Fg') + if (pert_method <= 0_pInt .or. pert_method >= 4_pInt) & + call IO_error(301_pInt,ext_msg='pert_method') + if (nHomog < 1_pInt) call IO_error(301_pInt,ext_msg='nHomog') + if (nMPstate < 1_pInt) call IO_error(301_pInt,ext_msg='nMPstate') + if (nCryst < 1_pInt) call IO_error(301_pInt,ext_msg='nCryst') + if (nState < 1_pInt) call IO_error(301_pInt,ext_msg='nState') + if (nStress < 1_pInt) call IO_error(301_pInt,ext_msg='nStress') + if (subStepMinCryst <= 0.0_pReal) call IO_error(301_pInt,ext_msg='subStepMinCryst') + if (subStepSizeCryst <= 0.0_pReal) call IO_error(301_pInt,ext_msg='subStepSizeCryst') + if (stepIncreaseCryst <= 0.0_pReal) call IO_error(301_pInt,ext_msg='stepIncreaseCryst') + if (subStepMinHomog <= 0.0_pReal) call IO_error(301_pInt,ext_msg='subStepMinHomog') + if (subStepSizeHomog <= 0.0_pReal) call IO_error(301_pInt,ext_msg='subStepSizeHomog') + if (stepIncreaseHomog <= 0.0_pReal) call IO_error(301_pInt,ext_msg='stepIncreaseHomog') + if (rTol_crystalliteState <= 0.0_pReal) call IO_error(301_pInt,ext_msg='rTol_crystalliteState') + if (rTol_crystalliteStress <= 0.0_pReal) call IO_error(301_pInt,ext_msg='rTol_crystalliteStress') + if (aTol_crystalliteStress <= 0.0_pReal) call IO_error(301_pInt,ext_msg='aTol_crystalliteStress') + if (any(numerics_integrator <= 0_pInt) .or. any(numerics_integrator >= 6_pInt)) & + call IO_error(301_pInt,ext_msg='integrator') + if (numerics_unitlength <= 0.0_pReal) call IO_error(301_pInt,ext_msg='unitlength') + if (absTol_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='absTol_RGC') + if (relTol_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='relTol_RGC') + if (absMax_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='absMax_RGC') + if (relMax_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='relMax_RGC') + if (pPert_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='pPert_RGC') + if (xSmoo_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='xSmoo_RGC') + if (viscPower_RGC < 0.0_pReal) call IO_error(301_pInt,ext_msg='viscPower_RGC') + if (viscModus_RGC < 0.0_pReal) call IO_error(301_pInt,ext_msg='viscModus_RGC') + if (refRelaxRate_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='refRelaxRate_RGC') + if (maxdRelax_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='maxdRelax_RGC') + if (maxVolDiscr_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='maxVolDiscr_RGC') + if (volDiscrMod_RGC < 0.0_pReal) call IO_error(301_pInt,ext_msg='volDiscrMod_RGC') + if (volDiscrPow_RGC <= 0.0_pReal) call IO_error(301_pInt,ext_msg='volDiscrPw_RGC') + if (residualStiffness < 0.0_pReal) call IO_error(301_pInt,ext_msg='residualStiffness') + if (itmax <= 1_pInt) call IO_error(301_pInt,ext_msg='itmax') + if (itmin > itmax .or. itmin < 1_pInt) call IO_error(301_pInt,ext_msg='itmin') + if (maxCutBack < 0_pInt) call IO_error(301_pInt,ext_msg='maxCutBack') + if (stagItMax < 0_pInt) call IO_error(301_pInt,ext_msg='maxStaggeredIter') + if (vacancyPolyOrder < 0_pInt) call IO_error(301_pInt,ext_msg='vacancyPolyOrder') + if (err_struct_tolRel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_struct_tolRel') + if (err_struct_tolAbs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_struct_tolAbs') + if (err_thermal_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_thermal_tolabs') + if (err_thermal_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_thermal_tolrel') + if (err_damage_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_damage_tolabs') + if (err_damage_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_damage_tolrel') + if (err_vacancyflux_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_vacancyflux_tolabs') + if (err_vacancyflux_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_vacancyflux_tolrel') + if (err_porosity_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_porosity_tolabs') + if (err_porosity_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_porosity_tolrel') + if (err_hydrogenflux_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_hydrogenflux_tolabs') + if (err_hydrogenflux_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_hydrogenflux_tolrel') +#ifdef Spectral + if (continueCalculation /= 0_pInt .and. & + continueCalculation /= 1_pInt) call IO_error(301_pInt,ext_msg='continueCalculation') + if (divergence_correction < 0_pInt .or. & + divergence_correction > 2_pInt) call IO_error(301_pInt,ext_msg='divergence_correction') + if (update_gamma .and. & + .not. memory_efficient) call IO_error(error_ID = 847_pInt) + if (err_stress_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_stress_tolRel') + if (err_stress_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_stress_tolAbs') + if (err_div_tolRel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_div_tolRel') + if (err_div_tolAbs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_div_tolAbs') + if (err_curl_tolRel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_curl_tolRel') + if (err_curl_tolAbs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_curl_tolAbs') + if (polarAlpha <= 0.0_pReal .or. & + polarAlpha > 2.0_pReal) call IO_error(301_pInt,ext_msg='polarAlpha') + if (polarBeta < 0.0_pReal .or. & + polarBeta > 2.0_pReal) call IO_error(301_pInt,ext_msg='polarBeta') +#endif + +end subroutine numerics_init + +end module numerics diff --git a/src/plastic_disloUCLA.f90 b/src/plastic_disloUCLA.f90 new file mode 100644 index 000000000..d95a5e6a4 --- /dev/null +++ b/src/plastic_disloUCLA.f90 @@ -0,0 +1,2116 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author David Cereceda, Lawrence Livermore National Laboratory +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incoprorating dislocation and twinning physics +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module plastic_disloUCLA + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_disloUCLA_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_disloUCLA_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_disloUCLA_output !< name of each post result output + + real(pReal), parameter, private :: & + kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_disloUCLA_Noutput !< number of outputs per instance of this plasticity + + integer(pInt), dimension(:), allocatable, private :: & + plastic_disloUCLA_totalNslip, & !< total number of active slip systems for each instance + plastic_disloUCLA_totalNtwin !< total number of active twin systems for each instance + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_disloUCLA_Nslip, & !< number of active slip systems for each family and instance + plastic_disloUCLA_Ntwin !< number of active twin systems for each family and instance + + real(pReal), dimension(:), allocatable, private :: & + plastic_disloUCLA_CAtomicVolume, & !< atomic volume in Bugers vector unit + plastic_disloUCLA_D0, & !< prefactor for self-diffusion coefficient + plastic_disloUCLA_Qsd, & !< activation energy for dislocation climb + plastic_disloUCLA_GrainSize, & !< grain size + plastic_disloUCLA_MaxTwinFraction, & !< maximum allowed total twin volume fraction + plastic_disloUCLA_CEdgeDipMinDistance, & !< + plastic_disloUCLA_Cmfptwin, & !< + plastic_disloUCLA_Cthresholdtwin, & !< + plastic_disloUCLA_SolidSolutionStrength, & !< Strength due to elements in solid solution + plastic_disloUCLA_L0, & !< Length of twin nuclei in Burgers vectors + plastic_disloUCLA_xc, & !< critical distance for formation of twin nucleus + plastic_disloUCLA_VcrossSlip, & !< cross slip volume + plastic_disloUCLA_SFE_0K, & !< stacking fault energy at zero K + plastic_disloUCLA_dSFE_dT, & !< temperature dependance of stacking fault energy + plastic_disloUCLA_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful + plastic_disloUCLA_aTolRho, & !< absolute tolerance for integration of dislocation density + plastic_disloUCLA_aTolTwinFrac !< absolute tolerance for integration of twin volume fraction + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_disloUCLA_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_disloUCLA_Ctwin3333 !< twin elasticity matrix for each instance + real(pReal), dimension(:,:), allocatable, private :: & + plastic_disloUCLA_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance + plastic_disloUCLA_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance + plastic_disloUCLA_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance + plastic_disloUCLA_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance + plastic_disloUCLA_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance + plastic_disloUCLA_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance + plastic_disloUCLA_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance + plastic_disloUCLA_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance + plastic_disloUCLA_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance + plastic_disloUCLA_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance + plastic_disloUCLA_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance + plastic_disloUCLA_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance + plastic_disloUCLA_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance + plastic_disloUCLA_tau_r, & !< stress to bring partial close together for each twin system and instance + plastic_disloUCLA_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance + plastic_disloUCLA_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance + plastic_disloUCLA_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_disloUCLA_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_disloUCLA_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance + plastic_disloUCLA_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance + plastic_disloUCLA_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_disloUCLA_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance + plastic_disloUCLA_pPerSlipFamily, & !< p-exponent in glide velocity + plastic_disloUCLA_qPerSlipFamily, & !< q-exponent in glide velocity + !* mobility law parameters + plastic_disloUCLA_kinkheight, & !< height of the kink pair + plastic_disloUCLA_omega, & !< attempt frequency for kink pair nucleation + plastic_disloUCLA_kinkwidth, & !< width of the kink pair + plastic_disloUCLA_dislolength, & !< dislocation length (lamda) + plastic_disloUCLA_friction, & !< friction coeff. B (kMC) + !* + plastic_disloUCLA_rPerTwinFamily, & !< r-exponent in twin nucleation rate + plastic_disloUCLA_nonSchmidCoeff !< non-Schmid coefficients (bcc) + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_disloUCLA_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance + plastic_disloUCLA_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance + plastic_disloUCLA_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance + plastic_disloUCLA_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance + plastic_disloUCLA_forestProjectionEdge !< matrix of forest projections of edge dislocations for each instance + + enum, bind(c) + enumerator :: undefined_ID, & + edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID, & + twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_disloUCLA_outputID !< ID of each post result output + + type, private :: tDisloUCLAState + real(pReal), pointer, dimension(:,:) :: & + rhoEdge, & + rhoEdgeDip, & + accshear_slip, & + twinFraction, & + accshear_twin, & + invLambdaSlip, & + invLambdaSlipTwin, & + invLambdaTwin, & + mfp_slip, & + mfp_twin, & + threshold_stress_slip, & + threshold_stress_twin, & + twinVolume + end type + type(tDisloUCLAState ), allocatable, dimension(:), private :: & + state, & + state0, & + dotState + + public :: & + plastic_disloUCLA_init, & + plastic_disloUCLA_homogenizedC, & + plastic_disloUCLA_microstructure, & + plastic_disloUCLA_LpAndItsTangent, & + plastic_disloUCLA_dotState, & + plastic_disloUCLA_postResults + private :: & + plastic_disloUCLA_stateInit, & + plastic_disloUCLA_aTolState + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333, & + math_mul3x3 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_DISLOUCLA_label, & + PLASTICITY_DISLOUCLA_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,& + f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & + offset_slip, index_myFamily, index_otherFamily, & + startIndex, endIndex + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOUCLA_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOUCLA_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_disloUCLA_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(plastic_disloUCLA_output(maxval(phase_Noutput),maxNinstance)) + plastic_disloUCLA_output = '' + allocate(plastic_disloUCLA_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_disloUCLA_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_disloUCLA_CAtomicVolume(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_D0(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Qsd(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_GrainSize(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_MaxTwinFraction(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Cmfptwin(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Cthresholdtwin(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_SolidSolutionStrength(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_L0(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_xc(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_VcrossSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_aTolRho(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_aTolTwinFrac(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_SFE_0K(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_dSFE_dT(maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default + allocate(plastic_disloUCLA_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_kinkheight(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_omega(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_kinkwidth(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_dislolength(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_friction(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_disloUCLA_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_disloUCLA_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance),source=0.0_pReal) + allocate(plastic_disloUCLA_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), source=0.0_pReal) + + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + if(allocated(tempPerTwin)) deallocate(tempPerTwin) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + allocate(tempPerTwin(Nchunks_TwinFamilies)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOUCLA_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('edge_density') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_density_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('dipole_density') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = dipole_density_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_slip','shearrate_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_slip') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_slip_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('edge_dipole_distance') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = edge_dipole_distance_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stress_exponent') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = stress_exponent_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('twin_fraction') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = twin_fraction_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_twin','shearrate_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = shear_rate_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = accumulated_shear_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = mfp_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = resolved_stress_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_twin') + plastic_disloUCLA_Noutput(instance) = plastic_disloUCLA_Noutput(instance) + 1_pInt + plastic_disloUCLA_outputID(plastic_disloUCLA_Noutput(instance),instance) = threshold_stress_twin_ID + plastic_disloUCLA_output(plastic_disloUCLA_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip system families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + plastic_disloUCLA_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip',& + 'kink_height','omega','kink_width','dislolength','friction_coeff') + do j = 1_pInt, Nchunks_SlipFamilies + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('rhoedge0') + plastic_disloUCLA_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('rhoedgedip0') + plastic_disloUCLA_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('slipburgers') + plastic_disloUCLA_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('qedge') + plastic_disloUCLA_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('v0') + plastic_disloUCLA_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('clambdaslip') + plastic_disloUCLA_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau_peierls') + if (lattice_structure(phase) /= LATTICE_bcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOUCLA_label//')') + plastic_disloUCLA_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('p_slip') + plastic_disloUCLA_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('q_slip') + plastic_disloUCLA_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('kink_height') + plastic_disloUCLA_kinkheight(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('omega') + plastic_disloUCLA_omega(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('kink_width') + plastic_disloUCLA_kinkwidth(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('dislolength') + plastic_disloUCLA_dislolength(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + case ('friction_coeff') + plastic_disloUCLA_friction(1:Nchunks_SlipFamilies,instance) = & + tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on slip number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_disloUCLA_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ndot0','twinsize','twinburgers','r_twin') + do j = 1_pInt, Nchunks_TwinFamilies + tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('ndot0') + if (lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOUCLA_label//')') + plastic_disloUCLA_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinsize') + plastic_disloUCLA_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinburgers') + plastic_disloUCLA_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('r_twin') + plastic_disloUCLA_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip','interactionslipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_disloUCLA_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin','interactionsliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_disloUCLA_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip','interactiontwinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_disloUCLA_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin','interactiontwintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_disloUCLA_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOUCLA_label//')') + do j = 1_pInt,Nchunks_nonSchmid + plastic_disloUCLA_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin systems + case ('grainsize') + plastic_disloUCLA_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('maxtwinfraction') + plastic_disloUCLA_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('d0') + plastic_disloUCLA_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('qsd') + plastic_disloUCLA_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_rho') + plastic_disloUCLA_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_disloUCLA_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cmfptwin') + plastic_disloUCLA_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cthresholdtwin') + plastic_disloUCLA_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('solidsolutionstrength') + plastic_disloUCLA_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('l0') + plastic_disloUCLA_L0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('xc') + plastic_disloUCLA_xc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('vcrossslip') + plastic_disloUCLA_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cedgedipmindistance') + plastic_disloUCLA_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('catomicvolume') + plastic_disloUCLA_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('sfe_0k') + plastic_disloUCLA_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dsfe_dt') + plastic_disloUCLA_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dipoleformationfactor') + plastic_disloUCLA_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then + instance = phase_plasticityInstance(phase) + if (sum(plastic_disloUCLA_Nslip(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOUCLA_label//')') + if (sum(plastic_disloUCLA_Ntwin(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOUCLA_label//')') + do f = 1_pInt,lattice_maxNslipFamily + if (plastic_disloUCLA_Nslip(f,instance) > 0_pInt) then + if (plastic_disloUCLA_rhoEdge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_rhoEdgeDip0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_v0PerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOUCLA_label//')') + endif + enddo + do f = 1_pInt,lattice_maxNtwinFamily + if (plastic_disloUCLA_Ntwin(f,instance) > 0_pInt) then + if (plastic_disloUCLA_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='ndot0 ('//PLASTICITY_DISLOUCLA_label//')') + endif + enddo + if (plastic_disloUCLA_CAtomicVolume(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_D0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_Qsd(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOUCLA_label//')') + if (sum(plastic_disloUCLA_Ntwin(:,instance)) > 0_pInt) then + if (abs(plastic_disloUCLA_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & + abs(plastic_disloUCLA_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & + lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOUCLA_label//')') + if (plastic_disloUCLA_aTolTwinFrac(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOUCLA_label//')') + endif + if (abs(plastic_disloUCLA_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & + plastic_disloUCLA_dipoleFormationFactor(instance) /= 1.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOUCLA_label//')') + +!-------------------------------------------------------------------------------------------------- +! Determine total number of active slip or twin systems + plastic_disloUCLA_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_disloUCLA_Nslip(:,instance)) + plastic_disloUCLA_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_disloUCLA_Ntwin(:,instance)) + plastic_disloUCLA_totalNslip(instance) = sum(plastic_disloUCLA_Nslip(:,instance)) + plastic_disloUCLA_totalNtwin(instance) = sum(plastic_disloUCLA_Ntwin(:,instance)) + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + maxTotalNslip = maxval(plastic_disloUCLA_totalNslip) + maxTotalNtwin = maxval(plastic_disloUCLA_totalNtwin) + + allocate(plastic_disloUCLA_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_tau_r(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) + + allocate(plastic_disloUCLA_interactionMatrix_SlipSlip(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from slip activity + maxval(plastic_disloUCLA_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_interactionMatrix_SlipTwin(maxval(plastic_disloUCLA_totalNslip),& ! slip resistance from twin activity + maxval(plastic_disloUCLA_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_interactionMatrix_TwinSlip(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_disloUCLA_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_interactionMatrix_TwinTwin(maxval(plastic_disloUCLA_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_disloUCLA_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & + source=0.0_pReal) + allocate(plastic_disloUCLA_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_disloUCLA_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) + + allocate(state(maxNinstance)) + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + myPhase2: if (phase_plasticity(phase) == PLASTICITY_disloUCLA_ID) then + NofMyPhase=count(material_phase==phase) + instance = phase_plasticityInstance(phase) + + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputs: do o = 1_pInt,plastic_disloUCLA_Noutput(instance) + select case(plastic_disloUCLA_outputID(o,instance)) + case(edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID & + ) + mySize = ns + case(twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID & + ) + mySize = nt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + plastic_disloUCLA_sizePostResult(o,instance) = mySize + plastic_disloUCLA_sizePostResults(instance) = plastic_disloUCLA_sizePostResults(instance) + mySize + endif + enddo outputs + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + + sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & + + int(size(['twinFraction','accsheartwin']),pInt) * nt + sizeDeltaState = 0_pInt + sizeState = sizeDotState & + + int(size(['invLambdaSlip ','invLambdaSlipTwin ',& + 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & + + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& + 'twinVolume ']),pInt) * nt + + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_disloUCLA_sizePostResults(instance) + plasticState(phase)%nSlip = plastic_disloucla_totalNslip(instance) + plasticState(phase)%nTwin = plastic_disloucla_totalNtwin(instance) + plasticState(phase)%nTrans= 0_pInt + allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + offset_slip = 2_pInt*plasticState(phase)%nSlip + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) + !* Process slip related parameters ------------------------------------------------ + + mySlipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + mySlipSystems: do j = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + + !* Burgers vector, + ! dislocation velocity prefactor, + ! mean free path prefactor, + ! and minimum dipole distance + + plastic_disloUCLA_burgersPerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_burgersPerSlipFamily(f,instance) + + plastic_disloUCLA_QedgePerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_QedgePerSlipFamily(f,instance) + + plastic_disloUCLA_v0PerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_v0PerSlipFamily(f,instance) + + plastic_disloUCLA_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_CLambdaSlipPerSlipFamily(f,instance) + + !* Calculation of forest projections for edge dislocations + !* Interaction matrices + + otherSlipFamilies: do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) + otherSlipSystems: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) + plastic_disloUCLA_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & + abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & + lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) + plastic_disloUCLA_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo otherSlipSystems; enddo otherSlipFamilies + + otherTwinFamilies: do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) + otherTwinSystems: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) + plastic_disloUCLA_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo otherTwinSystems; enddo otherTwinFamilies + + enddo mySlipSystems + enddo mySlipFamilies + + !* Process twin related parameters ------------------------------------------------ + + myTwinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(plastic_disloUCLA_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list + myTwinSystems: do j = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) + + !* Burgers vector, + ! nucleation rate prefactor, + ! and twin size + + plastic_disloUCLA_burgersPerTwinSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_burgersPerTwinFamily(f,instance) + + plastic_disloUCLA_Ndot0PerTwinSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_Ndot0PerTwinFamily(f,instance) + + plastic_disloUCLA_twinsizePerTwinSystem(index_myFamily+j,instance) = & + plastic_disloUCLA_twinsizePerTwinFamily(f,instance) + + !* Rotate twin elasticity matrices + index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list + do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt + do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt + plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & + plastic_disloUCLA_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & + lattice_C3333(p,q,r,s,instance) * & + lattice_Qtwin(l,p,index_otherFamily+j,phase) * & + lattice_Qtwin(m,q,index_otherFamily+j,phase) * & + lattice_Qtwin(n,r,index_otherFamily+j,phase) * & + lattice_Qtwin(o,s,index_otherFamily+j,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo; enddo + plastic_disloUCLA_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & + math_Mandel3333to66(plastic_disloUCLA_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) + + !* Interaction matrices + otherSlipFamilies2: do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_disloUCLA_Nslip(1:o-1_pInt,instance)) + otherSlipSystems2: do k = 1_pInt,plastic_disloUCLA_Nslip(o,instance) + plastic_disloUCLA_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo otherSlipSystems2; enddo otherSlipFamilies2 + + otherTwinFamilies2: do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_disloUCLA_Ntwin(1:o-1_pInt,instance)) + otherTwinSystems2: do k = 1_pInt,plastic_disloUCLA_Ntwin(o,instance) + plastic_disloUCLA_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_disloUCLA_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo otherTwinSystems2; enddo otherTwinFamilies2 + + enddo myTwinSystems + enddo myTwinFamilies + + startIndex=1_pInt + endIndex=ns + state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+ns + state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+ns + state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+nt + state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+nt + state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1_pInt + endIndex=endIndex+ns + state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) + + call plastic_disloUCLA_stateInit(phase,instance) + call plastic_disloUCLA_aTolState(phase,instance) + endif myPhase2 + + enddo initializeInstances + +end subroutine plastic_disloUCLA_init + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_stateInit(ph,instance) + use math, only: & + pi + use lattice, only: & + lattice_maxNslipFamily, & + lattice_mu + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + real(pReal), dimension(plasticState(ph)%sizeState) :: tempState + + integer(pInt) :: i,j,f,ns,nt, index_myFamily + real(pReal), dimension(plastic_disloUCLA_totalNslip(instance)) :: & + rhoEdge0, & + rhoEdgeDip0, & + invLambdaSlip0, & + MeanFreePathSlip0, & + tauSlipThreshold0 + real(pReal), dimension(plastic_disloUCLA_totalNtwin(instance)) :: & + MeanFreePathTwin0,TwinVolume0 + tempState = 0.0_pReal + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables + do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_disloUCLA_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + rhoEdge0(index_myFamily+1_pInt: & + index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & + plastic_disloUCLA_rhoEdge0(f,instance) + rhoEdgeDip0(index_myFamily+1_pInt: & + index_myFamily+plastic_disloUCLA_Nslip(f,instance)) = & + plastic_disloUCLA_rhoEdgeDip0(f,instance) + enddo + + tempState(1_pInt:ns) = rhoEdge0 + tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent slip microstructural variables + forall (i = 1_pInt:ns) & + invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_forestProjectionEdge(1:ns,i,instance)))/ & + plastic_disloUCLA_CLambdaSlipPerSlipSystem(i,instance) + tempState(3_pInt*ns+2_pInt*nt+1:4_pInt*ns+2_pInt*nt) = invLambdaSlip0 + + forall (i = 1_pInt:ns) & + MeanFreePathSlip0(i) = & + plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_disloUCLA_GrainSize(instance)) + tempState(5_pInt*ns+3_pInt*nt+1:6_pInt*ns+3_pInt*nt) = MeanFreePathSlip0 + + forall (i = 1_pInt:ns) & + tauSlipThreshold0(i) = & + lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(i,instance) * & + sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_disloUCLA_interactionMatrix_SlipSlip(i,1:ns,instance))) + + tempState(6_pInt*ns+4_pInt*nt+1:7_pInt*ns+4_pInt*nt) = tauSlipThreshold0 + + + +!-------------------------------------------------------------------------------------------------- +! initialize dependent twin microstructural variables + forall (j = 1_pInt:nt) & + MeanFreePathTwin0(j) = plastic_disloUCLA_GrainSize(instance) + tempState(6_pInt*ns+3_pInt*nt+1_pInt:6_pInt*ns+4_pInt*nt) = MeanFreePathTwin0 + + forall (j = 1_pInt:nt) & + TwinVolume0(j) = & + (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) + tempState(7_pInt*ns+5_pInt*nt+1_pInt:7_pInt*ns+6_pInt*nt) = TwinVolume0 + +plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) + +end subroutine plastic_disloUCLA_stateInit + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + ph, & + instance ! number specifying the current instance of the plasticity + + ! Tolerance state for dislocation densities + plasticState(ph)%aTolState(1_pInt:2_pInt*plastic_disloUCLA_totalNslip(instance)) = & + plastic_disloUCLA_aTolRho(instance) + + ! Tolerance state for accumulated shear due to slip + plasticState(ph)%aTolState(2_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & + 3_pInt*plastic_disloUCLA_totalNslip(instance))=1e6_pReal + + + ! Tolerance state for twin volume fraction + plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+1_pInt: & + 3_pInt*plastic_disloUCLA_totalNslip(instance)+& + plastic_disloUCLA_totalNtwin(instance)) = & + plastic_disloUCLA_aTolTwinFrac(instance) + +! Tolerance state for accumulated shear due to twin + plasticState(ph)%aTolState(3_pInt*plastic_disloUCLA_totalNslip(instance)+ & + plastic_disloUCLA_totalNtwin(instance)+1_pInt: & + 3_pInt*plastic_disloUCLA_totalNslip(instance)+ & + 2_pInt*plastic_disloUCLA_totalNtwin(instance)) = 1e6_pReal + +end subroutine plastic_disloUCLA_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenized elasticity matrix +!-------------------------------------------------------------------------------------------------- +function plastic_disloUCLA_homogenizedC(ipc,ip,el) + use material, only: & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_C66 + + implicit none + real(pReal), dimension(6,6) :: & + plastic_disloUCLA_homogenizedC + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,i, & + ph, & + of + real(pReal) :: sumf + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + !* Homogenized elasticity matrix + plastic_disloUCLA_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) + do i=1_pInt,nt + plastic_disloUCLA_homogenizedC = plastic_disloUCLA_homogenizedC & + + state(instance)%twinFraction(i,of)*plastic_disloUCLA_Ctwin66(1:6,1:6,i,instance) + enddo + +end function plastic_disloUCLA_homogenizedC + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_microstructure(temperature,ipc,ip,el) + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + phaseAt, phasememberAt + use lattice, only: & + lattice_mu, & + lattice_nu + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + temperature !< temperature at IP + + integer(pInt) :: & + instance, & + ns,nt,s,t, & + ph, & + of + real(pReal) :: & + sumf,sfe,x0 + real(pReal), dimension(plastic_disloUCLA_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Stacking fault energy + sfe = plastic_disloUCLA_SFE_0K(instance) + & + plastic_disloUCLA_dSFE_dT(instance) * Temperature + + !* rescaled twin volume fraction for topology + forall (t = 1_pInt:nt) & + fOverStacksize(t) = & + state(instance)%twinFraction(t,of)/plastic_disloUCLA_twinsizePerTwinSystem(t,instance) + + !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation + forall (s = 1_pInt:ns) & + state(instance)%invLambdaSlip(s,of) = & + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_disloUCLA_forestProjectionEdge(1:ns,s,instance)))/ & + plastic_disloUCLA_CLambdaSlipPerSlipSystem(s,instance) + !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation + !$OMP CRITICAL (evilmatmul) + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal + if (nt > 0_pInt .and. ns > 0_pInt) & + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & + matmul(plastic_disloUCLA_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin + !$OMP CRITICAL (evilmatmul) + if (nt > 0_pInt) & + state(instance)%invLambdaTwin(1_pInt:nt,of) = & + matmul(plastic_disloUCLA_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* mean free path between 2 obstacles seen by a moving dislocation + do s = 1_pInt,ns + if (nt > 0_pInt) then + state(instance)%mfp_slip(s,of) = & + plastic_disloUCLA_GrainSize(instance)/(1.0_pReal+plastic_disloUCLA_GrainSize(instance)*& + (state(instance)%invLambdaSlip(s,of)+state(instance)%invLambdaSlipTwin(s,of))) + else + state(instance)%mfp_slip(s,of) = & + plastic_disloUCLA_GrainSize(instance)/& + (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) + endif + enddo + + !* mean free path between 2 obstacles seen by a growing twin + forall (t = 1_pInt:nt) & + state(instance)%mfp_twin(t,of) = & + (plastic_disloUCLA_Cmfptwin(instance)*plastic_disloUCLA_GrainSize(instance))/& + (1.0_pReal+plastic_disloUCLA_GrainSize(instance)*state(instance)%invLambdaTwin(t,of)) + + !* threshold stress for dislocation motion + forall (s = 1_pInt:ns) & + state(instance)%threshold_stress_slip(s,of) = & + lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(s,instance)*& + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_disloUCLA_interactionMatrix_SlipSlip(s,1:ns,instance))) + + !* threshold stress for growing twin + forall (t = 1_pInt:nt) & + state(instance)%threshold_stress_twin(t,of) = & + plastic_disloUCLA_Cthresholdtwin(instance)*& + (sfe/(3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance))+& + 3.0_pReal*plastic_disloUCLA_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& + (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(t,instance))) + + !* final twin volume after growth + forall (t = 1_pInt:nt) & + state(instance)%twinVolume(t,of) = & + (pi/4.0_pReal)*plastic_disloUCLA_twinsizePerTwinSystem(t,instance)*state(instance)%mfp_twin(t,of)**(2.0_pReal) + + !* equilibrium seperation of partial dislocations + do t = 1_pInt,nt + x0 = lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& + (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) + plastic_disloUCLA_tau_r(t,instance)= & + lattice_mu(ph)*plastic_disloUCLA_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& + (1/(x0+plastic_disloUCLA_xc(instance))+cos(pi/3.0_pReal)/x0) !!! used where?? + enddo + +end subroutine plastic_disloUCLA_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + math_Plain3333to99, & + math_Mandel6to33, & + math_Mandel33to6, & + math_spectralDecompositionSym33, & + math_symmetric33, & + math_mul33x3 + use material, only: & + material_phase, & + phase_plasticityInstance, & + !plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily,& + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid, & + lattice_shearTwin, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + integer(pInt), intent(in) :: ipc,ip,el + real(pReal), intent(in) :: Temperature + real(pReal), dimension(6), intent(in) :: Tstar_v + real(pReal), dimension(3,3), intent(out) :: Lp + real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 + + integer(pInt) :: instance,ph,of,ns,nt,f,i,j,k,l,m,n,index_myFamily,s1,s2 + real(pReal) :: sumf,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0, & + tau_slip_pos,tau_slip_neg,vel_slip,dvel_slip,& + dgdot_dtauslip_pos,dgdot_dtauslip_neg,dgdot_dtautwin,tau_twin,gdot_twin,stressRatio + real(pReal), dimension(3,3,2) :: & + nonSchmid_tensor + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar3333 + real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip_pos,gdot_slip_neg + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Dislocation glide part + gdot_slip_pos = 0.0_pReal + gdot_slip_neg = 0.0_pReal + dgdot_dtauslip_pos = 0.0_pReal + dgdot_dtauslip_neg = 0.0_pReal + + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j+1_pInt + !* Boltzmann ratio + BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& + plastic_disloUCLA_v0PerSlipSystem(j,instance) + !* Resolved shear stress on slip system + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k, index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_disloUCLA_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) + enddo nonSchmidSystems + + significantPostitiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratio + stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_pos & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_pos(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_pos) + + !* Derivatives of shear rates + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_pos & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_pos & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + dgdot_dtauslip_pos = DotGamma0 * dvel_slip + + endif significantPostitiveStress + significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratio + stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_neg & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_neg(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_neg) + + !* Derivatives of shear rates + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_neg & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_neg & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + + dgdot_dtauslip_neg = DotGamma0 * dvel_slip + + endif significantNegativeStress + !* Plastic velocity gradient for dislocation glide + Lp = Lp + (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + (dgdot_dtauslip_pos*nonSchmid_tensor(m,n,1)+& + dgdot_dtauslip_neg*nonSchmid_tensor(m,n,2))*0.5_pReal*& + lattice_Sslip(k,l,1,index_myFamily+i,ph) + enddo slipSystems + enddo slipFamilies + +!-------------------------------------------------------------------------------------------------- +! correct Lp and dLp_dTstar3333 for twinned fraction + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + Lp = Lp * (1.0_pReal - sumf) + dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf) + +!-------------------------------------------------------------------------------------------------- +! Mechanical twinning part + gdot_twin = 0.0_pReal + dgdot_dtautwin = 0.0_pReal + j = 0_pInt + twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) + j = j+1_pInt + !* Resolved shear stress on twin system + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_twin > tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then + Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive gdot_slip_pos (= gdot_slip_neg) + abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) + else + Ndot0=0.0_pReal + end if + case default + Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) + end select + gdot_twin = & + (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) + dgdot_dtautwin = ((gdot_twin*plastic_disloUCLA_rPerTwinFamily(f,instance))/tau_twin)*StressRatio_r + endif + + !* Plastic velocity gradient for mechanical twinning + Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin*& + lattice_Stwin(k,l,index_myFamily+i,ph)*& + lattice_Stwin(m,n,index_myFamily+i,ph) + enddo twinSystems + enddo twinFamilies + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + +end subroutine plastic_disloUCLA_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_disloUCLA_dotState(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid, & + lattice_sheartwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,f,i,j,k,index_myFamily,s1,s2, & + ph, & + of + real(pReal) :: & + sumf, & + stressRatio_p,& + BoltzmannRatio,& + DotGamma0,& + stressRatio, & + EdgeDipMinDistance,& + AtomicVolume,& + VacancyDiffusion,& + StressRatio_r,& + Ndot0,& + tau_slip_pos,& + tau_slip_neg,& + DotRhoMultiplication,& + EdgeDipDistance, & + DotRhoEdgeDipAnnihilation, & + DotRhoEdgeEdgeAnnihilation, & + ClimbVelocity, & + DotRhoEdgeDipClimb, & + DotRhoDipFormation, & + tau_twin, & + vel_slip, & + gdot_slip + real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip_pos, gdot_slip_neg + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + plasticState(ph)%dotState(:,of) = 0.0_pReal + + !* Dislocation density evolution + gdot_slip_pos = 0.0_pReal + gdot_slip_neg = 0.0_pReal + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j+1_pInt + !* Boltzmann ratio + BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& + plastic_disloUCLA_v0PerSlipSystem(j,instance) + !* Resolved shear stress on slip system + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + + significantPositiveStress: if((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau_slip_pos)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_pos & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_pos(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_pos) + endif significantPositiveStress + significantNegativeStress: if((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau_slip_neg)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_neg & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_neg(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_neg) + endif significantNegativeStress + gdot_slip = (gdot_slip_pos(j)+gdot_slip_neg(j))*0.5_pReal + !* Multiplication + DotRhoMultiplication = abs(gdot_slip)/& + (plastic_disloUCLA_burgersPerSlipSystem(j,instance)* & + state(instance)%mfp_slip(j,of)) + + !* Dipole formation + EdgeDipMinDistance = & + plastic_disloUCLA_CEdgeDipMinDistance(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance) + if (abs(tau_slip_pos) <= tiny(0.0_pReal)) then + DotRhoDipFormation = 0.0_pReal + else + EdgeDipDistance = & + (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(tau_slip_pos)) + if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) + if (EdgeDipDistance tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then + Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) + abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_disloUCLA_L0(instance)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) + else + Ndot0=0.0_pReal + end if + case default + Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) + end select + + dotState(instance)%twinFraction(j, of) = & + (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*& + state(instance)%twinVolume(j, of)*Ndot0*exp(-StressRatio_r) + !* Dotstate for accumulated shear due to twin + dotState(instance)%accshear_twin(j,of) = dotState(ph)%twinFraction(j,of) * & + lattice_sheartwin(index_myfamily+i,ph) + endif + enddo twinSystems + enddo twinFamilies + +end subroutine plastic_disloUCLA_dotState + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_disloUCLA_postResults(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance,& + !plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid, & + lattice_shearTwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(plastic_disloUCLA_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_disloUCLA_postResults + + integer(pInt) :: & + instance,& + ns,nt,& + f,o,i,c,j,k,index_myFamily,& + s1,s2, & + ph, & + of + real(pReal) :: sumf,tau_twin,StressRatio_p,StressRatio_pminus1,& + BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0,stressRatio + real(pReal) :: dvel_slip, vel_slip + real(pReal), dimension(plastic_disloUCLA_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip_pos,dgdot_dtauslip_pos,tau_slip_pos,gdot_slip_neg,dgdot_dtauslip_neg,tau_slip_neg + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_disloUCLA_totalNslip(instance) + nt = plastic_disloUCLA_totalNtwin(instance) + + !* Total twin volume fraction + sumf = sum(state(ph)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Required output + c = 0_pInt + plastic_disloUCLA_postResults = 0.0_pReal + + do o = 1_pInt,plastic_disloUCLA_Noutput(instance) + select case(plastic_disloUCLA_outputID(o,instance)) + + case (edge_density_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) + c = c + ns + case (dipole_density_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) + c = c + ns + case (shear_rate_slip_ID,shear_rate_twin_ID,stress_exponent_ID) + gdot_slip_pos = 0.0_pReal + gdot_slip_neg = 0.0_pReal + dgdot_dtauslip_pos = 0.0_pReal + dgdot_dtauslip_neg = 0.0_pReal + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j + 1_pInt + !* Boltzmann ratio + BoltzmannRatio = plastic_disloUCLA_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_disloUCLA_burgersPerSlipSystem(j,instance)*& + plastic_disloUCLA_v0PerSlipSystem(j,instance) + !* Resolved shear stress on slip system + tau_slip_pos(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + tau_slip_neg(j) = tau_slip_pos(j) + + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_disloUCLA_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + + significantPositiveTau: if((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then + !* Stress ratio + stressRatio = ((abs(tau_slip_pos(j))-state(instance)%threshold_stress_slip(j, of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_pos(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_pos(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_pos(j)) + !* Derivatives of shear rates + + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_pos(j) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_pos(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_pos(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + + dgdot_dtauslip_pos(j) = DotGamma0 * dvel_slip + + endif significantPositiveTau + significantNegativeTau: if((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau_slip_neg(j))-state(instance)%threshold_stress_slip(j, of))/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+& + plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))) + stressRatio_p = stressRatio** plastic_disloUCLA_pPerSlipFamily(f,instance) + stressRatio_pminus1 = stressRatio**(plastic_disloUCLA_pPerSlipFamily(f,instance)-1.0_pReal) + !* Shear rates due to slip + vel_slip = 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * (tau_slip_neg(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + / ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) + + gdot_slip_neg(j) = DotGamma0 & + * vel_slip & + * sign(1.0_pReal,tau_slip_neg(j)) + !* Derivatives of shear rates + dvel_slip = & + 2.0_pReal*plastic_disloUCLA_burgersPerSlipFamily(f,instance) & + * plastic_disloUCLA_kinkheight(f,instance) * plastic_disloUCLA_omega(f,instance) & + * ( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) ) & + * ( & + (exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + + tau_slip_neg(j) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) ) &!deltaf(f) + ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + ) & + - (tau_slip_neg(j) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) ) & + * (2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * (abs(exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)))& !deltaf(i) + *BoltzmannRatio*plastic_disloUCLA_pPerSlipFamily(f,instance)& + *plastic_disloUCLA_qPerSlipFamily(f,instance)/& + (plastic_disloUCLA_SolidSolutionStrength(instance)+plastic_disloUCLA_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_disloUCLA_qPerSlipFamily(f,instance)-1.0_pReal) )& !deltaf(f) + ) & + ) & + / ( & + ( & + 2.0_pReal*(plastic_disloUCLA_burgersPerSlipFamily(f,instance)**2.0_pReal)*tau_slip_neg(j) & + + plastic_disloUCLA_omega(f,instance) * plastic_disloUCLA_friction(f,instance) & + *(( state(instance)%mfp_slip(j,of) - plastic_disloUCLA_kinkwidth(f,instance) )**2.0_pReal) & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_disloUCLA_qPerSlipFamily(f,instance)) & + )**2.0_pReal & + ) + + + dgdot_dtauslip_neg(j) = DotGamma0 * dvel_slip + + endif significantNegativeTau + enddo slipSystems + enddo slipFamilies + + if (plastic_disloUCLA_outputID(o,instance) == shear_rate_slip_ID) then + plastic_disloUCLA_postResults(c+1:c+ns) = (gdot_slip_pos + gdot_slip_neg)*0.5_pReal + c = c + ns + elseif (plastic_disloUCLA_outputID(o,instance) == shear_rate_twin_ID) then + if (nt > 0_pInt) then + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1,plastic_disloUCLA_Ntwin(f,instance) + j = j + 1_pInt + + !* Resolved shear stress on twin system + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + !* Stress ratios + StressRatio_r = (state(instance)%threshold_stress_twin(j, of)/ & + tau_twin)**plastic_disloUCLA_rPerTwinFamily(f,instance) + + !* Shear rates due to twin + if ( tau_twin > 0.0_pReal ) then + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin < plastic_disloUCLA_tau_r(j,instance)) then + Ndot0=(abs(gdot_slip_pos(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !no non-Schmid behavior for fcc, just take the not influenced positive slip (gdot_slip_pos = gdot_slip_neg) + abs(gdot_slip_pos(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_disloUCLA_L0(instance)*& + plastic_disloUCLA_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_disloUCLA_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_disloUCLA_tau_r(j,instance)-tau_twin))) + else + Ndot0=0.0_pReal + end if + + case default + Ndot0=plastic_disloUCLA_Ndot0PerTwinSystem(j,instance) + end select + plastic_disloUCLA_postResults(c+j) = & + (plastic_disloUCLA_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0*exp(-StressRatio_r) + endif + enddo twinSystems1 + enddo twinFamilies1 + endif + c = c + nt + elseif(plastic_disloUCLA_outputID(o,instance) == stress_exponent_ID) then + do j = 1_pInt, ns + if (abs(gdot_slip_pos(j)+gdot_slip_neg(j))<=tiny(0.0_pReal)) then + plastic_disloUCLA_postResults(c+j) = 0.0_pReal + else + plastic_disloUCLA_postResults(c+j) = (tau_slip_pos(j)+tau_slip_neg(j))/& + (gdot_slip_pos(j)+gdot_slip_neg(j))*& + (dgdot_dtauslip_pos(j)+dgdot_dtauslip_neg(j))* 0.5_pReal + endif + enddo + c = c + ns + endif + + case (accumulated_shear_slip_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & + state(instance)%accshear_slip(1_pInt:ns, of) + c = c + ns + case (mfp_slip_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) =& + state(instance)%mfp_slip(1_pInt:ns, of) + c = c + ns + case (resolved_stress_slip_ID) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j + 1_pInt + plastic_disloUCLA_postResults(c+j) =& + dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + enddo slipSystems1; enddo slipFamilies1 + c = c + ns + case (threshold_stress_slip_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+ns) = & + state(instance)%threshold_stress_slip(1_pInt:ns,of) + c = c + ns + case (edge_dipole_distance_ID) + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems2: do i = 1_pInt,plastic_disloUCLA_Nslip(f,instance) + j = j + 1_pInt + plastic_disloUCLA_postResults(c+j) = & + (3.0_pReal*lattice_mu(ph)*plastic_disloUCLA_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) + plastic_disloUCLA_postResults(c+j)=min(plastic_disloUCLA_postResults(c+j),& + state(instance)%mfp_slip(j,of)) + enddo slipSystems2; enddo slipFamilies2 + c = c + ns + case (twin_fraction_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt, of) + c = c + nt + + case (accumulated_shear_twin_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt, of) + c = c + nt + + case (mfp_twin_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt, of) + c = c + nt + + case (resolved_stress_twin_ID) + if (nt > 0_pInt) then + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_disloUCLA_Ntwin(f,instance) + j = j + 1_pInt + plastic_disloUCLA_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + enddo twinSystems2; enddo twinFamilies2 + endif + c = c + nt + case (threshold_stress_twin_ID) + plastic_disloUCLA_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt, of) + c = c + nt + end select + enddo +end function plastic_disloUCLA_postResults + +end module plastic_disloUCLA diff --git a/src/plastic_dislotwin.f90 b/src/plastic_dislotwin.f90 new file mode 100644 index 000000000..532312bfd --- /dev/null +++ b/src/plastic_dislotwin.f90 @@ -0,0 +1,2542 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incoprorating dislocation and twinning physics +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module plastic_dislotwin + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_dislotwin_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_dislotwin_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_dislotwin_output !< name of each post result output + + real(pReal), parameter, private :: & + kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_dislotwin_Noutput !< number of outputs per instance of this plasticity + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_dislotwin_totalNslip, & !< total number of active slip systems for each instance + plastic_dislotwin_totalNtwin, & !< total number of active twin systems for each instance + plastic_dislotwin_totalNtrans !< number of active transformation systems + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_dislotwin_Nslip, & !< number of active slip systems for each family and instance + plastic_dislotwin_Ntwin, & !< number of active twin systems for each family and instance + plastic_dislotwin_Ntrans !< number of active transformation systems for each family and instance + + real(pReal), dimension(:), allocatable, private :: & + plastic_dislotwin_CAtomicVolume, & !< atomic volume in Bugers vector unit + plastic_dislotwin_D0, & !< prefactor for self-diffusion coefficient + plastic_dislotwin_Qsd, & !< activation energy for dislocation climb + plastic_dislotwin_GrainSize, & !< grain size + plastic_dislotwin_pShearBand, & !< p-exponent in shearband velocity + plastic_dislotwin_qShearBand, & !< q-exponent in shearband velocity + plastic_dislotwin_MaxTwinFraction, & !< maximum allowed total twin volume fraction + plastic_dislotwin_CEdgeDipMinDistance, & !< + plastic_dislotwin_Cmfptwin, & !< + plastic_dislotwin_Cthresholdtwin, & !< + plastic_dislotwin_SolidSolutionStrength, & !< Strength due to elements in solid solution + plastic_dislotwin_L0_twin, & !< Length of twin nuclei in Burgers vectors + plastic_dislotwin_L0_trans, & !< Length of trans nuclei in Burgers vectors + plastic_dislotwin_xc_twin, & !< critical distance for formation of twin nucleus + plastic_dislotwin_xc_trans, & !< critical distance for formation of trans nucleus + plastic_dislotwin_VcrossSlip, & !< cross slip volume + plastic_dislotwin_sbResistance, & !< value for shearband resistance (might become an internal state variable at some point) + plastic_dislotwin_sbVelocity, & !< value for shearband velocity_0 + plastic_dislotwin_sbQedge, & !< value for shearband systems Qedge + plastic_dislotwin_SFE_0K, & !< stacking fault energy at zero K + plastic_dislotwin_dSFE_dT, & !< temperature dependance of stacking fault energy + plastic_dislotwin_dipoleFormationFactor, & !< scaling factor for dipole formation: 0: off, 1: on. other values not useful + plastic_dislotwin_aTolRho, & !< absolute tolerance for integration of dislocation density + plastic_dislotwin_aTolTwinFrac, & !< absolute tolerance for integration of twin volume fraction + plastic_dislotwin_aTolTransFrac, & !< absolute tolerance for integration of trans volume fraction + plastic_dislotwin_deltaG, & !< Free energy difference between austensite and martensite + plastic_dislotwin_Cmfptrans, & !< + plastic_dislotwin_Cthresholdtrans, & !< + plastic_dislotwin_transStackHeight !< Stack height of hex nucleus + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctwin3333 !< twin elasticity matrix for each instance + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctrans66 !< trans elasticity matrix in Mandel notation for each instance + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_dislotwin_Ctrans3333 !< trans elasticity matrix for each instance + real(pReal), dimension(:,:), allocatable, private :: & + plastic_dislotwin_rhoEdge0, & !< initial edge dislocation density per slip system for each family and instance + plastic_dislotwin_rhoEdgeDip0, & !< initial edge dipole density per slip system for each family and instance + plastic_dislotwin_burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each slip family and instance + plastic_dislotwin_burgersPerSlipSystem, & !< absolute length of burgers vector [m] for each slip system and instance + plastic_dislotwin_burgersPerTwinFamily, & !< absolute length of burgers vector [m] for each twin family and instance + plastic_dislotwin_burgersPerTwinSystem, & !< absolute length of burgers vector [m] for each twin system and instance + plastic_dislotwin_burgersPerTransFamily, & !< absolute length of burgers vector [m] for each trans family and instance + plastic_dislotwin_burgersPerTransSystem, & !< absolute length of burgers vector [m] for each trans system and instance + plastic_dislotwin_QedgePerSlipFamily, & !< activation energy for glide [J] for each slip family and instance + plastic_dislotwin_QedgePerSlipSystem, & !< activation energy for glide [J] for each slip system and instance + plastic_dislotwin_v0PerSlipFamily, & !< dislocation velocity prefactor [m/s] for each family and instance + plastic_dislotwin_v0PerSlipSystem, & !< dislocation velocity prefactor [m/s] for each slip system and instance + plastic_dislotwin_tau_peierlsPerSlipFamily, & !< Peierls stress [Pa] for each family and instance + plastic_dislotwin_Ndot0PerTwinFamily, & !< twin nucleation rate [1/m³s] for each twin family and instance + plastic_dislotwin_Ndot0PerTwinSystem, & !< twin nucleation rate [1/m³s] for each twin system and instance + plastic_dislotwin_Ndot0PerTransFamily, & !< trans nucleation rate [1/m³s] for each trans family and instance + plastic_dislotwin_Ndot0PerTransSystem, & !< trans nucleation rate [1/m³s] for each trans system and instance + plastic_dislotwin_tau_r_twin, & !< stress to bring partial close together for each twin system and instance + plastic_dislotwin_tau_r_trans, & !< stress to bring partial close together for each trans system and instance + plastic_dislotwin_twinsizePerTwinFamily, & !< twin thickness [m] for each twin family and instance + plastic_dislotwin_twinsizePerTwinSystem, & !< twin thickness [m] for each twin system and instance + plastic_dislotwin_CLambdaSlipPerSlipFamily, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_dislotwin_CLambdaSlipPerSlipSystem, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_dislotwin_lamellarsizePerTransFamily, & !< martensite lamellar thickness [m] for each trans family and instance + plastic_dislotwin_lamellarsizePerTransSystem, & !< martensite lamellar thickness [m] for each trans system and instance + plastic_dislotwin_interaction_SlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance + plastic_dislotwin_interaction_SlipTwin, & !< coefficients for slip-twin interaction for each interaction type and instance + plastic_dislotwin_interaction_TwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_dislotwin_interaction_TwinTwin, & !< coefficients for twin-twin interaction for each interaction type and instance + plastic_dislotwin_interaction_SlipTrans, & !< coefficients for slip-trans interaction for each interaction type and instance + plastic_dislotwin_interaction_TransSlip, & !< coefficients for trans-slip interaction for each interaction type and instance + plastic_dislotwin_interaction_TransTrans, & !< coefficients for trans-trans interaction for each interaction type and instance + plastic_dislotwin_pPerSlipFamily, & !< p-exponent in glide velocity + plastic_dislotwin_qPerSlipFamily, & !< q-exponent in glide velocity + plastic_dislotwin_rPerTwinFamily, & !< r-exponent in twin nucleation rate + plastic_dislotwin_sPerTransFamily !< s-exponent in trans nucleation rate + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_dislotwin_interactionMatrix_SlipSlip, & !< interaction matrix of the different slip systems for each instance + plastic_dislotwin_interactionMatrix_SlipTwin, & !< interaction matrix of slip systems with twin systems for each instance + plastic_dislotwin_interactionMatrix_TwinSlip, & !< interaction matrix of twin systems with slip systems for each instance + plastic_dislotwin_interactionMatrix_TwinTwin, & !< interaction matrix of the different twin systems for each instance + plastic_dislotwin_interactionMatrix_SlipTrans, & !< interaction matrix of slip systems with trans systems for each instance + plastic_dislotwin_interactionMatrix_TransSlip, & !< interaction matrix of trans systems with slip systems for each instance + plastic_dislotwin_interactionMatrix_TransTrans, & !< interaction matrix of the different trans systems for each instance + plastic_dislotwin_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance + plastic_dislotwin_projectionMatrix_Trans !< matrix for projection of slip system shear on fault band (twin) systems for each instance + + real(pReal), dimension(:,:,:,:,:), allocatable, private :: & + plastic_dislotwin_sbSv + + enum, bind(c) + enumerator :: undefined_ID, & + edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID, & + twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID, & + resolved_stress_shearband_ID, & + shear_rate_shearband_ID, & + sb_eigenvalues_ID, & + sb_eigenvectors_ID, & + stress_trans_fraction_ID, & + strain_trans_fraction_ID, & + trans_fraction_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_dislotwin_outputID !< ID of each post result output + type, private :: tDislotwinState + real(pReal), pointer, dimension(:,:) :: & + rhoEdge, & + rhoEdgeDip, & + accshear_slip, & + twinFraction, & + accshear_twin, & + stressTransFraction, & + strainTransFraction , & + invLambdaSlip, & + invLambdaSlipTwin, & + invLambdaTwin, & + invLambdaSlipTrans, & + invLambdaTrans, & + mfp_slip, & + mfp_twin, & + mfp_trans, & + threshold_stress_slip, & + threshold_stress_twin, & + threshold_stress_trans, & + twinVolume, & + martensiteVolume + end type + type(tDislotwinState), allocatable, dimension(:), private :: & + state, & + state0, & + dotState + + public :: & + plastic_dislotwin_init, & + plastic_dislotwin_homogenizedC, & + plastic_dislotwin_microstructure, & + plastic_dislotwin_LpAndItsTangent, & + plastic_dislotwin_dotState, & + plastic_dislotwin_postResults + private :: & + plastic_dislotwin_stateInit, & + plastic_dislotwin_aTolState + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333, & + math_mul3x3 + use mesh, only: & + mesh_maxNips, & + mesh_NcpElems + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + homogenization_maxNgrains, & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_DISLOTWIN_label, & + PLASTICITY_DISLOTWIN_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,maxTotalNslip,maxTotalNtwin,maxTotalNtrans,& + f,instance,j,k,l,m,n,o,p,q,r,s,ns,nt,nr, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipTrans = 0_pInt, Nchunks_TransSlip = 0_pInt, Nchunks_TransTrans = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, Nchunks_TransFamilies = 0_pInt, & + offset_slip, index_myFamily, index_otherFamily, & + startIndex, endIndex + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip, tempPerTwin, tempPerTrans + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_DISLOTWIN_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_DISLOTWIN_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_dislotwin_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(plastic_dislotwin_output(maxval(phase_Noutput),maxNinstance)) + plastic_dislotwin_output = '' + allocate(plastic_dislotwin_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_dislotwin_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_totalNtrans(maxNinstance), source=0_pInt) + allocate(plastic_dislotwin_CAtomicVolume(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_D0(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Qsd(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_GrainSize(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_pShearBand(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_qShearBand(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_MaxTwinFraction(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cmfptwin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cthresholdtwin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_SolidSolutionStrength(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_L0_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_L0_trans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_xc_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_xc_trans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_VcrossSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_aTolRho(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_aTolTwinFrac(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_aTolTransFrac(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_sbResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_sbVelocity(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_sbQedge(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_SFE_0K(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_dSFE_dT(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_dipoleFormationFactor(maxNinstance), source=1.0_pReal) !should be on by default + allocate(plastic_dislotwin_deltaG(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cmfptrans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Cthresholdtrans(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_transStackHeight(maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_rhoEdge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_rhoEdgeDip0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTransFamily(lattice_maxNtransFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_QedgePerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_v0PerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_tau_peierlsPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_pPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_qPerSlipFamily(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTransFamily(lattice_maxNtransFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_twinsizePerTwinFamily(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_CLambdaSlipPerSlipFamily(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_rPerTwinFamily(lattice_maxNtwinFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_SlipTrans(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TransSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_interaction_TransTrans(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_sbSv(6,6,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) + allocate(plastic_dislotwin_lamellarsizePerTransFamily(lattice_maxNtransFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_sPerTransFamily(lattice_maxNtransFamily,maxNinstance),source=0.0_pReal) + + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) + Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase)> 0_pInt) + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_SlipTrans = maxval(lattice_interactionSlipTrans(:,:,phase)) + Nchunks_TransSlip = maxval(lattice_interactionTransSlip(:,:,phase)) + Nchunks_TransTrans = maxval(lattice_interactionTransTrans(:,:,phase)) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + if(allocated(tempPerTwin)) deallocate(tempPerTwin) + if(allocated(tempPerTrans)) deallocate(tempPerTrans) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + allocate(tempPerTwin(Nchunks_TwinFamilies)) + allocate(tempPerTrans(Nchunks_TransFamilies)) + endif + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_DISLOTWIN_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('edge_density') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_density_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('dipole_density') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = dipole_density_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_slip','shearrate_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_slip') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_slip_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('edge_dipole_distance') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = edge_dipole_distance_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stress_exponent') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_exponent_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('twin_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = twin_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_twin','shearrate_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulated_shear_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = accumulated_shear_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('mfp_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = mfp_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('threshold_stress_twin') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = threshold_stress_twin_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolved_stress_shearband') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = resolved_stress_shearband_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_rate_shearband','shearrate_shearband') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = shear_rate_shearband_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('sb_eigenvalues') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvalues_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('sb_eigenvectors') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = sb_eigenvectors_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stress_trans_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = stress_trans_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('strain_trans_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = strain_trans_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('trans_fraction','total_trans_fraction') + plastic_dislotwin_Noutput(instance) = plastic_dislotwin_Noutput(instance) + 1_pInt + plastic_dislotwin_outputID(plastic_dislotwin_Noutput(instance),instance) = trans_fraction_ID + plastic_dislotwin_output(plastic_dislotwin_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip system families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + plastic_dislotwin_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('rhoedge0','rhoedgedip0','slipburgers','qedge','v0','clambdaslip','tau_peierls','p_slip','q_slip') + do j = 1_pInt, Nchunks_SlipFamilies + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('rhoedge0') + plastic_dislotwin_rhoEdge0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('rhoedgedip0') + plastic_dislotwin_rhoEdgeDip0(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('slipburgers') + plastic_dislotwin_burgersPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('qedge') + plastic_dislotwin_QedgePerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('v0') + plastic_dislotwin_v0PerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('clambdaslip') + plastic_dislotwin_CLambdaSlipPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau_peierls') + if (lattice_structure(phase) /= LATTICE_bcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for non-bcc ('//PLASTICITY_DISLOTWIN_label//')') + plastic_dislotwin_tau_peierlsPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('p_slip') + plastic_dislotwin_pPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('q_slip') + plastic_dislotwin_qPerSlipFamily(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on slip number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_dislotwin_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ndot0_twin','twinsize','twinburgers','r_twin') + do j = 1_pInt, Nchunks_TwinFamilies + tempPerTwin(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('ndot0_twin') + if (lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') + plastic_dislotwin_Ndot0PerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinsize') + plastic_dislotwin_twinsizePerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('twinburgers') + plastic_dislotwin_burgersPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + case ('r_twin') + plastic_dislotwin_rPerTwinFamily(1:Nchunks_TwinFamilies,instance) = tempPerTwin(1:Nchunks_TwinFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of transformation system families + case ('ntrans') + if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & + call IO_warning(53_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + Nchunks_TransFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TransFamilies + plastic_dislotwin_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ndot0_trans','lamellarsize','transburgers','s_trans') + do j = 1_pInt, Nchunks_TransFamilies + tempPerTrans(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('ndot0_trans') + if (lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_warning(42_pInt,ext_msg=trim(tag)//' for fcc ('//PLASTICITY_DISLOTWIN_label//')') + plastic_dislotwin_Ndot0PerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + case ('lamellarsize') + plastic_dislotwin_lamellarsizePerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + case ('transburgers') + plastic_dislotwin_burgersPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + case ('s_trans') + plastic_dislotwin_sPerTransFamily(1:Nchunks_TransFamilies,instance) = tempPerTrans(1:Nchunks_TransFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip','interactionslipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_dislotwin_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin','interactionsliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_dislotwin_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip','interactiontwinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_dislotwin_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin','interactiontwintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_dislotwin_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptrans','interactionsliptrans') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTrans) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_SlipTrans + plastic_dislotwin_interaction_SlipTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_transslip','interactiontransslip') + if (chunkPos(1) < 1_pInt + Nchunks_TransSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TransSlip + plastic_dislotwin_interaction_TransSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_transtrans','interactiontranstrans') + if (chunkPos(1) < 1_pInt + Nchunks_TransTrans) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_DISLOTWIN_label//')') + do j = 1_pInt, Nchunks_TransTrans + plastic_dislotwin_interaction_TransTrans(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin/trans systems + case ('grainsize') + plastic_dislotwin_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('maxtwinfraction') + plastic_dislotwin_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('p_shearband') + plastic_dislotwin_pShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('q_shearband') + plastic_dislotwin_qShearBand(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('d0') + plastic_dislotwin_D0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('qsd') + plastic_dislotwin_Qsd(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_rho') + plastic_dislotwin_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_dislotwin_aTolTwinFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_transfrac') + plastic_dislotwin_aTolTransFrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cmfptwin') + plastic_dislotwin_Cmfptwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cthresholdtwin') + plastic_dislotwin_Cthresholdtwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('solidsolutionstrength') + plastic_dislotwin_SolidSolutionStrength(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('l0_twin') + plastic_dislotwin_L0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('l0_trans') + plastic_dislotwin_L0_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('xc_twin') + plastic_dislotwin_xc_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('xc_trans') + plastic_dislotwin_xc_trans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('vcrossslip') + plastic_dislotwin_VcrossSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cedgedipmindistance') + plastic_dislotwin_CEdgeDipMinDistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('catomicvolume') + plastic_dislotwin_CAtomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('sfe_0k') + plastic_dislotwin_SFE_0K(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dsfe_dt') + plastic_dislotwin_dSFE_dT(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('dipoleformationfactor') + plastic_dislotwin_dipoleFormationFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('shearbandresistance') + plastic_dislotwin_sbResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('shearbandvelocity') + plastic_dislotwin_sbVelocity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('qedgepersbsystem') + plastic_dislotwin_sbQedge(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('deltag') + plastic_dislotwin_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cmfptrans') + plastic_dislotwin_Cmfptrans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cthresholdtrans') + plastic_dislotwin_Cthresholdtrans(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('transstackheight') + plastic_dislotwin_transStackHeight(instance) = IO_floatValue(line,chunkPos,2_pInt) + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then + instance = phase_plasticityInstance(phase) + + if (sum(plastic_dislotwin_Nslip(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Nslip ('//PLASTICITY_DISLOTWIN_label//')') + if (sum(plastic_dislotwin_Ntwin(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Ntwin ('//PLASTICITY_DISLOTWIN_label//')') + if (sum(plastic_dislotwin_Ntrans(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='Ntrans ('//PLASTICITY_DISLOTWIN_label//')') + do f = 1_pInt,lattice_maxNslipFamily + if (plastic_dislotwin_Nslip(f,instance) > 0_pInt) then + if (plastic_dislotwin_rhoEdge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdge0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_rhoEdgeDip0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rhoEdgeDip0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_burgersPerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='slipBurgers ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_v0PerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau_peierls ('//PLASTICITY_DISLOTWIN_label//')') + endif + enddo + do f = 1_pInt,lattice_maxNtwinFamily + if (plastic_dislotwin_Ntwin(f,instance) > 0_pInt) then + if (plastic_dislotwin_burgersPerTwinFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_Ndot0PerTwinFamily(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='ndot0_twin ('//PLASTICITY_DISLOTWIN_label//')') + endif + enddo + if (plastic_dislotwin_CAtomicVolume(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='cAtomicVolume ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_D0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='D0 ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_Qsd(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='Qsd ('//PLASTICITY_DISLOTWIN_label//')') + if (sum(plastic_dislotwin_Ntwin(:,instance)) > 0_pInt) then + if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & + abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & + lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolRho ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_aTolTwinFrac(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolTwinFrac ('//PLASTICITY_DISLOTWIN_label//')') + endif + if (sum(plastic_dislotwin_Ntrans(:,instance)) > 0_pInt) then + if (abs(plastic_dislotwin_SFE_0K(instance)) <= tiny(0.0_pReal) .and. & + abs(plastic_dislotwin_dSFE_dT(instance)) <= tiny(0.0_pReal) .and. & + lattice_structure(phase) == LATTICE_fcc_ID) & + call IO_error(211_pInt,el=instance,ext_msg='SFE0K ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_aTolTransFrac(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTolTransFrac ('//PLASTICITY_DISLOTWIN_label//')') + endif + if (plastic_dislotwin_sbResistance(instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sbResistance ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_sbVelocity(instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sbVelocity ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & + plastic_dislotwin_pShearBand(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='pShearBand ('//PLASTICITY_DISLOTWIN_label//')') + if (abs(plastic_dislotwin_dipoleFormationFactor(instance)) > tiny(0.0_pReal) .and. & + plastic_dislotwin_dipoleFormationFactor(instance) /= 1.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='dipoleFormationFactor ('//PLASTICITY_DISLOTWIN_label//')') + if (plastic_dislotwin_sbVelocity(instance) > 0.0_pReal .and. & + plastic_dislotwin_qShearBand(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='qShearBand ('//PLASTICITY_DISLOTWIN_label//')') + +!-------------------------------------------------------------------------------------------------- +! Determine total number of active slip or twin systems + plastic_dislotwin_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_dislotwin_Nslip(:,instance)) + plastic_dislotwin_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_dislotwin_Ntwin(:,instance)) + plastic_dislotwin_Ntrans(:,instance)= min(lattice_NtransSystem(:,phase),plastic_dislotwin_Ntrans(:,instance)) + plastic_dislotwin_totalNslip(instance) = sum(plastic_dislotwin_Nslip(:,instance)) + plastic_dislotwin_totalNtwin(instance) = sum(plastic_dislotwin_Ntwin(:,instance)) + plastic_dislotwin_totalNtrans(instance) = sum(plastic_dislotwin_Ntrans(:,instance)) + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + maxTotalNslip = maxval(plastic_dislotwin_totalNslip) + maxTotalNtwin = maxval(plastic_dislotwin_totalNtwin) + maxTotalNtrans = maxval(plastic_dislotwin_totalNtrans) + + allocate(plastic_dislotwin_burgersPerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_burgersPerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_QedgePerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_v0PerSlipSystem(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ndot0PerTransSystem(maxTotalNtrans, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_tau_r_twin(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_tau_r_trans(maxTotalNtrans, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_twinsizePerTwinSystem(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_CLambdaSlipPerSlipSystem(maxTotalNslip, maxNinstance),source=0.0_pReal) + allocate(plastic_dislotwin_lamellarsizePerTransSystem(maxTotalNtrans, maxNinstance),source=0.0_pReal) + + allocate(plastic_dislotwin_interactionMatrix_SlipSlip(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from slip activity + maxval(plastic_dislotwin_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_SlipTwin(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from twin activity + maxval(plastic_dislotwin_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TwinSlip(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_dislotwin_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TwinTwin(maxval(plastic_dislotwin_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_dislotwin_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_SlipTrans(maxval(plastic_dislotwin_totalNslip),& ! slip resistance from trans activity + maxval(plastic_dislotwin_totalNtrans),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TransSlip(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from slip activity + maxval(plastic_dislotwin_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_interactionMatrix_TransTrans(maxval(plastic_dislotwin_totalNtrans),& ! trans resistance from trans activity + maxval(plastic_dislotwin_totalNtrans),& + maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_projectionMatrix_Trans(maxTotalNtrans,maxTotalNslip,maxNinstance), & + source=0.0_pReal) + allocate(plastic_dislotwin_Ctwin66(6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ctwin3333(3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ctrans66(6,6,maxTotalNtrans,maxNinstance), source=0.0_pReal) + allocate(plastic_dislotwin_Ctrans3333(3,3,3,3,maxTotalNtrans,maxNinstance), source=0.0_pReal) + + allocate(state(maxNinstance)) + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + myPhase2: if (phase_plasticity(phase) == PLASTICITY_dislotwin_ID) then + NofMyPhase=count(material_phase==phase) + instance = phase_plasticityInstance(phase) + + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_dislotwin_Noutput(instance) + select case(plastic_dislotwin_outputID(o,instance)) + case(edge_density_ID, & + dipole_density_ID, & + shear_rate_slip_ID, & + accumulated_shear_slip_ID, & + mfp_slip_ID, & + resolved_stress_slip_ID, & + threshold_stress_slip_ID, & + edge_dipole_distance_ID, & + stress_exponent_ID & + ) + mySize = ns + case(twin_fraction_ID, & + shear_rate_twin_ID, & + accumulated_shear_twin_ID, & + mfp_twin_ID, & + resolved_stress_twin_ID, & + threshold_stress_twin_ID & + ) + mySize = nt + case(resolved_stress_shearband_ID, & + shear_rate_shearband_ID & + ) + mySize = 6_pInt + case(sb_eigenvalues_ID) + mySize = 3_pInt + case(sb_eigenvectors_ID) + mySize = 9_pInt + case(stress_trans_fraction_ID, & + strain_trans_fraction_ID, & + trans_fraction_ID & + ) + mySize = nr + end select + + if (mySize > 0_pInt) then ! any meaningful output found + plastic_dislotwin_sizePostResult(o,instance) = mySize + plastic_dislotwin_sizePostResults(instance) = plastic_dislotwin_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + + sizeDotState = int(size(['rhoEdge ','rhoEdgeDip ','accshearslip']),pInt) * ns & + + int(size(['twinFraction','accsheartwin']),pInt) * nt & + + int(size(['stressTransFraction','strainTransFraction']),pInt) * nr + sizeDeltaState = 0_pInt + sizeState = sizeDotState & + + int(size(['invLambdaSlip ','invLambdaSlipTwin ','invLambdaSlipTrans',& + 'meanFreePathSlip ','tauSlipThreshold ']),pInt) * ns & + + int(size(['invLambdaTwin ','meanFreePathTwin','tauTwinThreshold',& + 'twinVolume ']),pInt) * nt & + + int(size(['invLambdaTrans ','meanFreePathTrans','tauTransThreshold', & + 'martensiteVolume ']),pInt) * nr + + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_dislotwin_sizePostResults(instance) + plasticState(phase)%nSlip = plastic_dislotwin_totalNslip(instance) + plasticState(phase)%nTwin = plastic_dislotwin_totalNtwin(instance) + plasticState(phase)%nTrans= plastic_dislotwin_totalNtrans(instance) + allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + offset_slip = 2_pInt*plasticState(phase)%nslip + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nslip,1:NofMyPhase) + + !* Process slip related parameters ------------------------------------------------ + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + slipSystemsLoop: do j = 1_pInt,plastic_dislotwin_Nslip(f,instance) + + !* Burgers vector, + ! dislocation velocity prefactor, + ! mean free path prefactor, + ! and minimum dipole distance + + plastic_dislotwin_burgersPerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_burgersPerSlipFamily(f,instance) + + plastic_dislotwin_QedgePerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_QedgePerSlipFamily(f,instance) + + plastic_dislotwin_v0PerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_v0PerSlipFamily(f,instance) + + plastic_dislotwin_CLambdaSlipPerSlipSystem(index_myFamily+j,instance) = & + plastic_dislotwin_CLambdaSlipPerSlipFamily(f,instance) + + !* Calculation of forest projections for edge dislocations + !* Interaction matrices + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_dislotwin_forestProjectionEdge(index_myFamily+j,index_otherFamily+k,instance) = & + abs(math_mul3x3(lattice_sn(:,sum(lattice_NslipSystem(1:f-1,phase))+j,phase), & + lattice_st(:,sum(lattice_NslipSystem(1:o-1,phase))+k,phase))) + plastic_dislotwin_interactionMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_dislotwin_interactionMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtransFamily + index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) + plastic_dislotwin_interactionMatrix_SlipTrans(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_SlipTrans(lattice_interactionSlipTrans( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo slipSystemsLoop + enddo slipFamiliesLoop + + !* Process twin related parameters ------------------------------------------------ + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(plastic_dislotwin_Ntwin(1:f-1_pInt,instance)) ! index in truncated twin system list + twinSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntwin(f,instance) + + !* Burgers vector, + ! nucleation rate prefactor, + ! and twin size + + plastic_dislotwin_burgersPerTwinSystem(index_myFamily+j,instance) = & + plastic_dislotwin_burgersPerTwinFamily(f,instance) + + plastic_dislotwin_Ndot0PerTwinSystem(index_myFamily+j,instance) = & + plastic_dislotwin_Ndot0PerTwinFamily(f,instance) + + plastic_dislotwin_twinsizePerTwinSystem(index_myFamily+j,instance) = & + plastic_dislotwin_twinsizePerTwinFamily(f,instance) + + !* Rotate twin elasticity matrices + index_otherFamily = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) ! index in full lattice twin list + do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt + do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt + plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) = & + plastic_dislotwin_Ctwin3333(l,m,n,o,index_myFamily+j,instance) + & + lattice_C3333(p,q,r,s,instance) * & + lattice_Qtwin(l,p,index_otherFamily+j,phase) * & + lattice_Qtwin(m,q,index_otherFamily+j,phase) * & + lattice_Qtwin(n,r,index_otherFamily+j,phase) * & + lattice_Qtwin(o,s,index_otherFamily+j,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo; enddo + plastic_dislotwin_Ctwin66(1:6,1:6,index_myFamily+j,instance) = & + math_Mandel3333to66(plastic_dislotwin_Ctwin3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) + + !* Interaction matrices + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_dislotwin_interactionMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_dislotwin_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_dislotwin_interactionMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo twinSystemsLoop + enddo twinFamiliesLoop + + !* Process transformation related parameters ------------------------------------------------ + transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily + index_myFamily = sum(plastic_dislotwin_Ntrans(1:f-1_pInt,instance)) ! index in truncated trans system list + transSystemsLoop: do j = 1_pInt,plastic_dislotwin_Ntrans(f,instance) + + !* Burgers vector, + ! nucleation rate prefactor, + ! and martensite size + + plastic_dislotwin_burgersPerTransSystem(index_myFamily+j,instance) = & + plastic_dislotwin_burgersPerTransFamily(f,instance) + + plastic_dislotwin_Ndot0PerTransSystem(index_myFamily+j,instance) = & + plastic_dislotwin_Ndot0PerTransFamily(f,instance) + + plastic_dislotwin_lamellarsizePerTransSystem(index_myFamily+j,instance) = & + plastic_dislotwin_lamellarsizePerTransFamily(f,instance) + + !* Rotate trans elasticity matrices + index_otherFamily = sum(lattice_NtransSystem(1:f-1_pInt,phase)) ! index in full lattice trans list + do l = 1_pInt,3_pInt; do m = 1_pInt,3_pInt; do n = 1_pInt,3_pInt; do o = 1_pInt,3_pInt + do p = 1_pInt,3_pInt; do q = 1_pInt,3_pInt; do r = 1_pInt,3_pInt; do s = 1_pInt,3_pInt + plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) = & + plastic_dislotwin_Ctrans3333(l,m,n,o,index_myFamily+j,instance) + & + lattice_trans_C3333(p,q,r,s,instance) * & + lattice_Qtrans(l,p,index_otherFamily+j,phase) * & + lattice_Qtrans(m,q,index_otherFamily+j,phase) * & + lattice_Qtrans(n,r,index_otherFamily+j,phase) * & + lattice_Qtrans(o,s,index_otherFamily+j,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo; enddo + plastic_dislotwin_Ctrans66(1:6,1:6,index_myFamily+j,instance) = & + math_Mandel3333to66(plastic_dislotwin_Ctrans3333(1:3,1:3,1:3,1:3,index_myFamily+j,instance)) + + !* Interaction matrices + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_dislotwin_interactionMatrix_TransSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TransSlip(lattice_interactionTransSlip( & + sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtransFamily + index_otherFamily = sum(plastic_dislotwin_Ntrans(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Ntrans(o,instance) ! loop over (active) systems in other family (trans) + plastic_dislotwin_interactionMatrix_TransTrans(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_dislotwin_interaction_TransTrans(lattice_interactionTransTrans( & + sum(lattice_NtransSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtransSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + !* Projection matrices for shear from slip systems to fault-band (twin) systems for strain-induced martensite nucleation + select case(trans_lattice_structure(phase)) + case (LATTICE_bcc_ID) + do o = 1_pInt,lattice_maxNtransFamily + index_otherFamily = sum(plastic_dislotwin_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_dislotwin_Nslip(o,instance) ! loop over (active) systems in other family (trans) + plastic_dislotwin_projectionMatrix_Trans(index_myFamily+j,index_otherFamily+k,instance) = & + lattice_projectionTrans( sum(lattice_NtransSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, phase) + enddo; enddo + end select + + enddo transSystemsLoop + enddo transFamiliesLoop + + startIndex=1_pInt + endIndex=ns + state(instance)%rhoEdge=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdge=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdge=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%rhoEdgeDip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%rhoEdgeDip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%rhoEdgeDip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%accshear_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%twinFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%twinFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%accshear_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%accshear_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%accshear_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%stressTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%stressTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%stressTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%strainTransFraction=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%strainTransFraction=>plasticState(phase)%state0(startIndex:endIndex,:) + dotState(instance)%strainTransFraction=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlipTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlipTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%invLambdaTwin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaTwin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%invLambdaSlipTrans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaSlipTrans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%invLambdaTrans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%invLambdaTrans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%mfp_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%mfp_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%mfp_trans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%mfp_trans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+ns + state(instance)%threshold_stress_slip=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_slip=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%threshold_stress_twin=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_twin=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%threshold_stress_trans=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%threshold_stress_trans=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nt + state(instance)%twinVolume=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%twinVolume=>plasticState(phase)%state0(startIndex:endIndex,:) + + startIndex=endIndex+1 + endIndex=endIndex+nr + state(instance)%martensiteVolume=>plasticState(phase)%state(startIndex:endIndex,:) + state0(instance)%martensiteVolume=>plasticState(phase)%state0(startIndex:endIndex,:) + + call plastic_dislotwin_stateInit(phase,instance) + call plastic_dislotwin_aTolState(phase,instance) + endif myPhase2 + + enddo initializeInstances +end subroutine plastic_dislotwin_init + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_stateInit(ph,instance) + use math, only: & + pi + use lattice, only: & + lattice_maxNslipFamily, & + lattice_mu + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + real(pReal), dimension(plasticState(ph)%sizeState) :: tempState + + integer(pInt) :: i,j,f,ns,nt,nr, index_myFamily + real(pReal), dimension(plastic_dislotwin_totalNslip(instance)) :: & + rhoEdge0, & + rhoEdgeDip0, & + invLambdaSlip0, & + MeanFreePathSlip0, & + tauSlipThreshold0 + real(pReal), dimension(plastic_dislotwin_totalNtwin(instance)) :: & + MeanFreePathTwin0,TwinVolume0 + real(pReal), dimension(plastic_dislotwin_totalNtrans(instance)) :: & + MeanFreePathTrans0,MartensiteVolume0 + tempState = 0.0_pReal + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables + do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(plastic_dislotwin_Nslip(1:f-1_pInt,instance)) ! index in truncated slip system list + rhoEdge0(index_myFamily+1_pInt: & + index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & + plastic_dislotwin_rhoEdge0(f,instance) + rhoEdgeDip0(index_myFamily+1_pInt: & + index_myFamily+plastic_dislotwin_Nslip(f,instance)) = & + plastic_dislotwin_rhoEdgeDip0(f,instance) + enddo + + tempState(1_pInt:ns) = rhoEdge0 + tempState(ns+1_pInt:2_pInt*ns) = rhoEdgeDip0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent slip microstructural variables + forall (i = 1_pInt:ns) & + invLambdaSlip0(i) = sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_forestProjectionEdge(1:ns,i,instance)))/ & + plastic_dislotwin_CLambdaSlipPerSlipSystem(i,instance) + tempState(3_pInt*ns+2_pInt*nt+2_pInt*nr+1:4_pInt*ns+2_pInt*nt+2_pInt*nr) = invLambdaSlip0 + + forall (i = 1_pInt:ns) & + MeanFreePathSlip0(i) = & + plastic_dislotwin_GrainSize(instance)/(1.0_pReal+invLambdaSlip0(i)*plastic_dislotwin_GrainSize(instance)) + tempState(6_pInt*ns+3_pInt*nt+3_pInt*nr+1:7_pInt*ns+3_pInt*nt+3_pInt*nr) = MeanFreePathSlip0 + + forall (i = 1_pInt:ns) & + tauSlipThreshold0(i) = & + lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(i,instance) * & + sqrt(dot_product((rhoEdge0+rhoEdgeDip0),plastic_dislotwin_interactionMatrix_SlipSlip(i,1:ns,instance))) + + tempState(7_pInt*ns+4_pInt*nt+4_pInt*nr+1:8_pInt*ns+4_pInt*nt+4_pInt*nr) = tauSlipThreshold0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent twin microstructural variables + forall (j = 1_pInt:nt) & + MeanFreePathTwin0(j) = plastic_dislotwin_GrainSize(instance) + tempState(7_pInt*ns+3_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+3_pInt*nr) = MeanFreePathTwin0 + + forall (j = 1_pInt:nt) & + TwinVolume0(j) = & + (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(j,instance)*MeanFreePathTwin0(j)**(2.0_pReal) + tempState(8_pInt*ns+5_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+5_pInt*nr) = TwinVolume0 + +!-------------------------------------------------------------------------------------------------- +! initialize dependent trans microstructural variables + forall (j = 1_pInt:nr) & + MeanFreePathTrans0(j) = plastic_dislotwin_GrainSize(instance) + tempState(7_pInt*ns+4_pInt*nt+3_pInt*nr+1_pInt:7_pInt*ns+4_pInt*nt+4_pInt*nr) = MeanFreePathTrans0 + + forall (j = 1_pInt:nr) & + MartensiteVolume0(j) = & + (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(j,instance)*MeanFreePathTrans0(j)**(2.0_pReal) + tempState(8_pInt*ns+6_pInt*nt+5_pInt*nr+1_pInt:8_pInt*ns+6_pInt*nt+6_pInt*nr) = MartensiteVolume0 + +plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) + +end subroutine plastic_dislotwin_stateInit + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + ph, & + instance ! number specifying the current instance of the plasticity + + integer(pInt) :: ns, nt, nr + + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + ! Tolerance state for dislocation densities + plasticState(ph)%aTolState(1_pInt: & + 2_pInt*ns) = plastic_dislotwin_aTolRho(instance) + + ! Tolerance state for accumulated shear due to slip + plasticState(ph)%aTolState(2_pInt*ns+1_pInt: & + 3_pInt*ns)=1.0e6_pReal + + ! Tolerance state for twin volume fraction + plasticState(ph)%aTolState(3_pInt*ns+1_pInt: & + 3_pInt*ns+nt) = plastic_dislotwin_aTolTwinFrac(instance) + + ! Tolerance state for accumulated shear due to twin + plasticState(ph)%aTolState(3_pInt*ns+nt+1_pInt: & + 3_pInt*ns+2_pInt*nt) = 1.0e6_pReal + +! Tolerance state for stress-assisted martensite volume fraction + plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+1_pInt: & + 3_pInt*ns+2_pInt*nt+nr) = plastic_dislotwin_aTolTransFrac(instance) + +! Tolerance state for strain-induced martensite volume fraction + plasticState(ph)%aTolState(3_pInt*ns+2_pInt*nt+nr+1_pInt: & + 3_pInt*ns+2_pInt*nt+2_pInt*nr) = plastic_dislotwin_aTolTransFrac(instance) + +end subroutine plastic_dislotwin_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenized elasticity matrix +!-------------------------------------------------------------------------------------------------- +function plastic_dislotwin_homogenizedC(ipc,ip,el) + use material, only: & + phase_plasticityInstance, & + phaseAt, phasememberAt + use lattice, only: & + lattice_C66 + + implicit none + real(pReal), dimension(6,6) :: & + plastic_dislotwin_homogenizedC + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,nr,i, & + ph, & + of + real(pReal) :: sumf, sumftr + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + + !* Homogenized elasticity matrix + plastic_dislotwin_homogenizedC = (1.0_pReal-sumf-sumftr)*lattice_C66(1:6,1:6,ph) + do i=1_pInt,nt + plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & + + state(instance)%twinFraction(i,of)*plastic_dislotwin_Ctwin66(1:6,1:6,i,instance) + enddo + do i=1_pInt,nr + plastic_dislotwin_homogenizedC = plastic_dislotwin_homogenizedC & + + (state(instance)%stressTransFraction(i,of) + state(instance)%strainTransFraction(i,of))*& + plastic_dislotwin_Ctrans66(1:6,1:6,i,instance) + enddo + + end function plastic_dislotwin_homogenizedC + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_microstructure(temperature,ipc,ip,el) + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + !plasticState, & !!!!delete + phaseAt, phasememberAt + use lattice, only: & + lattice_mu, & + lattice_nu + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + temperature !< temperature at IP + + integer(pInt) :: & + instance, & + ns,nt,nr,s,t,r, & + ph, & + of + real(pReal) :: & + sumf,sfe,x0,sumftr + real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: fOverStacksize + real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + ftransOverLamellarSize + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + + !* Stacking fault energy + sfe = plastic_dislotwin_SFE_0K(instance) + & + plastic_dislotwin_dSFE_dT(instance) * Temperature + + !* rescaled twin volume fraction for topology + forall (t = 1_pInt:nt) & + fOverStacksize(t) = & + state(instance)%twinFraction(t,of)/plastic_dislotwin_twinsizePerTwinSystem(t,instance) + + !* rescaled trans volume fraction for topology + forall (r = 1_pInt:nr) & + ftransOverLamellarSize(r) = & + (state(instance)%stressTransFraction(r,of)+state(instance)%strainTransFraction(r,of))/& + plastic_dislotwin_lamellarsizePerTransSystem(r,instance) + + !* 1/mean free distance between 2 forest dislocations seen by a moving dislocation + forall (s = 1_pInt:ns) & + state(instance)%invLambdaSlip(s,of) = & + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_dislotwin_forestProjectionEdge(1:ns,s,instance)))/ & + plastic_dislotwin_CLambdaSlipPerSlipSystem(s,instance) + + !* 1/mean free distance between 2 twin stacks from different systems seen by a moving dislocation + !$OMP CRITICAL (evilmatmul) + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = 0.0_pReal + if (nt > 0_pInt .and. ns > 0_pInt) & + state(instance)%invLambdaSlipTwin(1_pInt:ns,of) = & + matmul(plastic_dislotwin_interactionMatrix_SlipTwin(1:ns,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* 1/mean free distance between 2 twin stacks from different systems seen by a growing twin + !$OMP CRITICAL (evilmatmul) + if (nt > 0_pInt) & + state(instance)%invLambdaTwin(1_pInt:nt,of) = & + matmul(plastic_dislotwin_interactionMatrix_TwinTwin(1:nt,1:nt,instance),fOverStacksize(1:nt))/(1.0_pReal-sumf) + !$OMP END CRITICAL (evilmatmul) + + !* 1/mean free distance between 2 martensite lamellar from different systems seen by a moving dislocation + state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = 0.0_pReal + if (nr > 0_pInt .and. ns > 0_pInt) & + state(instance)%invLambdaSlipTrans(1_pInt:ns,of) = & + matmul(plastic_dislotwin_interactionMatrix_SlipTrans(1:ns,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) + + !* 1/mean free distance between 2 martensite stacks from different systems seen by a growing martensite (1/lambda_trans) + if (nr > 0_pInt) & + state(instance)%invLambdaTrans(1_pInt:nr,of) = & + matmul(plastic_dislotwin_interactionMatrix_TransTrans(1:nr,1:nr,instance),ftransOverLamellarSize(1:nr))/(1.0_pReal-sumftr) + + !* mean free path between 2 obstacles seen by a moving dislocation + do s = 1_pInt,ns + if ((nt > 0_pInt) .or. (nr > 0_pInt)) then + state(instance)%mfp_slip(s,of) = & + plastic_dislotwin_GrainSize(instance)/(1.0_pReal+plastic_dislotwin_GrainSize(instance)*& + (state(instance)%invLambdaSlip(s,of) + & + state(instance)%invLambdaSlipTwin(s,of) + & + state(instance)%invLambdaSlipTrans(s,of))) + else + state(instance)%mfp_slip(s,of) = & + plastic_dislotwin_GrainSize(instance)/& + (1.0_pReal+plastic_dislotwin_GrainSize(instance)*(state(instance)%invLambdaSlip(s,of))) !!!!!! correct? + endif + enddo + + !* mean free path between 2 obstacles seen by a growing twin + forall (t = 1_pInt:nt) & + state(instance)%mfp_twin(t,of) = & + plastic_dislotwin_Cmfptwin(instance)*plastic_dislotwin_GrainSize(instance)/& + (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(ph)%invLambdaTwin(t,of)) + + !* mean free path between 2 obstacles seen by a growing martensite + forall (r = 1_pInt:nr) & + state(instance)%mfp_trans(r,of) = & + plastic_dislotwin_Cmfptrans(instance)*plastic_dislotwin_GrainSize(instance)/& + (1.0_pReal+plastic_dislotwin_GrainSize(instance)*state(instance)%invLambdaTrans(r,of)) + + !* threshold stress for dislocation motion + forall (s = 1_pInt:ns) & + state(instance)%threshold_stress_slip(s,of) = & + lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(s,instance)*& + sqrt(dot_product((state(instance)%rhoEdge(1_pInt:ns,of)+state(instance)%rhoEdgeDip(1_pInt:ns,of)),& + plastic_dislotwin_interactionMatrix_SlipSlip(s,1:ns,instance))) + + !* threshold stress for growing twin + forall (t = 1_pInt:nt) & + state(instance)%threshold_stress_twin(t,of) = & + plastic_dislotwin_Cthresholdtwin(instance)* & + (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)) & + + 3.0_pReal*plastic_dislotwin_burgersPerTwinSystem(t,instance)*lattice_mu(ph)/& + (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(t,instance)) & + ) + + !* threshold stress for growing martensite + forall (r = 1_pInt:nr) & + state(instance)%threshold_stress_trans(r,of) = & + plastic_dislotwin_Cthresholdtrans(instance)* & + (sfe/(3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & + + 3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)*lattice_mu(ph)/& + (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(r,instance))& + + plastic_dislotwin_transStackHeight(instance)*plastic_dislotwin_deltaG(instance)/ & + (3.0_pReal*plastic_dislotwin_burgersPerTransSystem(r,instance)) & + ) + + !* final twin volume after growth + forall (t = 1_pInt:nt) & + state(instance)%twinVolume(t,of) = & + (pi/4.0_pReal)*plastic_dislotwin_twinsizePerTwinSystem(t,instance)*& + state(instance)%mfp_twin(t,of)**(2.0_pReal) + + !* final martensite volume after growth + forall (r = 1_pInt:nr) & + state(instance)%martensiteVolume(r,of) = & + (pi/4.0_pReal)*plastic_dislotwin_lamellarsizePerTransSystem(r,instance)*& + state(instance)%mfp_trans(r,of)**(2.0_pReal) + + !* equilibrium separation of partial dislocations (twin) + do t = 1_pInt,nt + x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)**(2.0_pReal)/& + (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) + plastic_dislotwin_tau_r_twin(t,instance)= & + lattice_mu(ph)*plastic_dislotwin_burgersPerTwinSystem(t,instance)/(2.0_pReal*pi)*& + (1/(x0+plastic_dislotwin_xc_twin(instance))+cos(pi/3.0_pReal)/x0) + enddo + + !* equilibrium separation of partial dislocations (trans) + do r = 1_pInt,nr + x0 = lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)**(2.0_pReal)/& + (sfe*8.0_pReal*pi)*(2.0_pReal+lattice_nu(ph))/(1.0_pReal-lattice_nu(ph)) + plastic_dislotwin_tau_r_trans(r,instance)= & + lattice_mu(ph)*plastic_dislotwin_burgersPerTransSystem(r,instance)/(2.0_pReal*pi)*& + (1/(x0+plastic_dislotwin_xc_trans(instance))+cos(pi/3.0_pReal)/x0) + enddo + +end subroutine plastic_dislotwin_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + math_Plain3333to99, & + math_Mandel6to33, & + math_Mandel33to6, & + math_spectralDecompositionSym, & + math_tensorproduct33, & + math_symmetric33, & + math_mul33x3 + use material, only: & + material_phase, & + phase_plasticityInstance, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_Strans, & + lattice_Strans_v, & + lattice_maxNslipFamily,& + lattice_maxNtwinFamily, & + lattice_maxNtransFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NtransSystem, & + lattice_shearTwin, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + integer(pInt), intent(in) :: ipc,ip,el + real(pReal), intent(in) :: Temperature + real(pReal), dimension(6), intent(in) :: Tstar_v + real(pReal), dimension(3,3), intent(out) :: Lp + real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 + + integer(pInt) :: instance,ph,of,ns,nt,nr,f,i,j,k,l,m,n,index_myFamily,s1,s2 + real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,StressRatio_r,BoltzmannRatio,DotGamma0,Ndot0_twin,stressRatio, & + Ndot0_trans,StressRatio_s + real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 + real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,dgdot_dtauslip,tau_slip + real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,dgdot_dtautwin,tau_twin + real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_trans,dgdot_dtautrans,tau_trans + real(pReal), dimension(6) :: gdot_sb,dgdot_dtausb,tau_sb + real(pReal), dimension(3,3) :: eigVectors, sb_Smatrix + real(pReal), dimension(3) :: eigValues, sb_s, sb_m + logical :: error + real(pReal), dimension(3,6), parameter :: & + sb_sComposition = & + reshape(real([& + 1, 0, 1, & + 1, 0,-1, & + 1, 1, 0, & + 1,-1, 0, & + 0, 1, 1, & + 0, 1,-1 & + ],pReal),[ 3,6]), & + sb_mComposition = & + reshape(real([& + 1, 0,-1, & + 1, 0,+1, & + 1,-1, 0, & + 1, 1, 0, & + 0, 1,-1, & + 0, 1, 1 & + ],pReal),[ 3,6]) + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Dislocation glide part + gdot_slip = 0.0_pReal + dgdot_dtauslip = 0.0_pReal + j = 0_pInt + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystemsLoop: do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on slip system + tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + + if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) + StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0 & + * exp(-BoltzmannRatio*(1-StressRatio_p) ** plastic_dislotwin_qPerSlipFamily(f,instance)) & + * sign(1.0_pReal,tau_slip(j)) + + !* Derivatives of shear rates + dgdot_dtauslip(j) = & + abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& + *plastic_dislotwin_qPerSlipFamily(f,instance)/& + (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) + endif + + !* Plastic velocity gradient for dislocation glide + Lp = Lp + gdot_slip(j)*lattice_Sslip(:,:,1,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& + lattice_Sslip(k,l,1,index_myFamily+i,ph)*& + lattice_Sslip(m,n,1,index_myFamily+i,ph) + enddo slipSystemsLoop + enddo slipFamiliesLoop + +!-------------------------------------------------------------------------------------------------- +! correct Lp and dLp_dTstar3333 for twinned and transformed fraction + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + Lp = Lp * (1.0_pReal - sumf - sumftr) + dLp_dTstar3333 = dLp_dTstar3333 * (1.0_pReal - sumf - sumftr) + +!-------------------------------------------------------------------------------------------------- +! Shear banding (shearband) part + if(abs(plastic_dislotwin_sbVelocity(instance)) > tiny(0.0_pReal) .and. & + abs(plastic_dislotwin_sbResistance(instance)) > tiny(0.0_pReal)) then + gdot_sb = 0.0_pReal + dgdot_dtausb = 0.0_pReal + call math_spectralDecompositionSym(math_Mandel6to33(Tstar_v),eigValues,eigVectors,error) + do j = 1_pInt,6_pInt + sb_s = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_sComposition(1:3,j)) + sb_m = 0.5_pReal*sqrt(2.0_pReal)*math_mul33x3(eigVectors,sb_mComposition(1:3,j)) + sb_Smatrix = math_tensorproduct33(sb_s,sb_m) + plastic_dislotwin_sbSv(1:6,j,ipc,ip,el) = math_Mandel33to6(math_symmetric33(sb_Smatrix)) + + !* Calculation of Lp + !* Resolved shear stress on shear banding system + tau_sb(j) = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) + + !* Stress ratios + if (abs(tau_sb(j)) < tol_math_check) then + StressRatio_p = 0.0_pReal + StressRatio_pminus1 = 0.0_pReal + else + StressRatio_p = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& + **plastic_dislotwin_pShearBand(instance) + StressRatio_pminus1 = (abs(tau_sb(j))/plastic_dislotwin_sbResistance(instance))& + **(plastic_dislotwin_pShearBand(instance)-1.0_pReal) + endif + + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = plastic_dislotwin_sbVelocity(instance) + + !* Shear rates due to shearband + gdot_sb(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qShearBand(instance))*sign(1.0_pReal,tau_sb(j)) + + !* Derivatives of shear rates + dgdot_dtausb(j) = & + ((abs(gdot_sb(j))*BoltzmannRatio*& + plastic_dislotwin_pShearBand(instance)*plastic_dislotwin_qShearBand(instance))/& + plastic_dislotwin_sbResistance(instance))*& + StressRatio_pminus1*(1_pInt-StressRatio_p)**(plastic_dislotwin_qShearBand(instance)-1.0_pReal) + + !* Plastic velocity gradient for shear banding + Lp = Lp + gdot_sb(j)*sb_Smatrix + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtausb(j)*& + sb_Smatrix(k,l)*& + sb_Smatrix(m,n) + enddo + end if + +!-------------------------------------------------------------------------------------------------- +! Mechanical twinning part + gdot_twin = 0.0_pReal + dgdot_dtautwin = 0.0_pReal + j = 0_pInt + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on twin system + tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_twin(j) > tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then + Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(ph)%rhoEdgeDip(s2,of))+& !!!!! correct? + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) + else + Ndot0_twin=0.0_pReal + end if + case default + Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) + end select + gdot_twin(j) = & + (1.0_pReal-sumf-sumftr)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) + dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_dislotwin_rPerTwinFamily(f,instance))/tau_twin(j))*StressRatio_r + endif + + !* Plastic velocity gradient for mechanical twinning + Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& + lattice_Stwin(k,l,index_myFamily+i,ph)*& + lattice_Stwin(m,n,index_myFamily+i,ph) + enddo twinSystemsLoop + enddo twinFamiliesLoop + + !* Phase transformation part + gdot_trans = 0.0_pReal + dgdot_dtautrans = 0.0_pReal + j = 0_pInt + transFamiliesLoop: do f = 1_pInt,lattice_maxNtransFamily + index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family + transSystemsLoop: do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) + j = j+1_pInt + + !* Resolved shear stress on transformation system + tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_trans(j) > tol_math_check) then + StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) + !* Shear rates and their derivatives due to transformation + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then + Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& !!!!! correct? + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) + else + Ndot0_trans=0.0_pReal + end if + case default + Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) + end select + gdot_trans(j) = & + (1.0_pReal-sumf-sumftr)*& + state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) + dgdot_dtautrans(j) = ((gdot_trans(j)*plastic_dislotwin_sPerTransFamily(f,instance))/tau_trans(j))*StressRatio_s + endif + + !* Plastic velocity gradient for phase transformation + Lp = Lp + gdot_trans(j)*lattice_Strans(:,:,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautrans(j)*& + lattice_Strans(k,l,index_myFamily+i,ph)*& + lattice_Strans(m,n,index_myFamily+i,ph) + + enddo transSystemsLoop + enddo transFamiliesLoop + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + +end subroutine plastic_dislotwin_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_dislotwin_dotState(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_Strans_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_maxNtransFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NtransSystem, & + lattice_sheartwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + lattice_fccTobcc_transNucleationTwinPair, & + lattice_fccTobcc_shearCritTrans, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: instance,ns,nt,nr,f,i,j,index_myFamily,s1,s2, & + ph, & + of + real(pReal) :: sumf,sumftr,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,& + EdgeDipMinDistance,AtomicVolume,VacancyDiffusion,StressRatio_r,Ndot0_twin,stressRatio,& + Ndot0_trans,StressRatio_s,EdgeDipDistance, ClimbVelocity,DotRhoEdgeDipClimb,DotRhoEdgeDipAnnihilation, & + DotRhoDipFormation,DotRhoMultiplication,DotRhoEdgeEdgeAnnihilation + real(pReal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,tau_slip + + real(pReal), dimension(plastic_dislotwin_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + tau_twin + real(pReal), dimension(plastic_dislotwin_totalNtrans(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + tau_trans + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + plasticState(instance)%dotState(:,of) = 0.0_pReal + + !* Total transformed volume fraction + sumftr = sum(state(instance)%stressTransFraction(1_pInt:nr,of)) + & + sum(state(instance)%strainTransFraction(1_pInt:nr,of)) + + !* Dislocation density evolution + gdot_slip = 0.0_pReal + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + !* Resolved shear stress on slip system + tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + + if((abs(tau_slip(j))-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio =((abs(tau_slip(j))- state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) + StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + plasticState(ph)%state(j, of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)*& + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)** & + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau_slip(j)) + endif + !* Multiplication + DotRhoMultiplication = abs(gdot_slip(j))/& + (plastic_dislotwin_burgersPerSlipSystem(j,instance)*state(instance)%mfp_slip(j,of)) + !* Dipole formation + EdgeDipMinDistance = & + plastic_dislotwin_CEdgeDipMinDistance(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance) + if (abs(tau_slip(j)) <= tiny(0.0_pReal)) then + DotRhoDipFormation = 0.0_pReal + else + EdgeDipDistance = & + (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(tau_slip(j))) + if (EdgeDipDistance>state(instance)%mfp_slip(j,of)) EdgeDipDistance=state(instance)%mfp_slip(j,of) + if (EdgeDipDistance tol_math_check) then + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/& + tau_twin(j))**plastic_dislotwin_rPerTwinFamily(f,instance) + !* Shear rates and their derivatives due to twin + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_twin(j) < plastic_dislotwin_tau_r_twin(j,instance)) then + Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_twin(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_twin(j,instance)-tau_twin(j)))) + else + Ndot0_twin=0.0_pReal + end if + case default + Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) + end select + dotState(instance)%twinFraction(j,of) = & + (1.0_pReal-sumf-sumftr)*& + state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) + !* Dotstate for accumulated shear due to twin + dotState(instance)%accshear_twin(j,of) = dotState(instance)%twinFraction(j,of) * & + lattice_sheartwin(index_myfamily+i,ph) + endif + enddo + enddo + + !* Transformation volume fraction evolution + j = 0_pInt + do f = 1_pInt,lattice_maxNtransFamily ! loop over all trans families + index_myFamily = sum(lattice_NtransSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Ntrans(f,instance) ! process each (active) trans system in family + j = j+1_pInt + + !* Resolved shear stress on transformation system + tau_trans(j) = dot_product(Tstar_v,lattice_Strans_v(:,index_myFamily+i,ph)) + + !* Stress ratios + if (tau_trans(j) > tol_math_check) then + StressRatio_s = (state(instance)%threshold_stress_trans(j,of)/& + tau_trans(j))**plastic_dislotwin_sPerTransFamily(f,instance) + !* Shear rates and their derivatives due to transformation + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau_trans(j) < plastic_dislotwin_tau_r_trans(j,instance)) then + Ndot0_trans=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_trans(instance)*plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_trans(j,instance)-tau_trans(j)))) + else + Ndot0_trans=0.0_pReal + end if + case default + Ndot0_trans=plastic_dislotwin_Ndot0PerTransSystem(j,instance) + end select + dotState(instance)%strainTransFraction(j,of) = & + (1.0_pReal-sumf-sumftr)*& + state(instance)%martensiteVolume(j,of)*Ndot0_trans*exp(-StressRatio_s) + !* Dotstate for accumulated shear due to transformation + !dotState(instance)%accshear_trans(j,of) = dotState(instance)%strainTransFraction(j,of) * & + ! lattice_sheartrans(index_myfamily+i,ph) + endif + + enddo + enddo + +end subroutine plastic_dislotwin_dotState + + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_dislotwin_postResults(Tstar_v,Temperature,ipc,ip,el) + use prec, only: & + tol_math_check + use math, only: & + pi, & + math_Mandel6to33, & + math_eigenvaluesSym33, & + math_spectralDecompositionSym33 + use material, only: & + material_phase, & + phase_plasticityInstance,& + phaseAt, phasememberAt + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_shearTwin, & + lattice_mu, & + lattice_structure, & + lattice_fcc_twinNucleationSlipPair, & + LATTICE_fcc_ID + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(plastic_dislotwin_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_dislotwin_postResults + integer(pInt) :: & + instance,& + ns,nt,nr,& + f,o,i,c,j,index_myFamily,& + s1,s2, & + ph, & + of + real(pReal) :: sumf,tau,StressRatio_p,StressRatio_pminus1,BoltzmannRatio,DotGamma0,StressRatio_r,Ndot0_twin,dgdot_dtauslip, & + stressRatio + real(preal), dimension(plastic_dislotwin_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip + real(pReal), dimension(3,3) :: eigVectors + real(pReal), dimension (3) :: eigValues + + !* Shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_dislotwin_totalNslip(instance) + nt = plastic_dislotwin_totalNtwin(instance) + nr = plastic_dislotwin_totalNtrans(instance) + + !* Total twin volume fraction + sumf = sum(state(instance)%twinFraction(1_pInt:nt,of)) ! safe for nt == 0 + + !* Required output + c = 0_pInt + plastic_dislotwin_postResults = 0.0_pReal + do o = 1_pInt,plastic_dislotwin_Noutput(instance) + select case(plastic_dislotwin_outputID(o,instance)) + + case (edge_density_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdge(1_pInt:ns,of) + c = c + ns + case (dipole_density_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = state(instance)%rhoEdgeDip(1_pInt:ns,of) + c = c + ns + case (shear_rate_slip_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt ! could be taken from state by now! + + !* Resolved shear stress on slip system + tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + !* Stress ratios + if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + stressRatio = ((abs(tau)-state(ph)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))) + StressRatio_p = stressRatio** plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = stressRatio**(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + plastic_dislotwin_postResults(c+j) = & + DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) + else + plastic_dislotwin_postResults(c+j) = 0.0_pReal + endif + + enddo ; enddo + c = c + ns + case (accumulated_shear_slip_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = & + state(instance)%accshear_slip(1_pInt:ns,of) + c = c + ns + case (mfp_slip_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) =& + state(instance)%mfp_slip(1_pInt:ns,of) + c = c + ns + case (resolved_stress_slip_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + plastic_dislotwin_postResults(c+j) =& + dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + enddo; enddo + c = c + ns + case (threshold_stress_slip_ID) + plastic_dislotwin_postResults(c+1_pInt:c+ns) = & + state(instance)%threshold_stress_slip(1_pInt:ns,of) + c = c + ns + case (edge_dipole_distance_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + plastic_dislotwin_postResults(c+j) = & + (3.0_pReal*lattice_mu(ph)*plastic_dislotwin_burgersPerSlipSystem(j,instance))/& + (16.0_pReal*pi*abs(dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)))) + plastic_dislotwin_postResults(c+j)=min(plastic_dislotwin_postResults(c+j),& + state(instance)%mfp_slip(j,of)) + ! plastic_dislotwin_postResults(c+j)=max(plastic_dislotwin_postResults(c+j),& + ! plasticState(ph)%state(4*ns+2*nt+2*nr+j, of)) + enddo; enddo + c = c + ns + case (resolved_stress_shearband_ID) + do j = 1_pInt,6_pInt ! loop over all shearband families + plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v, & + plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) + enddo + c = c + 6_pInt + case (shear_rate_shearband_ID) + do j = 1_pInt,6_pInt ! loop over all shearbands + !* Resolved shear stress on shearband system + tau = dot_product(Tstar_v,plastic_dislotwin_sbSv(1:6,j,ipc,ip,el)) + !* Stress ratios + if (abs(tau) < tol_math_check) then + StressRatio_p = 0.0_pReal + StressRatio_pminus1 = 0.0_pReal + else + StressRatio_p = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& + plastic_dislotwin_pShearBand(instance) + StressRatio_pminus1 = (abs(tau)/plastic_dislotwin_sbResistance(instance))**& + (plastic_dislotwin_pShearBand(instance)-1.0_pReal) + endif + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_sbQedge(instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = plastic_dislotwin_sbVelocity(instance) + ! Shear rate due to shear band + plastic_dislotwin_postResults(c+j) = & + DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**plastic_dislotwin_qShearBand(instance))*& + sign(1.0_pReal,tau) + enddo + c = c + 6_pInt + case (twin_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%twinFraction(1_pInt:nt,of) + c = c + nt + case (shear_rate_twin_ID) + if (nt > 0_pInt) then + + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + + !* Resolved shear stress on slip system + tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + !* Stress ratios + if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) + else + gdot_slip(j) = 0.0_pReal + endif + enddo;enddo + + j = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily ! loop over all twin families + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1,plastic_dislotwin_Ntwin(f,instance) ! process each (active) twin system in family + j = j + 1_pInt + + tau = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + + !* Shear rates due to twin + if ( tau > 0.0_pReal ) then + select case(lattice_structure(ph)) + case (LATTICE_fcc_ID) + s1=lattice_fcc_twinNucleationSlipPair(1,index_myFamily+i) + s2=lattice_fcc_twinNucleationSlipPair(2,index_myFamily+i) + if (tau < plastic_dislotwin_tau_r_twin(j,instance)) then + Ndot0_twin=(abs(gdot_slip(s1))*(state(instance)%rhoEdge(s2,of)+state(instance)%rhoEdgeDip(s2,of))+& + abs(gdot_slip(s2))*(state(instance)%rhoEdge(s1,of)+state(instance)%rhoEdgeDip(s1,of)))/& + (plastic_dislotwin_L0_twin(instance)*& + plastic_dislotwin_burgersPerSlipSystem(j,instance))*& + (1.0_pReal-exp(-plastic_dislotwin_VcrossSlip(instance)/(kB*Temperature)*& + (plastic_dislotwin_tau_r_twin(j,instance)-tau))) + else + Ndot0_twin=0.0_pReal + end if + case default + Ndot0_twin=plastic_dislotwin_Ndot0PerTwinSystem(j,instance) + end select + StressRatio_r = (state(instance)%threshold_stress_twin(j,of)/tau) & + **plastic_dislotwin_rPerTwinFamily(f,instance) + plastic_dislotwin_postResults(c+j) = & + (plastic_dislotwin_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& + state(instance)%twinVolume(j,of)*Ndot0_twin*exp(-StressRatio_r) + endif + + enddo ; enddo + endif + c = c + nt + case (accumulated_shear_twin_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%accshear_twin(1_pInt:nt,of) + c = c + nt + case (mfp_twin_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%mfp_twin(1_pInt:nt,of) + c = c + nt + case (resolved_stress_twin_ID) + if (nt > 0_pInt) then + j = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily ! loop over all slip families + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Ntwin(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + plastic_dislotwin_postResults(c+j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + enddo; enddo + endif + c = c + nt + case (threshold_stress_twin_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nt) = state(instance)%threshold_stress_twin(1_pInt:nt,of) + c = c + nt + case (stress_exponent_ID) + j = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily ! loop over all slip families + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_dislotwin_Nslip(f,instance) ! process each (active) slip system in family + j = j + 1_pInt + + !* Resolved shear stress on slip system + tau = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + if((abs(tau)-state(instance)%threshold_stress_slip(j,of)) > tol_math_check) then + !* Stress ratios + StressRatio_p = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **plastic_dislotwin_pPerSlipFamily(f,instance) + StressRatio_pminus1 = ((abs(tau)-state(instance)%threshold_stress_slip(j,of))/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance)))& + **(plastic_dislotwin_pPerSlipFamily(f,instance)-1.0_pReal) + !* Boltzmann ratio + BoltzmannRatio = plastic_dislotwin_QedgePerSlipSystem(j,instance)/(kB*Temperature) + !* Initial shear rates + DotGamma0 = & + state(instance)%rhoEdge(j,of)*plastic_dislotwin_burgersPerSlipSystem(j,instance)* & + plastic_dislotwin_v0PerSlipSystem(j,instance) + + !* Shear rates due to slip + gdot_slip(j) = DotGamma0*exp(-BoltzmannRatio*(1_pInt-StressRatio_p)**& + plastic_dislotwin_qPerSlipFamily(f,instance))*sign(1.0_pReal,tau) + + !* Derivatives of shear rates + dgdot_dtauslip = & + abs(gdot_slip(j))*BoltzmannRatio*plastic_dislotwin_pPerSlipFamily(f,instance)& + *plastic_dislotwin_qPerSlipFamily(f,instance)/& + (plastic_dislotwin_SolidSolutionStrength(instance)+& + plastic_dislotwin_tau_peierlsPerSlipFamily(f,instance))*& + StressRatio_pminus1*(1-StressRatio_p)**(plastic_dislotwin_qPerSlipFamily(f,instance)-1.0_pReal) + + else + gdot_slip(j) = 0.0_pReal + dgdot_dtauslip = 0.0_pReal + endif + + !* Stress exponent + if (abs(gdot_slip(j))<=tiny(0.0_pReal)) then + plastic_dislotwin_postResults(c+j) = 0.0_pReal + else + plastic_dislotwin_postResults(c+j) = (tau/gdot_slip(j))*dgdot_dtauslip + endif + enddo ; enddo + c = c + ns + case (sb_eigenvalues_ID) + plastic_dislotwin_postResults(c+1_pInt:c+3_pInt) = math_eigenvaluesSym33(math_Mandel6to33(Tstar_v)) + c = c + 3_pInt + case (sb_eigenvectors_ID) + call math_spectralDecompositionSym33(math_Mandel6to33(Tstar_v),eigValues,eigVectors) + plastic_dislotwin_postResults(c+1_pInt:c+9_pInt) = reshape(eigVectors,[9]) + c = c + 9_pInt + case (stress_trans_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nr) = & + state(instance)%stressTransFraction(1_pInt:nr,of) + c = c + nr + case (strain_trans_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nr) = & + state(instance)%strainTransFraction(1_pInt:nr,of) + c = c + nr + case (trans_fraction_ID) + plastic_dislotwin_postResults(c+1_pInt:c+nr) = & + state(instance)%stressTransFraction(1_pInt:nr,of) + & + state(instance)%strainTransFraction(1_pInt:nr,of) + c = c + nr + end select + enddo +end function plastic_dislotwin_postResults + +end module plastic_dislotwin \ No newline at end of file diff --git a/src/plastic_isotropic.f90 b/src/plastic_isotropic.f90 new file mode 100644 index 000000000..13481b9a7 --- /dev/null +++ b/src/plastic_isotropic.f90 @@ -0,0 +1,678 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for isotropic (ISOTROPIC) plasticity +!> @details Isotropic (ISOTROPIC) Plasticity which resembles the phenopowerlaw plasticity without +!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an +!! untextured polycrystal +!-------------------------------------------------------------------------------------------------- +module plastic_isotropic +#ifdef HDF + use hdf5, only: & + HID_T +#endif + + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_isotropic_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_isotropic_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_isotropic_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_isotropic_Noutput !< number of outputs per instance + + enum, bind(c) + enumerator :: undefined_ID, & + flowstress_ID, & + strainrate_ID + end enum + + type, private :: tParameters !< container type for internal constitutive parameters + integer(kind(undefined_ID)), allocatable, dimension(:) :: & + outputID + real(pReal) :: & + fTaylor, & + tau0, & + gdot0, & + n, & + h0, & + h0_slopeLnRate, & + tausat, & + a, & + aTolFlowstress, & + aTolShear , & + tausat_SinhFitA, & + tausat_SinhFitB, & + tausat_SinhFitC, & + tausat_SinhFitD + logical :: & + dilatation + end type + + type(tParameters), dimension(:), allocatable, private :: param !< containers of constitutive parameters (len Ninstance) + + type, private :: tIsotropicState !< internal state aliases + real(pReal), pointer, dimension(:) :: & ! scalars along NipcMyInstance + flowstress, & + accumulatedShear + end type + type, private :: tIsotropicAbsTol !< internal alias for abs tolerance in state + real(pReal), pointer :: & ! scalars along NipcMyInstance + flowstress, & + accumulatedShear + end type + type(tIsotropicState), allocatable, dimension(:), private :: & !< state aliases per instance + state, & + state0, & + dotState + type(tIsotropicAbsTol), allocatable, dimension(:), private :: & !< state aliases per instance + stateAbsTol + + public :: & + plastic_isotropic_init, & + plastic_isotropic_LpAndItsTangent, & + plastic_isotropic_LiAndItsTangent, & + plastic_isotropic_dotState, & + plastic_isotropic_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic + use numerics, only: & + analyticJaco, & + worldrank, & + numerics_integrator + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_ISOTROPIC_label, & + PLASTICITY_ISOTROPIC_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + + use lattice + + implicit none + integer(pInt), intent(in) :: fileUnit + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + o, & + phase, & + instance, & + maxNinstance, & + mySize, & + sizeDotState, & + sizeState, & + sizeDeltaState + character(len=65536) :: & + tag = '', & + outputtag = '', & + line = '', & + extmsg = '' + integer(pInt) :: NipcMyPhase + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_ISOTROPIC_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_ISOTROPIC_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_isotropic_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_isotropic_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) + allocate(plastic_isotropic_output(maxval(phase_Noutput), maxNinstance)) + plastic_isotropic_output = '' + allocate(plastic_isotropic_Noutput(maxNinstance), source=0_pInt) + + allocate(param(maxNinstance)) ! one container of parameters per instance + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + phase = phase + 1_pInt ! advance section counter + if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then + instance = phase_plasticityInstance(phase) + + endif + cycle ! skip to next line + endif + if (phase > 0_pInt) then; if (phase_plasticity(phase) == PLASTICITY_ISOTROPIC_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + allocate(param(instance)%outputID(phase_Noutput(phase))) ! allocate space for IDs of every requested output + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + extmsg = trim(tag)//' ('//PLASTICITY_ISOTROPIC_label//')' ! prepare error message identifier + + select case(tag) + case ('(output)') + outputtag = IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + select case(outputtag) + case ('flowstress') + plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt + param(instance)%outputID (plastic_isotropic_Noutput(instance)) = flowstress_ID + plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag + case ('strainrate') + plastic_isotropic_Noutput(instance) = plastic_isotropic_Noutput(instance) + 1_pInt + param(instance)%outputID (plastic_isotropic_Noutput(instance)) = strainrate_ID + plastic_isotropic_output(plastic_isotropic_Noutput(instance),instance) = outputtag + + end select + + case ('/dilatation/') + param(instance)%dilatation = .true. + + case ('tau0') + param(instance)%tau0 = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%tau0 < 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('gdot0') + param(instance)%gdot0 = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%gdot0 <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('n') + param(instance)%n = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%n <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('h0') + param(instance)%h0 = IO_floatValue(line,chunkPos,2_pInt) + + case ('h0_slope','slopelnrate') + param(instance)%h0_slopeLnRate = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat') + param(instance)%tausat = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%tausat <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('tausat_sinhfita') + param(instance)%tausat_SinhFitA = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat_sinhfitb') + param(instance)%tausat_SinhFitB = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat_sinhfitc') + param(instance)%tausat_SinhFitC = IO_floatValue(line,chunkPos,2_pInt) + + case ('tausat_sinhfitd') + param(instance)%tausat_SinhFitD = IO_floatValue(line,chunkPos,2_pInt) + + case ('a', 'w0') + param(instance)%a = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%a <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('taylorfactor') + param(instance)%fTaylor = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%fTaylor <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('atol_flowstress') + param(instance)%aTolFlowstress = IO_floatValue(line,chunkPos,2_pInt) + if (param(instance)%aTolFlowstress <= 0.0_pReal) call IO_error(211_pInt,ext_msg=extmsg) + + case ('atol_shear') + param(instance)%aTolShear = IO_floatValue(line,chunkPos,2_pInt) + + case default + + end select + endif; endif + enddo parsingFile + + allocate(state(maxNinstance)) ! internal state aliases + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + allocate(stateAbsTol(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop over every plasticity + myPhase: if (phase_plasticity(phase) == PLASTICITY_isotropic_ID) then ! isolate instances of own constitutive description + NipcMyPhase = count(material_phase == phase) ! number of own material points (including point components ipc) + instance = phase_plasticityInstance(phase) +!-------------------------------------------------------------------------------------------------- +! sanity checks + if (param(instance)%aTolShear <= 0.0_pReal) & + param(instance)%aTolShear = 1.0e-6_pReal ! default absolute tolerance 1e-6 + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) + select case(param(instance)%outputID(o)) + case(flowstress_ID,strainrate_ID) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_isotropic_sizePostResult(o,instance) = mySize + plastic_isotropic_sizePostResults(instance) = & + plastic_isotropic_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = 2_pInt ! flowstress, accumulated_shear + sizeDotState = sizeState ! both evolve + sizeDeltaState = 0_pInt ! no sudden jumps in state + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_isotropic_sizePostResults(instance) + plasticState(phase)%nSlip = 1 + plasticState(phase)%nTwin = 0 + plasticState(phase)%nTrans= 0 + allocate(plasticState(phase)%aTolState ( sizeState)) + + allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase),source=0.0_pReal) + + allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase),source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase),source=0.0_pReal) + +!-------------------------------------------------------------------------------------------------- +! globally required state aliases + plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NipcMyPhase) + plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NipcMyPhase) + +!-------------------------------------------------------------------------------------------------- +! locally defined state aliases + state(instance)%flowstress => plasticState(phase)%state (1,1:NipcMyPhase) + state0(instance)%flowstress => plasticState(phase)%state0 (1,1:NipcMyPhase) + dotState(instance)%flowstress => plasticState(phase)%dotState (1,1:NipcMyPhase) + stateAbsTol(instance)%flowstress => plasticState(phase)%aTolState(1) + + state(instance)%accumulatedShear => plasticState(phase)%state (2,1:NipcMyPhase) + state0(instance)%accumulatedShear => plasticState(phase)%state0 (2,1:NipcMyPhase) + dotState(instance)%accumulatedShear => plasticState(phase)%dotState (2,1:NipcMyPhase) + stateAbsTol(instance)%accumulatedShear => plasticState(phase)%aTolState(2) + +!-------------------------------------------------------------------------------------------------- +! init state + state0(instance)%flowstress = param(instance)%tau0 + state0(instance)%accumulatedShear = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! init absolute state tolerances + stateAbsTol(instance)%flowstress = param(instance)%aTolFlowstress + stateAbsTol(instance)%accumulatedShear = param(instance)%aTolShear + + endif myPhase + enddo initializeInstances + +end subroutine plastic_isotropic_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_e, & + debug_i, & + debug_g + use math, only: & + math_mul6x6, & + math_Mandel6to33, & + math_Plain3333to99, & + math_deviatoric33, & + math_mul33xx33, & + math_transpose33 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(3,3) :: & + Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal) :: & + gamma_dot, & !< strainrate + norm_Tstar_dev, & !< euclidean norm of Tstar_dev + squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev + integer(pInt) :: & + instance, of, & + k, l, m, n + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + + Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress + squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) + norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) + + if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero + Lp = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + else + gamma_dot = param(instance)%gdot0 & + * ( sqrt(1.5_pReal) * norm_Tstar_dev / param(instance)%fTaylor / state(instance)%flowstress(of) ) & + **param(instance)%n + + Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/param(instance)%fTaylor + + if (iand(debug_level(debug_constitutive), debug_levelExtensive) /= 0_pInt & + .and. ((el == debug_e .and. ip == debug_i .and. ipc == debug_g) & + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then + write(6,'(a,i8,1x,i2,1x,i3)') '<< CONST isotropic >> at el ip g ',el,ip,ipc + write(6,'(/,a,/,3(12x,3(f12.4,1x)/))') '<< CONST isotropic >> Tstar (dev) / MPa', & + math_transpose33(Tstar_dev_33(1:3,1:3))*1.0e-6_pReal + write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> norm Tstar / MPa', norm_Tstar_dev*1.0e-6_pReal + write(6,'(/,a,/,f12.5)') '<< CONST isotropic >> gdot', gamma_dot + end if +!-------------------------------------------------------------------------------------------------- +! Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & + Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal + forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & + dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal + dLp_dTstar99 = math_Plain3333to99(gamma_dot / param(instance)%fTaylor * & + dLp_dTstar_3333 / norm_Tstar_dev) + end if +end subroutine plastic_isotropic_LpAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_LiAndItsTangent(Li,dLi_dTstar_3333,Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6, & + math_Mandel6to33, & + math_Plain3333to99, & + math_spherical33, & + math_mul33xx33 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Li !< plastic velocity gradient + + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(3,3) :: & + Tstar_sph_33 !< sphiatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor + real(pReal), dimension(3,3,3,3), intent(out) :: & + dLi_dTstar_3333 !< derivative of Li with respect to Tstar as 4th order tensor + real(pReal) :: & + gamma_dot, & !< strainrate + norm_Tstar_sph, & !< euclidean norm of Tstar_sph + squarenorm_Tstar_sph !< square of the euclidean norm of Tstar_sph + integer(pInt) :: & + instance, of, & + k, l, m, n + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + + Tstar_sph_33 = math_spherical33(math_Mandel6to33(Tstar_v)) ! spherical part of 2nd Piola-Kirchhoff stress + squarenorm_Tstar_sph = math_mul33xx33(Tstar_sph_33,Tstar_sph_33) + norm_Tstar_sph = sqrt(squarenorm_Tstar_sph) + + if (param(instance)%dilatation) then + if (norm_Tstar_sph <= 0.0_pReal) then ! Tstar == 0 --> both Li and dLi_dTstar are zero + Li = 0.0_pReal + dLi_dTstar_3333 = 0.0_pReal + else + gamma_dot = param(instance)%gdot0 & + * (sqrt(1.5_pReal) * norm_Tstar_sph / param(instance)%fTaylor / state(instance)%flowstress(of) ) & + **param(instance)%n + + Li = Tstar_sph_33/norm_Tstar_sph * gamma_dot/param(instance)%fTaylor + + !-------------------------------------------------------------------------------------------------- + ! Calculation of the tangent of Li + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLi_dTstar_3333(k,l,m,n) = (param(instance)%n-1.0_pReal) * & + Tstar_sph_33(k,l)*Tstar_sph_33(m,n) / squarenorm_Tstar_sph + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLi_dTstar_3333(k,l,k,l) = dLi_dTstar_3333(k,l,k,l) + 1.0_pReal + + dLi_dTstar_3333 = gamma_dot / param(instance)%fTaylor * & + dLi_dTstar_3333 / norm_Tstar_sph + endif + endif + +end subroutine plastic_isotropic_LiAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_isotropic_dotState(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6) :: & + Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + gamma_dot, & !< strainrate + hardening, & !< hardening coefficient + saturation, & !< saturation flowstress + norm_Tstar_v !< euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of !< shortcut notation for offset position in state array + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + +!-------------------------------------------------------------------------------------------------- +! norm of (deviatoric) 2nd Piola-Kirchhoff stress + if (param(instance)%dilatation) then + norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) + else + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + end if +!-------------------------------------------------------------------------------------------------- +! strain rate + gamma_dot = param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & + / &!----------------------------------------------------------------------------------- + (param(instance)%fTaylor*state(instance)%flowstress(of) ))**param(instance)%n + +!-------------------------------------------------------------------------------------------------- +! hardening coefficient + if (abs(gamma_dot) > 1e-12_pReal) then + if (abs(param(instance)%tausat_SinhFitA) <= tiny(0.0_pReal)) then + saturation = param(instance)%tausat + else + saturation = ( param(instance)%tausat & + + ( log( ( gamma_dot / param(instance)%tausat_SinhFitA& + )**(1.0_pReal / param(instance)%tausat_SinhFitD)& + + sqrt( ( gamma_dot / param(instance)%tausat_SinhFitA & + )**(2.0_pReal / param(instance)%tausat_SinhFitD) & + + 1.0_pReal ) & + ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) + )**(1.0_pReal / param(instance)%tausat_SinhFitC) & + / ( param(instance)%tausat_SinhFitB & + * (gamma_dot / param(instance)%gdot0)**(1.0_pReal / param(instance)%n) & + ) & + ) + endif + hardening = ( param(instance)%h0 + param(instance)%h0_slopeLnRate * log(gamma_dot) ) & + * abs( 1.0_pReal - state(instance)%flowstress(of)/saturation )**param(instance)%a & + * sign(1.0_pReal, 1.0_pReal - state(instance)%flowstress(of)/saturation) + else + hardening = 0.0_pReal + endif + + dotState(instance)%flowstress (of) = hardening * gamma_dot + dotState(instance)%accumulatedShear(of) = gamma_dot + +end subroutine plastic_isotropic_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_isotropic_postResults(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(plastic_isotropic_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_isotropic_postResults + + real(pReal), dimension(6) :: & + Tstar_dev_v !< deviatoric 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + norm_Tstar_v ! euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of, & !< shortcut notation for offset position in state array + c, & + o + + of = phasememberAt(ipc,ip,el) ! phasememberAt should be tackled by material and be renamed to material_phasemember + instance = phase_plasticityInstance(phaseAt(ipc,ip,el)) ! "phaseAt" equivalent to "material_phase" !! + +!-------------------------------------------------------------------------------------------------- +! norm of (deviatoric) 2nd Piola-Kirchhoff stress + if (param(instance)%dilatation) then + norm_Tstar_v = sqrt(math_mul6x6(Tstar_v,Tstar_v)) + else + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_v = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + end if + + c = 0_pInt + plastic_isotropic_postResults = 0.0_pReal + + outputsLoop: do o = 1_pInt,plastic_isotropic_Noutput(instance) + select case(param(instance)%outputID(o)) + case (flowstress_ID) + plastic_isotropic_postResults(c+1_pInt) = state(instance)%flowstress(of) + c = c + 1_pInt + case (strainrate_ID) + plastic_isotropic_postResults(c+1_pInt) = & + param(instance)%gdot0 * ( sqrt(1.5_pReal) * norm_Tstar_v & + / &!---------------------------------------------------------------------------------- + (param(instance)%fTaylor * state(instance)%flowstress(of)) ) ** param(instance)%n + c = c + 1_pInt + end select + enddo outputsLoop + +end function plastic_isotropic_postResults + + +end module plastic_isotropic diff --git a/src/plastic_j2.f90 b/src/plastic_j2.f90 new file mode 100644 index 000000000..89c022cc9 --- /dev/null +++ b/src/plastic_j2.f90 @@ -0,0 +1,579 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for isotropic (J2) plasticity +!> @details Isotropic (J2) Plasticity which resembles the phenopowerlaw plasticity without +!! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an +!! untextured polycrystal +!-------------------------------------------------------------------------------------------------- +module plastic_j2 +#ifdef HDF + use hdf5, only: & + HID_T +#endif + + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_j2_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_j2_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_j2_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_j2_Noutput !< number of outputs per instance + real(pReal), dimension(:), allocatable, private :: & + plastic_j2_fTaylor, & !< Taylor factor + plastic_j2_tau0, & !< initial plastic stress + plastic_j2_gdot0, & !< reference velocity + plastic_j2_n, & !< Visco-plastic parameter +!-------------------------------------------------------------------------------------------------- +! h0 as function of h0 = A + B log (gammadot) + plastic_j2_h0, & + plastic_j2_h0_slopeLnRate, & + plastic_j2_tausat, & !< final plastic stress + plastic_j2_a, & + plastic_j2_aTolResistance, & + plastic_j2_aTolShear, & +!-------------------------------------------------------------------------------------------------- +! tausat += (asinh((gammadot / SinhFitA)**(1 / SinhFitD)))**(1 / SinhFitC) / (SinhFitB * (gammadot / gammadot0)**(1/n)) + plastic_j2_tausat_SinhFitA, & !< fitting parameter for normalized strain rate vs. stress function + plastic_j2_tausat_SinhFitB, & !< fitting parameter for normalized strain rate vs. stress function + plastic_j2_tausat_SinhFitC, & !< fitting parameter for normalized strain rate vs. stress function + plastic_j2_tausat_SinhFitD !< fitting parameter for normalized strain rate vs. stress function + + enum, bind(c) + enumerator :: undefined_ID, & + flowstress_ID, & + strainrate_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_j2_outputID !< ID of each post result output + + +#ifdef HDF + type plastic_j2_tOutput + real(pReal), dimension(:), allocatable, private :: & + flowstress, & + strainrate + logical :: flowstressActive = .false., strainrateActive = .false. ! if we can write the output block wise, this is not needed anymore because we can do an if(allocated(xxx)) + end type plastic_j2_tOutput + type(plastic_j2_tOutput), allocatable, dimension(:) :: plastic_j2_Output2 +integer(HID_T), allocatable, dimension(:) :: outID +#endif + + + public :: & + plastic_j2_init, & + plastic_j2_LpAndItsTangent, & + plastic_j2_dotState, & + plastic_j2_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_j2_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) +#ifdef HDF + use hdf5 +#endif + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic + use numerics, only: & + analyticJaco, & + worldrank, & + numerics_integrator + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_error, & + IO_timeStamp, & +#ifdef HDF + tempResults, & + HDF5_addGroup, & + HDF5_addScalarDataset,& +#endif + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_J2_label, & + PLASTICITY_J2_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + + use lattice + + implicit none + integer(pInt), intent(in) :: fileUnit + + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + o, & + phase, & + maxNinstance, & + instance, & + mySize, & + sizeDotState, & + sizeState, & + sizeDeltaState + character(len=65536) :: & + tag = '', & + line = '' + integer(pInt) :: NofMyPhase + +#ifdef HDF + character(len=5) :: & + str1 + integer(HID_T) :: ID,ID2,ID4 +#endif + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_J2_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_J2_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + +#ifdef HDF + allocate(plastic_j2_Output2(maxNinstance)) + allocate(outID(maxNinstance)) +#endif + + allocate(plastic_j2_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_j2_sizePostResult(maxval(phase_Noutput), maxNinstance),source=0_pInt) + allocate(plastic_j2_output(maxval(phase_Noutput), maxNinstance)) + plastic_j2_output = '' + allocate(plastic_j2_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_j2_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_j2_fTaylor(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tau0(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_gdot0(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_n(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_h0(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_h0_slopeLnRate(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_a(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_aTolResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_aTolShear (maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitA(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitB(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitC(maxNinstance), source=0.0_pReal) + allocate(plastic_j2_tausat_SinhFitD(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + phase = phase + 1_pInt ! advance section counter + if (phase_plasticity(phase) == PLASTICITY_J2_ID) then + instance = phase_plasticityInstance(phase) +#ifdef HDF + outID(instance)=HDF5_addGroup(str1,tempResults) +#endif + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_J2_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('flowstress') + plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt + plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = flowstress_ID + plastic_j2_output(plastic_j2_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) +#ifdef HDF + call HDF5_addScalarDataset(outID(instance),myConstituents,'flowstress','MPa') + allocate(plastic_j2_Output2(instance)%flowstress(myConstituents)) + plastic_j2_Output2(instance)%flowstressActive = .true. +#endif + case ('strainrate') + plastic_j2_Noutput(instance) = plastic_j2_Noutput(instance) + 1_pInt + plastic_j2_outputID(plastic_j2_Noutput(instance),instance) = strainrate_ID + plastic_j2_output(plastic_j2_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) +#ifdef HDF + call HDF5_addScalarDataset(outID(instance),myConstituents,'strainrate','1/s') + allocate(plastic_j2_Output2(instance)%strainrate(myConstituents)) + plastic_j2_Output2(instance)%strainrateActive = .true. +#endif + case default + + end select + case ('tau0') + plastic_j2_tau0(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_tau0(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('gdot0') + plastic_j2_gdot0(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_gdot0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('n') + plastic_j2_n(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_n(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('h0') + plastic_j2_h0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_slope','slopelnrate') + plastic_j2_h0_slopeLnRate(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat') + plastic_j2_tausat(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_tausat(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('tausat_sinhfita') + plastic_j2_tausat_SinhFitA(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat_sinhfitb') + plastic_j2_tausat_SinhFitB(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat_sinhfitc') + plastic_j2_tausat_SinhFitC(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('tausat_sinhfitd') + plastic_j2_tausat_SinhFitD(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('a', 'w0') + plastic_j2_a(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_a(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('taylorfactor') + plastic_j2_fTaylor(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_fTaylor(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('atol_resistance') + plastic_j2_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + if (plastic_j2_aTolResistance(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_J2_label//')') + case ('atol_shear') + plastic_j2_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case default + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_j2_ID) then + NofMyPhase=count(material_phase==phase) + instance = phase_plasticityInstance(phase) +!-------------------------------------------------------------------------------------------------- +! sanity checks + if (plastic_j2_aTolShear(instance) <= 0.0_pReal) & + plastic_j2_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) + select case(plastic_j2_outputID(o,instance)) + case(flowstress_ID,strainrate_ID) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_j2_sizePostResult(o,instance) = mySize + plastic_j2_sizePostResults(instance) = & + plastic_j2_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = 2_pInt + sizeDotState = sizeState + sizeDeltaState = 0_pInt + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_j2_sizePostResults(instance) + plasticState(phase)%nSlip = 1 + plasticState(phase)%nTwin = 0 + plasticState(phase)%nTrans= 0 + allocate(plasticState(phase)%aTolState ( sizeState)) + plasticState(phase)%aTolState(1) = plastic_j2_aTolResistance(instance) + plasticState(phase)%aTolState(2) = plastic_j2_aTolShear(instance) + allocate(plasticState(phase)%state0 ( sizeState,NofMyPhase)) + plasticState(phase)%state0(1,1:NofMyPhase) = plastic_j2_tau0(instance) + plasticState(phase)%state0(2,1:NofMyPhase) = 0.0_pReal + allocate(plasticState(phase)%partionedState0 ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase),source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase),source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + plasticState(phase)%slipRate => plasticState(phase)%dotState(2:2,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => plasticState(phase)%state (2:2,1:NofMyPhase) + endif myPhase + enddo initializeInstances + +end subroutine plastic_j2_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_j2_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6, & + math_Mandel6to33, & + math_Plain3333to99, & + math_deviatoric33, & + math_mul33xx33 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + real(pReal), dimension(3,3) :: & + Tstar_dev_33 !< deviatoric part of the 2nd Piola Kirchhoff stress tensor as 2nd order tensor + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar_3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal) :: & + gamma_dot, & !< strainrate + norm_Tstar_dev, & !< euclidean norm of Tstar_dev + squarenorm_Tstar_dev !< square of the euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & + k, l, m, n + + instance = phase_plasticityInstance(material_phase(ipc,ip,el)) + Tstar_dev_33 = math_deviatoric33(math_Mandel6to33(Tstar_v)) ! deviatoric part of 2nd Piola-Kirchhoff stress + squarenorm_Tstar_dev = math_mul33xx33(Tstar_dev_33,Tstar_dev_33) + norm_Tstar_dev = sqrt(squarenorm_Tstar_dev) + + if (norm_Tstar_dev <= 0.0_pReal) then ! Tstar == 0 --> both Lp and dLp_dTstar are zero + Lp = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + else + gamma_dot = plastic_j2_gdot0(instance) & + * (sqrt(1.5_pReal) * norm_Tstar_dev / (plastic_j2_fTaylor(instance) * & + plasticState(phaseAt(ipc,ip,el))%state(1,phasememberAt(ipc,ip,el)))) & + **plastic_j2_n(instance) + + Lp = Tstar_dev_33/norm_Tstar_dev * gamma_dot/plastic_j2_fTaylor(instance) + +!-------------------------------------------------------------------------------------------------- +! Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,m,n) = (plastic_j2_n(instance)-1.0_pReal) * & + Tstar_dev_33(k,l)*Tstar_dev_33(m,n) / squarenorm_Tstar_dev + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar_3333(k,l,k,l) = dLp_dTstar_3333(k,l,k,l) + 1.0_pReal + forall (k=1_pInt:3_pInt,m=1_pInt:3_pInt) & + dLp_dTstar_3333(k,k,m,m) = dLp_dTstar_3333(k,k,m,m) - 1.0_pReal/3.0_pReal + dLp_dTstar99 = math_Plain3333to99(gamma_dot / plastic_j2_fTaylor(instance) * & + dLp_dTstar_3333 / norm_Tstar_dev) + end if +end subroutine plastic_j2_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_j2_dotState(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + material_phase, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6) :: & + Tstar_dev_v !< deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + gamma_dot, & !< strainrate + hardening, & !< hardening coefficient + saturation, & !< saturation resistance + norm_Tstar_dev !< euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of, & !< shortcut notation for offset position in state array + ph !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(material_phase(ipc,ip,el)) + +!-------------------------------------------------------------------------------------------------- +! norm of deviatoric part of 2nd Piola-Kirchhoff stress + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + +!-------------------------------------------------------------------------------------------------- +! strain rate + gamma_dot = plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & + / &!----------------------------------------------------------------------------------- + (plastic_j2_fTaylor(instance)*plasticState(ph)%state(1,of)) )**plastic_j2_n(instance) + +!-------------------------------------------------------------------------------------------------- +! hardening coefficient + if (abs(gamma_dot) > 1e-12_pReal) then + if (abs(plastic_j2_tausat_SinhFitA(instance)) <= tiny(0.0_pReal)) then + saturation = plastic_j2_tausat(instance) + else + saturation = ( plastic_j2_tausat(instance) & + + ( log( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance)& + )**(1.0_pReal / plastic_j2_tausat_SinhFitD(instance))& + + sqrt( ( gamma_dot / plastic_j2_tausat_SinhFitA(instance) & + )**(2.0_pReal / plastic_j2_tausat_SinhFitD(instance)) & + + 1.0_pReal ) & + ) & ! asinh(K) = ln(K + sqrt(K^2 +1)) + )**(1.0_pReal / plastic_j2_tausat_SinhFitC(instance)) & + / ( plastic_j2_tausat_SinhFitB(instance) & + * (gamma_dot / plastic_j2_gdot0(instance))**(1.0_pReal / plastic_j2_n(instance)) & + ) & + ) + endif + hardening = ( plastic_j2_h0(instance) + plastic_j2_h0_slopeLnRate(instance) * log(gamma_dot) ) & + * abs( 1.0_pReal - plasticState(ph)%state(1,of)/saturation )**plastic_j2_a(instance) & + * sign(1.0_pReal, 1.0_pReal - plasticState(ph)%state(1,of)/saturation) + else + hardening = 0.0_pReal + endif + + plasticState(ph)%dotState(1,of) = hardening * gamma_dot + plasticState(ph)%dotState(2,of) = gamma_dot + +end subroutine plastic_j2_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_j2_postResults(Tstar_v,ipc,ip,el) + use math, only: & + math_mul6x6 + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(plastic_j2_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_j2_postResults + + real(pReal), dimension(6) :: & + Tstar_dev_v ! deviatoric part of the 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal) :: & + norm_Tstar_dev ! euclidean norm of Tstar_dev + integer(pInt) :: & + instance, & !< instance of my instance (unique number of my constitutive model) + of, & !< shortcut notation for offset position in state array + ph, & !< shortcut notation for phase ID (unique number of all phases, regardless of constitutive model) + c, & + o + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(material_phase(ipc,ip,el)) + +!-------------------------------------------------------------------------------------------------- +! calculate deviatoric part of 2nd Piola-Kirchhoff stress and its norm + Tstar_dev_v(1:3) = Tstar_v(1:3) - sum(Tstar_v(1:3))/3.0_pReal + Tstar_dev_v(4:6) = Tstar_v(4:6) + norm_Tstar_dev = sqrt(math_mul6x6(Tstar_dev_v,Tstar_dev_v)) + + c = 0_pInt + plastic_j2_postResults = 0.0_pReal + + outputsLoop: do o = 1_pInt,plastic_j2_Noutput(instance) + select case(plastic_j2_outputID(o,instance)) + case (flowstress_ID) + plastic_j2_postResults(c+1_pInt) = plasticState(ph)%state(1,of) + c = c + 1_pInt + case (strainrate_ID) + plastic_j2_postResults(c+1_pInt) = & + plastic_j2_gdot0(instance) * ( sqrt(1.5_pReal) * norm_Tstar_dev & + / &!---------------------------------------------------------------------------------- + (plastic_j2_fTaylor(instance) * plasticState(ph)%state(1,of)) ) ** plastic_j2_n(instance) + c = c + 1_pInt + end select + enddo outputsLoop + +end function plastic_j2_postResults + + +end module plastic_j2 diff --git a/src/plastic_none.f90 b/src/plastic_none.f90 new file mode 100644 index 000000000..f624a80a2 --- /dev/null +++ b/src/plastic_none.f90 @@ -0,0 +1,109 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for purely elastic material +!-------------------------------------------------------------------------------------------------- +module plastic_none + use prec, only: & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_none_sizePostResults + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_none_sizePostResult !< size of each post result output + + public :: & + plastic_none_init + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_none_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelBasic + use IO, only: & + IO_timeStamp + use numerics, only: & + worldrank, & + numerics_integrator + use material, only: & + phase_plasticity, & + PLASTICITY_NONE_label, & + material_phase, & + plasticState, & + PLASTICITY_none_ID + + implicit none + + integer(pInt) :: & + maxNinstance, & + phase, & + NofMyPhase, & + sizeState, & + sizeDotState, & + sizeDeltaState + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONE_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_none_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + if (phase_plasticity(phase) == PLASTICITY_none_ID) then + NofMyPhase=count(material_phase==phase) + + sizeState = 0_pInt + plasticState(phase)%sizeState = sizeState + sizeDotState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + sizeDeltaState = 0_pInt + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = 0_pInt + plasticState(phase)%nSlip = 0_pInt + plasticState(phase)%nTwin = 0_pInt + plasticState(phase)%nTrans = 0_pInt + allocate(plasticState(phase)%aTolState (sizeState)) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase)) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase)) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase)) + allocate(plasticState(phase)%state (sizeState,NofMyPhase)) + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase)) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase)) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase)) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase)) + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase)) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NofMyPhase)) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase)) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase)) + endif + enddo initializeInstances + + allocate(plastic_none_sizePostResults(maxNinstance), source=0_pInt) + +end subroutine plastic_none_init + +end module plastic_none diff --git a/src/plastic_nonlocal.f90 b/src/plastic_nonlocal.f90 new file mode 100644 index 000000000..1922c08e2 --- /dev/null +++ b/src/plastic_nonlocal.f90 @@ -0,0 +1,4031 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Christoph Kords, 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 +!> @brief material subroutine for plasticity including dislocation flux +!-------------------------------------------------------------------------------------------------- +module plastic_nonlocal + use prec, only: & + pReal, & + pInt + + implicit none + private + character(len=22), dimension(11), parameter, private :: & + BASICSTATES = ['rhoSglEdgePosMobile ', & + 'rhoSglEdgeNegMobile ', & + 'rhoSglScrewPosMobile ', & + 'rhoSglScrewNegMobile ', & + 'rhoSglEdgePosImmobile ', & + 'rhoSglEdgeNegImmobile ', & + 'rhoSglScrewPosImmobile', & + 'rhoSglScrewNegImmobile', & + 'rhoDipEdge ', & + 'rhoDipScrew ', & + 'accumulatedshear ' ] !< list of "basic" microstructural state variables that are independent from other state variables + + character(len=16), dimension(3), parameter, private :: & + DEPENDENTSTATES = ['rhoForest ', & + 'tauThreshold ', & + 'tauBack ' ] !< list of microstructural state variables that depend on other state variables + + character(len=20), dimension(6), parameter, private :: & + OTHERSTATES = ['velocityEdgePos ', & + 'velocityEdgeNeg ', & + 'velocityScrewPos ', & + 'velocityScrewNeg ', & + 'maxDipoleHeightEdge ', & + 'maxDipoleHeightScrew' ] !< list of other dependent state variables that are not updated by microstructure + + real(pReal), parameter, private :: & + KB = 1.38e-23_pReal !< Physical parameter, Boltzmann constant in J/Kelvin + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_nonlocal_sizeDotState, & !< number of dotStates = number of basic state variables + plastic_nonlocal_sizeDependentState, & !< number of dependent state variables + plastic_nonlocal_sizeState, & !< total number of state variables + plastic_nonlocal_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_nonlocal_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_nonlocal_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_nonlocal_Noutput !< number of outputs per instance of this plasticity + + integer(pInt), dimension(:,:), allocatable, private :: & + iGamma, & !< state indices for accumulated shear + iRhoF, & !< state indices for forest density + iTauF, & !< state indices for critical resolved shear stress + iTauB !< state indices for backstress + integer(pInt), dimension(:,:,:), allocatable, private :: & + iRhoU, & !< state indices for unblocked density + iRhoB, & !< state indices for blocked density + iRhoD, & !< state indices for dipole density + iV, & !< state indices for dislcation velocities + iD !< state indices for stable dipole height + + integer(pInt), dimension(:), allocatable, public, protected :: & + totalNslip !< total number of active slip systems for each instance + + integer(pInt), dimension(:,:), allocatable, private :: & + Nslip, & !< number of active slip systems for each family and instance + slipFamily, & !< lookup table relating active slip system to slip family for each instance + slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance + colinearSystem !< colinear system to the active slip system (only valid for fcc!) + + real(pReal), dimension(:), allocatable, private :: & + atomicVolume, & !< atomic volume + Dsd0, & !< prefactor for self-diffusion coefficient + selfDiffusionEnergy, & !< activation enthalpy for diffusion + aTolRho, & !< absolute tolerance for dislocation density in state integration + aTolShear, & !< absolute tolerance for accumulated shear in state integration + significantRho, & !< density considered significant + significantN, & !< number of dislocations considered significant + cutoffRadius, & !< cutoff radius for dislocation stress + doublekinkwidth, & !< width of a doubkle kink in multiples of the burgers vector length b + solidSolutionEnergy, & !< activation energy for solid solution in J + solidSolutionSize, & !< solid solution obstacle size in multiples of the burgers vector length + solidSolutionConcentration, & !< concentration of solid solution in atomic parts + pParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) + qParam, & !< parameter for kinetic law (Kocks,Argon,Ashby) + viscosity, & !< viscosity for dislocation glide in Pa s + fattack, & !< attack frequency in Hz + rhoSglScatter, & !< standard deviation of scatter in initial dislocation density + surfaceTransmissivity, & !< transmissivity at free surface + grainboundaryTransmissivity, & !< transmissivity at grain boundary (identified by different texture) + CFLfactor, & !< safety factor for CFL flux condition + fEdgeMultiplication, & !< factor that determines how much edge dislocations contribute to multiplication (0...1) + rhoSglRandom, & + rhoSglRandomBinning, & + linetensionEffect, & + edgeJogFactor + + real(pReal), dimension(:,:), allocatable, private :: & + rhoSglEdgePos0, & !< initial edge_pos dislocation density per slip system for each family and instance + rhoSglEdgeNeg0, & !< initial edge_neg dislocation density per slip system for each family and instance + rhoSglScrewPos0, & !< initial screw_pos dislocation density per slip system for each family and instance + rhoSglScrewNeg0, & !< initial screw_neg dislocation density per slip system for each family and instance + rhoDipEdge0, & !< initial edge dipole dislocation density per slip system for each family and instance + rhoDipScrew0, & !< initial screw dipole dislocation density per slip system for each family and instance + lambda0PerSlipFamily, & !< mean free path prefactor for each family and instance + lambda0, & !< mean free path prefactor for each slip system and instance + burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each family and instance + burgers, & !< absolute length of burgers vector [m] for each slip system and instance + interactionSlipSlip !< coefficients for slip-slip interaction for each interaction type and instance + + real(pReal), dimension(:,:,:), allocatable, private :: & + minDipoleHeightPerSlipFamily, & !< minimum stable edge/screw dipole height for each family and instance + minDipoleHeight, & !< minimum stable edge/screw dipole height for each slip system and instance + peierlsStressPerSlipFamily, & !< Peierls stress (edge and screw) + peierlsStress, & !< Peierls stress (edge and screw) + forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance + forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance + interactionMatrixSlipSlip !< interaction matrix of the different slip systems for each instance + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + lattice2slip, & !< orthogonal transformation matrix from lattice coordinate system to slip coordinate system (passive rotation !!!) + rhoDotEdgeJogsOutput, & + sourceProbability + + real(pReal), dimension(:,:,:,:,:), allocatable, private :: & + rhoDotFluxOutput, & + rhoDotMultiplicationOutput, & + rhoDotSingle2DipoleGlideOutput, & + rhoDotAthermalAnnihilationOutput, & + rhoDotThermalAnnihilationOutput, & + nonSchmidProjection !< combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) + + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + compatibility !< slip system compatibility between me and my neighbors + + real(pReal), dimension(:,:), allocatable, private :: & + nonSchmidCoeff + + logical, dimension(:), allocatable, private :: & + shortRangeStressCorrection, & !< flag indicating the use of the short range stress correction by a excess density gradient term + probabilisticMultiplication + + enum, bind(c) + enumerator :: undefined_ID, & + rho_ID, & + delta_ID, & + rho_edge_ID, & + rho_screw_ID, & + rho_sgl_ID, & + delta_sgl_ID, & + rho_sgl_edge_ID, & + rho_sgl_edge_pos_ID, & + rho_sgl_edge_neg_ID, & + rho_sgl_screw_ID, & + rho_sgl_screw_pos_ID, & + rho_sgl_screw_neg_ID, & + rho_sgl_mobile_ID, & + rho_sgl_edge_mobile_ID, & + rho_sgl_edge_pos_mobile_ID, & + rho_sgl_edge_neg_mobile_ID, & + rho_sgl_screw_mobile_ID, & + rho_sgl_screw_pos_mobile_ID, & + rho_sgl_screw_neg_mobile_ID, & + rho_sgl_immobile_ID, & + rho_sgl_edge_immobile_ID, & + rho_sgl_edge_pos_immobile_ID, & + rho_sgl_edge_neg_immobile_ID, & + rho_sgl_screw_immobile_ID, & + rho_sgl_screw_pos_immobile_ID, & + rho_sgl_screw_neg_immobile_ID, & + rho_dip_ID, & + delta_dip_ID, & + rho_dip_edge_ID, & + rho_dip_screw_ID, & + excess_rho_ID, & + excess_rho_edge_ID, & + excess_rho_screw_ID, & + rho_forest_ID, & + shearrate_ID, & + resolvedstress_ID, & + resolvedstress_external_ID, & + resolvedstress_back_ID, & + resistance_ID, & + rho_dot_ID, & + rho_dot_sgl_ID, & + rho_dot_sgl_mobile_ID, & + rho_dot_dip_ID, & + rho_dot_gen_ID, & + rho_dot_gen_edge_ID, & + rho_dot_gen_screw_ID, & + rho_dot_sgl2dip_ID, & + rho_dot_sgl2dip_edge_ID, & + rho_dot_sgl2dip_screw_ID, & + rho_dot_ann_ath_ID, & + rho_dot_ann_the_ID, & + rho_dot_ann_the_edge_ID, & + rho_dot_ann_the_screw_ID, & + rho_dot_edgejogs_ID, & + rho_dot_flux_ID, & + rho_dot_flux_mobile_ID, & + rho_dot_flux_edge_ID, & + rho_dot_flux_screw_ID, & + velocity_edge_pos_ID, & + velocity_edge_neg_ID, & + velocity_screw_pos_ID, & + velocity_screw_neg_ID, & + slipdirectionx_ID, & + slipdirectiony_ID, & + slipdirectionz_ID, & + slipnormalx_ID, & + slipnormaly_ID, & + slipnormalz_ID, & + fluxdensity_edge_posx_ID, & + fluxdensity_edge_posy_ID, & + fluxdensity_edge_posz_ID, & + fluxdensity_edge_negx_ID, & + fluxdensity_edge_negy_ID, & + fluxdensity_edge_negz_ID, & + fluxdensity_screw_posx_ID, & + fluxdensity_screw_posy_ID, & + fluxdensity_screw_posz_ID, & + fluxdensity_screw_negx_ID, & + fluxdensity_screw_negy_ID, & + fluxdensity_screw_negz_ID, & + maximumdipoleheight_edge_ID, & + maximumdipoleheight_screw_ID, & + accumulatedshear_ID, & + dislocationstress_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_nonlocal_outputID !< ID of each post result output + + public :: & + plastic_nonlocal_init, & + plastic_nonlocal_stateInit, & + plastic_nonlocal_aTolState, & + plastic_nonlocal_microstructure, & + plastic_nonlocal_LpAndItsTangent, & + plastic_nonlocal_dotState, & + plastic_nonlocal_deltaState, & + plastic_nonlocal_updateCompatibility, & + plastic_nonlocal_postResults + + private :: & + plastic_nonlocal_kinetics, & + plastic_nonlocal_dislocationstress + + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_init(fileUnit) +use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) +use math, only: math_Mandel3333to66, & + math_Voigt66to3333, & + math_mul3x3, & + math_transpose33 +use IO, only: IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF +use debug, only: debug_level, & + debug_constitutive, & + debug_levelBasic +use mesh, only: mesh_NcpElems, & + mesh_maxNips, & + mesh_maxNipNeighbors +use material, only: phase_plasticity, & + homogenization_maxNgrains, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_NONLOCAL_label, & + PLASTICITY_NONLOCAL_ID, & + plasticState, & + MATERIAL_partPhase ,& + material_phase +use lattice +use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + +implicit none +integer(pInt), intent(in) :: fileUnit + +!*** local variables +integer(pInt), allocatable, dimension(:) :: chunkPos +integer(pInt) :: phase, & + maxNinstances, & + maxTotalNslip, & + f, & ! index of my slip family + instance, & ! index of my instance of this plasticity + l, & + ns, & ! short notation for total number of active slip systems for the current instance + o, & ! index of my output + s, & ! index of my slip system + s1, & ! index of my slip system + s2, & ! index of my slip system + it, & ! index of my interaction type + t, & ! index of dislocation type + c, & ! index of dislocation character + Nchunks_SlipSlip = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, & + Nchunks_nonSchmid = 0_pInt, & + mySize = 0_pInt ! to suppress warnings, safe as init is called only once + character(len=65536) :: & + tag = '', & + line = '' + + integer(pInt) :: sizeState, sizeDotState,sizeDependentState, sizeDeltaState + + + integer(pInt) :: NofMyPhase + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONLOCAL_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) + if (maxNinstances == 0) return ! we don't have to do anything if there's no instance for this constitutive law + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstances + +!*** memory allocation for global variables + +allocate(plastic_nonlocal_sizeDotState(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizeDependentState(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizeState(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizePostResults(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_sizePostResult(maxval(phase_Noutput), maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_Noutput(maxNinstances), source=0_pInt) +allocate(plastic_nonlocal_output(maxval(phase_Noutput), maxNinstances)) + plastic_nonlocal_output = '' +allocate(plastic_nonlocal_outputID(maxval(phase_Noutput), maxNinstances), source=undefined_ID) +allocate(Nslip(lattice_maxNslipFamily,maxNinstances), source=0_pInt) +allocate(slipFamily(lattice_maxNslip,maxNinstances), source=0_pInt) +allocate(slipSystemLattice(lattice_maxNslip,maxNinstances), source=0_pInt) +allocate(totalNslip(maxNinstances), source=0_pInt) +allocate(atomicVolume(maxNinstances), source=0.0_pReal) +allocate(Dsd0(maxNinstances), source=-1.0_pReal) +allocate(selfDiffusionEnergy(maxNinstances), source=0.0_pReal) +allocate(aTolRho(maxNinstances), source=0.0_pReal) +allocate(aTolShear(maxNinstances), source=0.0_pReal) +allocate(significantRho(maxNinstances), source=0.0_pReal) +allocate(significantN(maxNinstances), source=0.0_pReal) +allocate(cutoffRadius(maxNinstances), source=-1.0_pReal) +allocate(doublekinkwidth(maxNinstances), source=0.0_pReal) +allocate(solidSolutionEnergy(maxNinstances), source=0.0_pReal) +allocate(solidSolutionSize(maxNinstances), source=0.0_pReal) +allocate(solidSolutionConcentration(maxNinstances), source=0.0_pReal) +allocate(pParam(maxNinstances), source=1.0_pReal) +allocate(qParam(maxNinstances), source=1.0_pReal) +allocate(viscosity(maxNinstances), source=0.0_pReal) +allocate(fattack(maxNinstances), source=0.0_pReal) +allocate(rhoSglScatter(maxNinstances), source=0.0_pReal) +allocate(rhoSglRandom(maxNinstances), source=0.0_pReal) +allocate(rhoSglRandomBinning(maxNinstances), source=1.0_pReal) +allocate(surfaceTransmissivity(maxNinstances), source=1.0_pReal) +allocate(grainboundaryTransmissivity(maxNinstances), source=-1.0_pReal) +allocate(CFLfactor(maxNinstances), source=2.0_pReal) +allocate(fEdgeMultiplication(maxNinstances), source=0.0_pReal) +allocate(linetensionEffect(maxNinstances), source=0.0_pReal) +allocate(edgeJogFactor(maxNinstances), source=1.0_pReal) +allocate(shortRangeStressCorrection(maxNinstances), source=.false.) +allocate(probabilisticMultiplication(maxNinstances), source=.false.) + +allocate(rhoSglEdgePos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoSglEdgeNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoSglScrewPos0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoSglScrewNeg0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoDipEdge0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(rhoDipScrew0(lattice_maxNslipFamily,maxNinstances), source=-1.0_pReal) +allocate(burgersPerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) +allocate(lambda0PerSlipFamily(lattice_maxNslipFamily,maxNinstances), source=0.0_pReal) +allocate(interactionSlipSlip(lattice_maxNinteraction,maxNinstances), source=0.0_pReal) +allocate(minDipoleHeightPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=-1.0_pReal) +allocate(peierlsStressPerSlipFamily(lattice_maxNslipFamily,2,maxNinstances), source=0.0_pReal) +allocate(nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstances), source=0.0_pReal) + + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through phases of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_SlipSlip = maxval(lattice_InteractionSlipSlip(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + endif + cycle + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then ! one of my phases. do not short-circuit here (.and. with next if statement). It's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('rho') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('delta') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('delta_sgl') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_sgl_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_pos_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_neg_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_pos_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_neg_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_pos_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_pos_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_edge_neg_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_edge_neg_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_pos_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_pos_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_sgl_screw_neg_immobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_sgl_screw_neg_immobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('delta_dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = delta_dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dip_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dip_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dip_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('excess_rho') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('excess_rho_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('excess_rho_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = excess_rho_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_forest') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_forest_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = shearrate_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_external') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_external_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_back') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resolvedstress_back_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = resistance_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_gen') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_gen_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_gen_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_gen_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl2dip') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl2dip_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_sgl2dip_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_sgl2dip_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_ath') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_ath_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_the') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_the_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_ann_the_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_ann_the_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_edgejogs') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_edgejogs_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux_mobile') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_mobile_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rho_dot_flux_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = rho_dot_flux_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_edge_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_edge_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_edge_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_screw_pos') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_pos_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_screw_neg') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = velocity_screw_neg_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipdirection.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipdirection.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectiony_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipdirection.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipdirectionz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipnormal.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipnormal.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormaly_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('slipnormal.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = slipnormalz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_pos.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_pos.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_pos.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_posz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_neg.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_neg.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_edge_neg.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_edge_negz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_pos.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_pos.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_pos.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_posz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_neg.x') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negx_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_neg.y') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negy_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('fluxdensity_screw_neg.z') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = fluxdensity_screw_negz_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('maximumdipoleheight_edge') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_edge_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('maximumdipoleheight_screw') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = maximumdipoleheight_screw_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear','accumulated_shear') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = accumulatedshear_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('dislocationstress') + plastic_nonlocal_Noutput(instance) = plastic_nonlocal_Noutput(instance) + 1_pInt + plastic_nonlocal_outputID(plastic_nonlocal_Noutput(instance),instance) = dislocationstress_ID + plastic_nonlocal_output(plastic_nonlocal_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + case ('nslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do f = 1_pInt, Nchunks_SlipFamilies + Nslip(f,instance) = IO_intValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosgledgepos0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglEdgePos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosgledgeneg0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglEdgeNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosglscrewpos0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglScrewPos0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhosglscrewneg0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoSglScrewNeg0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhodipedge0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoDipEdge0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('rhodipscrew0') + do f = 1_pInt, Nchunks_SlipFamilies + rhoDipScrew0(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('lambda0') + do f = 1_pInt, Nchunks_SlipFamilies + lambda0PerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case ('burgers') + do f = 1_pInt, Nchunks_SlipFamilies + burgersPerSlipFamily(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('cutoffradius','r') + cutoffRadius(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('minimumdipoleheightedge','ddipminedge') + do f = 1_pInt, Nchunks_SlipFamilies + minDipoleHeightPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('minimumdipoleheightscrew','ddipminscrew') + do f = 1_pInt, Nchunks_SlipFamilies + minDipoleHeightPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('atomicvolume') + atomicVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('selfdiffusionprefactor','dsd0') + Dsd0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('selfdiffusionenergy','qsd') + selfDiffusionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('atol_rho','atol_density','absolutetolerancedensity','absolutetolerance_density') + aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('atol_shear','atol_plasticshear','atol_accumulatedshear','absolutetoleranceshear','absolutetolerance_shear') + aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('significantrho','significant_rho','significantdensity','significant_density') + significantRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('significantn','significant_n','significantdislocations','significant_dislcations') + significantN(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('interaction_slipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_LABEL//')') + do it = 1_pInt,Nchunks_SlipSlip + interactionSlipSlip(it,instance) = IO_floatValue(line,chunkPos,1_pInt+it) + enddo + case('linetension','linetensioneffect','linetension_effect') + linetensionEffect(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('edgejog','edgejogs','edgejogeffect','edgejog_effect') + edgeJogFactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('peierlsstressedge','peierlsstress_edge') + do f = 1_pInt, Nchunks_SlipFamilies + peierlsStressPerSlipFamily(f,1_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('peierlsstressscrew','peierlsstress_screw') + do f = 1_pInt, Nchunks_SlipFamilies + peierlsStressPerSlipFamily(f,2_pInt,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('doublekinkwidth') + doublekinkwidth(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('solidsolutionenergy') + solidSolutionEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('solidsolutionsize') + solidSolutionSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('solidsolutionconcentration') + solidSolutionConcentration(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('p') + pParam(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('q') + qParam(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('viscosity','glideviscosity') + viscosity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('attackfrequency','fattack') + fattack(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('rhosglscatter') + rhoSglScatter(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('rhosglrandom') + rhoSglRandom(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('rhosglrandombinning') + rhoSglRandomBinning(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('surfacetransmissivity') + surfaceTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('grainboundarytransmissivity') + grainboundaryTransmissivity(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('cflfactor') + CFLfactor(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('fedgemultiplication','edgemultiplicationfactor','edgemultiplication') + fEdgeMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) + case('shortrangestresscorrection') + shortRangeStressCorrection(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_NONLOCAL_label//')') + do f = 1_pInt,Nchunks_nonSchmid + nonSchmidCoeff(f,instance) = IO_floatValue(line,chunkPos,1_pInt+f) + enddo + case('probabilisticmultiplication','randomsources','randommultiplication','discretesources') + probabilisticMultiplication(instance) = IO_floatValue(line,chunkPos,2_pInt) > 0.0_pReal + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then + instance = phase_plasticityInstance(phase) + if (sum(Nslip(:,instance)) <= 0_pInt) & + call IO_error(211_pInt,ext_msg='Nslip ('//PLASTICITY_NONLOCAL_label//')') + do o = 1_pInt,maxval(phase_Noutput) + if(len(plastic_nonlocal_output(o,instance)) > 64_pInt) & + call IO_error(666_pInt) + enddo + do f = 1_pInt,lattice_maxNslipFamily + if (Nslip(f,instance) > 0_pInt) then + if (rhoSglEdgePos0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglEdgePos0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglEdgeNeg0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglEdgeNeg0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglScrewPos0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglScrewPos0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglScrewNeg0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglScrewNeg0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoDipEdge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoDipEdge0 ('//PLASTICITY_NONLOCAL_label//')') + if (rhoDipScrew0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoDipScrew0 ('//PLASTICITY_NONLOCAL_label//')') + if (burgersPerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='Burgers ('//PLASTICITY_NONLOCAL_label//')') + if (lambda0PerSlipFamily(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='lambda0 ('//PLASTICITY_NONLOCAL_label//')') + if (minDipoleHeightPerSlipFamily(f,1,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='minimumDipoleHeightEdge ('//PLASTICITY_NONLOCAL_label//')') + if (minDipoleHeightPerSlipFamily(f,2,instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='minimumDipoleHeightScrew ('//PLASTICITY_NONLOCAL_label//')') + if (peierlsStressPerSlipFamily(f,1,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='peierlsStressEdge ('//PLASTICITY_NONLOCAL_label//')') + if (peierlsStressPerSlipFamily(f,2,instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='peierlsStressScrew ('//PLASTICITY_NONLOCAL_label//')') + endif + enddo + if (any(interactionSlipSlip(1:maxval(lattice_interactionSlipSlip(:,:,phase)),instance) < 0.0_pReal)) & + call IO_error(211_pInt,ext_msg='interaction_SlipSlip ('//PLASTICITY_NONLOCAL_label//')') + if (linetensionEffect(instance) < 0.0_pReal .or. linetensionEffect(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='linetension ('//PLASTICITY_NONLOCAL_label//')') + if (edgeJogFactor(instance) < 0.0_pReal .or. edgeJogFactor(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='edgejog ('//PLASTICITY_NONLOCAL_label//')') + if (cutoffRadius(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='r ('//PLASTICITY_NONLOCAL_label//')') + if (atomicVolume(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='atomicVolume ('//PLASTICITY_NONLOCAL_label//')') + if (Dsd0(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='selfDiffusionPrefactor ('//PLASTICITY_NONLOCAL_label//')') + if (selfDiffusionEnergy(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='selfDiffusionEnergy ('//PLASTICITY_NONLOCAL_label//')') + if (aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='aTol_rho ('//PLASTICITY_NONLOCAL_label//')') + if (aTolShear(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='aTol_shear ('//PLASTICITY_NONLOCAL_label//')') + if (significantRho(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='significantRho ('//PLASTICITY_NONLOCAL_label//')') + if (significantN(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='significantN ('//PLASTICITY_NONLOCAL_label//')') + if (doublekinkwidth(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='doublekinkwidth ('//PLASTICITY_NONLOCAL_label//')') + if (solidSolutionEnergy(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='solidSolutionEnergy ('//PLASTICITY_NONLOCAL_label//')') + if (solidSolutionSize(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='solidSolutionSize ('//PLASTICITY_NONLOCAL_label//')') + if (solidSolutionConcentration(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='solidSolutionConcentration ('//PLASTICITY_NONLOCAL_label//')') + if (pParam(instance) <= 0.0_pReal .or. pParam(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='p ('//PLASTICITY_NONLOCAL_label//')') + if (qParam(instance) < 1.0_pReal .or. qParam(instance) > 2.0_pReal) & + call IO_error(211_pInt,ext_msg='q ('//PLASTICITY_NONLOCAL_label//')') + if (viscosity(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='viscosity ('//PLASTICITY_NONLOCAL_label//')') + if (fattack(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='attackFrequency ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglScatter(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglScatter ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglRandom(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglRandom ('//PLASTICITY_NONLOCAL_label//')') + if (rhoSglRandomBinning(instance) <= 0.0_pReal) & + call IO_error(211_pInt,ext_msg='rhoSglRandomBinning ('//PLASTICITY_NONLOCAL_label//')') + if (surfaceTransmissivity(instance) < 0.0_pReal .or. surfaceTransmissivity(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='surfaceTransmissivity ('//PLASTICITY_NONLOCAL_label//')') + if (grainboundaryTransmissivity(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='grainboundaryTransmissivity ('//PLASTICITY_NONLOCAL_label//')') + if (CFLfactor(instance) < 0.0_pReal) & + call IO_error(211_pInt,ext_msg='CFLfactor ('//PLASTICITY_NONLOCAL_label//')') + if (fEdgeMultiplication(instance) < 0.0_pReal .or. fEdgeMultiplication(instance) > 1.0_pReal) & + call IO_error(211_pInt,ext_msg='edgemultiplicationfactor ('//PLASTICITY_NONLOCAL_label//')') + + + !*** determine total number of active slip systems + Nslip(1:lattice_maxNslipFamily,instance) = min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase), & + Nslip(1:lattice_maxNslipFamily,instance) ) ! we can't use more slip systems per family than specified in lattice + totalNslip(instance) = sum(Nslip(1:lattice_maxNslipFamily,instance)) + endif myPhase +enddo sanityChecks + + +!*** allocation of variables whose size depends on the total number of active slip systems + +maxTotalNslip = maxval(totalNslip) + +allocate(iRhoU(maxTotalNslip,4,maxNinstances), source=0_pInt) +allocate(iRhoB(maxTotalNslip,4,maxNinstances), source=0_pInt) +allocate(iRhoD(maxTotalNslip,2,maxNinstances), source=0_pInt) +allocate(iV(maxTotalNslip,4,maxNinstances), source=0_pInt) +allocate(iD(maxTotalNslip,2,maxNinstances), source=0_pInt) +allocate(iGamma(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(iRhoF(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(iTauF(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(iTauB(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(burgers(maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(lambda0(maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(minDipoleHeight(maxTotalNslip,2,maxNinstances), source=-1.0_pReal) +allocate(forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(lattice2slip(1:3, 1:3, maxTotalNslip,maxNinstances), source=0.0_pReal) +allocate(sourceProbability(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=2.0_pReal) + +allocate(rhoDotFluxOutput(maxTotalNslip,8,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotMultiplicationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotSingle2DipoleGlideOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotAthermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotThermalAnnihilationOutput(maxTotalNslip,2,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(rhoDotEdgeJogsOutput(maxTotalNslip,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) + +allocate(compatibility(2,maxTotalNslip,maxTotalNslip,mesh_maxNipNeighbors,mesh_maxNips,mesh_NcpElems), & + source=0.0_pReal) +allocate(peierlsStress(maxTotalNslip,2,maxNinstances), source=0.0_pReal) +allocate(colinearSystem(maxTotalNslip,maxNinstances), source=0_pInt) +allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + NofMyPhase=count(material_phase==phase) + myPhase2: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID .and. NofMyPhase/=0) then + instance = phase_plasticityInstance(phase) + !*** Inverse lookup of my slip system family and the slip system in lattice + + l = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily + do s = 1_pInt,Nslip(f,instance) + l = l + 1_pInt + slipFamily(l,instance) = f + slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt, phase)) + s + enddo; enddo + + + !*** determine size of state array + + ns = totalNslip(instance) + + sizeDotState = int(size(BASICSTATES),pInt) * ns + sizeDependentState = int(size(DEPENDENTSTATES),pInt) * ns + sizeState = sizeDotState + sizeDependentState & + + int(size(OTHERSTATES),pInt) * ns + sizeDeltaState = sizeDotState + + !*** determine indices to state array + + l = 0_pInt + do t = 1_pInt,4_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iRhoU(s,t,instance) = l + enddo + enddo + do t = 1_pInt,4_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iRhoB(s,t,instance) = l + enddo + enddo + do c = 1_pInt,2_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iRhoD(s,c,instance) = l + enddo + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iGamma(s,instance) = l + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iRhoF(s,instance) = l + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iTauF(s,instance) = l + enddo + do s = 1_pInt,ns + l = l + 1_pInt + iTauB(s,instance) = l + enddo + do t = 1_pInt,4_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iV(s,t,instance) = l + enddo + enddo + do c = 1_pInt,2_pInt + do s = 1_pInt,ns + l = l + 1_pInt + iD(s,c,instance) = l + enddo + enddo + if (iD(ns,2,instance) /= sizeState) & ! check if last index is equal to size of state + call IO_error(0_pInt, ext_msg = 'state indices not properly set ('//PLASTICITY_NONLOCAL_label//')') + + + !*** determine size of postResults array + + outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) + select case(plastic_nonlocal_outputID(o,instance)) + case( rho_ID, & + delta_ID, & + rho_edge_ID, & + rho_screw_ID, & + rho_sgl_ID, & + delta_sgl_ID, & + rho_sgl_edge_ID, & + rho_sgl_edge_pos_ID, & + rho_sgl_edge_neg_ID, & + rho_sgl_screw_ID, & + rho_sgl_screw_pos_ID, & + rho_sgl_screw_neg_ID, & + rho_sgl_mobile_ID, & + rho_sgl_edge_mobile_ID, & + rho_sgl_edge_pos_mobile_ID, & + rho_sgl_edge_neg_mobile_ID, & + rho_sgl_screw_mobile_ID, & + rho_sgl_screw_pos_mobile_ID, & + rho_sgl_screw_neg_mobile_ID, & + rho_sgl_immobile_ID, & + rho_sgl_edge_immobile_ID, & + rho_sgl_edge_pos_immobile_ID, & + rho_sgl_edge_neg_immobile_ID, & + rho_sgl_screw_immobile_ID, & + rho_sgl_screw_pos_immobile_ID, & + rho_sgl_screw_neg_immobile_ID, & + rho_dip_ID, & + delta_dip_ID, & + rho_dip_edge_ID, & + rho_dip_screw_ID, & + excess_rho_ID, & + excess_rho_edge_ID, & + excess_rho_screw_ID, & + rho_forest_ID, & + shearrate_ID, & + resolvedstress_ID, & + resolvedstress_external_ID, & + resolvedstress_back_ID, & + resistance_ID, & + rho_dot_ID, & + rho_dot_sgl_ID, & + rho_dot_sgl_mobile_ID, & + rho_dot_dip_ID, & + rho_dot_gen_ID, & + rho_dot_gen_edge_ID, & + rho_dot_gen_screw_ID, & + rho_dot_sgl2dip_ID, & + rho_dot_sgl2dip_edge_ID, & + rho_dot_sgl2dip_screw_ID, & + rho_dot_ann_ath_ID, & + rho_dot_ann_the_ID, & + rho_dot_ann_the_edge_ID, & + rho_dot_ann_the_screw_ID, & + rho_dot_edgejogs_ID, & + rho_dot_flux_ID, & + rho_dot_flux_mobile_ID, & + rho_dot_flux_edge_ID, & + rho_dot_flux_screw_ID, & + velocity_edge_pos_ID, & + velocity_edge_neg_ID, & + velocity_screw_pos_ID, & + velocity_screw_neg_ID, & + slipdirectionx_ID, & + slipdirectiony_ID, & + slipdirectionz_ID, & + slipnormalx_ID, & + slipnormaly_ID, & + slipnormalz_ID, & + fluxdensity_edge_posx_ID, & + fluxdensity_edge_posy_ID, & + fluxdensity_edge_posz_ID, & + fluxdensity_edge_negx_ID, & + fluxdensity_edge_negy_ID, & + fluxdensity_edge_negz_ID, & + fluxdensity_screw_posx_ID, & + fluxdensity_screw_posy_ID, & + fluxdensity_screw_posz_ID, & + fluxdensity_screw_negx_ID, & + fluxdensity_screw_negy_ID, & + fluxdensity_screw_negz_ID, & + maximumdipoleheight_edge_ID, & + maximumdipoleheight_screw_ID, & + accumulatedshear_ID ) + mySize = totalNslip(instance) + case(dislocationstress_ID) + mySize = 6_pInt + case default + end select + + if (mySize > 0_pInt) then ! any meaningful output found + plastic_nonlocal_sizePostResult(o,instance) = mySize + plastic_nonlocal_sizePostResults(instance) = plastic_nonlocal_sizePostResults(instance) + mySize + endif + enddo outputsLoop + + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_nonlocal_sizePostResults(instance) + plasticState(phase)%nonlocal = .true. + plasticState(phase)%nSlip = totalNslip(instance) + plasticState(phase)%nTwin = 0_pInt + plasticState(phase)%nTrans= 0_pInt + allocate(plasticState(phase)%aTolState (sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) + + do s1 = 1_pInt,ns + f = slipFamily(s1,instance) + + !*** burgers vector, mean free path prefactor and minimum dipole distance for each slip system + + burgers(s1,instance) = burgersPerSlipFamily(f,instance) + lambda0(s1,instance) = lambda0PerSlipFamily(f,instance) + minDipoleHeight(s1,1:2,instance) = minDipoleHeightPerSlipFamily(f,1:2,instance) + peierlsStress(s1,1:2,instance) = peierlsStressPerSlipFamily(f,1:2,instance) + + do s2 = 1_pInt,ns + + !*** calculation of forest projections for edge and screw dislocations. s2 acts as forest for s1 + + forestProjectionEdge(s1,s2,instance) & + = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & + lattice_st(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of edge dislocations is the projection of (t = b x n) onto the slip normal of the respective slip plane + + forestProjectionScrew(s1,s2,instance) & + = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & + lattice_sd(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of screw dislocations is the projection of b onto the slip normal of the respective splip plane + + !*** calculation of interaction matrices + + interactionMatrixSlipSlip(s1,s2,instance) & + = interactionSlipSlip(lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & + slipSystemLattice(s2,instance), & + phase), instance) + + !*** colinear slip system (only makes sense for fcc like it is defined here) + + if (lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & + slipSystemLattice(s2,instance), & + phase) == 3_pInt) then + colinearSystem(s1,instance) = s2 + endif + + enddo + + !*** rotation matrix from lattice configuration to slip system + + lattice2slip(1:3,1:3,s1,instance) & + = math_transpose33( reshape([ lattice_sd(1:3, slipSystemLattice(s1,instance), phase), & + -lattice_st(1:3, slipSystemLattice(s1,instance), phase), & + lattice_sn(1:3, slipSystemLattice(s1,instance), phase)], [3,3])) + enddo + + + !*** combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) + !* four types t: + !* 1) positive screw at positive resolved stress + !* 2) positive screw at negative resolved stress + !* 3) negative screw at positive resolved stress + !* 4) negative screw at negative resolved stress + + do s = 1_pInt,ns + do l = 1_pInt,lattice_NnonSchmid(phase) + nonSchmidProjection(1:3,1:3,1,s,instance) = nonSchmidProjection(1:3,1:3,1,s,instance) & + + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l,slipSystemLattice(s,instance),phase) + nonSchmidProjection(1:3,1:3,2,s,instance) = nonSchmidProjection(1:3,1:3,2,s,instance) & + + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l+1,slipSystemLattice(s,instance),phase) + enddo + nonSchmidProjection(1:3,1:3,3,s,instance) = -nonSchmidProjection(1:3,1:3,2,s,instance) + nonSchmidProjection(1:3,1:3,4,s,instance) = -nonSchmidProjection(1:3,1:3,1,s,instance) + forall (t = 1:4) & + nonSchmidProjection(1:3,1:3,t,s,instance) = nonSchmidProjection(1:3,1:3,t,s,instance) & + + lattice_Sslip(1:3,1:3,1,slipSystemLattice(s,instance),phase) + enddo + + call plastic_nonlocal_aTolState(phase,instance) + endif myPhase2 + + enddo initializeInstances + +end subroutine plastic_nonlocal_init + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- + +subroutine plastic_nonlocal_stateInit() +use IO, only: IO_error +use lattice, only: lattice_maxNslipFamily +use math, only: math_sampleGaussVar +use mesh, only: mesh_ipVolume, & + mesh_NcpElems, & + mesh_element, & + FE_Nips, & + FE_geomtype +use material, only: material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticity ,& + PLASTICITY_NONLOCAL_ID +implicit none + +integer(pInt) :: e, & + i, & + ns, & ! short notation for total number of active slip systems + f, & ! index of lattice family + from, & + upto, & + s, & ! index of slip system + t, & + j, & + instance, & + maxNinstances +real(pReal), dimension(2) :: noise +real(pReal), dimension(4) :: rnd +real(pReal) meanDensity, & + totalVolume, & + densityBinning, & + minimumIpVolume + +maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) + +do instance = 1_pInt,maxNinstances + ns = totalNslip(instance) + + ! randomly distribute dislocation segments on random slip system and of random type in the volume + if (rhoSglRandom(instance) > 0.0_pReal) then + + ! get the total volume of the instance + + minimumIpVolume = huge(1.0_pReal) + totalVolume = 0.0_pReal + do e = 1_pInt,mesh_NcpElems + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & + .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then + totalVolume = totalVolume + mesh_ipVolume(i,e) + minimumIpVolume = min(minimumIpVolume, mesh_ipVolume(i,e)) + endif + enddo + enddo + densityBinning = rhoSglRandomBinning(instance) / minimumIpVolume ** (2.0_pReal / 3.0_pReal) + + ! subsequently fill random ips with dislocation segments until we reach the desired overall density + + meanDensity = 0.0_pReal + do while(meanDensity < rhoSglRandom(instance)) + call random_number(rnd) + e = nint(rnd(1)*real(mesh_NcpElems,pReal)+0.5_pReal,pInt) + i = nint(rnd(2)*real(FE_Nips(FE_geomtype(mesh_element(2,e))),pReal)+0.5_pReal,pInt) + if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & + .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then + s = nint(rnd(3)*real(ns,pReal)+0.5_pReal,pInt) + t = nint(rnd(4)*4.0_pReal+0.5_pReal,pInt) + meanDensity = meanDensity + densityBinning * mesh_ipVolume(i,e) / totalVolume + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) = & + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,t,instance),phaseAt(1,i,e)) & + + densityBinning + endif + enddo + ! homogeneous distribution of density with some noise + else + do e = 1_pInt,mesh_NcpElems + do i = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,e))) + if (PLASTICITY_NONLOCAL_ID == phase_plasticity(material_phase(1,i,e)) & + .and. instance == phase_plasticityInstance(material_phase(1,i,e))) then + do f = 1_pInt,lattice_maxNslipFamily + from = 1_pInt + sum(Nslip(1:f-1_pInt,instance)) + upto = sum(Nslip(1:f,instance)) + do s = from,upto + do j = 1_pInt,2_pInt + noise(j) = math_sampleGaussVar(0.0_pReal, rhoSglScatter(instance)) + enddo + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,1,instance),phasememberAt(1,i,e)) = & + rhoSglEdgePos0(f,instance) + noise(1) + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,2,instance),phasememberAt(1,i,e)) = & + rhoSglEdgeNeg0(f,instance) + noise(1) + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,3,instance),phasememberAt(1,i,e)) = & + rhoSglScrewPos0(f,instance) + noise(2) + plasticState(phaseAt(1,i,e))%state0(iRhoU(s,4,instance),phasememberAt(1,i,e)) = & + rhoSglScrewNeg0(f,instance) + noise(2) + enddo + plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,1,instance),phasememberAt(1,i,e)) = & + rhoDipEdge0(f,instance) + plasticState(phaseAt(1,i,e))%state0(iRhoD(from:upto,2,instance),phasememberAt(1,i,e)) = & + rhoDipScrew0(f,instance) + enddo + endif + enddo + enddo + endif +enddo + +end subroutine plastic_nonlocal_stateInit + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + integer(pInt) :: & + ns, & + t, c + + ns = totalNslip(instance) + forall (t = 1_pInt:4_pInt) + plasticState(ph)%aTolState(iRhoU(1:ns,t,instance)) = aTolRho(instance) + plasticState(ph)%aTolState(iRhoB(1:ns,t,instance)) = aTolRho(instance) + end forall + forall (c = 1_pInt:2_pInt) & + plasticState(ph)%aTolState(iRhoD(1:ns,c,instance)) = aTolRho(instance) + + plasticState(ph)%aTolState(iGamma(1:ns,instance)) = aTolShear(instance) + +end subroutine plastic_nonlocal_aTolState + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates quantities characterizing the microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_microstructure(Fe, Fp, ip, el) +use IO, only: & + IO_error +use math, only: & + pi, & + math_mul33x3, & + math_mul3x3, & + math_inv33, & + math_transpose33 +use debug, only: & + debug_level, & + debug_constitutive, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use mesh, only: & + mesh_element, & + mesh_ipNeighborhood, & + mesh_ipCoordinates, & + mesh_ipVolume, & + mesh_ipAreaNormal, & + mesh_ipArea, & + FE_NipNeighbors, & + mesh_maxNipNeighbors, & + FE_geomtype, & + FE_celltype +use material, only: & + material_phase, & + phase_localPlasticity, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance +use lattice, only: & + lattice_sd, & + lattice_st, & + lattice_mu, & + lattice_nu, & + lattice_structure, & + LATTICE_bcc_ID, & + LATTICE_fcc_ID + +implicit none + +integer(pInt), intent(in) :: ip, & ! current integration point + el ! current element +real(pReal), dimension(3,3), intent(in) :: & + Fe, & ! elastic deformation gradient + Fp ! elastic deformation gradient + + integer(pInt) :: & + ph, & !< phase + of, & !< offset + np, & !< neighbor phase + no !< nieghbor offset + +integer(pInt) neighbor_el, & ! element number of neighboring material point + neighbor_ip, & ! integration point of neighboring material point + instance, & ! my instance of this plasticity + neighbor_instance, & ! instance of this plasticity of neighboring material point + neighbor_phase, & + ns, & ! total number of active slip systems at my material point + neighbor_ns, & ! total number of active slip systems at neighboring material point + c, & ! index of dilsocation character (edge, screw) + s, & ! slip system index + t, & ! index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) + dir, & + n, & + nRealNeighbors ! number of really existing neighbors +integer(pInt), dimension(2) :: neighbors +real(pReal) FVsize, & + correction, & + myRhoForest +real(pReal), dimension(2) :: rhoExcessGradient, & + rhoExcessGradient_over_rho, & + rhoTotal +real(pReal), dimension(3) :: rhoExcessDifferences, & + normal_latticeConf +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoForest, & ! forest dislocation density + tauBack, & ! back stress from pileup on same slip system + tauThreshold ! threshold shear stress +real(pReal), dimension(3,3) :: invFe, & ! inverse of elastic deformation gradient + invFp, & ! inverse of plastic deformation gradient + connections, & + invConnections +real(pReal), dimension(3,mesh_maxNipNeighbors) :: & + connection_latticeConf +real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoExcess +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + rhoDip ! dipole dislocation density (edge, screw) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))), & + totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + myInteractionMatrix ! corrected slip interaction matrix +real(pReal), dimension(2,maxval(totalNslip),mesh_maxNipNeighbors) :: & + neighbor_rhoExcess, & ! excess density at neighboring material point + neighbor_rhoTotal ! total density at neighboring material point +real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + m ! direction of dislocation motion + +ph = phaseAt(1,ip,el) +of = phasememberAt(1,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + +!*** get basic states + + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & + rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities + +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal +where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoDip) < significantRho(instance)) & + rhoDip = 0.0_pReal + +!*** calculate the forest dislocation density +!*** (= projection of screw and edge dislocations) + +forall (s = 1_pInt:ns) & + rhoForest(s) = dot_product((sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1)), & + forestProjectionEdge(s,1:ns,instance)) & + + dot_product((sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2)), & + forestProjectionScrew(s,1:ns,instance)) + + +!*** calculate the threshold shear stress for dislocation slip +!*** coefficients are corrected for the line tension effect +!*** (see Kubin,Devincre,Hoc; 2008; Modeling dislocation storage rates and mean free paths in face-centered cubic crystals) + +myInteractionMatrix = 0.0_pReal +myInteractionMatrix(1:ns,1:ns) = interactionMatrixSlipSlip(1:ns,1:ns,instance) +if (lattice_structure(ph) == LATTICE_bcc_ID .or. lattice_structure(ph) == LATTICE_fcc_ID) then ! only fcc and bcc + do s = 1_pInt,ns + myRhoForest = max(rhoForest(s),significantRho(instance)) + correction = ( 1.0_pReal - linetensionEffect(instance) & + + linetensionEffect(instance) & + * log(0.35_pReal * burgers(s,instance) * sqrt(myRhoForest)) & + / log(0.35_pReal * burgers(s,instance) * 1e6_pReal)) ** 2.0_pReal + myInteractionMatrix(s,1:ns) = correction * myInteractionMatrix(s,1:ns) + enddo +endif +forall (s = 1_pInt:ns) & + tauThreshold(s) = lattice_mu(ph) * burgers(s,instance) & + * sqrt(dot_product((sum(abs(rhoSgl),2) + sum(abs(rhoDip),2)), myInteractionMatrix(s,1:ns))) + + +!*** calculate the dislocation stress of the neighboring excess dislocation densities +!*** zero for material points of local plasticity + +tauBack = 0.0_pReal + +if (.not. phase_localPlasticity(ph) .and. shortRangeStressCorrection(instance)) then + invFe = math_inv33(Fe) + invFp = math_inv33(Fp) + rhoExcess(1,1:ns) = rhoSgl(1:ns,1) - rhoSgl(1:ns,2) + rhoExcess(2,1:ns) = rhoSgl(1:ns,3) - rhoSgl(1:ns,4) + FVsize = mesh_ipVolume(ip,el) ** (1.0_pReal/3.0_pReal) + + !* loop through my neighborhood and get the connection vectors (in lattice frame) and the excess densities + + nRealNeighbors = 0_pInt + neighbor_rhoTotal = 0.0_pReal + do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) + neighbor_el = mesh_ipNeighborhood(1,n,ip,el) + neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) + np = phaseAt(1,neighbor_ip,neighbor_el) + no = phasememberAt(1,neighbor_ip,neighbor_el) + if (neighbor_el > 0 .and. neighbor_ip > 0) then + neighbor_phase = material_phase(1,neighbor_ip,neighbor_el) + neighbor_instance = phase_plasticityInstance(neighbor_phase) + neighbor_ns = totalNslip(neighbor_instance) + if (.not. phase_localPlasticity(neighbor_phase) & + .and. neighbor_instance == instance) then ! same instance should be same structure + if (neighbor_ns == ns) then + nRealNeighbors = nRealNeighbors + 1_pInt + forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + + neighbor_rhoExcess(c,s,n) = & + max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles + - max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) ! negative mobiles + neighbor_rhoTotal(c,s,n) = & + max(plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no), 0.0_pReal) & ! positive mobiles + + max(plasticState(np)%state(iRhoU(s,2*c,neighbor_instance), no), 0.0_pReal) & ! negative mobiles + + abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads + + abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance), no)) & ! negative deads + + max(plasticState(np)%state(iRhoD(s,c,neighbor_instance), no), 0.0_pReal) ! dipoles + + endforall + connection_latticeConf(1:3,n) = & + math_mul33x3(invFe, mesh_ipCoordinates(1:3,neighbor_ip,neighbor_el) & + - mesh_ipCoordinates(1:3,ip,el)) + normal_latticeConf = math_mul33x3(math_transpose33(invFp), mesh_ipAreaNormal(1:3,n,ip,el)) + if (math_mul3x3(normal_latticeConf,connection_latticeConf(1:3,n)) < 0.0_pReal) then ! neighboring connection points in opposite direction to face normal: must be periodic image + connection_latticeConf(1:3,n) = normal_latticeConf * mesh_ipVolume(ip,el) & + / mesh_ipArea(n,ip,el) ! instead take the surface normal scaled with the diameter of the cell + endif + else + ! different number of active slip systems + call IO_error(-1_pInt,ext_msg='different number of active slip systems in neighboring IPs of same crystal structure') + endif + else + ! local neighbor or different lattice structure or different constitution instance -> use central values instead + connection_latticeConf(1:3,n) = 0.0_pReal + neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess + endif + else + ! free surface -> use central values instead + connection_latticeConf(1:3,n) = 0.0_pReal + neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess + endif + enddo + + + !* loop through the slip systems and calculate the dislocation gradient by + !* 1. interpolation of the excess density in the neighorhood + !* 2. interpolation of the dead dislocation density in the central volume + + m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) + m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) + + do s = 1_pInt,ns + + !* gradient from interpolation of neighboring excess density + + do c = 1_pInt,2_pInt + do dir = 1_pInt,3_pInt + neighbors(1) = 2_pInt * dir - 1_pInt + neighbors(2) = 2_pInt * dir + connections(dir,1:3) = connection_latticeConf(1:3,neighbors(1)) & + - connection_latticeConf(1:3,neighbors(2)) + rhoExcessDifferences(dir) = neighbor_rhoExcess(c,s,neighbors(1)) & + - neighbor_rhoExcess(c,s,neighbors(2)) + enddo + invConnections = math_inv33(connections) + if (all(abs(invConnections) <= tiny(0.0_pReal))) & ! check for failed in version (math_inv33 returns 0) and avoid floating point equality comparison + call IO_error(-1_pInt,ext_msg='back stress calculation: inversion error') + rhoExcessGradient(c) = math_mul3x3(m(1:3,s,c), & + math_mul33x3(invConnections,rhoExcessDifferences)) + enddo + + !* plus gradient from deads + + do t = 1_pInt,4_pInt + c = (t - 1_pInt) / 2_pInt + 1_pInt + rhoExcessGradient(c) = rhoExcessGradient(c) + rhoSgl(s,t+4_pInt) / FVsize + enddo + + !* normalized with the total density + + rhoExcessGradient_over_rho = 0.0_pReal + forall (c = 1_pInt:2_pInt) & + rhoTotal(c) = (sum(abs(rhoSgl(s,[2*c-1,2*c,2*c+3,2*c+4]))) + rhoDip(s,c) & + + sum(neighbor_rhoTotal(c,s,:))) / real(1_pInt + nRealNeighbors,pReal) + forall (c = 1_pInt:2_pInt, rhoTotal(c) > 0.0_pReal) & + rhoExcessGradient_over_rho(c) = rhoExcessGradient(c) / rhoTotal(c) + + !* gives the local stress correction when multiplied with a factor + + tauBack(s) = - lattice_mu(ph) * burgers(s,instance) / (2.0_pReal * pi) & + * (rhoExcessGradient_over_rho(1) / (1.0_pReal - lattice_nu(ph)) & + + rhoExcessGradient_over_rho(2)) + + enddo +endif + + +!*** set dependent states +plasticState(ph)%state(iRhoF(1:ns,instance),of) = rhoForest +plasticState(ph)%state(iTauF(1:ns,instance),of) = tauThreshold +plasticState(ph)%state(iTauB(1:ns,instance),of) = tauBack + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_microstructure at el ip ',el,ip + write(6,'(a,/,12x,12(e10.3,1x))') '<< CONST >> rhoForest', rhoForest + write(6,'(a,/,12x,12(f10.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold/1e6 + write(6,'(a,/,12x,12(f10.5,1x),/)') '<< CONST >> tauBack / MPa', tauBack/1e6 + endif +#endif + +end subroutine plastic_nonlocal_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates kinetics +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_kinetics(v, dv_dtau, dv_dtauNS, tau, tauNS, & + tauThreshold, c, Temperature, ip, el) + +use debug, only: debug_level, & + debug_constitutive, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use material, only: material_phase, & + phase_plasticityInstance + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el, & !< current element number + c !< dislocation character (1:edge, 2:screw) +real(pReal), intent(in) :: Temperature !< temperature +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & + intent(in) :: tau, & !< resolved external shear stress (without non Schmid effects) + tauNS, & !< resolved external shear stress (including non Schmid effects) + tauThreshold !< threshold shear stress + +!*** output variables +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))), & + intent(out) :: v, & !< velocity + dv_dtau, & !< velocity derivative with respect to resolved shear stress (without non Schmid contributions) + dv_dtauNS !< velocity derivative with respect to resolved shear stress (including non Schmid contributions) + +!*** local variables +integer(pInt) :: instance, & !< current instance of this plasticity + ns, & !< short notation for the total number of active slip systems + s !< index of my current slip system +real(pReal) tauRel_P, & + tauRel_S, & + tauEff, & !< effective shear stress + tPeierls, & !< waiting time in front of a peierls barriers + tSolidSolution, & !< waiting time in front of a solid solution obstacle + vViscous, & !< viscous glide velocity + dtPeierls_dtau, & !< derivative with respect to resolved shear stress + dtSolidSolution_dtau, & !< derivative with respect to resolved shear stress + meanfreepath_S, & !< mean free travel distance for dislocations between two solid solution obstacles + meanfreepath_P, & !< mean free travel distance for dislocations between two Peierls barriers + jumpWidth_P, & !< depth of activated area + jumpWidth_S, & !< depth of activated area + activationLength_P, & !< length of activated dislocation line + activationLength_S, & !< length of activated dislocation line + activationVolume_P, & !< volume that needs to be activated to overcome barrier + activationVolume_S, & !< volume that needs to be activated to overcome barrier + activationEnergy_P, & !< energy that is needed to overcome barrier + activationEnergy_S, & !< energy that is needed to overcome barrier + criticalStress_P, & !< maximum obstacle strength + criticalStress_S, & !< maximum obstacle strength + mobility !< dislocation mobility + + +instance = phase_plasticityInstance(material_phase(1_pInt,ip,el)) +ns = totalNslip(instance) + +v = 0.0_pReal +dv_dtau = 0.0_pReal +dv_dtauNS = 0.0_pReal + + +if (Temperature > 0.0_pReal) then + do s = 1_pInt,ns + if (abs(tau(s)) > tauThreshold(s)) then + + !* Peierls contribution + !* Effective stress includes non Schmid constributions + !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity + + tauEff = max(0.0_pReal, abs(tauNS(s)) - tauThreshold(s)) ! ensure that the effective stress is positive + meanfreepath_P = burgers(s,instance) + jumpWidth_P = burgers(s,instance) + activationLength_P = doublekinkwidth(instance) * burgers(s,instance) + activationVolume_P = activationLength_P * jumpWidth_P * burgers(s,instance) + criticalStress_P = peierlsStress(s,c,instance) + activationEnergy_P = criticalStress_P * activationVolume_P + tauRel_P = min(1.0_pReal, tauEff / criticalStress_P) ! ensure that the activation probability cannot become greater than one + tPeierls = 1.0_pReal / fattack(instance) & + * exp(activationEnergy_P / (KB * Temperature) & + * (1.0_pReal - tauRel_P**pParam(instance))**qParam(instance)) + if (tauEff < criticalStress_P) then + dtPeierls_dtau = tPeierls * pParam(instance) * qParam(instance) * activationVolume_P / (KB * Temperature) & + * (1.0_pReal - tauRel_P**pParam(instance))**(qParam(instance)-1.0_pReal) & + * tauRel_P**(pParam(instance)-1.0_pReal) + else + dtPeierls_dtau = 0.0_pReal + endif + + + !* Contribution from solid solution strengthening + !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity + + tauEff = abs(tau(s)) - tauThreshold(s) + meanfreepath_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) + jumpWidth_S = solidSolutionSize(instance) * burgers(s,instance) + activationLength_S = burgers(s,instance) / sqrt(solidSolutionConcentration(instance)) + activationVolume_S = activationLength_S * jumpWidth_S * burgers(s,instance) + activationEnergy_S = solidSolutionEnergy(instance) + criticalStress_S = activationEnergy_S / activationVolume_S + tauRel_S = min(1.0_pReal, tauEff / criticalStress_S) ! ensure that the activation probability cannot become greater than one + tSolidSolution = 1.0_pReal / fattack(instance) & + * exp(activationEnergy_S / (KB * Temperature) & + * (1.0_pReal - tauRel_S**pParam(instance))**qParam(instance)) + if (tauEff < criticalStress_S) then + dtSolidSolution_dtau = tSolidSolution * pParam(instance) * qParam(instance) & + * activationVolume_S / (KB * Temperature) & + * (1.0_pReal - tauRel_S**pParam(instance))**(qParam(instance)-1.0_pReal) & + * tauRel_S**(pParam(instance)-1.0_pReal) + else + dtSolidSolution_dtau = 0.0_pReal + endif + + + !* viscous glide velocity + + tauEff = abs(tau(s)) - tauThreshold(s) + mobility = burgers(s,instance) / viscosity(instance) + vViscous = mobility * tauEff + + + !* Mean velocity results from waiting time at peierls barriers and solid solution obstacles with respective meanfreepath of + !* free flight at glide velocity in between. + !* adopt sign from resolved stress + + v(s) = sign(1.0_pReal,tau(s)) & + / (tPeierls / meanfreepath_P + tSolidSolution / meanfreepath_S + 1.0_pReal / vViscous) + dv_dtau(s) = v(s) * v(s) * (dtSolidSolution_dtau / meanfreepath_S & + + mobility / (vViscous * vViscous)) + dv_dtauNS(s) = v(s) * v(s) * dtPeierls_dtau / meanfreepath_P + endif + enddo +endif + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) then + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_kinetics at el ip',el,ip + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauThreshold / MPa', tauThreshold / 1e6_pReal + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tau / MPa', tau / 1e6_pReal + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> tauNS / MPa', tauNS / 1e6_pReal + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> v / 1e-3m/s', v * 1e3 + write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtau', dv_dtau + write(6,'(a,/,12x,12(e12.5,1x))') '<< CONST >> dv_dtauNS', dv_dtauNS + endif +#endif + +end subroutine plastic_nonlocal_kinetics + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_LpAndItsTangent(Lp, dLp_dTstar99, Tstar_v, Temperature, ip, el) + +use math, only: math_Plain3333to99, & + math_mul6x6, & + math_mul33xx33, & + math_Mandel6to33 +use debug, only: debug_level, & + debug_constitutive, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use material, only: material_phase, & + plasticState, & + phaseAt, phasememberAt,& + phase_plasticityInstance +use lattice, only: lattice_Sslip, & + lattice_Sslip_v, & + lattice_NnonSchmid +use mesh, only: mesh_ipVolume + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el !< current element number +real(pReal), intent(in) :: Temperature !< temperature +real(pReal), dimension(6), intent(in) :: Tstar_v !< 2nd Piola-Kirchhoff stress in Mandel notation + + +!*** output variables +real(pReal), dimension(3,3), intent(out) :: Lp !< plastic velocity gradient +real(pReal), dimension(9,9), intent(out) :: dLp_dTstar99 !< derivative of Lp with respect to Tstar (9x9 matrix) + +!*** local variables +integer(pInt) instance, & !< current instance of this plasticity + ns, & !< short notation for the total number of active slip systems + i, & + j, & + k, & + l, & + ph, & !phase number + of, & !offset + t, & !< dislocation type + s, & !< index of my current slip system + sLattice !< index of my current slip system according to lattice order +real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 !< derivative of Lp with respect to Tstar (3x3x3x3 matrix) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl !< single dislocation densities (including blocked) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + v, & !< velocity + tauNS, & !< resolved shear stress including non Schmid and backstress terms + dv_dtau, & !< velocity derivative with respect to the shear stress + dv_dtauNS !< velocity derivative with respect to the shear stress +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + tau, & !< resolved shear stress including backstress terms + gdotTotal, & !< shear rate + tauBack, & !< back stress from dislocation gradients on same slip system + tauThreshold !< threshold shear stress +!*** shortcut for mapping +ph = phaseAt(1_pInt,ip,el) +of = phasememberAt(1_pInt,ip,el) + +!*** initialize local variables + +Lp = 0.0_pReal +dLp_dTstar3333 = 0.0_pReal + +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + + +!*** shortcut to state variables + + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + + rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) +endforall +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal + +tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) +tauThreshold = plasticState(ph)%state(iTauF(1:ns,instance),of) + + +!*** get resolved shear stress +!*** for screws possible non-schmid contributions are also taken into account + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauNS(s,1) = tau(s) + tauNS(s,2) = tau(s) + if (tau(s) > 0.0_pReal) then + tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,1,s,instance)) + tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,3,s,instance)) + else + tauNS(s,3) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,2,s,instance)) + tauNS(s,4) = math_mul33xx33(math_Mandel6to33(Tstar_v), nonSchmidProjection(1:3,1:3,4,s,instance)) + endif +enddo +forall (t = 1_pInt:4_pInt) & + tauNS(1:ns,t) = tauNS(1:ns,t) + tauBack ! add backstress +tau = tau + tauBack ! add backstress + + +!*** get dislocation velocity and its tangent and store the velocity in the state array + +! edges +call plastic_nonlocal_kinetics(v(1:ns,1), dv_dtau(1:ns,1), dv_dtauNS(1:ns,1), & + tau(1:ns), tauNS(1:ns,1), tauThreshold(1:ns), & + 1_pInt, Temperature, ip, el) +v(1:ns,2) = v(1:ns,1) +dv_dtau(1:ns,2) = dv_dtau(1:ns,1) +dv_dtauNS(1:ns,2) = dv_dtauNS(1:ns,1) + +!screws +if (lattice_NnonSchmid(ph) == 0_pInt) then ! no non-Schmid contributions + forall(t = 3_pInt:4_pInt) + v(1:ns,t) = v(1:ns,1) + dv_dtau(1:ns,t) = dv_dtau(1:ns,1) + dv_dtauNS(1:ns,t) = dv_dtauNS(1:ns,1) + endforall +else ! take non-Schmid contributions into account + do t = 3_pInt,4_pInt + call plastic_nonlocal_kinetics(v(1:ns,t), dv_dtau(1:ns,t), dv_dtauNS(1:ns,t), & + tau(1:ns), tauNS(1:ns,t), tauThreshold(1:ns), & + 2_pInt , Temperature, ip, el) + enddo +endif + + +!*** store velocity in state + +forall (t = 1_pInt:4_pInt) & + plasticState(ph)%state(iV(1:ns,t,instance),of) = v(1:ns,t) +!*** Bauschinger effect + +forall (s = 1_pInt:ns, t = 5_pInt:8_pInt, rhoSgl(s,t) * v(s,t-4_pInt) < 0.0_pReal) & + rhoSgl(s,t-4_pInt) = rhoSgl(s,t-4_pInt) + abs(rhoSgl(s,t)) + + +!*** Calculation of Lp and its tangent + +gdotTotal = sum(rhoSgl(1:ns,1:4) * v, 2) * burgers(1:ns,instance) + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + Lp = Lp + gdotTotal(s) * lattice_Sslip(1:3,1:3,1,sLattice,ph) + + ! Schmid contributions to tangent + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + + lattice_Sslip(i,j,1,sLattice,ph) * lattice_Sslip(k,l,1,sLattice,ph) & + * sum(rhoSgl(s,1:4) * dv_dtau(s,1:4)) * burgers(s,instance) + + ! non Schmid contributions to tangent + if (tau(s) > 0.0_pReal) then + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + + lattice_Sslip(i,j,1,sLattice,ph) & + * ( nonSchmidProjection(k,l,1,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & + + nonSchmidProjection(k,l,3,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & + * burgers(s,instance) + else + forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & + dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + + lattice_Sslip(i,j,1,sLattice,ph) & + * ( nonSchmidProjection(k,l,2,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & + + nonSchmidProjection(k,l,4,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & + * burgers(s,instance) + endif +enddo +dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_LpandItsTangent at el ip',el,ip + write(6,'(a,/,12x,12(f12.5,1x))') '<< CONST >> gdot total / 1e-3',gdotTotal*1e3_pReal + write(6,'(a,/,3(12x,3(f12.7,1x),/))') '<< CONST >> Lp',transpose(Lp) + endif +#endif + +end subroutine plastic_nonlocal_LpAndItsTangent + + + +!-------------------------------------------------------------------------------------------------- +!> @brief (instantaneous) incremental change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_deltaState(Tstar_v,ip,el) +use debug, only: debug_level, & + debug_constitutive, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_i, & + debug_e +use math, only: pi, & + math_mul6x6 +use lattice, only: lattice_Sslip_v ,& + lattice_mu, & + lattice_nu +use mesh, only: mesh_ipVolume +use material, only: material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + +implicit none +integer(pInt), intent(in) :: ip, & ! current grain number + el ! current element number +real(pReal), dimension(6), intent(in) :: Tstar_v ! current 2nd Piola-Kirchhoff stress in Mandel notation + + + integer(pInt) :: & + ph, & !< phase + of !< offset + +integer(pInt) ::instance, & ! current instance of this plasticity + ns, & ! short notation for the total number of active slip systems + c, & ! character of dislocation + t, & ! type of dislocation + s, & ! index of my current slip system + sLattice ! index of my current slip system according to lattice order +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),10) :: & + deltaRho, & ! density increment + deltaRhoRemobilization, & ! density increment by remobilization + deltaRhoDipole2SingleStress ! density increment by dipole dissociation (by stress change) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),8) :: & + rhoSgl ! current single dislocation densities (positive/negative screw and edge without dipoles) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),4) :: & + v ! dislocation glide velocity +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + tau, & ! current resolved shear stress + tauBack ! current back stress from pileups on same slip system +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,el))),2) :: & + rhoDip, & ! current dipole dislocation densities (screw and edge dipoles) + dLower, & ! minimum stable dipole distance for edges and screws + dUpper, & ! current maximum stable dipole distance for edges and screws + dUpperOld, & ! old maximum stable dipole distance for edges and screws + deltaDUpper ! change in maximum stable dipole distance for edges and screws + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_deltaState at el ip ',el,ip +#endif + + ph = phaseAt(1,ip,el) + of = phasememberAt(1,ip,el) + instance = phase_plasticityInstance(ph) + ns = totalNslip(instance) + + +!*** shortcut to state variables + + forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(ph)%state(iRhoB(s,t,instance),of) + v(s,t) = plasticState(ph)%state(iV(s,t,instance),of) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + rhoDip(s,c) = max(plasticState(ph)%state(iRhoD(s,c,instance),of), 0.0_pReal) ! ensure positive dipole densities + dUpperOld(s,c) = plasticState(ph)%state(iD(s,c,instance),of) +endforall + tauBack = plasticState(ph)%state(iTauB(1:ns,instance),of) + +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal +where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoDip) < significantRho(instance)) & + rhoDip = 0.0_pReal + + + + +!**************************************************************************** +!*** dislocation remobilization (bauschinger effect) + +deltaRhoRemobilization = 0.0_pReal +do t = 1_pInt,4_pInt + do s = 1_pInt,ns + if (rhoSgl(s,t+4_pInt) * v(s,t) < 0.0_pReal) then + deltaRhoRemobilization(s,t) = abs(rhoSgl(s,t+4_pInt)) + rhoSgl(s,t) = rhoSgl(s,t) + abs(rhoSgl(s,t+4_pInt)) + deltaRhoRemobilization(s,t+4_pInt) = - rhoSgl(s,t+4_pInt) + rhoSgl(s,t+4_pInt) = 0.0_pReal + endif + enddo +enddo + + + +!**************************************************************************** +!*** calculate dipole formation and dissociation by stress change + +!*** calculate limits for stable dipole height + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) + if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal +enddo +dLower = minDipoleHeight(1:ns,1:2,instance) +dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & + / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) +dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) / (4.0_pReal * pi * abs(tau)) + + +forall (c = 1_pInt:2_pInt) + where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& + abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & + dUpper(1:ns,c)) +end forall +dUpper = max(dUpper,dLower) +deltaDUpper = dUpper - dUpperOld + + +!*** dissociation by stress increase +deltaRhoDipole2SingleStress = 0.0_pReal +forall (c=1_pInt:2_pInt, s=1_pInt:ns, deltaDUpper(s,c) < 0.0_pReal .and. & + abs(dUpperOld(s,c) - dLower(s,c)) > tiny(0.0_pReal)) & + deltaRhoDipole2SingleStress(s,8_pInt+c) = rhoDip(s,c) * deltaDUpper(s,c) & + / (dUpperOld(s,c) - dLower(s,c)) + +forall (t=1_pInt:4_pInt) & + deltaRhoDipole2SingleStress(1_pInt:ns,t) = -0.5_pReal & + * deltaRhoDipole2SingleStress(1_pInt:ns,(t-1_pInt)/2_pInt+9_pInt) + + +!*** store new maximum dipole height in state + +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & + plasticState(ph)%state(iD(s,c,instance),of) = dUpper(s,c) + + + +!**************************************************************************** +!*** assign the changes in the dislocation densities to deltaState + +deltaRho = deltaRhoRemobilization & + + deltaRhoDipole2SingleStress +plasticState(ph)%deltaState(:,of) = 0.0_pReal +forall (s = 1:ns, t = 1_pInt:4_pInt) + plasticState(ph)%deltaState(iRhoU(s,t,instance),of)= deltaRho(s,t) + plasticState(ph)%deltaState(iRhoB(s,t,instance),of) = deltaRho(s,t+4_pInt) +endforall +forall (s = 1:ns, c = 1_pInt:2_pInt) & + plasticState(ph)%deltaState(iRhoD(s,c,instance),of) = deltaRho(s,c+8_pInt) + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation remobilization', deltaRhoRemobilization(1:ns,1:8) + write(6,'(a,/,10(12x,12(e12.5,1x),/),/)') '<< CONST >> dipole dissociation by stress increase', deltaRhoDipole2SingleStress + endif +#endif + +end subroutine plastic_nonlocal_deltaState + +!--------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!--------------------------------------------------------------------------------------------------- +subroutine plastic_nonlocal_dotState(Tstar_v, Fe, Fp, Temperature, & + timestep,subfrac, ip,el) + +use prec, only: DAMASK_NaN +use numerics, only: numerics_integrationMode, & + numerics_timeSyncing +use IO, only: IO_error +use debug, only: debug_level, & + debug_constitutive, & + debug_levelBasic, & + debug_levelExtensive, & + debug_levelSelective, & + debug_g, & + debug_i, & + debug_e +use math, only: math_mul6x6, & + math_mul3x3, & + math_mul33x3, & + math_mul33x33, & + math_inv33, & + math_det33, & + math_transpose33, & + pi +use mesh, only: mesh_NcpElems, & + mesh_maxNips, & + mesh_element, & + mesh_ipNeighborhood, & + mesh_ipVolume, & + mesh_ipArea, & + mesh_ipAreaNormal, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype +use material, only: homogenization_maxNgrains, & + material_phase, & + phase_plasticityInstance, & + phase_localPlasticity, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticity ,& + PLASTICITY_NONLOCAL_ID +use lattice, only: lattice_Sslip_v, & + lattice_sd, & + lattice_st ,& + lattice_mu, & + lattice_nu, & + lattice_structure, & + LATTICE_bcc_ID, & + LATTICE_fcc_ID + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el !< current element number +real(pReal), intent(in) :: Temperature, & !< temperature + timestep !< substepped crystallite time increment +real(pReal), dimension(6), intent(in) :: Tstar_v !< current 2nd Piola-Kirchhoff stress in Mandel notation +real(pReal), dimension(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + subfrac !< fraction of timestep at the beginning of the substepped crystallite time increment +real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + Fe, & !< elastic deformation gradient + Fp !< plastic deformation gradient + + +!*** local variables +integer(pInt) :: ph, & + instance, & !< current instance of this plasticity + neighbor_instance, & !< instance of my neighbor's plasticity + ns, & !< short notation for the total number of active slip systems + c, & !< character of dislocation + n, & !< index of my current neighbor + neighbor_el, & !< element number of my neighbor + neighbor_ip, & !< integration point of my neighbor + neighbor_n, & !< neighbor index pointing to me when looking from my neighbor + opposite_neighbor, & !< index of my opposite neighbor + opposite_ip, & !< ip of my opposite neighbor + opposite_el, & !< element index of my opposite neighbor + opposite_n, & !< neighbor index pointing to me when looking from my opposite neighbor + t, & !< type of dislocation + o,& !< offset shortcut + no,& !< neighbour offset shortcut + p,& !< phase shortcut + np,& !< neighbour phase shortcut + topp, & !< type of dislocation with opposite sign to t + s, & !< index of my current slip system + sLattice !< index of my current slip system according to lattice order +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),10) :: & + rhoDot, & !< density evolution + rhoDotMultiplication, & !< density evolution by multiplication + rhoDotFlux, & !< density evolution by flux + rhoDotSingle2DipoleGlide, & !< density evolution by dipole formation (by glide) + rhoDotAthermalAnnihilation, & !< density evolution by athermal annihilation + rhoDotThermalAnnihilation !< density evolution by thermal annihilation +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) + rhoSglOriginal, & + neighbor_rhoSgl, & !< current single dislocation densities of neighboring ip (positive/negative screw and edge without dipoles) + rhoSgl0, & !< single dislocation densities at start of cryst inc (positive/negative screw and edge without dipoles) + my_rhoSgl !< single dislocation densities of central ip (positive/negative screw and edge without dipoles) +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + v, & !< current dislocation glide velocity + v0, & !< dislocation glide velocity at start of cryst inc + my_v, & !< dislocation glide velocity of central ip + neighbor_v, & !< dislocation glide velocity of enighboring ip + gdot !< shear rates +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoForest, & !< forest dislocation density + tauThreshold, & !< threshold shear stress + tau, & !< current resolved shear stress + tauBack, & !< current back stress from pileups on same slip system + vClimb, & !< climb velocity of edge dipoles + nSources +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) + rhoDipOriginal, & + dLower, & !< minimum stable dipole distance for edges and screws + dUpper !< current maximum stable dipole distance for edges and screws +real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + m !< direction of dislocation motion +real(pReal), dimension(3,3) :: my_F, & !< my total deformation gradient + neighbor_F, & !< total deformation gradient of my neighbor + my_Fe, & !< my elastic deformation gradient + neighbor_Fe, & !< elastic deformation gradient of my neighbor + Favg !< average total deformation gradient of me and my neighbor +real(pReal), dimension(3) :: normal_neighbor2me, & !< interface normal pointing from my neighbor to me in neighbor's lattice configuration + normal_neighbor2me_defConf, & !< interface normal pointing from my neighbor to me in shared deformed configuration + normal_me2neighbor, & !< interface normal pointing from me to my neighbor in my lattice configuration + normal_me2neighbor_defConf !< interface normal pointing from me to my neighbor in shared deformed configuration +real(pReal) area, & !< area of the current interface + transmissivity, & !< overall transmissivity of dislocation flux to neighboring material point + lineLength, & !< dislocation line length leaving the current interface + selfDiffusion, & !< self diffusion + rnd, & + meshlength +logical considerEnteringFlux, & + considerLeavingFlux + + + p = phaseAt(1,ip,el) + o = phasememberAt(1,ip,el) + + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt)) & + write(6,'(/,a,i8,1x,i2,1x,i1,/)') '<< CONST >> nonlocal_dotState at el ip ',el,ip +#endif + +ph = material_phase(1_pInt,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + +tau = 0.0_pReal +gdot = 0.0_pReal + + +!*** shortcut to state variables + + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) + v(s,t) = plasticState(p)%state(iV (s,t,instance),o) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + rhoDip(s,c) = max(plasticState(p)%state(iRhoD(s,c,instance),o), 0.0_pReal) ! ensure positive dipole densities +endforall +rhoForest = plasticState(p)%state(iRhoF(1:ns,instance),o) +tauThreshold = plasticState(p)%state(iTauF(1:ns,instance),o) +tauBack = plasticState(p)%state(iTauB(1:ns,instance),o) + +rhoSglOriginal = rhoSgl +rhoDipOriginal = rhoDip +where (abs(rhoSgl) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl) < significantRho(instance)) & + rhoSgl = 0.0_pReal +where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoDip) < significantRho(instance)) & + rhoDip = 0.0_pReal + +if (numerics_timeSyncing) then + forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl0(s,t) = max(plasticState(p)%state0(iRhoU(s,t,instance),o), 0.0_pReal) + rhoSgl0(s,t+4_pInt) = plasticState(p)%state0(iRhoB(s,t,instance),o) + v0(s,t) = plasticState(p)%state0(iV (s,t,instance),o) + endforall + where (abs(rhoSgl0) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance) & + .or. abs(rhoSgl0) < significantRho(instance)) & + rhoSgl0 = 0.0_pReal +endif + + + +!*** sanity check for timestep + +if (timestep <= 0.0_pReal) then ! if illegal timestep... Why here and not on function entry?? + plasticState(p)%dotState = 0.0_pReal ! ...return without doing anything (-> zero dotState) + return +endif + + + +!**************************************************************************** +!*** Calculate shear rate + +forall (t = 1_pInt:4_pInt) & + gdot(1_pInt:ns,t) = rhoSgl(1_pInt:ns,t) * burgers(1:ns,instance) * v(1:ns,t) + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> rho / 1/m^2', rhoSgl, rhoDip + write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> gdot / 1/s',gdot + endif +#endif + + + +!**************************************************************************** +!*** calculate limits for stable dipole height + +do s = 1_pInt,ns ! loop over slip systems + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) + if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal +enddo + +dLower = minDipoleHeight(1:ns,1:2,instance) +dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & + / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) +dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & + / (4.0_pReal * pi * abs(tau)) +forall (c = 1_pInt:2_pInt) + where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& + abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & + dUpper(1:ns,c)) +end forall +dUpper = max(dUpper,dLower) + +!**************************************************************************** +!*** calculate dislocation multiplication + +rhoDotMultiplication = 0.0_pReal +if (lattice_structure(ph) == LATTICE_bcc_ID) then ! BCC + forall (s = 1:ns, sum(abs(v(s,1:4))) > 0.0_pReal) + rhoDotMultiplication(s,1:2) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication + * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path + ! * 2.0_pReal * sum(abs(v(s,3:4))) / sum(abs(v(s,1:4))) ! ratio of screw to overall velocity determines edge generation + rhoDotMultiplication(s,3:4) = sum(abs(gdot(s,3:4))) / burgers(s,instance) & ! assuming double-cross-slip of screws to be decisive for multiplication + * sqrt(rhoForest(s)) / lambda0(s,instance) ! & ! mean free path + ! * 2.0_pReal * sum(abs(v(s,1:2))) / sum(abs(v(s,1:4))) ! ratio of edge to overall velocity determines screw generation + endforall + +else ! ALL OTHER STRUCTURES + if (probabilisticMultiplication(instance)) then + meshlength = mesh_ipVolume(ip,el)**0.333_pReal + where(sum(rhoSgl(1:ns,1:4),2) > 0.0_pReal) + nSources = (sum(rhoSgl(1:ns,1:2),2) * fEdgeMultiplication(instance) + sum(rhoSgl(1:ns,3:4),2)) & + / sum(rhoSgl(1:ns,1:4),2) * meshlength / lambda0(1:ns,instance)*sqrt(rhoForest(1:ns)) + elsewhere + nSources = meshlength / lambda0(1:ns,instance) * sqrt(rhoForest(1:ns)) + endwhere + do s = 1_pInt,ns + if (nSources(s) < 1.0_pReal) then + if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal) then + call random_number(rnd) + sourceProbability(s,1_pInt,ip,el) = rnd + !$OMP FLUSH(sourceProbability) + endif + if (sourceProbability(s,1_pInt,ip,el) > 1.0_pReal - nSources(s)) then + rhoDotMultiplication(s,1:4) = sum(rhoSglOriginal(s,1:4) * abs(v(s,1:4))) / meshlength + endif + else + sourceProbability(s,1_pInt,ip,el) = 2.0_pReal + rhoDotMultiplication(s,1:4) = & + (sum(abs(gdot(s,1:2))) * fEdgeMultiplication(instance) + sum(abs(gdot(s,3:4)))) & + / burgers(s,instance) * sqrt(rhoForest(s)) / lambda0(s,instance) + endif + enddo +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) & + write(6,'(a,/,4(12x,12(f12.5,1x),/,/))') '<< CONST >> sources', nSources +#endif + else + rhoDotMultiplication(1:ns,1:4) = spread( & + (sum(abs(gdot(1:ns,1:2)),2) * fEdgeMultiplication(instance) + sum(abs(gdot(1:ns,3:4)),2)) & + * sqrt(rhoForest(1:ns)) / lambda0(1:ns,instance) / burgers(1:ns,instance), 2, 4) + endif +endif + + + +!**************************************************************************** +!*** calculate dislocation fluxes (only for nonlocal plasticity) + +rhoDotFlux = 0.0_pReal +!? why needed here +if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then ! only for nonlocal plasticity + + !*** check CFL (Courant-Friedrichs-Lewy) condition for flux + + if (any( abs(gdot) > 0.0_pReal & ! any active slip system ... + .and. CFLfactor(instance) * abs(v) * timestep & + > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el)))) then ! ...with velocity above critical value (we use the reference volume and area for simplicity here) +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then + write(6,'(a,i5,a,i2)') '<< CONST >> CFL condition not fullfilled at el ',el,' ip ',ip + write(6,'(a,e10.3,a,e10.3)') '<< CONST >> velocity is at ', & + maxval(abs(v), abs(gdot) > 0.0_pReal & + .and. CFLfactor(instance) * abs(v) * timestep & + > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el))), & + ' at a timestep of ',timestep + write(6,'(a)') '<< CONST >> enforcing cutback !!!' + endif +#endif + plasticState(p)%dotState = DAMASK_NaN ! -> return NaN and, hence, enforce cutback + return + endif + + + !*** be aware of the definition of lattice_st = lattice_sd x lattice_sn !!! + !*** opposite sign to our p vector in the (s,p,n) triplet !!! + + m(1:3,1:ns,1) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) + m(1:3,1:ns,2) = -lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) + m(1:3,1:ns,3) = -lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) + m(1:3,1:ns,4) = lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) + + my_Fe = Fe(1:3,1:3,1_pInt,ip,el) + my_F = math_mul33x33(my_Fe, Fp(1:3,1:3,1_pInt,ip,el)) + + do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) ! loop through my neighbors +! write(6,*) 'c' + neighbor_el = mesh_ipNeighborhood(1,n,ip,el) + neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) + neighbor_n = mesh_ipNeighborhood(3,n,ip,el) + np = phaseAt(1,neighbor_ip,neighbor_el) + no = phasememberAt(1,neighbor_ip,neighbor_el) + + opposite_neighbor = n + mod(n,2_pInt) - mod(n+1_pInt,2_pInt) + opposite_el = mesh_ipNeighborhood(1,opposite_neighbor,ip,el) + opposite_ip = mesh_ipNeighborhood(2,opposite_neighbor,ip,el) + opposite_n = mesh_ipNeighborhood(3,opposite_neighbor,ip,el) + + if (neighbor_n > 0_pInt) then ! if neighbor exists, average deformation gradient + neighbor_instance = phase_plasticityInstance(material_phase(1_pInt,neighbor_ip,neighbor_el)) + neighbor_Fe = Fe(1:3,1:3,1_pInt,neighbor_ip,neighbor_el) + neighbor_F = math_mul33x33(neighbor_Fe, Fp(1:3,1:3,1_pInt,neighbor_ip,neighbor_el)) + Favg = 0.5_pReal * (my_F + neighbor_F) + else ! if no neighbor, take my value as average + Favg = my_F + endif + + + !* FLUX FROM MY NEIGHBOR TO ME + !* This is only considered, if I have a neighbor of nonlocal plasticity + !* (also nonlocal constitutive law with local properties) that is at least a little bit + !* compatible. + !* If it's not at all compatible, no flux is arriving, because everything is dammed in front of + !* my neighbor's interface. + !* The entering flux from my neighbor will be distributed on my slip systems according to the + !*compatibility + + considerEnteringFlux = .false. + neighbor_v = 0.0_pReal ! needed for check of sign change in flux density below + neighbor_rhoSgl = 0.0_pReal + if (neighbor_n > 0_pInt) then + if (phase_plasticity(material_phase(1,neighbor_ip,neighbor_el)) == PLASTICITY_NONLOCAL_ID & + .and. any(compatibility(:,:,:,n,ip,el) > 0.0_pReal)) & + considerEnteringFlux = .true. + endif + + if (considerEnteringFlux) then + if(numerics_timeSyncing .and. (subfrac(1_pInt,neighbor_ip,neighbor_el) /= subfrac(1_pInt,ip,el))) & + then ! for timesyncing: in case of a timestep at the interface we have to use "state0" to make sure that fluxes n both sides are equal + forall (s = 1:ns, t = 1_pInt:4_pInt) + + neighbor_v(s,t) = plasticState(np)%state0(iV (s,t,neighbor_instance),no) + neighbor_rhoSgl(s,t) = max(plasticState(np)%state0(iRhoU(s,t,neighbor_instance),no),0.0_pReal) + + endforall + else + forall (s = 1:ns, t = 1_pInt:4_pInt) + neighbor_v(s,t) = plasticState(np)%state(iV (s,t,neighbor_instance),no) + neighbor_rhoSgl(s,t) = max(plasticState(np)%state(iRhoU(s,t,neighbor_instance),no), & + 0.0_pReal) + endforall + endif + + where (neighbor_rhoSgl * mesh_ipVolume(neighbor_ip,neighbor_el) ** 0.667_pReal < significantN(instance) & + .or. neighbor_rhoSgl < significantRho(instance)) & + neighbor_rhoSgl = 0.0_pReal + normal_neighbor2me_defConf = math_det33(Favg) * math_mul33x3(math_inv33(transpose(Favg)), & + mesh_ipAreaNormal(1:3,neighbor_n,neighbor_ip,neighbor_el)) ! calculate the normal of the interface in (average) deformed configuration (now pointing from my neighbor to me!!!) + normal_neighbor2me = math_mul33x3(transpose(neighbor_Fe), normal_neighbor2me_defConf) & + / math_det33(neighbor_Fe) ! interface normal in the lattice configuration of my neighbor + area = mesh_ipArea(neighbor_n,neighbor_ip,neighbor_el) * norm2(normal_neighbor2me) + normal_neighbor2me = normal_neighbor2me / norm2(normal_neighbor2me) ! normalize the surface normal to unit length + do s = 1_pInt,ns + do t = 1_pInt,4_pInt + c = (t + 1_pInt) / 2 + topp = t + mod(t,2_pInt) - mod(t+1_pInt,2_pInt) + if (neighbor_v(s,t) * math_mul3x3(m(1:3,s,t), normal_neighbor2me) > 0.0_pReal & ! flux from my neighbor to me == entering flux for me + .and. v(s,t) * neighbor_v(s,t) >= 0.0_pReal ) then ! ... only if no sign change in flux density + lineLength = neighbor_rhoSgl(s,t) * neighbor_v(s,t) & + * math_mul3x3(m(1:3,s,t), normal_neighbor2me) * area ! positive line length that wants to enter through this interface + where (compatibility(c,1_pInt:ns,s,n,ip,el) > 0.0_pReal) & ! positive compatibility... + rhoDotFlux(1_pInt:ns,t) = rhoDotFlux(1_pInt:ns,t) & + + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to equally signed mobile dislocation type + * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal + where (compatibility(c,1_pInt:ns,s,n,ip,el) < 0.0_pReal) & ! ..negative compatibility... + rhoDotFlux(1_pInt:ns,topp) = rhoDotFlux(1_pInt:ns,topp) & + + lineLength / mesh_ipVolume(ip,el) & ! ... transferring to opposite signed mobile dislocation type + * compatibility(c,1_pInt:ns,s,n,ip,el) ** 2.0_pReal + endif + enddo + enddo + endif + + + !* FLUX FROM ME TO MY NEIGHBOR + !* This is not considered, if my opposite neighbor has a different constitutive law than nonlocal (still considered for nonlocal law with lcal properties). + !* Then, we assume, that the opposite(!) neighbor sends an equal amount of dislocations to me. + !* So the net flux in the direction of my neighbor is equal to zero: + !* leaving flux to neighbor == entering flux from opposite neighbor + !* In case of reduced transmissivity, part of the leaving flux is stored as dead dislocation density. + !* That means for an interface of zero transmissivity the leaving flux is fully converted to dead dislocations. + + considerLeavingFlux = .true. + if (opposite_n > 0_pInt) then + if (phase_plasticity(material_phase(1,opposite_ip,opposite_el)) /= PLASTICITY_NONLOCAL_ID) & + considerLeavingFlux = .false. + endif + + if (considerLeavingFlux) then + + !* timeSyncing mode: If the central ip has zero subfraction, always use "state0". This is needed in case of + !* a synchronization step for the central ip, because then "state" contains the values at the end of the + !* previously converged full time step. Also, if either me or my neighbor has zero subfraction, we have to + !* use "state0" to make sure that fluxes on both sides of the (potential) timestep are equal. + my_rhoSgl = rhoSgl + my_v = v + if(numerics_timeSyncing) then + if (abs(subfrac(1_pInt,ip,el))<= tiny(0.0_pReal)) then + my_rhoSgl = rhoSgl0 + my_v = v0 + elseif (neighbor_n > 0_pInt) then + if (abs(subfrac(1_pInt,neighbor_ip,neighbor_el))<= tiny(0.0_pReal)) then + my_rhoSgl = rhoSgl0 + my_v = v0 + endif + endif + endif + + normal_me2neighbor_defConf = math_det33(Favg) & + * math_mul33x3(math_inv33(math_transpose33(Favg)), & + mesh_ipAreaNormal(1:3,n,ip,el)) ! calculate the normal of the interface in (average) deformed configuration (pointing from me to my neighbor!!!) + normal_me2neighbor = math_mul33x3(math_transpose33(my_Fe), normal_me2neighbor_defConf) & + / math_det33(my_Fe) ! interface normal in my lattice configuration + area = mesh_ipArea(n,ip,el) * norm2(normal_me2neighbor) + normal_me2neighbor = normal_me2neighbor / norm2(normal_me2neighbor) ! normalize the surface normal to unit length + do s = 1_pInt,ns + do t = 1_pInt,4_pInt + c = (t + 1_pInt) / 2_pInt + if (my_v(s,t) * math_mul3x3(m(1:3,s,t), normal_me2neighbor) > 0.0_pReal ) then ! flux from me to my neighbor == leaving flux for me (might also be a pure flux from my mobile density to dead density if interface not at all transmissive) + if (my_v(s,t) * neighbor_v(s,t) >= 0.0_pReal) then ! no sign change in flux density + transmissivity = sum(compatibility(c,1_pInt:ns,s,n,ip,el)**2.0_pReal) ! overall transmissivity from this slip system to my neighbor + else ! sign change in flux density means sign change in stress which does not allow for dislocations to arive at the neighbor + transmissivity = 0.0_pReal + endif + lineLength = my_rhoSgl(s,t) * my_v(s,t) & + * math_mul3x3(m(1:3,s,t), normal_me2neighbor) * area ! positive line length of mobiles that wants to leave through this interface + rhoDotFlux(s,t) = rhoDotFlux(s,t) - lineLength / mesh_ipVolume(ip,el) ! subtract dislocation flux from current type + rhoDotFlux(s,t+4_pInt) = rhoDotFlux(s,t+4_pInt) & + + lineLength / mesh_ipVolume(ip,el) * (1.0_pReal - transmissivity) & + * sign(1.0_pReal, my_v(s,t)) ! dislocation flux that is not able to leave through interface (because of low transmissivity) will remain as immobile single density at the material point + endif + enddo + enddo + endif + + enddo ! neighbor loop +endif + + + +!**************************************************************************** +!*** calculate dipole formation and annihilation + +!*** formation by glide + +do c = 1_pInt,2_pInt + rhoDotSingle2DipoleGlide(1:ns,2*c-1) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile + + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile + + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) ! positive mobile --> negative immobile + + rhoDotSingle2DipoleGlide(1:ns,2*c) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) & ! negative mobile --> positive mobile + + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1)) & ! positive mobile --> negative mobile + + abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c))) ! negative mobile --> positive immobile + + rhoDotSingle2DipoleGlide(1:ns,2*c+3) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * rhoSgl(1:ns,2*c+3) * abs(gdot(1:ns,2*c)) ! negative mobile --> positive immobile + + rhoDotSingle2DipoleGlide(1:ns,2*c+4) = -2.0_pReal * dUpper(1:ns,c) / burgers(1:ns,instance) & + * rhoSgl(1:ns,2*c+4) * abs(gdot(1:ns,2*c-1)) ! positive mobile --> negative immobile + + rhoDotSingle2DipoleGlide(1:ns,c+8) = - rhoDotSingle2DipoleGlide(1:ns,2*c-1) & + - rhoDotSingle2DipoleGlide(1:ns,2*c) & + + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+3)) & + + abs(rhoDotSingle2DipoleGlide(1:ns,2*c+4)) +enddo + + +!*** athermal annihilation + +rhoDotAthermalAnnihilation = 0.0_pReal + +forall (c=1_pInt:2_pInt) & + rhoDotAthermalAnnihilation(1:ns,c+8_pInt) = -2.0_pReal * dLower(1:ns,c) / burgers(1:ns,instance) & + * ( 2.0_pReal * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1))) & ! was single hitting single + + 2.0_pReal * (abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c)) + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) & ! was single hitting immobile single or was immobile single hit by single + + rhoDip(1:ns,c) * (abs(gdot(1:ns,2*c-1)) + abs(gdot(1:ns,2*c)))) ! single knocks dipole constituent +! annihilated screw dipoles leave edge jogs behind on the colinear system +if (lattice_structure(ph) == LATTICE_fcc_ID) & ! only fcc + forall (s = 1:ns, colinearSystem(s,instance) > 0_pInt) & + rhoDotAthermalAnnihilation(colinearSystem(s,instance),1:2) = - rhoDotAthermalAnnihilation(s,10) & + * 0.25_pReal * sqrt(rhoForest(s)) * (dUpper(s,2) + dLower(s,2)) * edgeJogFactor(instance) + + + +!*** thermally activated annihilation of edge dipoles by climb + +rhoDotThermalAnnihilation = 0.0_pReal +selfDiffusion = Dsd0(instance) * exp(-selfDiffusionEnergy(instance) / (KB * Temperature)) +vClimb = atomicVolume(instance) * selfDiffusion / ( KB * Temperature ) & + * lattice_mu(ph) / ( 2.0_pReal * PI * (1.0_pReal-lattice_nu(ph)) ) & + * 2.0_pReal / ( dUpper(1:ns,1) + dLower(1:ns,1) ) +forall (s = 1_pInt:ns, dUpper(s,1) > dLower(s,1)) & + rhoDotThermalAnnihilation(s,9) = max(- 4.0_pReal * rhoDip(s,1) * vClimb(s) / (dUpper(s,1) - dLower(s,1)), & + - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & + - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have + + + +!**************************************************************************** +!*** assign the rates of dislocation densities to my dotState +!*** if evolution rates lead to negative densities, a cutback is enforced + +rhoDot = 0.0_pReal +rhoDot = rhoDotFlux & + + rhoDotMultiplication & + + rhoDotSingle2DipoleGlide & + + rhoDotAthermalAnnihilation & + + rhoDotThermalAnnihilation + +if (numerics_integrationMode == 1_pInt) then ! save rates for output if in central integration mode + rhoDotFluxOutput(1:ns,1:8,1_pInt,ip,el) = rhoDotFlux(1:ns,1:8) + rhoDotMultiplicationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotMultiplication(1:ns,[1,3]) + rhoDotSingle2DipoleGlideOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotSingle2DipoleGlide(1:ns,9:10) + rhoDotAthermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotAthermalAnnihilation(1:ns,9:10) + rhoDotThermalAnnihilationOutput(1:ns,1:2,1_pInt,ip,el) = rhoDotThermalAnnihilation(1:ns,9:10) + rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) = 2.0_pReal * rhoDotThermalAnnihilation(1:ns,1) +endif + + +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & + .and. ((debug_e == el .and. debug_i == ip .and. debug_g == 1_pInt)& + .or. .not. iand(debug_level(debug_constitutive),debug_levelSelective) /= 0_pInt )) then + write(6,'(a,/,4(12x,12(e12.5,1x),/))') '<< CONST >> dislocation multiplication', & + rhoDotMultiplication(1:ns,1:4) * timestep + write(6,'(a,/,8(12x,12(e12.5,1x),/))') '<< CONST >> dislocation flux', & + rhoDotFlux(1:ns,1:8) * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> dipole formation by glide', & + rhoDotSingle2DipoleGlide * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> athermal dipole annihilation', & + rhoDotAthermalAnnihilation * timestep + write(6,'(a,/,2(12x,12(e12.5,1x),/))') '<< CONST >> thermally activated dipole annihilation', & + rhoDotThermalAnnihilation(1:ns,9:10) * timestep + write(6,'(a,/,10(12x,12(e12.5,1x),/))') '<< CONST >> total density change', & + rhoDot * timestep + write(6,'(a,/,10(12x,12(f12.5,1x),/))') '<< CONST >> relative density change', & + rhoDot(1:ns,1:8) * timestep / (abs(rhoSglOriginal)+1.0e-10), & + rhoDot(1:ns,9:10) * timestep / (rhoDipOriginal+1.0e-10) + write(6,*) + endif +#endif + + +if ( any(rhoSglOriginal(1:ns,1:4) + rhoDot(1:ns,1:4) * timestep < -aTolRho(instance)) & + .or. any(rhoDipOriginal(1:ns,1:2) + rhoDot(1:ns,9:10) * timestep < -aTolRho(instance))) then +#ifndef _OPENMP + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then + write(6,'(a,i5,a,i2)') '<< CONST >> evolution rate leads to negative density at el ',el,' ip ',ip + write(6,'(a)') '<< CONST >> enforcing cutback !!!' + endif +#endif + plasticState(p)%dotState = DAMASK_NaN + return +else + forall (s = 1:ns, t = 1_pInt:4_pInt) + plasticState(p)%dotState(iRhoU(s,t,instance),o) = rhoDot(s,t) + plasticState(p)%dotState(iRhoB(s,t,instance),o) = rhoDot(s,t+4_pInt) + endforall + forall (s = 1:ns, c = 1_pInt:2_pInt) & + plasticState(p)%dotState(iRhoD(s,c,instance),o) = rhoDot(s,c+8_pInt) + forall (s = 1:ns) & + plasticState(p)%dotState(iGamma(s,instance),o) = sum(gdot(s,1:4)) +endif + +end subroutine plastic_nonlocal_dotState + + +!********************************************************************* +!* COMPATIBILITY UPDATE * +!* Compatibility is defined as normalized product of signed cosine * +!* of the angle between the slip plane normals and signed cosine of * +!* the angle between the slip directions. Only the largest values * +!* that sum up to a total of 1 are considered, all others are set to * +!* zero. * +!********************************************************************* +subroutine plastic_nonlocal_updateCompatibility(orientation,i,e) + +use math, only: math_mul3x3, & + math_qRot +use material, only: material_phase, & + material_texture, & + phase_localPlasticity, & + phase_plasticityInstance, & + homogenization_maxNgrains +use mesh, only: mesh_element, & + mesh_ipNeighborhood, & + mesh_maxNips, & + mesh_NcpElems, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype +use lattice, only: lattice_sn, & + lattice_sd, & + lattice_qDisorientation + +implicit none + +!* input variables +integer(pInt), intent(in) :: i, & ! ip index + e ! element index +real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + orientation ! crystal orientation in quaternions + +!* local variables +integer(pInt) Nneighbors, & ! number of neighbors + n, & ! neighbor index + neighbor_e, & ! element index of my neighbor + neighbor_i, & ! integration point index of my neighbor + ph, & + neighbor_phase, & + textureID, & + neighbor_textureID, & + instance, & ! instance of plasticity + ns, & ! number of active slip systems + s1, & ! slip system index (me) + s2 ! slip system index (my neighbor) +real(pReal), dimension(4) :: absoluteMisorientation ! absolute misorientation (without symmetry) between me and my neighbor +real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& + totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& + FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e))))) :: & + my_compatibility ! my_compatibility for current element and ip +real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & + slipNormal, & + slipDirection +real(pReal) my_compatibilitySum, & + thresholdValue, & + nThresholdValues +logical, dimension(totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & + belowThreshold + + +Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e)))) +ph = material_phase(1,i,e) +textureID = material_texture(1,i,e) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) +slipNormal(1:3,1:ns) = lattice_sn(1:3, slipSystemLattice(1:ns,instance), ph) +slipDirection(1:3,1:ns) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) + + +!*** start out fully compatible + +my_compatibility = 0.0_pReal +forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,1:Nneighbors) = 1.0_pReal + + +!*** Loop thrugh neighbors and check whether there is any my_compatibility. + +do n = 1_pInt,Nneighbors + neighbor_e = mesh_ipNeighborhood(1,n,i,e) + neighbor_i = mesh_ipNeighborhood(2,n,i,e) + + + !* FREE SURFACE + !* Set surface transmissivity to the value specified in the material.config + + if (neighbor_e <= 0_pInt .or. neighbor_i <= 0_pInt) then + forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,n) = sqrt(surfaceTransmissivity(instance)) + cycle + endif + + + !* PHASE BOUNDARY + !* If we encounter a different nonlocal "cpfem" phase at the neighbor, + !* we consider this to be a real "physical" phase boundary, so completely incompatible. + !* If one of the two "CPFEM" phases has a local plasticity law, + !* we do not consider this to be a phase boundary, so completely compatible. + + neighbor_phase = material_phase(1,neighbor_i,neighbor_e) + if (neighbor_phase /= ph) then + if (.not. phase_localPlasticity(neighbor_phase) .and. .not. phase_localPlasticity(ph)) then + forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,n) = 0.0_pReal ! = sqrt(0.0) + endif + cycle + endif + + + !* GRAIN BOUNDARY ! + !* fixed transmissivity for adjacent ips with different texture (only if explicitly given in material.config) + + if (grainboundaryTransmissivity(instance) >= 0.0_pReal) then + neighbor_textureID = material_texture(1,neighbor_i,neighbor_e) + if (neighbor_textureID /= textureID) then + if (.not. phase_localPlasticity(neighbor_phase)) then + forall(s1 = 1_pInt:ns) & + my_compatibility(1:2,s1,s1,n) = sqrt(grainboundaryTransmissivity(instance)) + endif + cycle + endif + + + !* GRAIN BOUNDARY ? + !* Compatibility defined by relative orientation of slip systems: + !* The my_compatibility value is defined as the product of the slip normal projection and the slip direction projection. + !* Its sign is always positive for screws, for edges it has the same sign as the slip normal projection. + !* Since the sum for each slip system can easily exceed one (which would result in a transmissivity larger than one), + !* only values above or equal to a certain threshold value are considered. This threshold value is chosen, such that + !* the number of compatible slip systems is minimized with the sum of the original my_compatibility values exceeding one. + !* Finally the smallest my_compatibility value is decreased until the sum is exactly equal to one. + !* All values below the threshold are set to zero. + else + absoluteMisorientation = lattice_qDisorientation(orientation(1:4,1,i,e), & + orientation(1:4,1,neighbor_i,neighbor_e)) ! no symmetry + do s1 = 1_pInt,ns ! my slip systems + do s2 = 1_pInt,ns ! my neighbor's slip systems + my_compatibility(1,s2,s1,n) = math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2))) & + * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) + my_compatibility(2,s2,s1,n) = abs(math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2)))) & + * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) + enddo + + my_compatibilitySum = 0.0_pReal + belowThreshold = .true. + do while (my_compatibilitySum < 1.0_pReal .and. any(belowThreshold(1:ns))) + thresholdValue = maxval(my_compatibility(2,1:ns,s1,n), belowThreshold(1:ns)) ! screws always positive + nThresholdValues = real(count(my_compatibility(2,1:ns,s1,n) == thresholdValue),pReal) + where (my_compatibility(2,1:ns,s1,n) >= thresholdValue) & + belowThreshold(1:ns) = .false. + if (my_compatibilitySum + thresholdValue * nThresholdValues > 1.0_pReal) & + where (abs(my_compatibility(1:2,1:ns,s1,n)) == thresholdValue) & ! MD: rather check below threshold? + my_compatibility(1:2,1:ns,s1,n) = sign((1.0_pReal - my_compatibilitySum) & + / nThresholdValues, my_compatibility(1:2,1:ns,s1,n)) + my_compatibilitySum = my_compatibilitySum + nThresholdValues * thresholdValue + enddo + where (belowThreshold(1:ns)) my_compatibility(1,1:ns,s1,n) = 0.0_pReal + where (belowThreshold(1:ns)) my_compatibility(2,1:ns,s1,n) = 0.0_pReal + enddo ! my slip systems cycle + endif + +enddo ! neighbor cycle + +compatibility(1:2,1:ns,1:ns,1:Nneighbors,i,e) = my_compatibility + +end subroutine plastic_nonlocal_updateCompatibility + +!********************************************************************* +!* calculates quantities characterizing the microstructure * +!********************************************************************* +function plastic_nonlocal_dislocationstress(Fe, ip, el) +use math, only: math_mul33x33, & + math_mul33x3, & + math_inv33, & + math_transpose33, & + pi +use mesh, only: mesh_NcpElems, & + mesh_maxNips, & + mesh_element, & + mesh_node0, & + mesh_cellCenterCoordinates, & + mesh_ipVolume, & + mesh_periodicSurface, & + FE_Nips, & + FE_geomtype +use material, only: homogenization_maxNgrains, & + material_phase, & + plasticState, & + phaseAt, phasememberAt,& + phase_localPlasticity, & + phase_plasticityInstance +use lattice, only: lattice_mu, & + lattice_nu + +implicit none + +!*** input variables +integer(pInt), intent(in) :: ip, & !< current integration point + el !< current element +real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + Fe !< elastic deformation gradient + +!*** output variables +real(pReal), dimension(3,3) :: plastic_nonlocal_dislocationstress + +!*** local variables +integer(pInt) neighbor_el, & !< element number of neighbor material point + neighbor_ip, & !< integration point of neighbor material point + instance, & !< my instance of this plasticity + neighbor_instance, & !< instance of this plasticity of neighbor material point + ph, & + neighbor_phase, & + ns, & !< total number of active slip systems at my material point + neighbor_ns, & !< total number of active slip systems at neighbor material point + c, & !< index of dilsocation character (edge, screw) + s, & !< slip system index + o,& !< offset shortcut + no,& !< neighbour offset shortcut + p,& !< phase shortcut + np,& !< neighbour phase shortcut + t, & !< index of dilsocation type (e+, e-, s+, s-, used e+, used e-, used s+, used s-) + dir, & + deltaX, deltaY, deltaZ, & + side, & + j +integer(pInt), dimension(2,3) :: periodicImages +real(pReal) x, y, z, & !< coordinates of connection vector in neighbor lattice frame + xsquare, ysquare, zsquare, & !< squares of respective coordinates + distance, & !< length of connection vector + segmentLength, & !< segment length of dislocations + lambda, & + R, Rsquare, Rcube, & + denominator, & + flipSign, & + neighbor_ipVolumeSideLength +real(pReal), dimension(3) :: connection, & !< connection vector between me and my neighbor in the deformed configuration + connection_neighborLattice, & !< connection vector between me and my neighbor in the lattice configuration of my neighbor + connection_neighborSlip, & !< connection vector between me and my neighbor in the slip system frame of my neighbor + maxCoord, minCoord, & + meshSize, & + coords, & !< x,y,z coordinates of cell center of ip volume + neighbor_coords !< x,y,z coordinates of cell center of neighbor ip volume +real(pReal), dimension(3,3) :: sigma, & !< dislocation stress for one slip system in neighbor material point's slip system frame + Tdislo_neighborLattice, & !< dislocation stress as 2nd Piola-Kirchhoff stress at neighbor material point + invFe, & !< inverse of my elastic deformation gradient + neighbor_invFe, & + neighborLattice2myLattice !< mapping from neighbor MPs lattice configuration to my lattice configuration +real(pReal), dimension(2,2,maxval(totalNslip)) :: & + neighbor_rhoExcess !< excess density at neighbor material point (edge/screw,mobile/dead,slipsystem) +real(pReal), dimension(2,maxval(totalNslip)) :: & + rhoExcessDead +real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl ! single dislocation density (edge+, edge-, screw+, screw-, used edge+, used edge-, used screw+, used screw-) + +ph = material_phase(1_pInt,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) +p = phaseAt(1,ip,el) +o = phasememberAt(1,ip,el) + +!*** get basic states + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = max(plasticState(p)%state(iRhoU(s,t,instance),o), 0.0_pReal) ! ensure positive single mobile densities + rhoSgl(s,t+4_pInt) = plasticState(p)%state(iRhoB(s,t,instance),o) +endforall + + + +!*** calculate the dislocation stress of the neighboring excess dislocation densities +!*** zero for material points of local plasticity + +plastic_nonlocal_dislocationstress = 0.0_pReal + +if (.not. phase_localPlasticity(ph)) then + invFe = math_inv33(Fe(1:3,1:3,1_pInt,ip,el)) + + !* in case of periodic surfaces we have to find out how many periodic images in each direction we need + + do dir = 1_pInt,3_pInt + maxCoord(dir) = maxval(mesh_node0(dir,:)) + minCoord(dir) = minval(mesh_node0(dir,:)) + enddo + meshSize = maxCoord - minCoord + coords = mesh_cellCenterCoordinates(ip,el) + periodicImages = 0_pInt + do dir = 1_pInt,3_pInt + if (mesh_periodicSurface(dir)) then + periodicImages(1,dir) = floor((coords(dir) - cutoffRadius(instance) - minCoord(dir)) / meshSize(dir), pInt) + periodicImages(2,dir) = ceiling((coords(dir) + cutoffRadius(instance) - maxCoord(dir)) / meshSize(dir), pInt) + endif + enddo + + + !* loop through all material points (also through their periodic images if present), + !* but only consider nonlocal neighbors within a certain cutoff radius R + + do neighbor_el = 1_pInt,mesh_NcpElems + ipLoop: do neighbor_ip = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,neighbor_el))) + neighbor_phase = material_phase(1_pInt,neighbor_ip,neighbor_el) + np = phaseAt(1,neighbor_ip,neighbor_el) + no = phasememberAt(1,neighbor_ip,neighbor_el) + + if (phase_localPlasticity(neighbor_phase)) cycle + neighbor_instance = phase_plasticityInstance(neighbor_phase) + neighbor_ns = totalNslip(neighbor_instance) + neighbor_invFe = math_inv33(Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) + neighbor_ipVolumeSideLength = mesh_ipVolume(neighbor_ip,neighbor_el) ** (1.0_pReal/3.0_pReal) ! reference volume used here + + forall (s = 1_pInt:neighbor_ns, c = 1_pInt:2_pInt) + neighbor_rhoExcess(c,1,s) = plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no) & ! positive mobiles + - plasticState(np)%state(iRhoU(s,2*c,neighbor_instance),no) ! negative mobiles + neighbor_rhoExcess(c,2,s) = abs(plasticState(np)%state(iRhoB(s,2*c-1,neighbor_instance),no)) & ! positive deads + - abs(plasticState(np)%state(iRhoB(s,2*c,neighbor_instance),no)) ! negative deads + + endforall + Tdislo_neighborLattice = 0.0_pReal + do deltaX = periodicImages(1,1),periodicImages(2,1) + do deltaY = periodicImages(1,2),periodicImages(2,2) + do deltaZ = periodicImages(1,3),periodicImages(2,3) + + + !* regular case + + if (neighbor_el /= el .or. neighbor_ip /= ip & + .or. deltaX /= 0_pInt .or. deltaY /= 0_pInt .or. deltaZ /= 0_pInt) then + + neighbor_coords = mesh_cellCenterCoordinates(neighbor_ip,neighbor_el) & + + [real(deltaX,pReal), real(deltaY,pReal), real(deltaZ,pReal)] * meshSize + connection = neighbor_coords - coords + distance = sqrt(sum(connection * connection)) + if (distance > cutoffRadius(instance)) cycle + + + !* the segment length is the minimum of the third root of the control volume and the ip distance + !* this ensures, that the central MP never sits on a neighbor dislocation segment + + connection_neighborLattice = math_mul33x3(neighbor_invFe, connection) + segmentLength = min(neighbor_ipVolumeSideLength, distance) + + + !* loop through all slip systems of the neighbor material point + !* and add up the stress contributions from egde and screw excess on these slip systems (if significant) + + do s = 1_pInt,neighbor_ns + if (all(abs(neighbor_rhoExcess(:,:,s)) < significantRho(instance))) cycle ! not significant + + + !* map the connection vector from the lattice into the slip system frame + + connection_neighborSlip = math_mul33x3(lattice2slip(1:3,1:3,s,neighbor_instance), & + connection_neighborLattice) + + + !* edge contribution to stress + sigma = 0.0_pReal + + x = connection_neighborSlip(1) + y = connection_neighborSlip(2) + z = connection_neighborSlip(3) + xsquare = x * x + ysquare = y * y + zsquare = z * z + + do j = 1_pInt,2_pInt + if (abs(neighbor_rhoExcess(1,j,s)) < significantRho(instance)) then + cycle + elseif (j > 1_pInt) then + x = connection_neighborSlip(1) & + + sign(0.5_pReal * segmentLength, & + plasticState(np)%state(iRhoB(s,1,neighbor_instance),no) & + - plasticState(np)%state(iRhoB(s,2,neighbor_instance),no)) + + xsquare = x * x + endif + + flipSign = sign(1.0_pReal, -y) + do side = 1_pInt,-1_pInt,-2_pInt + lambda = real(side,pReal) * 0.5_pReal * segmentLength - y + R = sqrt(xsquare + zsquare + lambda * lambda) + Rsquare = R * R + Rcube = Rsquare * R + denominator = R * (R + flipSign * lambda) + if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop + + sigma(1,1) = sigma(1,1) - real(side,pReal) & + * flipSign * z / denominator & + * (1.0_pReal + xsquare / Rsquare + xsquare / denominator) & + * neighbor_rhoExcess(1,j,s) + sigma(2,2) = sigma(2,2) - real(side,pReal) & + * (flipSign * 2.0_pReal * lattice_nu(ph) * z / denominator + z * lambda / Rcube) & + * neighbor_rhoExcess(1,j,s) + sigma(3,3) = sigma(3,3) + real(side,pReal) & + * flipSign * z / denominator & + * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & + * neighbor_rhoExcess(1,j,s) + sigma(1,2) = sigma(1,2) + real(side,pReal) & + * x * z / Rcube * neighbor_rhoExcess(1,j,s) + sigma(1,3) = sigma(1,3) + real(side,pReal) & + * flipSign * x / denominator & + * (1.0_pReal - zsquare / Rsquare - zsquare / denominator) & + * neighbor_rhoExcess(1,j,s) + sigma(2,3) = sigma(2,3) - real(side,pReal) & + * (lattice_nu(ph) / R - zsquare / Rcube) * neighbor_rhoExcess(1,j,s) + enddo + enddo + + !* screw contribution to stress + + x = connection_neighborSlip(1) ! have to restore this value, because position might have been adapted for edge deads before + do j = 1_pInt,2_pInt + if (abs(neighbor_rhoExcess(2,j,s)) < significantRho(instance)) then + cycle + elseif (j > 1_pInt) then + y = connection_neighborSlip(2) & + + sign(0.5_pReal * segmentLength, & + plasticState(np)%state(iRhoB(s,3,neighbor_instance),no) & + - plasticState(np)%state(iRhoB(s,4,neighbor_instance),no)) + ysquare = y * y + endif + + flipSign = sign(1.0_pReal, x) + do side = 1_pInt,-1_pInt,-2_pInt + lambda = x + real(side,pReal) * 0.5_pReal * segmentLength + R = sqrt(ysquare + zsquare + lambda * lambda) + Rsquare = R * R + Rcube = Rsquare * R + denominator = R * (R + flipSign * lambda) + if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop + + sigma(1,2) = sigma(1,2) - real(side,pReal) * flipSign * z & + * (1.0_pReal - lattice_nu(ph)) / denominator & + * neighbor_rhoExcess(2,j,s) + sigma(1,3) = sigma(1,3) + real(side,pReal) * flipSign * y & + * (1.0_pReal - lattice_nu(ph)) / denominator & + * neighbor_rhoExcess(2,j,s) + enddo + enddo + + if (all(abs(sigma) < 1.0e-10_pReal)) cycle ! SIGMA IS NOT A REAL STRESS, THATS WHY WE NEED A REALLY SMALL VALUE HERE + + !* copy symmetric parts + + sigma(2,1) = sigma(1,2) + sigma(3,1) = sigma(1,3) + sigma(3,2) = sigma(2,3) + + + !* scale stresses and map them into the neighbor material point's lattice configuration + + sigma = sigma * lattice_mu(neighbor_phase) * burgers(s,neighbor_instance) & + / (4.0_pReal * pi * (1.0_pReal - lattice_nu(neighbor_phase))) & + * mesh_ipVolume(neighbor_ip,neighbor_el) / segmentLength ! reference volume is used here (according to the segment length calculation) + Tdislo_neighborLattice = Tdislo_neighborLattice & + + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,neighbor_instance)), & + math_mul33x33(sigma, lattice2slip(1:3,1:3,s,neighbor_instance))) + + enddo ! slip system loop + + + !* special case of central ip volume + !* only consider dead dislocations + !* we assume that they all sit at a distance equal to half the third root of V + !* in direction of the according slip direction + + else + + forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & + + rhoExcessDead(c,s) = plasticState(p)%state(iRhoB(s,2*c-1,instance),o) & ! positive deads (here we use symmetry: if this has negative sign it is + !treated as negative density at positive position instead of positive + !density at negative position) + + plasticState(p)%state(iRhoB(s,2*c,instance),o) ! negative deads (here we use symmetry: if this has negative sign it is + !treated as positive density at positive position instead of negative + !density at negative position) + do s = 1_pInt,ns + if (all(abs(rhoExcessDead(:,s)) < significantRho(instance))) cycle ! not significant + sigma = 0.0_pReal ! all components except for sigma13 are zero + sigma(1,3) = - (rhoExcessDead(1,s) + rhoExcessDead(2,s) * (1.0_pReal - lattice_nu(ph))) & + * neighbor_ipVolumeSideLength * lattice_mu(ph) * burgers(s,instance) & + / (sqrt(2.0_pReal) * pi * (1.0_pReal - lattice_nu(ph))) + sigma(3,1) = sigma(1,3) + + Tdislo_neighborLattice = Tdislo_neighborLattice & + + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,instance)), & + math_mul33x33(sigma, lattice2slip(1:3,1:3,s,instance))) + + enddo ! slip system loop + + endif + + enddo ! deltaZ loop + enddo ! deltaY loop + enddo ! deltaX loop + + + !* map the stress from the neighbor MP's lattice configuration into the deformed configuration + !* and back into my lattice configuration + + neighborLattice2myLattice = math_mul33x33(invFe, Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) + plastic_nonlocal_dislocationstress = plastic_nonlocal_dislocationstress & + + math_mul33x33(neighborLattice2myLattice, & + math_mul33x33(Tdislo_neighborLattice, & + math_transpose33(neighborLattice2myLattice))) + + enddo ipLoop + enddo ! element loop + +endif + +end function plastic_nonlocal_dislocationstress + + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_nonlocal_postResults(Tstar_v,Fe,ip,el) + use math, only: & + math_mul6x6, & + math_mul33x3, & + math_mul33x33, & + pi + use mesh, only: & + mesh_NcpElems, & + mesh_maxNips + use material, only: & + homogenization_maxNgrains, & + material_phase, & + phaseAt, phasememberAt, & + plasticState, & + phase_plasticityInstance + use lattice, only: & + lattice_Sslip_v, & + lattice_sd, & + lattice_st, & + lattice_sn, & + lattice_mu, & + lattice_nu + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + Fe !< elastic deformation gradient + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + + real(pReal), dimension(plastic_nonlocal_sizePostResults(& + phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + plastic_nonlocal_postResults + + integer(pInt) :: & + ph, & + instance, & !< current instance of this plasticity + ns, & !< short notation for the total number of active slip systems + c, & !< character of dislocation + cs, & !< constitutive result index + o, & !< index of current output + of,& !< offset shortcut + t, & !< type of dislocation + s, & !< index of my current slip system + sLattice !< index of my current slip system according to lattice order + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & + rhoSgl, & !< current single dislocation densities (positive/negative screw and edge without dipoles) + rhoDotSgl !< evolution rate of single dislocation densities (positive/negative screw and edge without dipoles) + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & + gdot, & !< shear rates + v !< velocities + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + rhoForest, & !< forest dislocation density + tauThreshold, & !< threshold shear stress + tau, & !< current resolved shear stress + tauBack !< back stress from pileups on same slip system + real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) + rhoDotDip, & !< evolution rate of dipole dislocation densities (screw and edge dipoles) + dLower, & !< minimum stable dipole distance for edges and screws + dUpper !< current maximum stable dipole distance for edges and screws + real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & + m, & !< direction of dislocation motion for edge and screw (unit vector) + m_currentconf !< direction of dislocation motion for edge and screw (unit vector) in current configuration + real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & + n_currentconf !< slip system normal (unit vector) in current configuration + real(pReal), dimension(3,3) :: & + sigma + +ph = phaseAt(1,ip,el) +of = phasememberAt(1,ip,el) +instance = phase_plasticityInstance(ph) +ns = totalNslip(instance) + +cs = 0_pInt +plastic_nonlocal_postResults = 0.0_pReal + + +!* short hand notations for state variables + +forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) + rhoSgl(s,t) = plasticState(ph)%State(iRhoU(s,t,instance),of) + rhoSgl(s,t+4_pInt) = plasticState(ph)%State(iRhoB(s,t,instance),of) + v(s,t) = plasticState(ph)%State(iV(s,t,instance),of) + rhoDotSgl(s,t) = plasticState(ph)%dotState(iRhoU(s,t,instance),of) + rhoDotSgl(s,t+4_pInt) = plasticState(ph)%dotState(iRhoB(s,t,instance),of) +endforall +forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) + rhoDip(s,c) = plasticState(ph)%State(iRhoD(s,c,instance),of) + rhoDotDip(s,c) = plasticState(ph)%dotState(iRhoD(s,c,instance),of) +endforall +rhoForest = plasticState(ph)%State(iRhoF(1:ns,instance),of) +tauThreshold = plasticState(ph)%State(iTauF(1:ns,instance),of) +tauBack = plasticState(ph)%State(iTauB(1:ns,instance),of) + +!* Calculate shear rate + +forall (t = 1_pInt:4_pInt) & + gdot(1:ns,t) = rhoSgl(1:ns,t) * burgers(1:ns,instance) * v(1:ns,t) + + +!* calculate limits for stable dipole height + +do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) + if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal +enddo + +dLower = minDipoleHeight(1:ns,1:2,instance) +dUpper(1:ns,1) = lattice_mu(ph) * burgers(1:ns,instance) & + / (8.0_pReal * pi * (1.0_pReal - lattice_nu(ph)) * abs(tau)) +dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & + / (4.0_pReal * pi * abs(tau)) +forall (c = 1_pInt:2_pInt) + where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& + abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & + dUpper(1:ns,c)) +end forall +dUpper = max(dUpper,dLower) + + +!*** dislocation motion + +m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) +m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) +forall (c = 1_pInt:2_pInt, s = 1_pInt:ns) & + m_currentconf(1:3,s,c) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), m(1:3,s,c)) +forall (s = 1_pInt:ns) & + n_currentconf(1:3,s) = math_mul33x3(Fe(1:3,1:3,1_pInt,ip,el), & + lattice_sn(1:3,slipSystemLattice(s,instance),ph)) + + +outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) + select case(plastic_nonlocal_outputID(o,instance)) + case (rho_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) + sum(rhoDip,2) + cs = cs + ns + + case (rho_sgl_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) + cs = cs + ns + + case (rho_sgl_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,1:4)),2) + cs = cs + ns + + case (rho_sgl_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:8),2) + cs = cs + ns + + case (rho_dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDip,2) + cs = cs + ns + + case (rho_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1) + cs = cs + ns + + case (rho_sgl_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + cs = cs + ns + + case (rho_sgl_edge_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,1:2),2) + cs = cs + ns + + case (rho_sgl_edge_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:6),2) + cs = cs + ns + + case (rho_sgl_edge_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5)) + cs = cs + ns + + case (rho_sgl_edge_pos_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) + cs = cs + ns + + case (rho_sgl_edge_pos_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,5) + cs = cs + ns + + case (rho_sgl_edge_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6)) + cs = cs + ns + + case (rho_sgl_edge_neg_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) + cs = cs + ns + + case (rho_sgl_edge_neg_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,6) + cs = cs + ns + + case (rho_dip_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,1) + cs = cs + ns + + case (rho_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2) + cs = cs + ns + + case (rho_sgl_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + cs = cs + ns + + case (rho_sgl_screw_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,3:4),2) + cs = cs + ns + + case (rho_sgl_screw_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,7:8),2) + cs = cs + ns + + case (rho_sgl_screw_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7)) + cs = cs + ns + + case (rho_sgl_screw_pos_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) + cs = cs + ns + + case (rho_sgl_screw_pos_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,7) + cs = cs + ns + + case (rho_sgl_screw_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8)) + cs = cs + ns + + case (rho_sgl_screw_neg_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) + cs = cs + ns + + case (rho_sgl_screw_neg_immobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,8) + cs = cs + ns + + case (rho_dip_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,2) + cs = cs + ns + + case (excess_rho_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & + - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) & + + (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & + - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) + cs = cs + ns + + case (excess_rho_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & + - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) + cs = cs + ns + + case (excess_rho_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & + - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) + cs = cs + ns + + case (rho_forest_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoForest + cs = cs + ns + + case (delta_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2) + sum(rhoDip,2)) + cs = cs + ns + + case (delta_sgl_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2)) + cs = cs + ns + + case (delta_dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(rhoDip,2)) + cs = cs + ns + + case (shearrate_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(gdot,2) + cs = cs + ns + + case (resolvedstress_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tau + cs = cs + ns + + case (resolvedstress_back_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauBack + cs = cs + ns + + case (resolvedstress_external_ID) + do s = 1_pInt,ns + sLattice = slipSystemLattice(s,instance) + plastic_nonlocal_postResults(cs+s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + enddo + cs = cs + ns + + case (resistance_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauThreshold + cs = cs + ns + + case (rho_dot_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & + + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) & + + sum(rhoDotDip,2) + cs = cs + ns + + case (rho_dot_sgl_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & + + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) + cs = cs + ns + + case (rho_dot_sgl_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) + cs = cs + ns + + case (rho_dot_dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotDip,2) + cs = cs + ns + + case (rho_dot_gen_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_gen_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_gen_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_sgl2dip_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_sgl2dip_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_sgl2dip_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_ath_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotAthermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotAthermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_the_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & + + rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_the_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_ann_the_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_edgejogs_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) + cs = cs + ns + + case (rho_dot_flux_mobile_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) + cs = cs + ns + + case (rho_dot_flux_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) & + + sum(rhoDotFluxOutput(1:ns,5:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) + cs = cs + ns + + case (rho_dot_flux_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:2,1_pInt,ip,el),2) & + + sum(rhoDotFluxOutput(1:ns,5:6,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:6)),2) + cs = cs + ns + + case (rho_dot_flux_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,3:4,1_pInt,ip,el),2) & + + sum(rhoDotFluxOutput(1:ns,7:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,7:8)),2) + cs = cs + ns + + case (velocity_edge_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,1) + cs = cs + ns + + case (velocity_edge_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,2) + cs = cs + ns + + case (velocity_screw_pos_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,3) + cs = cs + ns + + case (velocity_screw_neg_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,4) + cs = cs + ns + + case (slipdirectionx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(1,1:ns,1) + cs = cs + ns + + case (slipdirectiony_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(2,1:ns,1) + cs = cs + ns + + case (slipdirectionz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(3,1:ns,1) + cs = cs + ns + + case (slipnormalx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(1,1:ns) + cs = cs + ns + + case (slipnormaly_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(2,1:ns) + cs = cs + ns + + case (slipnormalz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(3,1:ns) + cs = cs + ns + + case (fluxdensity_edge_posx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(1,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_posy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(2,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_posz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(3,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_negx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(1,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_negy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(2,1:ns,1) + cs = cs + ns + + case (fluxdensity_edge_negz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(3,1:ns,1) + cs = cs + ns + + case (fluxdensity_screw_posx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(1,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_posy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(2,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_posz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(3,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_negx_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(1,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_negy_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(2,1:ns,2) + cs = cs + ns + + case (fluxdensity_screw_negz_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(3,1:ns,2) + cs = cs + ns + + case (maximumdipoleheight_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,1) + cs = cs + ns + + case (maximumdipoleheight_screw_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,2) + cs = cs + ns + + case(dislocationstress_ID) + sigma = plastic_nonlocal_dislocationstress(Fe, ip, el) + plastic_nonlocal_postResults(cs+1_pInt) = sigma(1,1) + plastic_nonlocal_postResults(cs+2_pInt) = sigma(2,2) + plastic_nonlocal_postResults(cs+3_pInt) = sigma(3,3) + plastic_nonlocal_postResults(cs+4_pInt) = sigma(1,2) + plastic_nonlocal_postResults(cs+5_pInt) = sigma(2,3) + plastic_nonlocal_postResults(cs+6_pInt) = sigma(3,1) + cs = cs + 6_pInt + + case(accumulatedshear_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = plasticState(ph)%state(iGamma(1:ns,instance),of) + cs = cs + ns + + end select +enddo outputsLoop + +end function plastic_nonlocal_postResults + +end module plastic_nonlocal diff --git a/src/plastic_phenoplus.f90 b/src/plastic_phenoplus.f90 new file mode 100644 index 000000000..0a40edd84 --- /dev/null +++ b/src/plastic_phenoplus.f90 @@ -0,0 +1,1419 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @author Chen Zhang, Michigan State University +!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw +!... fitting +!-------------------------------------------------------------------------------------------------- +module plastic_phenoplus + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenoplus_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_phenoplus_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_phenoplus_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_phenoplus_Noutput !< number of outputs per instance of this constitution + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenoplus_totalNslip, & !< no. of slip system used in simulation + plastic_phenoplus_totalNtwin, & !< no. of twin system used in simulation + plastic_phenoplus_totalNtrans !< no. of trans system used in simulation + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_phenoplus_Nslip, & !< active number of slip systems per family (input parameter, per family) + plastic_phenoplus_Ntwin, & !< active number of twin systems per family (input parameter, per family) + plastic_phenoplus_Ntrans !< active number of trans systems per family (input parameter, per family) + + real(pReal), dimension(:), allocatable, private :: & + plastic_phenoplus_gdot0_slip, & !< reference shear strain rate for slip (input parameter) + plastic_phenoplus_gdot0_twin, & !< reference shear strain rate for twin (input parameter) + plastic_phenoplus_n_slip, & !< stress exponent for slip (input parameter) + plastic_phenoplus_n_twin, & !< stress exponent for twin (input parameter) + plastic_phenoplus_spr, & !< push-up factor for slip saturation due to twinning + plastic_phenoplus_twinB, & + plastic_phenoplus_twinC, & + plastic_phenoplus_twinD, & + plastic_phenoplus_twinE, & + plastic_phenoplus_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) + plastic_phenoplus_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) + plastic_phenoplus_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) + plastic_phenoplus_a_slip, & + plastic_phenoplus_aTolResistance, & + plastic_phenoplus_aTolShear, & + plastic_phenoplus_aTolTwinfrac, & + plastic_phenoplus_aTolTransfrac, & + plastic_phenoplus_Cnuc, & !< coefficient for strain-induced martensite nucleation + plastic_phenoplus_Cdwp, & !< coefficient for double well potential + plastic_phenoplus_Cgro, & !< coefficient for stress-assisted martensite growth + plastic_phenoplus_deltaG, & !< free energy difference between austensite and martensite [MPa] + plastic_phenoplus_kappa_max !< capped kappa for each slip system + + real(pReal), dimension(:,:), allocatable, private :: & + plastic_phenoplus_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) + plastic_phenoplus_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) + plastic_phenoplus_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) + plastic_phenoplus_nonSchmidCoeff, & + + plastic_phenoplus_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) + plastic_phenoplus_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) + plastic_phenoplus_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) + plastic_phenoplus_interaction_TwinTwin !< interaction factors twin - twin (input parameter) + + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_phenoplus_hardeningMatrix_SlipSlip, & + plastic_phenoplus_hardeningMatrix_SlipTwin, & + plastic_phenoplus_hardeningMatrix_TwinSlip, & + plastic_phenoplus_hardeningMatrix_TwinTwin + + enum, bind(c) + enumerator :: undefined_ID, & + resistance_slip_ID, & + accumulatedshear_slip_ID, & + shearrate_slip_ID, & + resolvedstress_slip_ID, & + kappa_slip_ID, & + totalshear_ID, & + resistance_twin_ID, & + accumulatedshear_twin_ID, & + shearrate_twin_ID, & + resolvedstress_twin_ID, & + totalvolfrac_twin_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_phenoplus_outputID !< ID of each post result output + + public :: & + plastic_phenoplus_init, & + plastic_phenoplus_microstructure, & + plastic_phenoplus_LpAndItsTangent, & + plastic_phenoplus_dotState, & + plastic_phenoplus_postResults + private :: & + plastic_phenoplus_aTolState, & + plastic_phenoplus_stateInit + + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_PHENOPLUS_label, & + PLASTICITY_PHENOPLUS_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + maxNinstance, & + instance,phase,j,k, f,o, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & + Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & + NipcMyPhase, & + offset_slip, index_myFamily, index_otherFamily, & + mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPLUS_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPLUS_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_phenoplus_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_sizePostResult(maxval(phase_Noutput),maxNinstance), & + source=0_pInt) + allocate(plastic_phenoplus_output(maxval(phase_Noutput),maxNinstance)) + plastic_phenoplus_output = '' + allocate(plastic_phenoplus_outputID(maxval(phase_Noutput),maxNinstance),source=undefined_ID) + allocate(plastic_phenoplus_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_Ntrans(lattice_maxNtransFamily,maxNinstance),source=0_pInt) + allocate(plastic_phenoplus_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_totalNtrans(maxNinstance), source=0_pInt) + allocate(plastic_phenoplus_gdot0_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_n_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_tau0_slip(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_tausat_slip(lattice_maxNslipFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_gdot0_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_n_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_tau0_twin(lattice_maxNtwinFamily,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_spr(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinB(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinC(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinD(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_twinE(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_h0_SlipSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_h0_TwinSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_h0_TwinTwin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_a_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolShear(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolTwinfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_aTolTransfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenoplus_Cnuc(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_Cdwp(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_Cgro(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_deltaG(maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_kappa_max(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase + Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPLUS_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('resistance_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_slip','accumulated_shear_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('kappa_slip') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = kappa_slip_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalshear') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalshear_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resistance_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_twin','accumulated_shear_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = accumulatedshear_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = shearrate_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = resolvedstress_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalvolfrac_twin') + plastic_phenoplus_Noutput(instance) = plastic_phenoplus_Noutput(instance) + 1_pInt + plastic_phenoplus_outputID(plastic_phenoplus_Noutput(instance),instance) = totalvolfrac_twin_ID + plastic_phenoplus_output(plastic_phenoplus_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case default + + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) + do j = 1_pInt, Nchunks_SlipFamilies + plastic_phenoplus_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tausat_slip','tau0_slip') + tempPerSlip = 0.0_pReal + do j = 1_pInt, Nchunks_SlipFamilies + if (plastic_phenoplus_Nslip(j,instance) > 0_pInt) & + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('tausat_slip') + plastic_phenoplus_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau0_slip') + plastic_phenoplus_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_phenoplus_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0_twin') + do j = 1_pInt, Nchunks_TwinFamilies + if (plastic_phenoplus_Ntwin(j,instance) > 0_pInt) & + plastic_phenoplus_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of transformation families + case ('ntrans') + if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + Nchunks_TransFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TransFamilies + plastic_phenoplus_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_phenoplus_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_phenoplus_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_phenoplus_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_phenoplus_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPLUS_label//')') + do j = 1_pInt,Nchunks_nonSchmid + plastic_phenoplus_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin systems + case ('gdot0_slip') + plastic_phenoplus_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_slip') + plastic_phenoplus_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('a_slip', 'w0_slip') + plastic_phenoplus_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('gdot0_twin') + plastic_phenoplus_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_twin') + plastic_phenoplus_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('s_pr') + plastic_phenoplus_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_b') + plastic_phenoplus_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_c') + plastic_phenoplus_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_d') + plastic_phenoplus_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_e') + plastic_phenoplus_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_slipslip') + plastic_phenoplus_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twinslip') + plastic_phenoplus_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twintwin') + plastic_phenoplus_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_resistance') + plastic_phenoplus_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_shear') + plastic_phenoplus_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_phenoplus_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_transfrac') + plastic_phenoplus_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('kappa_max') + plastic_phenoplus_kappa_max(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cnuc') + plastic_phenoplus_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cdwp') + plastic_phenoplus_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cgro') + plastic_phenoplus_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('deltag') + plastic_phenoplus_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) + case default + + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then + instance = phase_plasticityInstance(phase) + plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested + plastic_phenoplus_Nslip(1:lattice_maxNslipFamily,instance)) + plastic_phenoplus_Ntwin(1:lattice_maxNtwinFamily,instance) = & + min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested + plastic_phenoplus_Ntwin(:,instance)) + plastic_phenoplus_totalNslip(instance) = sum(plastic_phenoplus_Nslip(:,instance)) ! how many slip systems altogether + plastic_phenoplus_totalNtwin(instance) = sum(plastic_phenoplus_Ntwin(:,instance)) ! how many twin systems altogether + plastic_phenoplus_totalNtrans(instance) = sum(plastic_phenoplus_Ntrans(:,instance)) ! how many trans systems altogether + + if (any(plastic_phenoplus_tau0_slip(:,instance) < 0.0_pReal .and. & + plastic_phenoplus_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (plastic_phenoplus_gdot0_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (plastic_phenoplus_n_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (any(plastic_phenoplus_tausat_slip(:,instance) <= 0.0_pReal .and. & + plastic_phenoplus_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (any(abs(plastic_phenoplus_a_slip(instance)) <= tiny(0.0_pReal) .and. & + plastic_phenoplus_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPLUS_label//')') + if (any(plastic_phenoplus_tau0_twin(:,instance) < 0.0_pReal .and. & + plastic_phenoplus_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPLUS_label//')') + if ( plastic_phenoplus_gdot0_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenoplus_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPLUS_label//')') + if ( plastic_phenoplus_n_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenoplus_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPLUS_label//')') + if (plastic_phenoplus_aTolResistance(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa + if (plastic_phenoplus_aTolShear(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenoplus_aTolTwinfrac(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenoplus_aTolTransfrac(instance) <= 0.0_pReal) & + plastic_phenoplus_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + allocate(plastic_phenoplus_hardeningMatrix_SlipSlip(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from slip activity + maxval(plastic_phenoplus_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_hardeningMatrix_SlipTwin(maxval(plastic_phenoplus_totalNslip),& ! slip resistance from twin activity + maxval(plastic_phenoplus_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_hardeningMatrix_TwinSlip(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_phenoplus_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenoplus_hardeningMatrix_TwinTwin(maxval(plastic_phenoplus_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_phenoplus_totalNtwin),& + maxNinstance), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config + myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenoplus_ID) then ! only consider my phase + NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase + instance = phase_plasticityInstance(phase) ! which instance of my phase + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) + select case(plastic_phenoplus_outputID(o,instance)) + case(resistance_slip_ID, & + shearrate_slip_ID, & + accumulatedshear_slip_ID, & + resolvedstress_slip_ID, & + kappa_slip_ID & + ) + mySize = plastic_phenoplus_totalNslip(instance) + case(resistance_twin_ID, & + shearrate_twin_ID, & + accumulatedshear_twin_ID, & + resolvedstress_twin_ID & + ) + mySize = plastic_phenoplus_totalNtwin(instance) + case(totalshear_ID, & + totalvolfrac_twin_ID & + ) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_phenoplus_sizePostResult(o,instance) = mySize + plastic_phenoplus_sizePostResults(instance) = plastic_phenoplus_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = plastic_phenoplus_totalNslip(instance) & ! s_slip + + plastic_phenoplus_totalNtwin(instance) & ! s_twin + + 2_pInt & ! sum(gamma) + sum(f) + + plastic_phenoplus_totalNslip(instance) & ! accshear_slip + + plastic_phenoplus_totalNtwin(instance) & ! accshear_twin + + plastic_phenoplus_totalNslip(instance) ! kappa + + !sizeDotState = sizeState ! same as sizeState + !QUICK FIX: the dotState cannot have redundancy, which could cause unknown error + ! explicitly specify the size of the dotState to avoid this potential + ! memory leak issue. + sizeDotState = plastic_phenoplus_totalNslip(instance) & ! s_slip + + plastic_phenoplus_totalNtwin(instance) & ! s_twin + + 2_pInt & ! sum(gamma) + sum(f) + + plastic_phenoplus_totalNslip(instance) & ! accshear_slip + + plastic_phenoplus_totalNtwin(instance) ! accshear_twin + + sizeDeltaState = 0_pInt + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_phenoplus_sizePostResults(instance) + plasticState(phase)%nSlip =plastic_phenoplus_totalNslip(instance) + plasticState(phase)%nTwin =plastic_phenoplus_totalNtwin(instance) + plasticState(phase)%nTrans=plastic_phenoplus_totalNtrans(instance) + allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) + + offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + + do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X + index_myFamily = sum(plastic_phenoplus_Nslip(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenoplus_Nslip(f,instance) ! loop over (active) systems in my family (slip) + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenoplus_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenoplus_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + + do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X + index_myFamily = sum(plastic_phenoplus_Ntwin(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenoplus_Ntwin(f,instance) ! loop over (active) systems in my family (twin) + + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenoplus_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenoplus_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenoplus_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenoplus_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenoplus_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenoplus_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + + call plastic_phenoplus_stateInit(phase,instance) + call plastic_phenoplus_aTolState(phase,instance) + endif myPhase2 + enddo initializeInstances + +end subroutine plastic_phenoplus_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_stateInit(ph,instance) + use lattice, only: & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + integer(pInt) :: & + i + real(pReal), dimension(plasticState(ph)%sizeState) :: & + tempState + + tempState = 0.0_pReal + do i = 1_pInt,lattice_maxNslipFamily + tempState(1+sum(plastic_phenoplus_Nslip(1:i-1,instance)) : & + sum(plastic_phenoplus_Nslip(1:i ,instance))) = & + plastic_phenoplus_tau0_slip(i,instance) + enddo + + do i = 1_pInt,lattice_maxNtwinFamily + tempState(1+sum(plastic_phenoplus_Nslip(:,instance))+& + sum(plastic_phenoplus_Ntwin(1:i-1,instance)) : & + sum(plastic_phenoplus_Nslip(:,instance))+& + sum(plastic_phenoplus_Ntwin(1:i ,instance))) = & + plastic_phenoplus_tau0_twin(i,instance) + enddo + + plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array + 2, & ! along dimension 2 + size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) + +end subroutine plastic_phenoplus_stateInit + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + plasticState(ph)%aTolState(1:plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance)) = & + plastic_phenoplus_aTolResistance(instance) + plasticState(ph)%aTolState(1+plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance)) = & + plastic_phenoplus_aTolShear(instance) + plasticState(ph)%aTolState(2+plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance)) = & + plastic_phenoplus_aTolTwinFrac(instance) + plasticState(ph)%aTolState(3+plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance): & + 2+2*(plastic_phenoplus_totalNslip(instance)+ & + plastic_phenoplus_totalNtwin(instance))) = & + plastic_phenoplus_aTolShear(instance) + +end subroutine plastic_phenoplus_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate push-up factors (kappa) for each voxel based on its neighbors +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el) + use math, only: pi, & + math_mul33x33, & + math_mul3x3, & + math_transpose33, & + math_qDot, & + math_qRot, & + indeg + + use mesh, only: mesh_element, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype, & + mesh_maxNips, & + mesh_NcpElems, & + mesh_ipNeighborhood + + use material, only: material_phase, & + material_texture, & + phase_plasticityInstance, & + phaseAt, phasememberAt, & + homogenization_maxNgrains, & + plasticState + + use lattice, only: lattice_sn, & + lattice_sd, & + lattice_qDisorientation + + !***input variables + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + orientation ! crystal orientation in quaternions + + !***local variables + integer(pInt) instance, & !my instance of this plasticity + ph, & !my phase + of, & !my spatial position in memory (offset) + textureID, & !my texture + Nneighbors, & !number of neighbors (<= 6) + vld_Nneighbors, & !number of my valid neighbors + n, & !neighbor index (for iterating through all neighbors) + ns, & !number of slip system + nt, & !number of twin system + me_slip, & !my slip system index + neighbor_el, & !element number of neighboring material point + neighbor_ip, & !integration point of neighboring material point + neighbor_n, & !I have no idea what is this + neighbor_of, & !spatial position in memory for this neighbor (offset) + neighbor_ph, & !neighbor's phase + neighbor_tex, & !neighbor's texture ID + ne_slip_ac, & !loop to find neighbor shear + ne_slip, & !slip system index for neighbor + index_kappa, & !index of pushup factors in plasticState + offset_acshear_slip, & !offset in PlasticState for the accumulative shear + j !quickly loop through slip families + + real(pReal) kappa_max, & ! + tmp_myshear_slip, & !temp storage for accumulative shear for me + mprime_cut, & !m' cutoff to consider neighboring effect + avg_acshear_ne, & !the average accumulative shear from my neighbor + tmp_mprime, & !temp holder for m' value + tmp_acshear !temp holder for accumulative shear for m' + + + real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + m_primes, & !m' between me_alpha(one) and neighbor beta(all) + me_acshear, & !temp storage for ac_shear of one particular system for me + ne_acshear !temp storage for ac_shear of one particular system for one of my neighbor + + real(pReal), dimension(3,plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + slipNormal, & + slipDirect + + real(pReal), dimension(4) :: my_orientation, & !store my orientation + neighbor_orientation, & !store my neighbor orientation + absMisorientation + + real(pReal), dimension(FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) :: & + ne_mprimes !m' between each neighbor + + !***Get my properties + Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) + ph = phaseAt(ipc,ip,el) !get my phase + of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory + textureID = material_texture(1,ip,el) !get my texture ID + instance = phase_plasticityInstance(ph) !get my instance based on phase ID + ns = plastic_phenoplus_totalNslip(instance) + nt = plastic_phenoplus_totalNtwin(instance) + offset_acshear_slip = ns + nt + 2_pInt + index_kappa = ns + nt + 2_pInt + ns + nt !location of kappa in plasticState + mprime_cut = 0.7_pReal !set by Dr.Bieler + + !***gather my accumulative shear from palsticState + FINDMYSHEAR: do j = 1_pInt,ns + me_acshear(j) = plasticState(ph)%state(offset_acshear_slip+j, of) + enddo FINDMYSHEAR + + !***gather my orientation and slip systems + my_orientation = orientation(1:4, ipc, ip, el) + slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) + slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) + kappa_max = plastic_phenoplus_kappa_max(instance) !maximum pushups allowed (READIN) + + !***calculate kappa between me and all my neighbors + LOOPMYSLIP: DO me_slip=1_pInt,ns + vld_Nneighbors = Nneighbors + tmp_myshear_slip = me_acshear(me_slip) + tmp_mprime = 0.0_pReal !highest m' from all neighbors + tmp_acshear = 0.0_pReal !accumulative shear from highest m' + + !***go through my neighbors to find highest m' + LOOPNEIGHBORS: DO n=1_pInt,Nneighbors + neighbor_el = mesh_ipNeighborhood(1,n,ip,el) + neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) + neighbor_n = 1 !It is ipc + neighbor_of = phasememberAt( neighbor_n, neighbor_ip, neighbor_el) + neighbor_ph = phaseAt( neighbor_n, neighbor_ip, neighbor_el) + neighbor_tex = material_texture(1,neighbor_ip,neighbor_el) + neighbor_orientation = orientation(1:4, neighbor_n, neighbor_ip, neighbor_el) !ipc is always 1. + absMisorientation = lattice_qDisorientation(my_orientation, & + neighbor_orientation, & + 0_pInt) !no need for explicit calculation of symmetry + + !***find the accumulative shear for this neighbor + LOOPFINDNEISHEAR: DO ne_slip_ac=1_pInt, ns + ne_acshear(ne_slip_ac) = plasticState(ph)%state(offset_acshear_slip+ne_slip_ac, & + neighbor_of) + ENDDO LOOPFINDNEISHEAR + + !***calculate the average accumulative shear and use it as cutoff + avg_acshear_ne = SUM(ne_acshear)/ns + + !*** + IF (ph==neighbor_ph) THEN + !***walk through all the + LOOPNEIGHBORSLIP: DO ne_slip=1_pInt,ns + !***only consider slip system that is active (above average accumulative shear) + IF (ne_acshear(ne_slip) > avg_acshear_ne) THEN + m_primes(ne_slip) = abs(math_mul3x3(slipNormal(1:3,me_slip), & + math_qRot(absMisorientation, slipNormal(1:3,ne_slip)))) & + *abs(math_mul3x3(slipDirect(1:3,me_slip), & + math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) + !***find the highest m' and corresponding accumulative shear + IF (m_primes(ne_slip) > tmp_mprime) THEN + tmp_mprime = m_primes(ne_slip) + tmp_acshear = ne_acshear(ne_slip) + ENDIF + ENDIF + ENDDO LOOPNEIGHBORSLIP + + ELSE + ne_mprimes(n) = 0.0_pReal + vld_Nneighbors = vld_Nneighbors - 1_pInt + ENDIF + + ENDDO LOOPNEIGHBORS + + !***check if this element close to rim + IF (vld_Nneighbors < Nneighbors) THEN + !***rim voxel, no modification allowed + plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal + ELSE + !***patch voxel, started to calculate push up factor for gamma_dot + IF ((tmp_mprime > mprime_cut) .AND. (tmp_acshear > tmp_myshear_slip)) THEN + plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal / tmp_mprime + ELSE + !***minimum damping factor is 0.5 + plasticState(ph)%state(index_kappa+me_slip, of) = 0.5_pReal + tmp_mprime * 0.5_pReal + ENDIF + ENDIF + + ENDDO LOOPMYSLIP + +end subroutine plastic_phenoplus_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use math, only: & + math_Plain3333to99, & + math_Mandel6to33 + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + use material, only: & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + + integer(pInt) :: & + instance, & + nSlip, & + nTwin,index_Gamma,index_F,index_myFamily, index_kappa, & + f,i,j,k,l,m,n, & + of, & + ph + real(pReal) :: & + tau_slip_pos,tau_slip_neg, & + gdot_slip_pos,gdot_slip_neg, & + dgdot_dtauslip_pos,dgdot_dtauslip_neg, & + gdot_twin,dgdot_dtautwin,tau_twin + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal), dimension(3,3,2) :: & + nonSchmid_tensor + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + nSlip = plastic_phenoplus_totalNslip(instance) + nTwin = plastic_phenoplus_totalNtwin(instance) + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + index_kappa = nSlip + nTwin + 2_pInt +nSlip + nTwin + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Slip part + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenoplus_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) + enddo + + !***insert non-local effect here by modify gdot with kappa in plastic state + !***this implementation will most likely cause convergence issue + ! gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ! ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of)* & + ! plasticState(ph)%state(j+index_kappa, of))) & !in-place modification of gdot + ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) + + ! gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ! ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of)* & + ! plasticState(ph)%state(j+index_kappa, of))) & !?should we make it direction aware + ! **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) + + !***original calculation + gdot_slip_pos = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ((abs(tau_slip_pos)/(plasticState(ph)%state(j, of))) & !in-place modification of gdot + **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) + + gdot_slip_neg = 0.5_pReal*plastic_phenoplus_gdot0_slip(instance)* & + ((abs(tau_slip_neg)/(plasticState(ph)%state(j, of))) & !?should we make it direction aware + **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) + + !***MAGIC HERE***! + !***directly modify the amount of shear happens considering neighborhood + gdot_slip_pos = gdot_slip_pos * plasticState(ph)%state(j+index_kappa, of) + gdot_slip_neg = gdot_slip_neg * plasticState(ph)%state(j+index_kappa, of) + + Lp = Lp + (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then + dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenoplus_n_slip(instance)/tau_slip_pos + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,1) + endif + + if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then + dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenoplus_n_slip(instance)/tau_slip_neg + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,2) + endif + enddo slipSystems + enddo slipFamilies + +!-------------------------------------------------------------------------------------------------- +! Twinning part + j = 0_pInt + twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenoplus_gdot0_twin(instance)*& + (abs(tau_twin)/plasticState(ph)%state(nSlip+j,of))**& + plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_twin) > tiny(0.0_pReal)) then + dgdot_dtautwin = gdot_twin*plastic_phenoplus_n_twin(instance)/tau_twin + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & + lattice_Stwin(m,n,index_myFamily+i,ph) + endif + enddo twinSystems + enddo twinFamilies + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + + +end subroutine plastic_phenoplus_LpAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenoplus_dotState(Tstar_v,ipc,ip,el) + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_shearTwin, & + lattice_NnonSchmid + use material, only: & + material_phase, & + phaseAt, phasememberAt, & + plasticState, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + integer(pInt) :: & + instance,ph, & + nSlip,nTwin, & + f,i,j,k, & + index_Gamma,index_F,index_myFamily,& + offset_accshear_slip,offset_accshear_twin, offset_kappa, & + of + real(pReal) :: & + c_SlipSlip,c_TwinSlip,c_TwinTwin, & + ssat_offset, & + tau_slip_pos,tau_slip_neg,tau_twin + + real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip + real(pReal), dimension(plastic_phenoplus_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenoplus_totalNslip(instance) + nTwin = plastic_phenoplus_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + offset_accshear_slip = nSlip + nTwin + 2_pInt + offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + offset_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin + plasticState(ph)%dotState(:,of) = 0.0_pReal + + +!-------------------------------------------------------------------------------------------------- +! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices + c_SlipSlip = plastic_phenoplus_h0_SlipSlip(instance)*& + (1.0_pReal + plastic_phenoplus_twinC(instance)*plasticState(ph)%state(index_F,of)**& + plastic_phenoplus_twinB(instance)) + c_TwinSlip = plastic_phenoplus_h0_TwinSlip(instance)*& + plasticState(ph)%state(index_Gamma,of)**plastic_phenoplus_twinE(instance) + c_TwinTwin = plastic_phenoplus_h0_TwinTwin(instance)*& + plasticState(ph)%state(index_F,of)**plastic_phenoplus_twinD(instance) + +!-------------------------------------------------------------------------------------------------- +! calculate left and right vectors and calculate dot gammas + ssat_offset = plastic_phenoplus_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j+1_pInt + left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part + left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part + !***original implementation + right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & + **plastic_phenoplus_a_slip(instance)& + *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) + !***modify a_slip to get nonlocal effect + ! right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & + ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) & + ! **(plastic_phenoplus_a_slip(instance)*plasticState(ph)%state(j+offset_kappa, of))& + ! *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & + ! (plastic_phenoplus_tausat_slip(f,instance)+ssat_offset)) + right_TwinSlip(j) = 1.0_pReal ! no system-dependent part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot gamma + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + gdot_slip(j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance) & + +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenoplus_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + enddo slipSystems1 + enddo slipFamilies1 + + + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j+1_pInt + left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part + left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part + right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part + right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot vol frac + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenoplus_gdot0_twin(instance)*& + (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& + plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + enddo twinSystems1 + enddo twinFamilies1 + +!-------------------------------------------------------------------------------------------------- +! calculate the overall hardening based on above + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j + c_SlipSlip * left_SlipSlip(j) * & + dot_product(plastic_phenoplus_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & + right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + dot_product(plastic_phenoplus_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & + right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & + abs(gdot_slip(j)) + plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) + enddo slipSystems2 + enddo slipFamilies2 + + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j + c_TwinSlip * left_TwinSlip(j) * & + dot_product(plastic_phenoplus_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & + right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + c_TwinTwin * left_TwinTwin(j) * & + dot_product(plastic_phenoplus_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & + right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 + plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & + gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) + plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) + enddo twinSystems2 + enddo twinFamilies2 + + +end subroutine plastic_phenoplus_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_phenoplus_postResults(Tstar_v,ipc,ip,el) + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + real(pReal), dimension(plastic_phenoplus_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_phenoplus_postResults + + integer(pInt) :: & + instance,ph, of, & + nSlip,nTwin, & + o,f,i,c,j,k, & + index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily,index_kappa + real(pReal) :: & + tau_slip_pos,tau_slip_neg,tau + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenoplus_totalNslip(instance) + nTwin = plastic_phenoplus_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + index_accshear_slip = nSlip + nTwin + 2_pInt + 1_pInt + index_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + 1_pInt + index_kappa = nSlip + nTwin + 2_pInt + nSlip + nTwin + 1_pInt + + plastic_phenoplus_postResults = 0.0_pReal + c = 0_pInt + + outputsLoop: do o = 1_pInt,plastic_phenoplus_Noutput(instance) + select case(plastic_phenoplus_outputID(o,instance)) + case (resistance_slip_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) + c = c + nSlip + + case (accumulatedshear_slip_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& + index_accshear_slip+nSlip-1_pInt,of) + c = c + nSlip + + case (shearrate_slip_ID) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j + 1_pInt + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenoplus_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo + plastic_phenoplus_postResults(c+j) = plastic_phenoplus_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance) & + +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenoplus_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + + enddo slipSystems1 + enddo slipFamilies1 + c = c + nSlip + + case (resolvedstress_slip_ID) + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems2: do i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j + 1_pInt + plastic_phenoplus_postResults(c+j) = & + dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + enddo slipSystems2 + enddo slipFamilies2 + c = c + nSlip + + case (kappa_slip_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nSlip) = & + plasticState(ph)%state(index_kappa:index_kappa+nSlip-1_pInt,of) + c = c + nSlip + + case (totalshear_ID) + plastic_phenoplus_postResults(c+1_pInt) = & + plasticState(ph)%state(index_Gamma,of) + c = c + 1_pInt + + case (resistance_twin_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) + c = c + nTwin + + case (accumulatedshear_twin_ID) + plastic_phenoplus_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) + c = c + nTwin + + case (shearrate_twin_ID) + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j + 1_pInt + tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + plastic_phenoplus_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenoplus_gdot0_twin(instance)*& + (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& + plastic_phenoplus_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) + enddo twinSystems1 + enddo twinFamilies1 + c = c + nTwin + + case (resolvedstress_twin_ID) + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenoplus_Ntwin(f,instance) + j = j + 1_pInt + plastic_phenoplus_postResults(c+j) = & + dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + enddo twinSystems2 + enddo twinFamilies2 + c = c + nTwin + + case (totalvolfrac_twin_ID) + plastic_phenoplus_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) + c = c + 1_pInt + + end select + enddo outputsLoop + +end function plastic_phenoplus_postResults + +end module plastic_phenoplus diff --git a/src/plastic_phenopowerlaw.f90 b/src/plastic_phenopowerlaw.f90 new file mode 100644 index 000000000..1f8e16250 --- /dev/null +++ b/src/plastic_phenopowerlaw.f90 @@ -0,0 +1,1226 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for phenomenological crystal plasticity formulation using a powerlaw +!! fitting +!-------------------------------------------------------------------------------------------------- +module plastic_phenopowerlaw + use prec, only: & + pReal,& + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenopowerlaw_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_phenopowerlaw_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_phenopowerlaw_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_phenopowerlaw_Noutput !< number of outputs per instance of this constitution + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_phenopowerlaw_totalNslip, & !< no. of slip system used in simulation + plastic_phenopowerlaw_totalNtwin, & !< no. of twin system used in simulation + plastic_phenopowerlaw_totalNtrans !< no. of trans system used in simulation + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_phenopowerlaw_Nslip, & !< active number of slip systems per family (input parameter, per family) + plastic_phenopowerlaw_Ntwin, & !< active number of twin systems per family (input parameter, per family) + plastic_phenopowerlaw_Ntrans !< active number of trans systems per family (input parameter, per family) + + real(pReal), dimension(:), allocatable, private :: & + plastic_phenopowerlaw_gdot0_slip, & !< reference shear strain rate for slip (input parameter) + plastic_phenopowerlaw_gdot0_twin, & !< reference shear strain rate for twin (input parameter) + plastic_phenopowerlaw_n_slip, & !< stress exponent for slip (input parameter) + plastic_phenopowerlaw_n_twin, & !< stress exponent for twin (input parameter) + plastic_phenopowerlaw_spr, & !< push-up factor for slip saturation due to twinning + plastic_phenopowerlaw_twinB, & + plastic_phenopowerlaw_twinC, & + plastic_phenopowerlaw_twinD, & + plastic_phenopowerlaw_twinE, & + plastic_phenopowerlaw_h0_SlipSlip, & !< reference hardening slip - slip (input parameter) + plastic_phenopowerlaw_h0_TwinSlip, & !< reference hardening twin - slip (input parameter) + plastic_phenopowerlaw_h0_TwinTwin, & !< reference hardening twin - twin (input parameter) + plastic_phenopowerlaw_a_slip, & + plastic_phenopowerlaw_aTolResistance, & + plastic_phenopowerlaw_aTolShear, & + plastic_phenopowerlaw_aTolTwinfrac, & + plastic_phenopowerlaw_aTolTransfrac, & + plastic_phenopowerlaw_Cnuc, & !< coefficient for strain-induced martensite nucleation + plastic_phenopowerlaw_Cdwp, & !< coefficient for double well potential + plastic_phenopowerlaw_Cgro, & !< coefficient for stress-assisted martensite growth + plastic_phenopowerlaw_deltaG !< free energy difference between austensite and martensite [MPa] + + real(pReal), dimension(:,:), allocatable, private :: & + plastic_phenopowerlaw_tau0_slip, & !< initial critical shear stress for slip (input parameter, per family) + plastic_phenopowerlaw_tau0_twin, & !< initial critical shear stress for twin (input parameter, per family) + plastic_phenopowerlaw_tausat_slip, & !< maximum critical shear stress for slip (input parameter, per family) + plastic_phenopowerlaw_nonSchmidCoeff, & + + plastic_phenopowerlaw_interaction_SlipSlip, & !< interaction factors slip - slip (input parameter) + plastic_phenopowerlaw_interaction_SlipTwin, & !< interaction factors slip - twin (input parameter) + plastic_phenopowerlaw_interaction_TwinSlip, & !< interaction factors twin - slip (input parameter) + plastic_phenopowerlaw_interaction_TwinTwin !< interaction factors twin - twin (input parameter) + + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_phenopowerlaw_hardeningMatrix_SlipSlip, & + plastic_phenopowerlaw_hardeningMatrix_SlipTwin, & + plastic_phenopowerlaw_hardeningMatrix_TwinSlip, & + plastic_phenopowerlaw_hardeningMatrix_TwinTwin + + enum, bind(c) + enumerator :: undefined_ID, & + resistance_slip_ID, & + accumulatedshear_slip_ID, & + shearrate_slip_ID, & + resolvedstress_slip_ID, & + totalshear_ID, & + resistance_twin_ID, & + accumulatedshear_twin_ID, & + shearrate_twin_ID, & + resolvedstress_twin_ID, & + totalvolfrac_twin_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_phenopowerlaw_outputID !< ID of each post result output + + type, private :: tPhenopowerlawState + real(pReal), pointer, dimension(:,:) :: & + s_slip, & + s_twin, & + accshear_slip, & + accshear_twin + real(pReal), pointer, dimension(:) :: & + sumGamma, & + sumF + end type + + type(tPhenopowerlawState), allocatable, dimension(:), private :: & + dotState, & + state, & + state0 + + public :: & + plastic_phenopowerlaw_init, & + plastic_phenopowerlaw_LpAndItsTangent, & + plastic_phenopowerlaw_dotState, & + plastic_phenopowerlaw_postResults + private :: & + plastic_phenopowerlaw_aTolState, & + plastic_phenopowerlaw_stateInit + + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level, & + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66, & + math_Voigt66to3333 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_PHENOPOWERLAW_label, & + PLASTICITY_PHENOPOWERLAW_ID, & + material_phase, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + maxNinstance, & + instance,phase,j,k, f,o, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, & + Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & + Nchunks_TransFamilies = 0_pInt, Nchunks_nonSchmid = 0_pInt, & + NipcMyPhase, & + offset_slip, index_myFamily, index_otherFamily, & + mySize=0_pInt,sizeState,sizeDotState, sizeDeltaState, & + startIndex, endIndex + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), dimension(:), allocatable :: tempPerSlip + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPOWERLAW_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_PHENOPOWERLAW_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + + allocate(plastic_phenopowerlaw_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_sizePostResult(maxval(phase_Noutput),maxNinstance), & + source=0_pInt) + allocate(plastic_phenopowerlaw_output(maxval(phase_Noutput),maxNinstance)) + plastic_phenopowerlaw_output = '' + allocate(plastic_phenopowerlaw_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_phenopowerlaw_Noutput(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_Ntrans(lattice_maxNtransFamily,maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_totalNtrans(maxNinstance), source=0_pInt) + allocate(plastic_phenopowerlaw_gdot0_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_n_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_tau0_slip(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_tausat_slip(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(plastic_phenopowerlaw_gdot0_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_n_twin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_tau0_twin(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_spr(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinB(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinC(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinD(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_twinE(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_h0_SlipSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_h0_TwinSlip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_h0_TwinTwin(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_SlipSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_SlipTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_TwinSlip(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_interaction_TwinTwin(lattice_maxNinteraction,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_a_slip(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolResistance(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolShear(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolTwinfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_aTolTransfrac(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstance), & + source=0.0_pReal) + allocate(plastic_phenopowerlaw_Cnuc(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_Cdwp(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_Cgro(maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_deltaG(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase + phase = phase + 1_pInt ! advance phase section counter + if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) ! maximum number of slip families according to lattice type of current phase + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) ! maximum number of twin families according to lattice type of current phase + Nchunks_TransFamilies = count(lattice_NtransSystem(:,phase) > 0_pInt) ! maximum number of trans families according to lattice type of current phase + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + Nchunks_nonSchmid = lattice_NnonSchmid(phase) + if(allocated(tempPerSlip)) deallocate(tempPerSlip) + allocate(tempPerSlip(Nchunks_SlipFamilies)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_PHENOPOWERLAW_ID) then ! one of my phases. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('resistance_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_slip','accumulated_shear_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_slip') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_slip_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalshear') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalshear_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resistance_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('accumulatedshear_twin','accumulated_shear_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = accumulatedshear_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shearrate_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = shearrate_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resolvedstress_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = resolvedstress_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('totalvolfrac_twin') + plastic_phenopowerlaw_Noutput(instance) = plastic_phenopowerlaw_Noutput(instance) + 1_pInt + plastic_phenopowerlaw_outputID(plastic_phenopowerlaw_Noutput(instance),instance) = totalvolfrac_twin_ID + plastic_phenopowerlaw_output(plastic_phenopowerlaw_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case default + + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of slip families + case ('nslip') + if (chunkPos(1) < Nchunks_SlipFamilies + 1_pInt) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (chunkPos(1) > Nchunks_SlipFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt ! user specified number of (possibly) active slip families (e.g. 6 0 6 --> 3) + do j = 1_pInt, Nchunks_SlipFamilies + plastic_phenopowerlaw_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tausat_slip','tau0_slip') + tempPerSlip = 0.0_pReal + do j = 1_pInt, Nchunks_SlipFamilies + if (plastic_phenopowerlaw_Nslip(j,instance) > 0_pInt) & + tempPerSlip(j) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + select case(tag) + case ('tausat_slip') + plastic_phenopowerlaw_tausat_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + case ('tau0_slip') + plastic_phenopowerlaw_tau0_slip(1:Nchunks_SlipFamilies,instance) = tempPerSlip(1:Nchunks_SlipFamilies) + end select +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of twin families + case ('ntwin') + if (chunkPos(1) < Nchunks_TwinFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (chunkPos(1) > Nchunks_TwinFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + Nchunks_TwinFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TwinFamilies + plastic_phenopowerlaw_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0_twin') + do j = 1_pInt, Nchunks_TwinFamilies + if (plastic_phenopowerlaw_Ntwin(j,instance) > 0_pInt) & + plastic_phenopowerlaw_tau0_twin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of transformation families + case ('ntrans') + if (chunkPos(1) < Nchunks_TransFamilies + 1_pInt) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (chunkPos(1) > Nchunks_TransFamilies + 1_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + Nchunks_TransFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_TransFamilies + plastic_phenopowerlaw_Ntrans(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters depending on number of interactions + case ('interaction_slipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_phenopowerlaw_interaction_SlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_phenopowerlaw_interaction_SlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_phenopowerlaw_interaction_TwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_phenopowerlaw_interaction_TwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('nonschmid_coefficients') + if (chunkPos(1) < 1_pInt + Nchunks_nonSchmid) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_PHENOPOWERLAW_label//')') + do j = 1_pInt,Nchunks_nonSchmid + plastic_phenopowerlaw_nonSchmidCoeff(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo +!-------------------------------------------------------------------------------------------------- +! parameters independent of number of slip/twin systems + case ('gdot0_slip') + plastic_phenopowerlaw_gdot0_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_slip') + plastic_phenopowerlaw_n_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('a_slip', 'w0_slip') + plastic_phenopowerlaw_a_slip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('gdot0_twin') + plastic_phenopowerlaw_gdot0_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('n_twin') + plastic_phenopowerlaw_n_twin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('s_pr') + plastic_phenopowerlaw_spr(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_b') + plastic_phenopowerlaw_twinB(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_c') + plastic_phenopowerlaw_twinC(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_d') + plastic_phenopowerlaw_twinD(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twin_e') + plastic_phenopowerlaw_twinE(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_slipslip') + plastic_phenopowerlaw_h0_SlipSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twinslip') + plastic_phenopowerlaw_h0_TwinSlip(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('h0_twintwin') + plastic_phenopowerlaw_h0_TwinTwin(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_resistance') + plastic_phenopowerlaw_aTolResistance(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_shear') + plastic_phenopowerlaw_aTolShear(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_twinfrac') + plastic_phenopowerlaw_aTolTwinfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_transfrac') + plastic_phenopowerlaw_aTolTransfrac(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cnuc') + plastic_phenopowerlaw_Cnuc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cdwp') + plastic_phenopowerlaw_Cdwp(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('cgro') + plastic_phenopowerlaw_Cgro(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('deltag') + plastic_phenopowerlaw_deltaG(instance) = IO_floatValue(line,chunkPos,2_pInt) + case default + + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then + instance = phase_plasticityInstance(phase) + plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active slip systems per family to min of available and requested + plastic_phenopowerlaw_Nslip(1:lattice_maxNslipFamily,instance)) + plastic_phenopowerlaw_Ntwin(1:lattice_maxNtwinFamily,instance) = & + min(lattice_NtwinSystem(1:lattice_maxNtwinFamily,phase),& ! limit active twin systems per family to min of available and requested + plastic_phenopowerlaw_Ntwin(:,instance)) + plastic_phenopowerlaw_totalNslip(instance) = sum(plastic_phenopowerlaw_Nslip(:,instance)) ! how many slip systems altogether + plastic_phenopowerlaw_totalNtwin(instance) = sum(plastic_phenopowerlaw_Ntwin(:,instance)) ! how many twin systems altogether + plastic_phenopowerlaw_totalNtrans(instance) = sum(plastic_phenopowerlaw_Ntrans(:,instance)) ! how many trans systems altogether + + if (any(plastic_phenopowerlaw_tau0_slip(:,instance) < 0.0_pReal .and. & + plastic_phenopowerlaw_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (plastic_phenopowerlaw_gdot0_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (plastic_phenopowerlaw_n_slip(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='n_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (any(plastic_phenopowerlaw_tausat_slip(:,instance) <= 0.0_pReal .and. & + plastic_phenopowerlaw_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tausat_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (any(abs(plastic_phenopowerlaw_a_slip(instance)) <= tiny(0.0_pReal) .and. & + plastic_phenopowerlaw_Nslip(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='a_slip ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (any(plastic_phenopowerlaw_tau0_twin(:,instance) < 0.0_pReal .and. & + plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='tau0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') + if ( plastic_phenopowerlaw_gdot0_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='gdot0_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') + if ( plastic_phenopowerlaw_n_twin(instance) <= 0.0_pReal .and. & + any(plastic_phenopowerlaw_Ntwin(:,instance) > 0)) & + call IO_error(211_pInt,el=instance,ext_msg='n_twin ('//PLASTICITY_PHENOPOWERLAW_label//')') + if (plastic_phenopowerlaw_aTolResistance(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolResistance(instance) = 1.0_pReal ! default absolute tolerance 1 Pa + if (plastic_phenopowerlaw_aTolShear(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolShear(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenopowerlaw_aTolTwinfrac(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolTwinfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + if (plastic_phenopowerlaw_aTolTransfrac(instance) <= 0.0_pReal) & + plastic_phenopowerlaw_aTolTransfrac(instance) = 1.0e-6_pReal ! default absolute tolerance 1e-6 + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + allocate(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from slip activity + maxval(plastic_phenopowerlaw_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(maxval(plastic_phenopowerlaw_totalNslip),& ! slip resistance from twin activity + maxval(plastic_phenopowerlaw_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from slip activity + maxval(plastic_phenopowerlaw_totalNslip),& + maxNinstance), source=0.0_pReal) + allocate(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(maxval(plastic_phenopowerlaw_totalNtwin),& ! twin resistance from twin activity + maxval(plastic_phenopowerlaw_totalNtwin),& + maxNinstance), source=0.0_pReal) + allocate(state(maxNinstance)) + allocate(state0(maxNinstance)) + allocate(dotState(maxNinstance)) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) ! loop through all phases in material.config + myPhase2: if (phase_plasticity(phase) == PLASTICITY_phenopowerlaw_ID) then ! only consider my phase + NipcMyPhase = count(material_phase == phase) ! number of IPCs containing my phase + instance = phase_plasticityInstance(phase) ! which instance of my phase + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) + select case(plastic_phenopowerlaw_outputID(o,instance)) + case(resistance_slip_ID, & + shearrate_slip_ID, & + accumulatedshear_slip_ID, & + resolvedstress_slip_ID & + ) + mySize = plastic_phenopowerlaw_totalNslip(instance) + case(resistance_twin_ID, & + shearrate_twin_ID, & + accumulatedshear_twin_ID, & + resolvedstress_twin_ID & + ) + mySize = plastic_phenopowerlaw_totalNtwin(instance) + case(totalshear_ID, & + totalvolfrac_twin_ID & + ) + mySize = 1_pInt + case default + end select + + outputFound: if (mySize > 0_pInt) then + plastic_phenopowerlaw_sizePostResult(o,instance) = mySize + plastic_phenopowerlaw_sizePostResults(instance) = plastic_phenopowerlaw_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop +!-------------------------------------------------------------------------------------------------- +! allocate state arrays + sizeState = plastic_phenopowerlaw_totalNslip(instance) & ! s_slip + + plastic_phenopowerlaw_totalNtwin(instance) & ! s_twin + + 2_pInt & ! sum(gamma) + sum(f) + + plastic_phenopowerlaw_totalNslip(instance) & ! accshear_slip + + plastic_phenopowerlaw_totalNtwin(instance) ! accshear_twin + + sizeDotState = sizeState + sizeDeltaState = 0_pInt + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_phenopowerlaw_sizePostResults(instance) + plasticState(phase)%nSlip =plastic_phenopowerlaw_totalNslip(instance) + plasticState(phase)%nTwin =plastic_phenopowerlaw_totalNtwin(instance) + plasticState(phase)%nTrans=plastic_phenopowerlaw_totalNtrans(instance) + allocate(plasticState(phase)%aTolState ( sizeState), source=0.0_pReal) + allocate(plasticState(phase)%state0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state ( sizeState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NipcMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup ( sizeState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NipcMyPhase),source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2(sizeDotState,NipcMyPhase),source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NipcMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NipcMyPhase), source=0.0_pReal) + + offset_slip = plasticState(phase)%nSlip+plasticState(phase)%nTwin+2_pInt + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NipcMyPhase) + + do f = 1_pInt,lattice_maxNslipFamily ! >>> interaction slip -- X + index_myFamily = sum(plastic_phenopowerlaw_Nslip(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) ! loop over (active) systems in my family (slip) + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenopowerlaw_hardeningMatrix_SlipSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_SlipSlip(lattice_interactionSlipSlip( & + sum(lattice_NslipSystem(1:f-1,phase))+j, & + sum(lattice_NslipSystem(1:o-1,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenopowerlaw_hardeningMatrix_SlipTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_SlipTwin(lattice_interactionSlipTwin( & + sum(lattice_NslipSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + + do f = 1_pInt,lattice_maxNtwinFamily ! >>> interaction twin -- X + index_myFamily = sum(plastic_phenopowerlaw_Ntwin(1:f-1_pInt,instance)) + do j = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) ! loop over (active) systems in my family (twin) + + do o = 1_pInt,lattice_maxNslipFamily + index_otherFamily = sum(plastic_phenopowerlaw_Nslip(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Nslip(o,instance) ! loop over (active) systems in other family (slip) + plastic_phenopowerlaw_hardeningMatrix_TwinSlip(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_TwinSlip(lattice_interactionTwinSlip( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NslipSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + do o = 1_pInt,lattice_maxNtwinFamily + index_otherFamily = sum(plastic_phenopowerlaw_Ntwin(1:o-1_pInt,instance)) + do k = 1_pInt,plastic_phenopowerlaw_Ntwin(o,instance) ! loop over (active) systems in other family (twin) + plastic_phenopowerlaw_hardeningMatrix_TwinTwin(index_myFamily+j,index_otherFamily+k,instance) = & + plastic_phenopowerlaw_interaction_TwinTwin(lattice_interactionTwinTwin( & + sum(lattice_NtwinSystem(1:f-1_pInt,phase))+j, & + sum(lattice_NtwinSystem(1:o-1_pInt,phase))+k, & + phase), instance ) + enddo; enddo + + enddo; enddo + startIndex = 1_pInt + endIndex = plastic_phenopowerlaw_totalNslip(instance) + state (instance)%s_slip=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%s_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%s_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex + plastic_phenopowerlaw_totalNtwin(instance) + state (instance)%s_twin=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%s_twin=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%s_twin=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex + 1_pInt + state (instance)%sumGamma=>plasticState(phase)%state (startIndex,:) + state0 (instance)%sumGamma=>plasticState(phase)%state0 (startIndex,:) + dotState(instance)%sumGamma=>plasticState(phase)%dotState(startIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex + 1_pInt + state (instance)%sumF=>plasticState(phase)%state (startIndex,:) + state0 (instance)%sumF=>plasticState(phase)%state0 (startIndex,:) + dotState(instance)%sumF=>plasticState(phase)%dotState(startIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex +plastic_phenopowerlaw_totalNslip(instance) + state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + startIndex = endIndex + 1_pInt + endIndex = endIndex +plastic_phenopowerlaw_totalNtwin(instance) + state (instance)%accshear_slip=>plasticState(phase)%state (startIndex:endIndex,:) + state0 (instance)%accshear_slip=>plasticState(phase)%state0 (startIndex:endIndex,:) + dotState(instance)%accshear_slip=>plasticState(phase)%dotState(startIndex:endIndex,:) + + + call plastic_phenopowerlaw_stateInit(phase,instance) + call plastic_phenopowerlaw_aTolState(phase,instance) + endif myPhase2 + enddo initializeInstances + +end subroutine plastic_phenopowerlaw_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_stateInit(ph,instance) + use lattice, only: & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + integer(pInt) :: & + i + real(pReal), dimension(plasticState(ph)%sizeState) :: & + tempState + + tempState = 0.0_pReal + do i = 1_pInt,lattice_maxNslipFamily + tempState(1+sum(plastic_phenopowerlaw_Nslip(1:i-1,instance)) : & + sum(plastic_phenopowerlaw_Nslip(1:i ,instance))) = & + plastic_phenopowerlaw_tau0_slip(i,instance) + enddo + + do i = 1_pInt,lattice_maxNtwinFamily + tempState(1+sum(plastic_phenopowerlaw_Nslip(:,instance))+& + sum(plastic_phenopowerlaw_Ntwin(1:i-1,instance)) : & + sum(plastic_phenopowerlaw_Nslip(:,instance))+& + sum(plastic_phenopowerlaw_Ntwin(1:i ,instance))) = & + plastic_phenopowerlaw_tau0_twin(i,instance) + enddo + + plasticState(ph)%state0(:,:) = spread(tempState, & ! spread single tempstate array + 2, & ! along dimension 2 + size(plasticState(ph)%state0(1,:))) ! number of copies (number of IPCs) + +end subroutine plastic_phenopowerlaw_stateInit + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the relevant state values for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_aTolState(ph,instance) + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: & + instance, & !< number specifying the instance of the plasticity + ph + + plasticState(ph)%aTolState(1:plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance)) = & + plastic_phenopowerlaw_aTolResistance(instance) + plasticState(ph)%aTolState(1+plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance)) = & + plastic_phenopowerlaw_aTolShear(instance) + plasticState(ph)%aTolState(2+plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance)) = & + plastic_phenopowerlaw_aTolTwinFrac(instance) + plasticState(ph)%aTolState(3+plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance): & + 2+2*(plastic_phenopowerlaw_totalNslip(instance)+ & + plastic_phenopowerlaw_totalNtwin(instance))) = & + plastic_phenopowerlaw_aTolShear(instance) + +end subroutine plastic_phenopowerlaw_aTolState + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,ipc,ip,el) + use math, only: & + math_Plain3333to99, & + math_Mandel6to33 + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + use material, only: & + phaseAt, phasememberAt, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + + integer(pInt) :: & + instance, & + index_myFamily, & + f,i,j,k,l,m,n, & + of, & + ph + real(pReal) :: & + tau_slip_pos,tau_slip_neg, & + gdot_slip_pos,gdot_slip_neg, & + dgdot_dtauslip_pos,dgdot_dtauslip_neg, & + gdot_twin,dgdot_dtautwin,tau_twin + real(pReal), dimension(3,3,3,3) :: & + dLp_dTstar3333 !< derivative of Lp with respect to Tstar as 4th order tensor + real(pReal), dimension(3,3,2) :: & + nonSchmid_tensor + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! Slip part + j = 0_pInt + slipFamilies: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmid_tensor(1:3,1:3,1) = lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,1) + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + nonSchmid_tensor(1:3,1:3,1) = nonSchmid_tensor(1:3,1:3,1) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k,index_myFamily+i,ph) + nonSchmid_tensor(1:3,1:3,2) = nonSchmid_tensor(1:3,1:3,2) + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)*& + lattice_Sslip(1:3,1:3,2*k+1,index_myFamily+i,ph) + enddo + gdot_slip_pos = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & + ((abs(tau_slip_pos)/(state(instance)%s_slip(j,of))) & + **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_pos) + + gdot_slip_neg = 0.5_pReal*plastic_phenopowerlaw_gdot0_slip(instance)* & + ((abs(tau_slip_neg)/(state(instance)%s_slip(j,of))) & + **plastic_phenopowerlaw_n_slip(instance))*sign(1.0_pReal,tau_slip_neg) + + Lp = Lp + (1.0_pReal-state(instance)%sumF(of))*& ! 1-F + (gdot_slip_pos+gdot_slip_neg)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_slip_pos) > tiny(0.0_pReal)) then + dgdot_dtauslip_pos = gdot_slip_pos*plastic_phenopowerlaw_n_slip(instance)/tau_slip_pos + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_pos*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,1) + endif + + if (abs(gdot_slip_neg) > tiny(0.0_pReal)) then + dgdot_dtauslip_neg = gdot_slip_neg*plastic_phenopowerlaw_n_slip(instance)/tau_slip_neg + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtauslip_neg*lattice_Sslip(k,l,1,index_myFamily+i,ph)* & + nonSchmid_tensor(m,n,2) + endif + enddo slipSystems + enddo slipFamilies + +!-------------------------------------------------------------------------------------------------- +! Twinning part + j = 0_pInt + twinFamilies: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j+1_pInt + + ! Calculation of Lp + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin = (1.0_pReal-state(instance)%sumF(of))*& ! 1-F + plastic_phenopowerlaw_gdot0_twin(instance)*& + (abs(tau_twin)/state(instance)%s_twin(j,of))**& + plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + Lp = Lp + gdot_twin*lattice_Stwin(1:3,1:3,index_myFamily+i,ph) + + ! Calculation of the tangent of Lp + if (abs(gdot_twin) > tiny(0.0_pReal)) then + dgdot_dtautwin = gdot_twin*plastic_phenopowerlaw_n_twin(instance)/tau_twin + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = dLp_dTstar3333(k,l,m,n) + & + dgdot_dtautwin*lattice_Stwin(k,l,index_myFamily+i,ph)* & + lattice_Stwin(m,n,index_myFamily+i,ph) + endif + enddo twinSystems + enddo twinFamilies + + dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) + + +end subroutine plastic_phenopowerlaw_LpAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_phenopowerlaw_dotState(Tstar_v,ipc,ip,el) + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_shearTwin, & + lattice_NnonSchmid + use material, only: & + material_phase, & + phaseAt, phasememberAt, & + plasticState, & + phase_plasticityInstance + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + integer(pInt) :: & + instance,ph, & + nSlip,nTwin, & + f,i,j,k, & + index_Gamma,index_F,index_myFamily, & + offset_accshear_slip,offset_accshear_twin, & + of + real(pReal) :: & + c_SlipSlip,c_TwinSlip,c_TwinTwin, & + ssat_offset, & + tau_slip_pos,tau_slip_neg,tau_twin + + real(pReal), dimension(plastic_phenopowerlaw_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,left_SlipSlip,left_SlipTwin,right_SlipSlip,right_TwinSlip + real(pReal), dimension(plastic_phenopowerlaw_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,left_TwinSlip,left_TwinTwin,right_SlipTwin,right_TwinTwin + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenopowerlaw_totalNslip(instance) + nTwin = plastic_phenopowerlaw_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + offset_accshear_slip = nSlip + nTwin + 2_pInt + offset_accshear_twin = nSlip + nTwin + 2_pInt + nSlip + plasticState(ph)%dotState(:,of) = 0.0_pReal + + +!-------------------------------------------------------------------------------------------------- +! system-independent (nonlinear) prefactors to M_Xx (X influenced by x) matrices + c_SlipSlip = plastic_phenopowerlaw_h0_SlipSlip(instance)*& + (1.0_pReal + plastic_phenopowerlaw_twinC(instance)*plasticState(ph)%state(index_F,of)**& + plastic_phenopowerlaw_twinB(instance)) + c_TwinSlip = plastic_phenopowerlaw_h0_TwinSlip(instance)*& + plasticState(ph)%state(index_Gamma,of)**plastic_phenopowerlaw_twinE(instance) + c_TwinTwin = plastic_phenopowerlaw_h0_TwinTwin(instance)*& + plasticState(ph)%state(index_F,of)**plastic_phenopowerlaw_twinD(instance) + +!-------------------------------------------------------------------------------------------------- +! calculate left and right vectors and calculate dot gammas + ssat_offset = plastic_phenopowerlaw_spr(instance)*sqrt(plasticState(ph)%state(index_F,of)) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j+1_pInt + left_SlipSlip(j) = 1.0_pReal ! no system-dependent left part + left_SlipTwin(j) = 1.0_pReal ! no system-dependent left part + right_SlipSlip(j) = abs(1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) & + **plastic_phenopowerlaw_a_slip(instance)& + *sign(1.0_pReal,1.0_pReal-plasticState(ph)%state(j,of) / & + (plastic_phenopowerlaw_tausat_slip(f,instance)+ssat_offset)) + right_TwinSlip(j) = 1.0_pReal ! no system-dependent part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot gamma + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + nonSchmidSystems: do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k, index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo nonSchmidSystems + gdot_slip(j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance) & + +(abs(tau_slip_neg)/(plasticState(ph)%state(j,of)))**plastic_phenopowerlaw_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + enddo slipSystems1 + enddo slipFamilies1 + + + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j+1_pInt + left_TwinSlip(j) = 1.0_pReal ! no system-dependent left part + left_TwinTwin(j) = 1.0_pReal ! no system-dependent left part + right_SlipTwin(j) = 1.0_pReal ! no system-dependent right part + right_TwinTwin(j) = 1.0_pReal ! no system-dependent right part + +!-------------------------------------------------------------------------------------------------- +! Calculation of dot vol frac + tau_twin = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + gdot_twin(j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenopowerlaw_gdot0_twin(instance)*& + (abs(tau_twin)/plasticState(ph)%state(nslip+j,of))**& + plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau_twin)) + enddo twinSystems1 + enddo twinFamilies1 + +!-------------------------------------------------------------------------------------------------- +! calculate the overall hardening based on above + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j,of) = & ! evolution of slip resistance j + c_SlipSlip * left_SlipSlip(j) * & + dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipSlip(j,1:nSlip,instance), & + right_SlipSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + dot_product(plastic_phenopowerlaw_hardeningMatrix_SlipTwin(j,1:nTwin,instance), & + right_SlipTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + plasticState(ph)%dotState(index_Gamma,of) = plasticState(ph)%dotState(index_Gamma,of) + & + abs(gdot_slip(j)) + plasticState(ph)%dotState(offset_accshear_slip+j,of) = abs(gdot_slip(j)) + enddo slipSystems2 + enddo slipFamilies2 + + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j+1_pInt + plasticState(ph)%dotState(j+nSlip,of) = & ! evolution of twin resistance j + c_TwinSlip * left_TwinSlip(j) * & + dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinSlip(j,1:nSlip,instance), & + right_TwinSlip*abs(gdot_slip)) + & ! dot gamma_slip modulated by right-side slip factor + c_TwinTwin * left_TwinTwin(j) * & + dot_product(plastic_phenopowerlaw_hardeningMatrix_TwinTwin(j,1:nTwin,instance), & + right_TwinTwin*gdot_twin) ! dot gamma_twin modulated by right-side twin factor + if (plasticState(ph)%state(index_F,of) < 0.98_pReal) & ! ensure twin volume fractions stays below 1.0 + plasticState(ph)%dotState(index_F,of) = plasticState(ph)%dotState(index_F,of) + & + gdot_twin(j)/lattice_shearTwin(index_myFamily+i,ph) + plasticState(ph)%dotState(offset_accshear_twin+j,of) = abs(gdot_twin(j)) + enddo twinSystems2 + enddo twinFamilies2 + + +end subroutine plastic_phenopowerlaw_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_phenopowerlaw_postResults(Tstar_v,ipc,ip,el) + use material, only: & + material_phase, & + plasticState, & + phaseAt, phasememberAt, & + phase_plasticityInstance + use lattice, only: & + lattice_Sslip_v, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_NnonSchmid + + implicit none + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element !< microstructure state + + real(pReal), dimension(plastic_phenopowerlaw_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_phenopowerlaw_postResults + + integer(pInt) :: & + instance,ph, of, & + nSlip,nTwin, & + o,f,i,c,j,k, & + index_Gamma,index_F,index_accshear_slip,index_accshear_twin,index_myFamily + real(pReal) :: & + tau_slip_pos,tau_slip_neg,tau + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + + nSlip = plastic_phenopowerlaw_totalNslip(instance) + nTwin = plastic_phenopowerlaw_totalNtwin(instance) + + index_Gamma = nSlip + nTwin + 1_pInt + index_F = nSlip + nTwin + 2_pInt + index_accshear_slip = nSlip + nTwin + 3_pInt + index_accshear_twin = nSlip + nTwin + 3_pInt + nSlip + + plastic_phenopowerlaw_postResults = 0.0_pReal + c = 0_pInt + + outputsLoop: do o = 1_pInt,plastic_phenopowerlaw_Noutput(instance) + select case(plastic_phenopowerlaw_outputID(o,instance)) + case (resistance_slip_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(1:nSlip,of) + c = c + nSlip + + case (accumulatedshear_slip_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nSlip) = plasticState(ph)%state(index_accshear_slip:& + index_accshear_slip+nSlip-1_pInt,of) + c = c + nSlip + + case (shearrate_slip_ID) + j = 0_pInt + slipFamilies1: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems1: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j + 1_pInt + tau_slip_pos = dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_pos + do k = 1,lattice_NnonSchmid(ph) + tau_slip_pos = tau_slip_pos + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k,index_myFamily+i,ph)) + tau_slip_neg = tau_slip_neg + plastic_phenopowerlaw_nonSchmidCoeff(k,instance)* & + dot_product(Tstar_v,lattice_Sslip_v(1:6,2*k+1,index_myFamily+i,ph)) + enddo + plastic_phenopowerlaw_postResults(c+j) = plastic_phenopowerlaw_gdot0_slip(instance)*0.5_pReal* & + ((abs(tau_slip_pos)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance) & + +(abs(tau_slip_neg)/plasticState(ph)%state(j,of))**plastic_phenopowerlaw_n_slip(instance))& + *sign(1.0_pReal,tau_slip_pos) + + enddo slipSystems1 + enddo slipFamilies1 + c = c + nSlip + + case (resolvedstress_slip_ID) + j = 0_pInt + slipFamilies2: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + slipSystems2: do i = 1_pInt,plastic_phenopowerlaw_Nslip(f,instance) + j = j + 1_pInt + plastic_phenopowerlaw_postResults(c+j) = & + dot_product(Tstar_v,lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + enddo slipSystems2 + enddo slipFamilies2 + c = c + nSlip + + case (totalshear_ID) + plastic_phenopowerlaw_postResults(c+1_pInt) = & + plasticState(ph)%state(index_Gamma,of) + c = c + 1_pInt + + case (resistance_twin_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(1_pInt+nSlip:1_pInt+nSlip+nTwin-1_pInt,of) + c = c + nTwin + + case (accumulatedshear_twin_ID) + plastic_phenopowerlaw_postResults(c+1_pInt:c+nTwin) = & + plasticState(ph)%state(index_accshear_twin:index_accshear_twin+nTwin-1_pInt,of) + c = c + nTwin + case (shearrate_twin_ID) + j = 0_pInt + twinFamilies1: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems1: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j + 1_pInt + tau = dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + plastic_phenopowerlaw_postResults(c+j) = (1.0_pReal-plasticState(ph)%state(index_F,of))*& ! 1-F + plastic_phenopowerlaw_gdot0_twin(instance)*& + (abs(tau)/plasticState(ph)%state(j+nSlip,of))**& + plastic_phenopowerlaw_n_twin(instance)*max(0.0_pReal,sign(1.0_pReal,tau)) + enddo twinSystems1 + enddo twinFamilies1 + c = c + nTwin + + case (resolvedstress_twin_ID) + j = 0_pInt + twinFamilies2: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + twinSystems2: do i = 1_pInt,plastic_phenopowerlaw_Ntwin(f,instance) + j = j + 1_pInt + plastic_phenopowerlaw_postResults(c+j) = & + dot_product(Tstar_v,lattice_Stwin_v(1:6,index_myFamily+i,ph)) + enddo twinSystems2 + enddo twinFamilies2 + c = c + nTwin + + case (totalvolfrac_twin_ID) + plastic_phenopowerlaw_postResults(c+1_pInt) = plasticState(ph)%state(index_F,of) + c = c + 1_pInt + + end select + enddo outputsLoop + +end function plastic_phenopowerlaw_postResults + +end module plastic_phenopowerlaw diff --git a/src/plastic_titanmod.f90 b/src/plastic_titanmod.f90 new file mode 100644 index 000000000..abc6d661b --- /dev/null +++ b/src/plastic_titanmod.f90 @@ -0,0 +1,1913 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Alankar Alankar, 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 +!> @brief material subroutine for titanium +!-------------------------------------------------------------------------------------------------- +module plastic_titanmod + use prec, only: & + pReal, & + pInt + + implicit none + private + character(len=18), dimension(3), parameter, private :: & + plastic_titanmod_listBasicSlipStates = & + ['rho_edge ', 'rho_screw ', 'shear_system'] + character(len=18), dimension(1), parameter, private :: & + plastic_titanmod_listBasicTwinStates = ['gdot_twin'] + character(len=19), dimension(11), parameter, private :: & + plastic_titanmod_listDependentSlipStates = & + ['segment_edge ', 'segment_screw ', & + 'resistance_edge ', 'resistance_screw ', & + 'tau_slip ', & + 'velocity_edge ', 'velocity_screw ', & + 'gdot_slip_edge ', 'gdot_slip_screw ', & + 'stressratio_edge_p ', 'stressratio_screw_p' ] + character(len=18), dimension(2), parameter, private :: & + plastic_titanmod_listDependentTwinStates = & + ['twin_fraction', 'tau_twin '] + real(pReal), parameter, private :: & + kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin + + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_titanmod_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + plastic_titanmod_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + plastic_titanmod_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + plastic_titanmod_Noutput !< number of outputs per instance of this plasticity !< ID of the lattice structure + + integer(pInt), dimension(:), allocatable, public, protected :: & + plastic_titanmod_totalNslip, & !< total number of active slip systems for each instance + plastic_titanmod_totalNtwin !< total number of active twin systems for each instance + + integer(pInt), dimension(:,:), allocatable, private :: & + plastic_titanmod_Nslip, & !< number of active slip systems for each family and instance + plastic_titanmod_Ntwin, & !< number of active twin systems for each family and instance + plastic_titanmod_slipFamily, & !< lookup table relating active slip system to slip family for each instance + plastic_titanmod_twinFamily, & !< lookup table relating active twin system to twin family for each instance + plastic_titanmod_slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance + plastic_titanmod_twinSystemLattice !< lookup table relating active twin system index to lattice twin system index for each instance + + real(pReal), dimension(:), allocatable, private :: & + plastic_titanmod_debyefrequency, & !< Debye frequency + plastic_titanmod_kinkf0, & !< + plastic_titanmod_CAtomicVolume, & !< atomic volume in Bugers vector unit + plastic_titanmod_dc, & !< prefactor for self-diffusion coefficient + plastic_titanmod_twinhpconstant, & !< activation energy for dislocation climb + plastic_titanmod_GrainSize, & !< grain size - Not being used + plastic_titanmod_MaxTwinFraction, & !< maximum allowed total twin volume fraction + plastic_titanmod_r, & !< r-exponent in twin nucleation rate + plastic_titanmod_CEdgeDipMinDistance, & !< Not being used + plastic_titanmod_Cmfptwin, & !< Not being used + plastic_titanmod_Cthresholdtwin, & !< Not being used + plastic_titanmod_aTolRho !< absolute tolerance for integration of dislocation density + + real(pReal), dimension(:,:), allocatable, private :: & + plastic_titanmod_rho_edge0, & !< initial edge dislocation density per slip system for each family and instance + plastic_titanmod_rho_screw0, & !< initial screw dislocation density per slip system for each family and instance + plastic_titanmod_shear_system0, & !< accumulated shear on each system + plastic_titanmod_burgersPerSlipFam, & !< absolute length of burgers vector [m] for each slip family and instance + plastic_titanmod_burgersPerSlipSys, & !< absolute length of burgers vector [m] for each slip system and instance + plastic_titanmod_burgersPerTwinFam, & !< absolute length of burgers vector [m] for each twin family and instance + plastic_titanmod_burgersPerTwinSys, & !< absolute length of burgers vector [m] for each twin system and instance + plastic_titanmod_f0_PerSlipFam, & !< activation energy for glide [J] for each slip family and instance + plastic_titanmod_f0_PerSlipSys, & !< activation energy for glide [J] for each slip system and instance + plastic_titanmod_twinf0_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance + plastic_titanmod_twinf0_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance + plastic_titanmod_twinshearconstant_PerTwinFam, & !< activation energy for glide [J] for each twin family and instance + plastic_titanmod_twinshearconstant_PerTwinSys, & !< activation energy for glide [J] for each twin system and instance + plastic_titanmod_tau0e_PerSlipFam, & !< Initial yield stress for edge dislocations per slip family + plastic_titanmod_tau0e_PerSlipSys, & !< Initial yield stress for edge dislocations per slip system + plastic_titanmod_tau0s_PerSlipFam, & !< Initial yield stress for screw dislocations per slip family + plastic_titanmod_tau0s_PerSlipSys, & !< Initial yield stress for screw dislocations per slip system + plastic_titanmod_twintau0_PerTwinFam, & !< Initial yield stress for edge dislocations per twin family + plastic_titanmod_twintau0_PerTwinSys, & !< Initial yield stress for edge dislocations per twin system + plastic_titanmod_capre_PerSlipFam, & !< Capture radii for edge dislocations per slip family + plastic_titanmod_capre_PerSlipSys, & !< Capture radii for edge dislocations per slip system + plastic_titanmod_caprs_PerSlipFam, & !< Capture radii for screw dislocations per slip family + plastic_titanmod_caprs_PerSlipSys, & !< Capture radii for screw dislocations per slip system + plastic_titanmod_pe_PerSlipFam, & !< p-exponent in glide velocity + plastic_titanmod_ps_PerSlipFam, & !< p-exponent in glide velocity + plastic_titanmod_qe_PerSlipFam, & !< q-exponent in glide velocity + plastic_titanmod_qs_PerSlipFam, & !< q-exponent in glide velocity + plastic_titanmod_pe_PerSlipSys, & !< p-exponent in glide velocity + plastic_titanmod_ps_PerSlipSys, & !< p-exponent in glide velocity + plastic_titanmod_qe_PerSlipSys, & !< q-exponent in glide velocity + plastic_titanmod_qs_PerSlipSys, & !< q-exponent in glide velocity + plastic_titanmod_twinp_PerTwinFam, & !< p-exponent in glide velocity + plastic_titanmod_twinq_PerTwinFam, & !< q-exponent in glide velocity + plastic_titanmod_twinp_PerTwinSys, & !< p-exponent in glide velocity + plastic_titanmod_twinq_PerTwinSys, & !< p-exponent in glide velocity + plastic_titanmod_v0e_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance + plastic_titanmod_v0e_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance + plastic_titanmod_v0s_PerSlipFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance + plastic_titanmod_v0s_PerSlipSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance + plastic_titanmod_twingamma0_PerTwinFam, & !< edge dislocation velocity prefactor [m/s] for each family and instance + plastic_titanmod_twingamma0_PerTwinSys, & !< screw dislocation velocity prefactor [m/s] for each slip system and instance + plastic_titanmod_kinkcriticallength_PerSlipFam, & !< screw dislocation mobility prefactor for kink-pairs per slip family + plastic_titanmod_kinkcriticallength_PerSlipSys, & !< screw dislocation mobility prefactor for kink-pairs per slip system + plastic_titanmod_twinsizePerTwinFam, & !< twin thickness [m] for each twin family and instance + plastic_titanmod_twinsizePerTwinSys, & !< twin thickness [m] for each twin system and instance + plastic_titanmod_CeLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_titanmod_CeLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_titanmod_CsLambdaSlipPerSlipFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_titanmod_CsLambdaSlipPerSlipSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_titanmod_twinLambdaSlipPerTwinFam, & !< Adj. parameter for distance between 2 forest dislocations for each slip family and instance + plastic_titanmod_twinLambdaSlipPerTwinSys, & !< Adj. parameter for distance between 2 forest dislocations for each slip system and instance + plastic_titanmod_interactionSlipSlip, & !< coefficients for slip-slip interaction for each interaction type and instance + plastic_titanmod_interaction_ee, & !< coefficients for e-e interaction for each interaction type and instance + plastic_titanmod_interaction_ss, & !< coefficients for s-s interaction for each interaction type and instance + plastic_titanmod_interaction_es, & !< coefficients for e-s-twin interaction for each interaction type and instance + plastic_titanmod_interactionSlipTwin, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_titanmod_interactionTwinSlip, & !< coefficients for twin-slip interaction for each interaction type and instance + plastic_titanmod_interactionTwinTwin !< coefficients for twin-twin interaction for each interaction type and instance + + real(pReal), dimension(:,:,:), allocatable, private :: & + plastic_titanmod_interactionMatrixSlipSlip, & !< interaction matrix of the different slip systems for each instance + plastic_titanmod_interactionMatrix_ee, & !< interaction matrix of e-e for each instance + plastic_titanmod_interactionMatrix_ss, & !< interaction matrix of s-s for each instance + plastic_titanmod_interactionMatrix_es, & !< interaction matrix of e-s for each instance + plastic_titanmod_interactionMatrixSlipTwin, & !< interaction matrix of slip systems with twin systems for each instance + plastic_titanmod_interactionMatrixTwinSlip, & !< interaction matrix of twin systems with slip systems for each instance + plastic_titanmod_interactionMatrixTwinTwin, & !< interaction matrix of the different twin systems for each instance + plastic_titanmod_forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance + plastic_titanmod_forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance + plastic_titanmod_TwinforestProjectionEdge, & !< matrix of forest projections of edge dislocations in twin system for each instance + plastic_titanmod_TwinforestProjectionScrew !< matrix of forest projections of screw dislocations in twin system for each instance + + real(pReal), dimension(:,:,:,:), allocatable, private :: & + plastic_titanmod_Ctwin66 !< twin elasticity matrix in Mandel notation for each instance + + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & + plastic_titanmod_Ctwin3333 !< twin elasticity matrix for each instance + + enum, bind(c) + enumerator :: undefined_ID, & + rhoedge_ID, rhoscrew_ID, & + segment_edge_ID, segment_screw_ID, & + resistance_edge_ID, resistance_screw_ID, & + velocity_edge_ID, velocity_screw_ID, & + tau_slip_ID, & + gdot_slip_edge_ID, gdot_slip_screw_ID, & + gdot_slip_ID, & + stressratio_edge_p_ID, stressratio_screw_p_ID, & + shear_system_ID, & + twin_fraction_ID, & + shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & + rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & + rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & + shear_total_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + plastic_titanmod_outputID !< ID of each post result output + + public :: & + plastic_titanmod_microstructure, & + plastic_titanmod_stateInit, & + plastic_titanmod_init, & + plastic_titanmod_LpAndItsTangent, & + plastic_titanmod_dotState, & + plastic_titanmod_postResults, & + plastic_titanmod_homogenizedC + + contains + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use math, only: & + math_Mandel3333to66,& + math_Voigt66to3333,& + math_mul3x3 + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_plasticity, & + phase_plasticityInstance, & + phase_Noutput, & + PLASTICITY_TITANMOD_label, & + PLASTICITY_TITANMOD_ID, & + plasticState, & + MATERIAL_partPhase + use lattice + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: & + phase, & + instance, j, k, l, m, n, p, q, r, & + f, o, & + s, s1, s2, & + t, t1, t2, & + ns, nt, & + Nchunks_SlipSlip = 0_pInt, Nchunks_SlipTwin = 0_pInt, Nchunks_TwinSlip = 0_pInt, Nchunks_TwinTwin = 0_pInt, & + Nchunks_SlipFamilies = 0_pInt, Nchunks_TwinFamilies = 0_pInt, & + offset_slip, mySize, & + maxTotalNslip,maxTotalNtwin, maxNinstance + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase = 0_pInt + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_TITANMOD_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_plasticity == PLASTICITY_TITANMOD_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(plastic_titanmod_sizePostResults(maxNinstance), source=0_pInt) + allocate(plastic_titanmod_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) + allocate(plastic_titanmod_output(maxval(phase_Noutput),maxNinstance)) + plastic_titanmod_output = '' + allocate(plastic_titanmod_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(plastic_titanmod_Noutput(maxNinstance), source=0_pInt) + + allocate(plastic_titanmod_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_Ntwin(lattice_maxNtwinFamily,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_slipFamily(lattice_maxNslip,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_twinFamily(lattice_maxNtwin,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_slipSystemLattice(lattice_maxNslip,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_twinSystemLattice(lattice_maxNtwin,maxNinstance), source=0_pInt) + allocate(plastic_titanmod_totalNslip(maxNinstance), source=0_pInt) + allocate(plastic_titanmod_totalNtwin(maxNinstance), source=0_pInt) + allocate(plastic_titanmod_debyefrequency(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_kinkf0(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CAtomicVolume(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_dc(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinhpconstant(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_GrainSize(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_MaxTwinFraction(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_r(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CEdgeDipMinDistance(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Cmfptwin(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Cthresholdtwin(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_aTolRho(maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_rho_edge0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_rho_screw0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_shear_system0(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_burgersPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_burgersPerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_f0_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_capre_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_caprs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_pe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_ps_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qe_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qs_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0e_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0s_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_kinkcriticallength_PerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinsizePerTwinFam(lattice_maxNtwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CeLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CsLambdaSlipPerSlipFam(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_twinf0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinshearconstant_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twintau0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinp_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinq_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twingamma0_PerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinLambdaSlipPerTwinFam(lattice_maxNTwinFamily,maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_interactionSlipSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interaction_ee(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interaction_ss(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interaction_es(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionSlipTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionTwinSlip(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionTwinTwin(lattice_maxNinteraction,maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next section + phase = phase + 1_pInt ! advance section counter + if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then + Nchunks_SlipFamilies = count(lattice_NslipSystem(:,phase) > 0_pInt) + Nchunks_TwinFamilies = count(lattice_NtwinSystem(:,phase) > 0_pInt) + Nchunks_SlipSlip = maxval(lattice_interactionSlipSlip(:,:,phase)) + Nchunks_SlipTwin = maxval(lattice_interactionSlipTwin(:,:,phase)) + Nchunks_TwinSlip = maxval(lattice_interactionTwinSlip(:,:,phase)) + Nchunks_TwinTwin = maxval(lattice_interactionTwinTwin(:,:,phase)) + endif + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then ! one of my sections. Do not short-circuit here (.and. between if-statements), it's not safe in Fortran + instance = phase_plasticityInstance(phase) ! which instance of my plasticity is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('rhoedge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('segment_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('segment_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = segment_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('resistance_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = resistance_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('velocity_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = velocity_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('tau_slip') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = tau_slip_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('gdot_slip_edge') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_edge_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('gdot_slip_screw') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_screw_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('gdot_slip') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = gdot_slip_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stressratio_edge_p') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_edge_p_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('stressratio_screw_p') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = stressratio_screw_p_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_system') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_system_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('twin_fraction') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = twin_fraction_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_basal') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_basal_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_prism') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_prism_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_pyra') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyra_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_pyrca') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_pyrca_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_basal') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_basal_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_prism') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_prism_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_pyra') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyra_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoedge_pyrca') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoedge_pyrca_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_basal') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_basal_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_prism') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_prism_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_pyra') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyra_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('rhoscrew_pyrca') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = rhoscrew_pyrca_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + case ('shear_total') + plastic_titanmod_Noutput(instance) = plastic_titanmod_Noutput(instance) + 1_pInt + plastic_titanmod_outputID(plastic_titanmod_Noutput(instance),instance) = shear_total_ID + plastic_titanmod_output(plastic_titanmod_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + case ('debyefrequency') + plastic_titanmod_debyefrequency(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('kinkf0') + plastic_titanmod_kinkf0(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('nslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipFamilies) & + call IO_warning(50_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('ntwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinFamilies) & + call IO_warning(51_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_Ntwin(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + case ('rho_edge0') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_rho_edge0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('rho_screw0') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_rho_screw0(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('slipburgers') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_burgersPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinburgers') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_burgersPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('f0') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_f0_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinf0') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinf0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0e') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_tau0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twintau0') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twintau0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('tau0s') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_tau0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('capre') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_capre_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('caprs') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_caprs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('v0e') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_v0e_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twingamma0') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twingamma0_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('v0s') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_v0s_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('kinkcriticallength') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_kinkcriticallength_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinsize') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinsizePerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('celambdaslip') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_CeLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinlambdaslip') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinlambdaslipPerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('cslambdaslip') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_CsLambdaSlipPerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('grainsize') + plastic_titanmod_GrainSize(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('maxtwinfraction') + plastic_titanmod_MaxTwinFraction(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('pe') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_pe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinp') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinp_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('ps') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_ps_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('qe') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_qe_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinq') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinq_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('qs') + do j = 1_pInt, Nchunks_SlipFamilies + plastic_titanmod_qs_PerSlipFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('twinshearconstant') + do j = 1_pInt, Nchunks_TwinFamilies + plastic_titanmod_twinshearconstant_PerTwinFam(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('dc') + plastic_titanmod_dc(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('twinhpconstant') + plastic_titanmod_twinhpconstant(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('atol_rho') + plastic_titanmod_aTolRho(instance) = IO_floatValue(line,chunkPos,2_pInt) + case ('interactionee') + do j = 1_pInt, lattice_maxNinteraction + plastic_titanmod_interaction_ee(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interactionss') + do j = 1_pInt, lattice_maxNinteraction + plastic_titanmod_interaction_ss(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interactiones') + do j = 1_pInt, lattice_maxNinteraction + plastic_titanmod_interaction_es(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_slipslip','interactionslipslip') + if (chunkPos(1) < 1_pInt + Nchunks_SlipSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_SlipSlip + plastic_titanmod_interactionSlipSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_sliptwin','interactionsliptwin') + if (chunkPos(1) < 1_pInt + Nchunks_SlipTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_SlipTwin + plastic_titanmod_interactionSlipTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twinslip','interactiontwinslip') + if (chunkPos(1) < 1_pInt + Nchunks_TwinSlip) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_TwinSlip + plastic_titanmod_interactionTwinSlip(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + case ('interaction_twintwin','interactiontwintwin') + if (chunkPos(1) < 1_pInt + Nchunks_TwinTwin) & + call IO_warning(52_pInt,ext_msg=trim(tag)//' ('//PLASTICITY_TITANMOD_label//')') + do j = 1_pInt, Nchunks_TwinTwin + plastic_titanmod_interactionTwinTwin(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + end select + endif; endif + enddo parsingFile + + sanityChecks: do phase = 1_pInt, size(phase_plasticity) + myPhase: if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then + instance = phase_plasticityInstance(phase) + if (sum(plastic_titanmod_Nslip(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='nslip ('//PLASTICITY_TITANMOD_label//')') + if (sum(plastic_titanmod_Ntwin(:,instance)) < 0_pInt) & + call IO_error(211_pInt,el=instance,ext_msg='ntwin ('//PLASTICITY_TITANMOD_label//')') + do f = 1_pInt,lattice_maxNslipFamily + if (plastic_titanmod_Nslip(f,instance) > 0_pInt) then + if (plastic_titanmod_rho_edge0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rho_edge0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_rho_screw0(f,instance) < 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rho_screw0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_burgersPerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='slipburgers ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_f0_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='f0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_tau0e_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau0e ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_tau0s_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='tau0s ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_capre_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='capre ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_caprs_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='caprs ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_v0e_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0e ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_v0s_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='v0s ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='kinkCriticalLength ('//PLASTICITY_TITANMOD_label//')') + endif + enddo + do f = 1_pInt,lattice_maxNtwinFamily + if (plastic_titanmod_Ntwin(f,instance) > 0_pInt) then + if (plastic_titanmod_burgersPerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinburgers ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twinf0_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinf0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinshearconstant ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twintau0_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twintau0 ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twingamma0_PerTwinFam(f,instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twingamma0 ('//PLASTICITY_TITANMOD_label//')') + endif + enddo + if (plastic_titanmod_dc(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='dc ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_twinhpconstant(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='twinhpconstant ('//PLASTICITY_TITANMOD_label//')') + if (plastic_titanmod_aTolRho(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='aTol_rho ('//PLASTICITY_TITANMOD_label//')') + +!-------------------------------------------------------------------------------------------------- +! determine total number of active slip or twin systems + plastic_titanmod_Nslip(:,instance) = min(lattice_NslipSystem(:,phase),plastic_titanmod_Nslip(:,instance)) + plastic_titanmod_Ntwin(:,instance) = min(lattice_NtwinSystem(:,phase),plastic_titanmod_Ntwin(:,instance)) + plastic_titanmod_totalNslip(instance) = sum(plastic_titanmod_Nslip(:,instance)) + plastic_titanmod_totalNtwin(instance) = sum(plastic_titanmod_Ntwin(:,instance)) + endif myPhase + enddo sanityChecks + +!-------------------------------------------------------------------------------------------------- +! allocation of variables whose size depends on the total number of active slip systems + maxTotalNslip = maxval(plastic_titanmod_totalNslip) + maxTotalNtwin = maxval(plastic_titanmod_totalNtwin) + + allocate(plastic_titanmod_burgersPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_f0_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_tau0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_capre_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_caprs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_pe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_ps_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qe_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_qs_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0e_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_v0s_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_kinkcriticallength_PerSlipSys(maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CeLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_CsLambdaSlipPerSlipSys(maxTotalNslip, maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_burgersPerTwinSys(maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinf0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinshearconstant_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twintau0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinp_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinq_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twingamma0_PerTwinSys(maxTotalNTwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinsizePerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_twinLambdaSlipPerTwinSys(maxTotalNtwin, maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Ctwin66 (6,6,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_Ctwin3333 (3,3,3,3,maxTotalNtwin,maxNinstance), source=0.0_pReal) + + allocate(plastic_titanmod_interactionMatrixSlipSlip(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrix_ee(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrix_ss(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrix_es(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrixSlipTwin(maxTotalNslip,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrixTwinSlip(maxTotalNtwin,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_interactionMatrixTwinTwin(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_forestProjectionEdge(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_forestProjectionScrew(maxTotalNslip,maxTotalNslip,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_TwinforestProjectionEdge(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) + allocate(plastic_titanmod_TwinforestProjectionScrew(maxTotalNtwin,maxTotalNtwin,maxNinstance), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, size(phase_plasticity) + if (phase_plasticity(phase) == PLASTICITY_TITANMOD_ID) then + instance = phase_plasticityInstance(phase) + +!-------------------------------------------------------------------------------------------------- +! inverse lookup of slip system family + l = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily + do s = 1_pInt,plastic_titanmod_Nslip(f,instance) + l = l + 1_pInt + plastic_titanmod_slipFamily(l,instance) = f + plastic_titanmod_slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt,phase)) + s + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! inverse lookup of twin system family + l = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily + do t = 1_pInt,plastic_titanmod_Ntwin(f,instance) + l = l + 1_pInt + plastic_titanmod_twinFamily(l,instance) = f + plastic_titanmod_twinSystemLattice(l,instance) = sum(lattice_NtwinSystem(1:f-1_pInt,phase)) + t + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! determine size of state array + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + sizeDotState = & + size(plastic_titanmod_listBasicSlipStates)*ns + & + size(plastic_titanmod_listBasicTwinStates)*nt + sizeState = sizeDotState+ & + size(plastic_titanmod_listDependentSlipStates)*ns + & + size(plastic_titanmod_listDependentTwinStates)*nt + sizeDeltaState = 0_pInt + +!-------------------------------------------------------------------------------------------------- +! determine size of postResults array + outputsLoop: do o = 1_pInt,plastic_titanmod_Noutput(instance) + mySize = 0_pInt + select case(plastic_titanmod_outputID(o,instance)) + case(rhoedge_ID, rhoscrew_ID, & + segment_edge_ID, segment_screw_ID, & + resistance_edge_ID, resistance_screw_ID, & + velocity_edge_ID, velocity_screw_ID, & + tau_slip_ID, & + gdot_slip_edge_ID, gdot_slip_screw_ID, & + gdot_slip_ID, & + stressratio_edge_p_ID, stressratio_screw_p_ID, & + shear_system_ID) + mySize = plastic_titanmod_totalNslip(instance) + case(twin_fraction_ID) + mySize = plastic_titanmod_totalNtwin(instance) + case(shear_basal_ID, shear_prism_ID, shear_pyra_ID, shear_pyrca_ID, & ! use only if all 4 slip families in hex are considered + rhoedge_basal_ID, rhoedge_prism_ID, rhoedge_pyra_ID, rhoedge_pyrca_ID, & + rhoscrew_basal_ID, rhoscrew_prism_ID, rhoscrew_pyra_ID, rhoscrew_pyrca_ID, & + shear_total_ID) + mySize = 1_pInt + case default + call IO_error(105_pInt,ext_msg=plastic_titanmod_output(o,instance)// & + ' ('//PLASTICITY_TITANMOD_label//')') + end select + + outputFound: if (mySize > 0_pInt) then + plastic_titanmod_sizePostResult(o,instance) = mySize + plastic_titanmod_sizePostResults(instance) = plastic_titanmod_sizePostResults(instance) + mySize + endif outputFound + enddo outputsLoop +! Determine size of state array + plasticState(phase)%sizeState = sizeState + plasticState(phase)%sizeDotState = sizeDotState + plasticState(phase)%sizeDeltaState = sizeDeltaState + plasticState(phase)%sizePostResults = plastic_titanmod_sizePostResults(instance) + plasticState(phase)%nSlip =plastic_titanmod_totalNslip(instance) + plasticState(phase)%nTwin = 0_pInt + plasticState(phase)%nTrans= 0_pInt + allocate(plasticState(phase)%aTolState (sizeState), source=plastic_titanmod_aTolRho(instance)) + allocate(plasticState(phase)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(plasticState(phase)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(plasticState(phase)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(plasticState(phase)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(plasticState(phase)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(plasticState(phase)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(plasticState(phase)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + offset_slip = 2_pInt*plasticState(phase)%nSlip+1 + plasticState(phase)%slipRate => & + plasticState(phase)%dotState(offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) + plasticState(phase)%accumulatedSlip => & + plasticState(phase)%state (offset_slip+1:offset_slip+plasticState(phase)%nSlip,1:NofMyPhase) +!-------------------------------------------------------------------------------------------------- +! construction of the twin elasticity matrices + do j=1_pInt,lattice_maxNtwinFamily + do k=1_pInt,plastic_titanmod_Ntwin(j,instance) + do l=1_pInt,3_pInt ; do m=1_pInt,3_pInt ; do n=1_pInt,3_pInt ; do o=1_pInt,3_pInt + do p=1_pInt,3_pInt ; do q=1_pInt,3_pInt ; do r=1_pInt,3_pInt ; do s=1_pInt,3_pInt + plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) = & + plastic_titanmod_Ctwin3333(l,m,n,o,sum(plastic_titanmod_Nslip(1:j-1_pInt,instance))+k,instance) + & + lattice_C3333(p,q,r,s,phase)*& + lattice_Qtwin(l,p,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & + lattice_Qtwin(m,q,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & + lattice_Qtwin(n,r,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase)* & + lattice_Qtwin(o,s,sum(lattice_NslipSystem(1:j-1_pInt,phase))+k,phase) + enddo; enddo; enddo; enddo + enddo; enddo; enddo ; enddo + plastic_titanmod_Ctwin66(1:6,1:6,k,instance) = & + math_Mandel3333to66(plastic_titanmod_Ctwin3333(1:3,1:3,1:3,1:3,k,instance)) + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! Burgers vector, dislocation velocity prefactor for each slip system + do s = 1_pInt,plastic_titanmod_totalNslip(instance) + f = plastic_titanmod_slipFamily(s,instance) + + plastic_titanmod_burgersPerSlipSys(s,instance) = & + plastic_titanmod_burgersPerSlipFam(f,instance) + + plastic_titanmod_f0_PerSlipSys(s,instance) = & + plastic_titanmod_f0_PerSlipFam(f,instance) + + plastic_titanmod_tau0e_PerSlipSys(s,instance) = & + plastic_titanmod_tau0e_PerSlipFam(f,instance) + + plastic_titanmod_tau0s_PerSlipSys(s,instance) = & + plastic_titanmod_tau0s_PerSlipFam(f,instance) + + plastic_titanmod_capre_PerSlipSys(s,instance) = & + plastic_titanmod_capre_PerSlipFam(f,instance) + + plastic_titanmod_caprs_PerSlipSys(s,instance) = & + plastic_titanmod_caprs_PerSlipFam(f,instance) + + plastic_titanmod_v0e_PerSlipSys(s,instance) = & + plastic_titanmod_v0e_PerSlipFam(f,instance) + + plastic_titanmod_v0s_PerSlipSys(s,instance) = & + plastic_titanmod_v0s_PerSlipFam(f,instance) + + plastic_titanmod_kinkcriticallength_PerSlipSys(s,instance) = & + plastic_titanmod_kinkcriticallength_PerSlipFam(f,instance) + + plastic_titanmod_pe_PerSlipSys(s,instance) = & + plastic_titanmod_pe_PerSlipFam(f,instance) + + plastic_titanmod_ps_PerSlipSys(s,instance) = & + plastic_titanmod_ps_PerSlipFam(f,instance) + + plastic_titanmod_qe_PerSlipSys(s,instance) = & + plastic_titanmod_qe_PerSlipFam(f,instance) + + plastic_titanmod_qs_PerSlipSys(s,instance) = & + plastic_titanmod_qs_PerSlipFam(f,instance) + + plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance) = & + plastic_titanmod_CeLambdaSlipPerSlipFam(f,instance) + + plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance) = & + plastic_titanmod_CsLambdaSlipPerSlipFam(f,instance) + enddo + +!-------------------------------------------------------------------------------------------------- +! Burgers vector, nucleation rate prefactor and twin size for each twin system + do t = 1_pInt,plastic_titanmod_totalNtwin(instance) + f = plastic_titanmod_twinFamily(t,instance) + + plastic_titanmod_burgersPerTwinSys(t,instance) = & + plastic_titanmod_burgersPerTwinFam(f,instance) + + plastic_titanmod_twinsizePerTwinSys(t,instance) = & + plastic_titanmod_twinsizePerTwinFam(f,instance) + + plastic_titanmod_twinf0_PerTwinSys(t,instance) = & + plastic_titanmod_twinf0_PerTwinFam(f,instance) + + plastic_titanmod_twinshearconstant_PerTwinSys(t,instance) = & + plastic_titanmod_twinshearconstant_PerTwinFam(f,instance) + + plastic_titanmod_twintau0_PerTwinSys(t,instance) = & + plastic_titanmod_twintau0_PerTwinFam(f,instance) + + plastic_titanmod_twingamma0_PerTwinSys(t,instance) = & + plastic_titanmod_twingamma0_PerTwinFam(f,instance) + + plastic_titanmod_twinp_PerTwinSys(t,instance) = & + plastic_titanmod_twinp_PerTwinFam(f,instance) + + plastic_titanmod_twinq_PerTwinSys(t,instance) = & + plastic_titanmod_twinq_PerTwinFam(f,instance) + + plastic_titanmod_twinLambdaSlipPerTwinSys(t,instance) = & + plastic_titanmod_twinLambdaSlipPerTwinFam(f,instance) + enddo + +!-------------------------------------------------------------------------------------------------- +! Construction of interaction matrices + do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) + do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) + plastic_titanmod_interactionMatrixSlipSlip(s1,s2,instance) = & + plastic_titanmod_interactionSlipSlip(lattice_interactionSlipSlip( & + plastic_titanmod_slipSystemLattice(s1,instance),& + plastic_titanmod_slipSystemLattice(s2,instance),phase),instance) + + plastic_titanmod_interactionMatrix_ee(s1,s2,instance) = & + plastic_titanmod_interaction_ee(lattice_interactionSlipSlip ( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + + plastic_titanmod_interactionMatrix_ss(s1,s2,instance) = & + plastic_titanmod_interaction_ss(lattice_interactionSlipSlip( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + + plastic_titanmod_interactionMatrix_es(s1,s2,instance) = & + plastic_titanmod_interaction_es(lattice_interactionSlipSlip( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + enddo; enddo + + do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) + do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) + plastic_titanmod_interactionMatrixSlipTwin(s1,t2,instance) = & + plastic_titanmod_interactionSlipTwin(lattice_interactionSlipTwin( & + plastic_titanmod_slipSystemLattice(s1,instance), & + plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) + enddo; enddo + + do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) + do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) + plastic_titanmod_interactionMatrixTwinSlip(t1,s2,instance) = & + plastic_titanmod_interactionTwinSlip(lattice_interactionTwinSlip( & + plastic_titanmod_twinSystemLattice(t1,instance), & + plastic_titanmod_slipSystemLattice(s2,instance), phase),instance) + enddo; enddo + + do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) + do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) + plastic_titanmod_interactionMatrixTwinTwin(t1,t2,instance) = & + plastic_titanmod_interactionTwinTwin(lattice_interactionTwinTwin( & + plastic_titanmod_twinSystemLattice(t1,instance), & + plastic_titanmod_twinSystemLattice(t2,instance), phase),instance) + enddo; enddo + + do s1 = 1_pInt,plastic_titanmod_totalNslip(instance) + do s2 = 1_pInt,plastic_titanmod_totalNslip(instance) +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for edge dislocations + plastic_titanmod_forestProjectionEdge(s1,s2,instance) = & + abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & + lattice_st(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) + +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for screw dislocations + plastic_titanmod_forestProjectionScrew(s1,s2,instance) = & + abs(math_mul3x3(lattice_sn(:,plastic_titanmod_slipSystemLattice(s1,instance),phase), & + lattice_sd(:,plastic_titanmod_slipSystemLattice(s2,instance),phase))) + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for edge dislocations in twin system + do t1 = 1_pInt,plastic_titanmod_totalNtwin(instance) + do t2 = 1_pInt,plastic_titanmod_totalNtwin(instance) + plastic_titanmod_TwinforestProjectionEdge(t1,t2,instance) = & + abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & + lattice_tt(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) + +!-------------------------------------------------------------------------------------------------- +! calculation of forest projections for screw dislocations in twin system + plastic_titanmod_TwinforestProjectionScrew(t1,t2,instance) = & + abs(math_mul3x3(lattice_tn(:,plastic_titanmod_twinSystemLattice(t1,instance),phase), & + lattice_td(:,plastic_titanmod_twinSystemLattice(t2,instance),phase))) + enddo; enddo + call plastic_titanmod_stateInit(phase,instance) + endif + enddo initializeInstances + +end subroutine plastic_titanmod_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief sets the initial microstructural state for a given instance of this plasticity +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_stateInit(ph,instance) + use lattice, only: & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_mu + + use material, only: & + plasticState + + implicit none + integer(pInt), intent(in) :: instance !< number specifying the instance of the plasticity + integer(pInt), intent(in) :: ph !< number specifying the phase of the plasticity + + + integer(pInt) :: & + s,s0,s1, & + t,t0,t1, & + ns,nt,f + real(pReal), dimension(plastic_titanmod_totalNslip(instance)) :: & + rho_edge0, & + rho_screw0, & + shear_system0, & + segment_edge0, & + segment_screw0, & + resistance_edge0, & + resistance_screw0 + real(pReal), dimension(plastic_titanmod_totalNtwin(instance)) :: & + twingamma_dot0, & + resistance_twin0 + real(pReal), dimension(plasticState(ph)%sizeState) :: tempState !!!!!!!!!????????? check + + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + tempState = 0.0_pReal +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables for slip + s1 = 0_pInt + do f = 1_pInt,lattice_maxNslipFamily + s0 = s1 + 1_pInt + s1 = s0 + plastic_titanmod_Nslip(f,instance) - 1_pInt + do s = s0,s1 + rho_edge0(s) = plastic_titanmod_rho_edge0(f,instance) + rho_screw0(s) = plastic_titanmod_rho_screw0(f,instance) + shear_system0(s) = 0.0_pReal + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! initialize basic slip state variables for twin + t1 = 0_pInt + do f = 1_pInt,lattice_maxNtwinFamily + t0 = t1 + 1_pInt + t1 = t0 + plastic_titanmod_Ntwin(f,instance) - 1_pInt + do t = t0,t1 + twingamma_dot0(t)=0.0_pReal + enddo + enddo + +!-------------------------------------------------------------------------------------------------- +! initialize dependent slip microstructural variables + forall (s = 1_pInt:ns) + segment_edge0(s) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) + segment_screw0(s) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product((rho_edge0),plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product((rho_screw0),plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) + resistance_edge0(s) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & + sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & + dot_product((rho_screw0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) + resistance_screw0(s) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)* & + sqrt(dot_product((rho_edge0),plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & + dot_product((rho_screw0), plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) + end forall + + forall (t = 1_pInt:nt) & + resistance_twin0(t) = 0.0_pReal + +tempState = 0.0_pReal +tempState (1:ns) = rho_edge0 +tempState (1_pInt*ns+1_pInt:2_pInt*ns) = rho_screw0 +tempState (2_pInt*ns+1_pInt:3_pInt*ns) = shear_system0 +tempState (3_pInt*ns+1_pInt:3_pInt*ns+nt) = twingamma_dot0 +tempState (3_pInt*ns+nt+1_pInt:4_pInt*ns+nt) = segment_edge0 +tempState (4_pInt*ns+nt+1_pInt:5_pInt*ns+nt) = segment_screw0 +tempState (5_pInt*ns+nt+1_pInt:6_pInt*ns+nt) = resistance_edge0 +tempState (6_pInt*ns+nt+1_pInt:7_pInt*ns+nt) = resistance_screw0 +tempState (7_pInt*ns+nt+1_pInt:7_pInt*ns+2_pInt*nt)=resistance_twin0 + +plasticState(ph)%state0 = spread(tempState,2,size(plasticState(ph)%state(1,:))) +end subroutine plastic_titanmod_stateInit + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenized elasticity matrix +!-------------------------------------------------------------------------------------------------- +function plastic_titanmod_homogenizedC(ipc,ip,el) + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_C66 + +implicit none + real(pReal), dimension(6,6) :: & + plastic_titanmod_homogenizedC + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element +real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + volumefraction_PerTwinSys + integer(pInt) :: & + ph, & + of, & + instance, & + ns, nt, & + i + real(pReal) :: & + sumf + +!-------------------------------------------------------------------------------------------------- +! shortened notation +! ph = material_phase(ipc,ip,el) + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! total twin volume fraction + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + enddo + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + +!-------------------------------------------------------------------------------------------------- +! homogenized elasticity matrix + plastic_titanmod_homogenizedC = (1.0_pReal-sumf)*lattice_C66(1:6,1:6,ph) + do i=1_pInt,nt + plastic_titanmod_homogenizedC = plastic_titanmod_homogenizedC & + + volumefraction_PerTwinSys(i)*& + plastic_titanmod_Ctwin66(1:6,1:6,i,instance) + enddo + +end function plastic_titanmod_homogenizedC + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_microstructure(temperature,ipc,ip,el) + + use material, only: & + material_phase,& + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + use lattice, only: & + lattice_mu + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + temperature !< temperature at IP + integer(pInt) :: & + instance, & + ns, nt, s, t, & + i, & + ph, & + of + real(pReal) :: & + sumf, & + sfe ! stacking fault energy + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + volumefraction_PerTwinSys + +!-------------------------------------------------------------------------------------------------- + +!Shortened notation + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + +!-------------------------------------------------------------------------------------------------- +! total twin volume fraction + forall (i = 1_pInt:nt) & + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + + sfe = 0.0002_pReal*Temperature-0.0396_pReal + +!-------------------------------------------------------------------------------------------------- +! average segment length for edge dislocations in matrix + forall (s = 1_pInt:ns) & + plasticState(ph)%state(3_pInt*ns+nt+s, of) = plastic_titanmod_CeLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product(plasticState(ph)%state(1:ns, of), & + plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & + plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! average segment length for screw dislocations in matrix + forall (s = 1_pInt:ns) & + plasticState(ph)%state(4_pInt*ns+nt+s, of) = plastic_titanmod_CsLambdaSlipPerSlipSys(s,instance)/ & + sqrt(dot_product(plasticState(ph)%state(1:ns, of), & + plastic_titanmod_forestProjectionEdge(1:ns,s,instance))+ & + dot_product(plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of), & + plastic_titanmod_forestProjectionScrew(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! threshold stress or slip resistance for edge dislocation motion + forall (s = 1_pInt:ns) & + plasticState(ph)%state(5_pInt*ns+nt+s, of) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& + sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& + plastic_titanmod_interactionMatrix_ee(1:ns,s,instance))+ & + dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& + plastic_titanmod_interactionMatrix_es(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! threshold stress or slip resistance for screw dislocation motion + forall (s = 1_pInt:ns) & + plasticState(ph)%state(6_pInt*ns+nt+s, of) = & + lattice_mu(ph)*plastic_titanmod_burgersPerSlipSys(s,instance)*& + sqrt(dot_product((plasticState(ph)%state(1:ns, of)),& + plastic_titanmod_interactionMatrix_es(1:ns,s,instance))+ & + dot_product((plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of)),& + plastic_titanmod_interactionMatrix_ss(1:ns,s,instance))) +!-------------------------------------------------------------------------------------------------- +! threshold stress or slip resistance for dislocation motion in twin + forall (t = 1_pInt:nt) & + plasticState(ph)%state(7_pInt*ns+nt+t, of) = & + lattice_mu(ph)*plastic_titanmod_burgersPerTwinSys(t,instance)*& + (dot_product((abs(plasticState(ph)%state(2_pInt*ns+1_pInt:2_pInt*ns+nt, of))),& + plastic_titanmod_interactionMatrixTwinTwin(1:nt,t,instance))) + +! state=tempState + +end subroutine plastic_titanmod_microstructure + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates plastic velocity gradient and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_LpAndItsTangent(Lp,dLp_dTstar99,Tstar_v,temperature,ipc,ip,el) + use math, only: & + math_Plain3333to99, & + math_Mandel6to33 + use lattice, only: & + lattice_Sslip, & + lattice_Sslip_v, & + lattice_Stwin, & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem, & + lattice_structure, & + LATTICE_hex_ID + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + + implicit none + real(pReal), dimension(3,3), intent(out) :: & + Lp !< plastic velocity gradient + real(pReal), dimension(9,9), intent(out) :: & + dLp_dTstar99 !< derivative of Lp with respect to 2nd Piola Kirchhoff stress + + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(6), intent(in) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at IP + integer(pInt) :: & + index_myFamily, instance, & + ns,nt, & + f,i,j,k,l,m,n, & + ph, & + of + real(pReal) :: sumf, & + StressRatio_edge_p, minusStressRatio_edge_p, StressRatio_edge_pminus1, BoltzmannRatioedge, & + StressRatio_screw_p, minusStressRatio_screw_p, StressRatio_screw_pminus1, BoltzmannRatioscrew, & + twinStressRatio_p, twinminusStressRatio_p, twinStressRatio_pminus1, BoltzmannRatiotwin, & + twinDotGamma0, bottomstress_edge, bottomstress_screw, screwvelocity_prefactor + real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 + real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_slip,dgdot_dtauslip,tau_slip, & + edge_velocity, screw_velocity, & + gdot_slip_edge, gdot_slip_screw + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin,dgdot_dtautwin,tau_twin, volumefraction_PerTwinSys + +! tempState=state + + + +!-------------------------------------------------------------------------------------------------- +! shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + + enddo + + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + + + Lp = 0.0_pReal + dLp_dTstar3333 = 0.0_pReal + dLp_dTstar99 = 0.0_pReal + + !* Dislocation glide part + gdot_slip = 0.0_pReal + gdot_slip_edge = 0.0_pReal + gdot_slip_screw = 0.0_pReal + dgdot_dtauslip = 0.0_pReal + j = 0_pInt + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on slip system + tau_slip(j) = dot_product(Tstar_v,lattice_Sslip_v(:,1,index_myFamily+i,ph)) + if(lattice_structure(ph)==LATTICE_hex_ID) then ! only for prismatic and pyr systems in hex + screwvelocity_prefactor=plastic_titanmod_debyefrequency(instance)* & + plasticState(ph)%state(4_pInt*ns+nt+j, of)*(plastic_titanmod_burgersPerSlipSys(j,instance)/ & + plastic_titanmod_kinkcriticallength_PerSlipSys(j,instance))**2 + + !* Stress ratio for screw ! No slip resistance for screw dislocations, only Peierls stress + bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) + StressRatio_screw_p = ((abs(tau_slip(j)))/ & + ( bottomstress_screw) & + )**plastic_titanmod_ps_PerSlipSys(j,instance) + + if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then + minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p + else + minusStressRatio_screw_p=0.001_pReal + endif + + bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance) + StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/ & + ( bottomstress_screw) & + )**(plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio for screw + BoltzmannRatioscrew = plastic_titanmod_kinkf0(instance)/(kB*Temperature) + + else ! if the structure is not hex or the slip family is basal + screwvelocity_prefactor=plastic_titanmod_v0s_PerSlipSys(j,instance) + bottomstress_screw=plastic_titanmod_tau0s_PerSlipSys(j,instance)+ & + plasticState(ph)%state(6*ns+nt+j, of) + StressRatio_screw_p = ((abs(tau_slip(j)))/( bottomstress_screw ))**plastic_titanmod_ps_PerSlipSys(j,instance) + + if((1.0_pReal-StressRatio_screw_p)>0.001_pReal) then + minusStressRatio_screw_p=1.0_pReal-StressRatio_screw_p + else + minusStressRatio_screw_p=0.001_pReal + endif + + StressRatio_screw_pminus1 = ((abs(tau_slip(j)))/( bottomstress_screw))** & + (plastic_titanmod_ps_PerSlipSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio for screw + BoltzmannRatioscrew = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) + + endif + + !* Stress ratio for edge + bottomstress_edge=plastic_titanmod_tau0e_PerSlipSys(j,instance)+ & + plasticState(ph)%state(5*ns+nt+j, of) + StressRatio_edge_p = ((abs(tau_slip(j)))/ & + ( bottomstress_edge) & + )**plastic_titanmod_pe_PerSlipSys(j,instance) + + if((1.0_pReal-StressRatio_edge_p)>0.001_pReal) then + minusStressRatio_edge_p=1.0_pReal-StressRatio_edge_p + else + minusStressRatio_edge_p=0.001_pReal + endif + + StressRatio_edge_pminus1 = ((abs(tau_slip(j)))/( bottomstress_edge))** & + (plastic_titanmod_pe_PerSlipSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio for edge. For screws it is defined above + BoltzmannRatioedge = plastic_titanmod_f0_PerSlipSys(j,instance)/(kB*Temperature) + + screw_velocity(j) =screwvelocity_prefactor * & ! there is no v0 for screw now because it is included in the prefactor + exp(-BoltzmannRatioscrew*(minusStressRatio_screw_p)** & + plastic_titanmod_qs_PerSlipSys(j,instance)) + + edge_velocity(j) =plastic_titanmod_v0e_PerSlipSys(j,instance)*exp(-BoltzmannRatioedge* & + (minusStressRatio_edge_p)** & + plastic_titanmod_qe_PerSlipSys(j,instance)) + + !* Shear rates due to edge slip + gdot_slip_edge(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(j, of)* & + edge_velocity(j))* sign(1.0_pReal,tau_slip(j)) + !* Shear rates due to screw slip + gdot_slip_screw(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(plasticState(ph)%state(ns+j, of) * & + screw_velocity(j))* sign(1.0_pReal,tau_slip(j)) + !Total shear rate + + gdot_slip(j) = gdot_slip_edge(j) + gdot_slip_screw(j) + + plasticState(ph)%state( 7*ns+2*nt+j, of)= edge_velocity(j) + plasticState(ph)%state( 8*ns+2*nt+j, of)= screw_velocity(j) + plasticState(ph)%state( 9*ns+2*nt+j, of)= tau_slip(j) + plasticState(ph)%state(10*ns+2*nt+j, of)= gdot_slip_edge(j) + plasticState(ph)%state(11*ns+2*nt+j, of)= gdot_slip_screw(j) + plasticState(ph)%state(12*ns+2*nt+j, of)= StressRatio_edge_p + plasticState(ph)%state(13*ns+2*nt+j, of)= StressRatio_screw_p + + !* Derivatives of shear rates + dgdot_dtauslip(j) = plastic_titanmod_burgersPerSlipSys(j,instance)*(( & + ( & + ( & + ( & + (edge_velocity(j)*plasticState(ph)%state(j, of))) * & + BoltzmannRatioedge*& + plastic_titanmod_pe_PerSlipSys(j,instance)* & + plastic_titanmod_qe_PerSlipSys(j,instance) & + )/ & + bottomstress_edge & + )*& + StressRatio_edge_pminus1*(minusStressRatio_edge_p)** & + (plastic_titanmod_qe_PerSlipSys(j,instance)-1.0_pReal) & + ) + & + ( & + ( & + ( & + (plasticState(ph)%state(ns+j, of) * screw_velocity(j)) * & + BoltzmannRatioscrew* & + plastic_titanmod_ps_PerSlipSys(j,instance)* & + plastic_titanmod_qs_PerSlipSys(j,instance) & + )/ & + bottomstress_screw & + )*& + StressRatio_screw_pminus1*(minusStressRatio_screw_p)**(plastic_titanmod_qs_PerSlipSys(j,instance)-1.0_pReal) & + ) & + ) !* sign(1.0_pReal,tau_slip(j)) + + + +!************************************************* +!sumf=0.0_pReal + !* Plastic velocity gradient for dislocation glide + Lp = Lp + (1.0_pReal - sumf)*gdot_slip(j)*lattice_Sslip(1:3,1:3,1,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtauslip(j)*& + lattice_Sslip(k,l,1,index_myFamily+i,ph)*& + lattice_Sslip(m,n,1,index_myFamily+i,ph) + enddo + enddo slipFamiliesLoop + +!* Mechanical twinning part + gdot_twin = 0.0_pReal + dgdot_dtautwin = 0.0_pReal + j = 0_pInt + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + !* Calculation of Lp + !* Resolved shear stress on twin system + tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + +!************************************************************************************** + !* Stress ratios +! StressRatio_r = (plasticState(ph)%state6*ns+3*nt+j, of)/tau_twin(j))**plastic_titanmod_r(instance) + + !* Shear rates and their derivatives due to twin +! if ( tau_twin(j) > 0.0_pReal ) !then +! gdot_twin(j) = 0.0_pReal!& +! (plastic_titanmod_MaxTwinFraction(instance)-sumf)*lattice_shearTwin(index_myFamily+i,ph)*& +! plasticState(ph)%state(6*ns+4*nt+j, of)*plastic_titanmod_Ndot0PerTwinSys(f,instance)*exp(-StressRatio_r) +! dgdot_dtautwin(j) = ((gdot_twin(j)*plastic_titanmod_r(instance))/tau_twin(j))*StressRatio_r +! endif +!************************************************************************************** + + !* Stress ratio for edge + twinStressRatio_p = ((abs(tau_twin(j)))/ & + ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & + )**plastic_titanmod_twinp_PerTwinSys(j,instance) + + if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then + twinminusStressRatio_p=1.0_pReal-twinStressRatio_p + else + twinminusStressRatio_p=0.001_pReal + endif + + twinStressRatio_pminus1 = ((abs(tau_twin(j)))/ & + ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & + )**(plastic_titanmod_twinp_PerTwinSys(j,instance)-1.0_pReal) + + !* Boltzmann ratio + BoltzmannRatiotwin = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) + + !* Initial twin shear rates + TwinDotGamma0 = & + plastic_titanmod_twingamma0_PerTwinSys(j,instance) + + !* Shear rates due to twin + gdot_twin(j) =sign(1.0_pReal,tau_twin(j))*plastic_titanmod_twingamma0_PerTwinSys(j,instance)* & + exp(-BoltzmannRatiotwin*(twinminusStressRatio_p)**plastic_titanmod_twinq_PerTwinSys(j,instance)) + + + !* Derivatives of shear rates in twin + dgdot_dtautwin(j) = ( & + ( & + ( & + (abs(gdot_twin(j))) * & + BoltzmannRatiotwin*& + plastic_titanmod_twinp_PerTwinSys(j,instance)* & + plastic_titanmod_twinq_PerTwinSys(j,instance) & + )/ & + plastic_titanmod_twintau0_PerTwinSys(j,instance) & + )*& + twinStressRatio_pminus1*(twinminusStressRatio_p)** & + (plastic_titanmod_twinq_PerTwinSys(j,instance)-1.0_pReal) & + ) !* sign(1.0_pReal,tau_slip(j)) + + !* Plastic velocity gradient for mechanical twinning +! Lp = Lp + sumf*gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) + Lp = Lp + gdot_twin(j)*lattice_Stwin(:,:,index_myFamily+i,ph) + + !* Calculation of the tangent of Lp + forall (k=1_pInt:3_pInt,l=1_pInt:3_pInt,m=1_pInt:3_pInt,n=1_pInt:3_pInt) & + dLp_dTstar3333(k,l,m,n) = & + dLp_dTstar3333(k,l,m,n) + dgdot_dtautwin(j)*& + lattice_Stwin(k,l,index_myFamily+i,ph)*& + lattice_Stwin(m,n,index_myFamily+i,ph) + enddo + enddo twinFamiliesLoop + +dLp_dTstar99 = math_Plain3333to99(dLp_dTstar3333) +! tempState=state + + +end subroutine plastic_titanmod_LpAndItsTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +subroutine plastic_titanmod_dotState(Tstar_v,temperature,ipc,ip,el) + use lattice, only: & + lattice_Stwin_v, & + lattice_maxNslipFamily, & + lattice_maxNtwinFamily, & + lattice_NslipSystem, & + lattice_NtwinSystem + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + +implicit none + real(pReal), dimension(6), intent(in):: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor in Mandel notation + real(pReal), intent(in) :: & + temperature !< temperature at integration point + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + + integer(pInt) :: & + index_myFamily, instance, & + ns,nt,& + f,i,j, & + ph, & + of + real(pReal) :: & + sumf,BoltzmannRatio, & + twinStressRatio_p,twinminusStressRatio_p + real(pReal), dimension(plastic_titanmod_totalNslip(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + DotRhoEdgeGeneration, & + DotRhoEdgeAnnihilation, & + DotRhoScrewGeneration, & + DotRhoScrewAnnihilation + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + gdot_twin, & + tau_twin, & + volumefraction_PerTwinSys + +!-------------------------------------------------------------------------------------------------- +! shortened notation + + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + + enddo + + sumf = sum(abs(volumefraction_PerTwinSys(1_pInt:nt))) ! safe for nt == 0 + + plasticState(ph)%dotState(:,of) = 0.0_pReal + j = 0_pInt + slipFamiliesLoop: do f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Nslip(f,instance) ! process each (active) slip system in family + j = j+1_pInt + + DotRhoEdgeGeneration(j) = & ! multiplication of edge dislocations + plasticState(ph)%state(ns+j, of)*plasticState(ph)%state(8*ns+2*nt+j, of)/plasticState(ph)%state(4*ns+nt+j, of) + DotRhoScrewGeneration(j) = & ! multiplication of screw dislocations + plasticState(ph)%state(j, of)*plasticState(ph)%state(7*ns+2*nt+j, of)/plasticState(ph)%state(3*ns+nt+j, of) + DotRhoEdgeAnnihilation(j) = -((plasticState(ph)%state(j, of))**2)* & ! annihilation of edge dislocations + plastic_titanmod_capre_PerSlipSys(j,instance)*plasticState(ph)%state(7*ns+2*nt+j, of)*0.5_pReal + DotRhoScrewAnnihilation(j) = -((plasticState(ph)%state(ns+j, of))**2)* & ! annihilation of screw dislocations + plastic_titanmod_caprs_PerSlipSys(j,instance)*plasticState(ph)%state(8*ns+2*nt+j, of)*0.5_pReal + plasticState(ph)%dotState(j, of) = & ! edge dislocation density rate of change + DotRhoEdgeGeneration(j)+DotRhoEdgeAnnihilation(j) + + plasticState(ph)%dotState(ns+j, of) = & ! screw dislocation density rate of change + DotRhoScrewGeneration(j)+DotRhoScrewAnnihilation(j) + + plasticState(ph)%dotState(2*ns+j, of) = & ! sum of shear due to edge and screw + plasticState(ph)%state(10*ns+2*nt+j, of)+plasticState(ph)%state(11*ns+2*nt+j, of) + enddo + enddo slipFamiliesLoop + +!* Twin fraction evolution + j = 0_pInt + twinFamiliesLoop: do f = 1_pInt,lattice_maxNtwinFamily + index_myFamily = sum(lattice_NtwinSystem(1:f-1_pInt,ph)) ! at which index starts my family + do i = 1_pInt,plastic_titanmod_Ntwin(f,instance) ! process each (active) twin system in family + j = j+1_pInt + + !* Resolved shear stress on twin system + tau_twin(j) = dot_product(Tstar_v,lattice_Stwin_v(:,index_myFamily+i,ph)) + + !* Stress ratio for edge + twinStressRatio_p = ((abs(tau_twin(j)))/ & + ( plastic_titanmod_twintau0_PerTwinSys(j,instance)+plasticState(ph)%state(7*ns+nt+j, of)) & + )**(plastic_titanmod_twinp_PerTwinSys(j,instance)) + + + if((1.0_pReal-twinStressRatio_p)>0.001_pReal) then + twinminusStressRatio_p=1.0_pReal-twinStressRatio_p + else + twinminusStressRatio_p=0.001_pReal + endif + + BoltzmannRatio = plastic_titanmod_twinf0_PerTwinSys(j,instance)/(kB*Temperature) + + gdot_twin(j) =plastic_titanmod_twingamma0_PerTwinSys(j,instance)*exp(-BoltzmannRatio* & + (twinminusStressRatio_p)** & + plastic_titanmod_twinq_PerTwinSys(j,instance))*sign(1.0_pReal,tau_twin(j)) + + plasticState(ph)%dotState(3*ns+j, of)=gdot_twin(j) + + enddo + enddo twinFamiliesLoop + +end subroutine plastic_titanmod_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of constitutive results +!-------------------------------------------------------------------------------------------------- +function plastic_titanmod_postResults(ipc,ip,el) + use material, only: & + material_phase, & + phase_plasticityInstance, & + plasticState, & + phaseAt, phasememberAt + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(plastic_titanmod_sizePostResults(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + plastic_titanmod_postResults + + integer(pInt) :: & + instance, & + ns,nt,& + o,i,c, & + ph, & + of + real(pReal) :: sumf + + real(pReal), dimension(plastic_titanmod_totalNtwin(phase_plasticityInstance(material_phase(ipc,ip,el)))) :: & + volumefraction_PerTwinSys + +!-------------------------------------------------------------------------------------------------- +! shortened notation + of = phasememberAt(ipc,ip,el) + ph = phaseAt(ipc,ip,el) + instance = phase_plasticityInstance(ph) + ns = plastic_titanmod_totalNslip(instance) + nt = plastic_titanmod_totalNtwin(instance) + + do i=1_pInt,nt + volumefraction_PerTwinSys(i)=plasticState(ph)%state(3_pInt*ns+i, of)/ & + plastic_titanmod_twinshearconstant_PerTwinSys(i,instance) + enddo + + sumf = sum(abs(volumefraction_PerTwinSys(1:nt))) ! safe for nt == 0 + + +!-------------------------------------------------------------------------------------------------- +! required output + c = 0_pInt + plastic_titanmod_postResults = 0.0_pReal + + do o = 1_pInt,plastic_titanmod_Noutput(instance) + select case(plastic_titanmod_outputID(o,instance)) + case (rhoedge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(1_pInt:ns, of) + c = c + ns + case (rhoscrew_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(ns+1_pInt:2_pInt*ns, of) + c = c + ns + case (segment_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(3_pInt*ns+nt+1_pInt:4_pInt*ns+nt, of) + c = c + ns + case (segment_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(4_pInt*ns+nt+1_pInt:5_pInt*ns+nt, of) + c = c + ns + case (resistance_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(5_pInt*ns+nt+1_pInt:6_pInt*ns+nt, of) + c = c + ns + case (resistance_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(6_pInt*ns+nt+1_pInt:7_pInt*ns+nt, of) + c = c + ns + case (velocity_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(7*ns+2*nt+1:8*ns+2*nt, of) + c = c + ns + case (velocity_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = plasticState(ph)%state(8*ns+2*nt+1:9*ns+2*nt, of) + c = c + ns + case (tau_slip_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(9*ns+2*nt+1:10*ns+2*nt, of)) + c = c + ns + case (gdot_slip_edge_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) + c = c + ns + case (gdot_slip_screw_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) + c = c + ns + case (gdot_slip_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(10*ns+2*nt+1:11*ns+2*nt, of)) + & + abs(plasticState(ph)%state(11*ns+2*nt+1:12*ns+2*nt, of)) + c = c + ns + case (stressratio_edge_p_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(12*ns+2*nt+1:13*ns+2*nt, of)) + c = c + ns + case (stressratio_screw_p_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(13*ns+2*nt+1:14*ns+2*nt, of)) + c = c + ns + case (shear_system_ID) + plastic_titanmod_postResults(c+1_pInt:c+ns) = abs(plasticState(ph)%state(2*ns+1:3*ns, of)) + c = c + ns + case (shear_basal_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:2*ns+3, of))) + c = c + 1_pInt + case (shear_prism_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+4:2*ns+6, of))) + c = c + 1_pInt + case (shear_pyra_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+7:2*ns+12, of))) + c = c + 1_pInt + case (shear_pyrca_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+13:2*ns+24, of))) + c = c + 1_pInt + + case (rhoedge_basal_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(1:3, of)) + c = c + 1_pInt + case (rhoedge_prism_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(4:6, of)) + c = c + 1_pInt + case (rhoedge_pyra_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(7:12,of)) + c = c + 1_pInt + case (rhoedge_pyrca_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(13:24, of)) + c = c + 1_pInt + + case (rhoscrew_basal_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+1:ns+3, of)) + c = c + 1_pInt + case (rhoscrew_prism_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+4:ns+6, of)) + c = c + 1_pInt + case (rhoscrew_pyra_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+7:ns+12, of)) + c = c + 1_pInt + case (rhoscrew_pyrca_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(plasticState(ph)%state(ns+13:ns+24, of)) + c = c + 1_pInt + case (shear_total_ID) + plastic_titanmod_postResults(c+1_pInt:c+1_pInt) = sum(abs(plasticState(ph)%state(2*ns+1:3*ns, of))) + c = c + 1_pInt + case (twin_fraction_ID) + plastic_titanmod_postResults(c+1_pInt:c+nt) = abs(volumefraction_PerTwinSys(1:nt)) + c = c + nt + end select + enddo + +end function plastic_titanmod_postResults + +end module plastic_titanmod diff --git a/src/porosity_none.f90 b/src/porosity_none.f90 new file mode 100644 index 000000000..69f10a5c6 --- /dev/null +++ b/src/porosity_none.f90 @@ -0,0 +1,61 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for constant porosity +!-------------------------------------------------------------------------------------------------- +module porosity_none + + implicit none + private + + public :: & + porosity_none_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine porosity_none_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- porosity_'//POROSITY_none_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (porosity_type(homog) == POROSITY_none_ID) then + NofMyHomog = count(material_homog == homog) + porosityState(homog)%sizeState = 0_pInt + porosityState(homog)%sizePostResults = 0_pInt + allocate(porosityState(homog)%state0 (0_pInt,NofMyHomog), source=0.0_pReal) + allocate(porosityState(homog)%subState0(0_pInt,NofMyHomog), source=0.0_pReal) + allocate(porosityState(homog)%state (0_pInt,NofMyHomog), source=0.0_pReal) + + deallocate(porosity(homog)%p) + allocate (porosity(homog)%p(1), source=porosity_initialPhi(homog)) + + endif myhomog + enddo initializeInstances + + +end subroutine porosity_none_init + +end module porosity_none diff --git a/src/porosity_phasefield.f90 b/src/porosity_phasefield.f90 new file mode 100644 index 000000000..dc8b82b76 --- /dev/null +++ b/src/porosity_phasefield.f90 @@ -0,0 +1,450 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for phase field modelling of pore nucleation and growth +!> @details phase field model for pore nucleation and growth based on vacancy clustering +!-------------------------------------------------------------------------------------------------- +module porosity_phasefield + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + porosity_phasefield_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + porosity_phasefield_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + porosity_phasefield_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + porosity_phasefield_Noutput !< number of outputs per instance of this porosity + + enum, bind(c) + enumerator :: undefined_ID, & + porosity_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + porosity_phasefield_outputID !< ID of each post result output + + + public :: & + porosity_phasefield_init, & + porosity_phasefield_getFormationEnergy, & + porosity_phasefield_getSurfaceEnergy, & + porosity_phasefield_getSourceAndItsTangent, & + porosity_phasefield_getDiffusion33, & + porosity_phasefield_getMobility, & + porosity_phasefield_putPorosity, & + porosity_phasefield_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine porosity_phasefield_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + porosity_type, & + porosity_typeInstance, & + homogenization_Noutput, & + POROSITY_phasefield_label, & + POROSITY_phasefield_ID, & + material_homog, & + mappingHomogenization, & + porosityState, & + porosityMapping, & + porosity, & + porosity_initialPhi, & + material_partHomogenization, & + material_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- porosity_'//POROSITY_phasefield_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(porosity_type == POROSITY_phasefield_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(porosity_phasefield_sizePostResults(maxNinstance), source=0_pInt) + allocate(porosity_phasefield_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(porosity_phasefield_output (maxval(homogenization_Noutput),maxNinstance)) + porosity_phasefield_output = '' + allocate(porosity_phasefield_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(porosity_phasefield_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (porosity_type(section) == POROSITY_phasefield_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = porosity_typeInstance(section) ! which instance of my porosity is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('porosity') + porosity_phasefield_Noutput(instance) = porosity_phasefield_Noutput(instance) + 1_pInt + porosity_phasefield_outputID(porosity_phasefield_Noutput(instance),instance) = porosity_ID + porosity_phasefield_output(porosity_phasefield_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingHomog + + initializeInstances: do section = 1_pInt, size(porosity_type) + if (porosity_type(section) == POROSITY_phasefield_ID) then + NofMyHomog=count(material_homog==section) + instance = porosity_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,porosity_phasefield_Noutput(instance) + select case(porosity_phasefield_outputID(o,instance)) + case(porosity_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + porosity_phasefield_sizePostResult(o,instance) = mySize + porosity_phasefield_sizePostResults(instance) = porosity_phasefield_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 0_pInt + porosityState(section)%sizeState = sizeState + porosityState(section)%sizePostResults = porosity_phasefield_sizePostResults(instance) + allocate(porosityState(section)%state0 (sizeState,NofMyHomog)) + allocate(porosityState(section)%subState0(sizeState,NofMyHomog)) + allocate(porosityState(section)%state (sizeState,NofMyHomog)) + + nullify(porosityMapping(section)%p) + porosityMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(porosity(section)%p) + allocate(porosity(section)%p(NofMyHomog), source=porosity_initialPhi(section)) + + endif + + enddo initializeInstances +end subroutine porosity_phasefield_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized vacancy formation energy +!-------------------------------------------------------------------------------------------------- +function porosity_phasefield_getFormationEnergy(ip,el) + use lattice, only: & + lattice_vacancyFormationEnergy, & + lattice_vacancyVol + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + porosity_phasefield_getFormationEnergy + integer(pInt) :: & + grain + + porosity_phasefield_getFormationEnergy = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + porosity_phasefield_getFormationEnergy = porosity_phasefield_getFormationEnergy + & + lattice_vacancyFormationEnergy(material_phase(grain,ip,el))/ & + lattice_vacancyVol(material_phase(grain,ip,el)) + enddo + + porosity_phasefield_getFormationEnergy = & + porosity_phasefield_getFormationEnergy/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function porosity_phasefield_getFormationEnergy + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized pore surface energy (normalized by characteristic length) +!-------------------------------------------------------------------------------------------------- +function porosity_phasefield_getSurfaceEnergy(ip,el) + use lattice, only: & + lattice_vacancySurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + porosity_phasefield_getSurfaceEnergy + integer(pInt) :: & + grain + + porosity_phasefield_getSurfaceEnergy = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + porosity_phasefield_getSurfaceEnergy = porosity_phasefield_getSurfaceEnergy + & + lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) + enddo + + porosity_phasefield_getSurfaceEnergy = & + porosity_phasefield_getSurfaceEnergy/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function porosity_phasefield_getSurfaceEnergy + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates homogenized local driving force for pore nucleation and growth +!-------------------------------------------------------------------------------------------------- +subroutine porosity_phasefield_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) + use math, only : & + math_mul33x33, & + math_mul66x6, & + math_Mandel33to6, & + math_transpose33, & + math_I3 + use material, only: & + homogenization_Ngrains, & + material_homog, & + material_phase, & + phase_NstiffnessDegradations, & + phase_stiffnessDegradation, & + vacancyConc, & + vacancyfluxMapping, & + damage, & + damageMapping, & + STIFFNESS_DEGRADATION_damage_ID + use crystallite, only: & + crystallite_Fe + use constitutive, only: & + constitutive_homogenizedC + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + phi + integer(pInt) :: & + phase, & + grain, & + homog, & + mech + real(pReal) :: & + phiDot, dPhiDot_dPhi, Cv, W_e, strain(6), C(6,6) + + homog = material_homog(ip,el) + Cv = vacancyConc(homog)%p(vacancyfluxMapping(homog)%p(ip,el)) + + W_e = 0.0_pReal + do grain = 1, homogenization_Ngrains(homog) + phase = material_phase(grain,ip,el) + strain = math_Mandel33to6(math_mul33x33(math_transpose33(crystallite_Fe(1:3,1:3,grain,ip,el)), & + crystallite_Fe(1:3,1:3,grain,ip,el)) - math_I3)/2.0_pReal + C = constitutive_homogenizedC(grain,ip,el) + do mech = 1_pInt, phase_NstiffnessDegradations(phase) + select case(phase_stiffnessDegradation(mech,phase)) + case (STIFFNESS_DEGRADATION_damage_ID) + C = damage(homog)%p(damageMapping(homog)%p(ip,el))* & + damage(homog)%p(damageMapping(homog)%p(ip,el))* & + C + + end select + enddo + W_e = W_e + sum(abs(strain*math_mul66x6(C,strain))) + enddo + W_e = W_e/homogenization_Ngrains(homog) + + phiDot = 2.0_pReal*(1.0_pReal - phi)*(1.0_pReal - Cv)*(1.0_pReal - Cv) - & + 2.0_pReal*phi*(W_e + Cv*porosity_phasefield_getFormationEnergy(ip,el))/ & + porosity_phasefield_getSurfaceEnergy (ip,el) + dPhiDot_dPhi = - 2.0_pReal*(1.0_pReal - Cv)*(1.0_pReal - Cv) & + - 2.0_pReal*(W_e + Cv*porosity_phasefield_getFormationEnergy(ip,el))/ & + porosity_phasefield_getSurfaceEnergy (ip,el) + +end subroutine porosity_phasefield_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized nonlocal diffusion tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function porosity_phasefield_getDiffusion33(ip,el) + use lattice, only: & + lattice_PorosityDiffusion33 + use material, only: & + homogenization_Ngrains, & + material_phase, & + mappingHomogenization + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + porosity_phasefield_getDiffusion33 + integer(pInt) :: & + homog, & + grain + + homog = mappingHomogenization(2,ip,el) + porosity_phasefield_getDiffusion33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(homog) + porosity_phasefield_getDiffusion33 = porosity_phasefield_getDiffusion33 + & + crystallite_push33ToRef(grain,ip,el,lattice_PorosityDiffusion33(1:3,1:3,material_phase(grain,ip,el))) + enddo + + porosity_phasefield_getDiffusion33 = & + porosity_phasefield_getDiffusion33/ & + homogenization_Ngrains(homog) + +end function porosity_phasefield_getDiffusion33 + +!-------------------------------------------------------------------------------------------------- +!> @brief Returns homogenized phase field mobility +!-------------------------------------------------------------------------------------------------- +real(pReal) function porosity_phasefield_getMobility(ip,el) + use mesh, only: & + mesh_element + use lattice, only: & + lattice_PorosityMobility + use material, only: & + material_phase, & + homogenization_Ngrains + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + integer(pInt) :: & + ipc + + porosity_phasefield_getMobility = 0.0_pReal + + do ipc = 1, homogenization_Ngrains(mesh_element(3,el)) + porosity_phasefield_getMobility = porosity_phasefield_getMobility + lattice_PorosityMobility(material_phase(ipc,ip,el)) + enddo + + porosity_phasefield_getMobility = porosity_phasefield_getMobility/homogenization_Ngrains(mesh_element(3,el)) + +end function porosity_phasefield_getMobility + +!-------------------------------------------------------------------------------------------------- +!> @brief updates porosity with solution from phasefield PDE +!-------------------------------------------------------------------------------------------------- +subroutine porosity_phasefield_putPorosity(phi,ip,el) + use material, only: & + material_homog, & + porosityMapping, & + porosity + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + phi + integer(pInt) :: & + homog, & + offset + + homog = material_homog(ip,el) + offset = porosityMapping(homog)%p(ip,el) + porosity(homog)%p(offset) = phi + +end subroutine porosity_phasefield_putPorosity + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of porosity results +!-------------------------------------------------------------------------------------------------- +function porosity_phasefield_postResults(ip,el) + use material, only: & + mappingHomogenization, & + porosity_typeInstance, & + porosity + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(porosity_phasefield_sizePostResults(porosity_typeInstance(mappingHomogenization(2,ip,el)))) :: & + porosity_phasefield_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + instance = porosity_typeInstance(homog) + + c = 0_pInt + porosity_phasefield_postResults = 0.0_pReal + + do o = 1_pInt,porosity_phasefield_Noutput(instance) + select case(porosity_phasefield_outputID(o,instance)) + + case (porosity_ID) + porosity_phasefield_postResults(c+1_pInt) = porosity(homog)%p(offset) + c = c + 1 + end select + enddo +end function porosity_phasefield_postResults + +end module porosity_phasefield diff --git a/src/prec.f90 b/src/prec.f90 new file mode 100644 index 000000000..e39a32cfa --- /dev/null +++ b/src/prec.f90 @@ -0,0 +1,192 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @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 Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH +!> @brief setting precision for real and int type depending on makros "FLOAT" and "INT" +!> @details setting precision for real and int type and for DAMASK_NaN. Definition is made +!! depending on makros "FLOAT" and "INT" defined during compilation +!! for details on NaN see https://software.intel.com/en-us/forums/topic/294680 +!-------------------------------------------------------------------------------------------------- +module prec + +#if !(defined(__GFORTRAN__) && __GNUC__ < 5) + use, intrinsic :: & ! unfortunately not avialable in gfortran <= 5 + IEEE_arithmetic +#endif + + implicit none + private +#if (FLOAT==4) +#if defined(Spectral) || defined(FEM) + SPECTRAL SOLVER AND OWN FEM DO NOT SUPPORT SINGLE PRECISION, STOPPING COMPILATION +#endif + integer, parameter, public :: pReal = 4 !< floating point single precition (was selected_real_kind(6,37), number with 6 significant digits, up to 1e+-37) +#ifdef __INTEL_COMPILER + real(pReal), parameter, public :: DAMASK_NaN = Z'7F800001' !< quiet NaN for single precision (from http://www.hpc.unimelb.edu.au/doc/f90lrm/dfum_035.html, copy can be found in documentation/Code/Fortran) +#endif +#ifdef __GFORTRAN__ + real(pReal), parameter, public :: DAMASK_NaN = real(Z'7F800001', pReal) !< quiet NaN for single precision (from http://www.hpc.unimelb.edu.au/doc/f90lrm/dfum_035.html, copy can be found in documentation/Code/Fortran) +#endif +#elif (FLOAT==8) + integer, parameter, public :: pReal = 8 !< floating point double precision (was selected_real_kind(15,300), number with 15 significant digits, up to 1e+-300) +#ifdef __INTEL_COMPILER + real(pReal), parameter, public :: DAMASK_NaN = Z'7FF8000000000000' !< quiet NaN for double precision (from http://www.hpc.unimelb.edu.au/doc/f90lrm/dfum_035.html, copy can be found in documentation/Code/Fortran) +#endif +#ifdef __GFORTRAN__ + real(pReal), parameter, public :: DAMASK_NaN = real(Z'7FF8000000000000',pReal) !< quiet NaN for double precision (from http://www.hpc.unimelb.edu.au/doc/f90lrm/dfum_035.html, copy can be found in documentation/Code/Fortran) +#endif +#else + NO SUITABLE PRECISION FOR REAL SELECTED, STOPPING COMPILATION +#endif + +#if (INT==4) + integer, parameter, public :: pInt = 4 !< integer representation 32 bit (was selected_int_kind(9), number with at least up to +- 1e9) +#elif (INT==8) + integer, parameter, public :: pInt = 8 !< integer representation 64 bit (was selected_int_kind(12), number with at least up to +- 1e12) +#else + NO SUITABLE PRECISION FOR INTEGER SELECTED, STOPPING COMPILATION +#endif + + integer, parameter, public :: pLongInt = 8 !< integer representation 64 bit (was selected_int_kind(12), number with at least up to +- 1e12) + real(pReal), parameter, public :: tol_math_check = 1.0e-8_pReal !< tolerance for internal math self-checks (rotation) + + integer(pInt), allocatable, dimension(:) :: realloc_lhs_test + + type, public :: p_vec !< variable length datatype used for storage of state + real(pReal), dimension(:), pointer :: p + end type p_vec + + type, public :: p_intvec + integer(pInt), dimension(:), pointer :: p + end type p_intvec + +!http://stackoverflow.com/questions/3948210/can-i-have-a-pointer-to-an-item-in-an-allocatable-array + type, public :: tState + integer(pInt) :: & + sizeState = 0_pInt , & !< size of state + sizeDotState = 0_pInt, & !< size of dot state, i.e. parts of the state that are integrated + sizeDeltaState = 0_pInt, & !< size of delta state, i.e. parts of the state that have discontinuous rates + sizePostResults = 0_pInt !< size of output data + real(pReal), pointer, dimension(:), contiguous :: & + atolState + real(pReal), pointer, dimension(:,:), contiguous :: & ! a pointer is needed here because we might point to state/doState. However, they will never point to something, but are rather allocated and, hence, contiguous + state, & !< state + dotState, & !< state rate + state0 + real(pReal), allocatable, dimension(:,:) :: & + partionedState0, & + subState0, & + state_backup, & + deltaState, & + previousDotState, & !< state rate of previous xxxx + previousDotState2, & !< state rate two xxxx ago + dotState_backup, & !< backup of state rate + RK4dotState + real(pReal), allocatable, dimension(:,:,:) :: & + RKCK45dotState + end type + + type, extends(tState), public :: tPlasticState + integer(pInt) :: & + nSlip = 0_pInt , & + nTwin = 0_pInt, & + nTrans = 0_pInt + logical :: & + nonlocal = .false. !< absolute tolerance for state integration + real(pReal), pointer, dimension(:,:), contiguous :: & + slipRate, & !< slip rate + accumulatedSlip !< accumulated plastic slip + end type + + type, public :: tSourceState + type(tState), dimension(:), allocatable :: p !< tState for each active source mechanism in a phase + end type + + type, public :: tHomogMapping + integer(pInt), pointer, dimension(:,:) :: p + end type + + type, public :: tPhaseMapping + integer(pInt), pointer, dimension(:,:,:) :: p + end type + +#ifdef FEM + type, public :: tOutputData + integer(pInt) :: & + sizeIpCells = 0_pInt , & + sizeResults = 0_pInt + real(pReal), allocatable, dimension(:,:) :: & + output !< output data + end type +#endif + + public :: & + prec_init, & + prec_isNaN + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief reporting precision and checking if DAMASK_NaN is set correctly +!-------------------------------------------------------------------------------------------------- +subroutine prec_init + use, intrinsic :: & + iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + + implicit none + integer(pInt) :: worldrank = 0_pInt +#ifdef PETSc +#include + PetscErrorCode :: ierr +#endif + external :: & + quit, & + MPI_Comm_rank, & + MPI_Abort + +#ifdef PETSc + call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) +#endif + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- prec init -+>>>' +#include "compilation_info.f90" + write(6,'(a,i3)') ' Bytes for pReal: ',pReal + write(6,'(a,i3)') ' Bytes for pInt: ',pInt + write(6,'(a,i3)') ' Bytes for pLongInt: ',pLongInt + write(6,'(a,e10.3)') ' NaN: ', DAMASK_NaN + write(6,'(a,l3)') ' NaN != NaN: ',DAMASK_NaN /= DAMASK_NaN + write(6,'(a,l3,/)') ' NaN check passed ',prec_isNAN(DAMASK_NaN) + endif mainProcess + + if ((.not. prec_isNaN(DAMASK_NaN)) .or. (DAMASK_NaN == DAMASK_NaN)) call quit(9000) + realloc_lhs_test = [1_pInt,2_pInt] + if (realloc_lhs_test(2)/=2_pInt) call quit(9000) + + +end subroutine prec_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief figures out if a floating point number is NaN +! basically just a small wrapper, because gfortran < 4.9 does not have the IEEE module +!-------------------------------------------------------------------------------------------------- +logical elemental function prec_isNaN(a) + + implicit none + real(pReal), intent(in) :: a + +#if (defined(__GFORTRAN__) && __GNUC__ < 5) + intrinsic :: isNaN + prec_isNaN = isNaN(a) +#else + prec_isNaN = IEEE_is_NaN(a) +#endif +end function prec_isNaN + +end module prec diff --git a/src/quit__genmod.f90 b/src/quit__genmod.f90 new file mode 100644 index 000000000..ef0a49bc0 --- /dev/null +++ b/src/quit__genmod.f90 @@ -0,0 +1,8 @@ + !COMPILER-GENERATED INTERFACE MODULE: Thu Mar 3 12:28:23 2016 + MODULE QUIT__genmod + INTERFACE + SUBROUTINE QUIT(STOP_ID) + INTEGER(KIND=4), INTENT(IN) :: STOP_ID + END SUBROUTINE QUIT + END INTERFACE + END MODULE QUIT__genmod diff --git a/src/source_damage_anisoBrittle.f90 b/src/source_damage_anisoBrittle.f90 new file mode 100644 index 000000000..a751eefdc --- /dev/null +++ b/src/source_damage_anisoBrittle.f90 @@ -0,0 +1,425 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @brief material subroutine incorporating anisotropic brittle damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_anisoBrittle + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_anisoBrittle_sizePostResults, & !< cumulative size of post results + source_damage_anisoBrittle_offset, & !< which source is my current source mechanism? + source_damage_anisoBrittle_instance !< instance of source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_anisoBrittle_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_anisoBrittle_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_anisoBrittle_Noutput !< number of outputs per instance of this source + + integer(pInt), dimension(:), allocatable, private :: & + source_damage_anisoBrittle_totalNcleavage !< total number of cleavage systems + + integer(pInt), dimension(:,:), allocatable, private :: & + source_damage_anisoBrittle_Ncleavage !< number of cleavage systems per family + + real(pReal), dimension(:), allocatable, private :: & + source_damage_anisoBrittle_aTol, & + source_damage_anisoBrittle_sdot_0, & + source_damage_anisoBrittle_N + + real(pReal), dimension(:,:), allocatable, private :: & + source_damage_anisoBrittle_critDisp, & + source_damage_anisoBrittle_critLoad + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_anisoBrittle_outputID !< ID of each post result output + + + public :: & + source_damage_anisoBrittle_init, & + source_damage_anisoBrittle_dotState, & + source_damage_anisobrittle_getRateAndItsTangent, & + source_damage_anisoBrittle_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoBrittle_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_anisoBrittle_label, & + SOURCE_damage_anisoBrittle_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + use lattice, only: & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + integer(pInt) :: Nchunks_CleavageFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoBrittle_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_anisoBrittle_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_anisoBrittle_offset(material_Nphase), source=0_pInt) + allocate(source_damage_anisoBrittle_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_anisoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoBrittle_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_anisoBrittle_ID) & + source_damage_anisoBrittle_offset(phase) = source + enddo + enddo + + allocate(source_damage_anisoBrittle_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_output(maxval(phase_Noutput),maxNinstance)) + source_damage_anisoBrittle_output = '' + allocate(source_damage_anisoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_anisoBrittle_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_critDisp(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_critLoad(lattice_maxNcleavageFamily,maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_Ncleavage(lattice_maxNcleavageFamily,maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_totalNcleavage(maxNinstance), source=0_pInt) + allocate(source_damage_anisoBrittle_aTol(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_sdot_0(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoBrittle_N(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_anisoBrittle_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('anisobrittle_drivingforce') + source_damage_anisoBrittle_Noutput(instance) = source_damage_anisoBrittle_Noutput(instance) + 1_pInt + source_damage_anisoBrittle_outputID(source_damage_anisoBrittle_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_anisoBrittle_output(source_damage_anisoBrittle_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('anisobrittle_atol') + source_damage_anisoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisobrittle_sdot0') + source_damage_anisoBrittle_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisobrittle_ratesensitivity') + source_damage_anisoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('ncleavage') ! + Nchunks_CleavageFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_CleavageFamilies + source_damage_anisoBrittle_Ncleavage(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticaldisplacement') + do j = 1_pInt, Nchunks_CleavageFamilies + source_damage_anisoBrittle_critDisp(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisobrittle_criticalload') + do j = 1_pInt, Nchunks_CleavageFamilies + source_damage_anisoBrittle_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then + instance = source_damage_anisoBrittle_instance(phase) + source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance) = & + min(lattice_NcleavageSystem(1:lattice_maxNcleavageFamily,phase),& ! limit active cleavage systems per family to min of available and requested + source_damage_anisoBrittle_Ncleavage(1:lattice_maxNcleavageFamily,instance)) + source_damage_anisoBrittle_totalNcleavage(instance) = sum(source_damage_anisoBrittle_Ncleavage(:,instance)) ! how many cleavage systems altogether + if (source_damage_anisoBrittle_aTol(instance) < 0.0_pReal) & + source_damage_anisoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_anisoBrittle_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoBrittle_LABEL//')') + if (any(source_damage_anisoBrittle_critDisp(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_displacement ('//SOURCE_damage_anisoBrittle_LABEL//')') + if (any(source_damage_anisoBrittle_critLoad(1:Nchunks_CleavageFamilies,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='critical_load ('//SOURCE_damage_anisoBrittle_LABEL//')') + if (source_damage_anisoBrittle_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoBrittle_LABEL//')') + endif myPhase + enddo sanityChecks + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_anisoBrittle_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_anisoBrittle_instance(phase) + sourceOffset = source_damage_anisoBrittle_offset(phase) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) + select case(source_damage_anisoBrittle_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_anisoBrittle_sizePostResult(o,instance) = mySize + source_damage_anisoBrittle_sizePostResults(instance) = source_damage_anisoBrittle_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoBrittle_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_anisoBrittle_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_anisoBrittle_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoBrittle_dotState(Tstar_v, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState, & + material_homog, & + damage, & + damageMapping + use lattice, only: & + lattice_Scleavage_v, & + lattice_maxNcleavageFamily, & + lattice_NcleavageSystem + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) + integer(pInt) :: & + phase, & + constituent, & + instance, & + sourceOffset, & + damageOffset, & + homog, & + f, i, index_myFamily + real(pReal) :: & + traction_d, traction_t, traction_n, traction_crit + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoBrittle_instance(phase) + sourceOffset = source_damage_anisoBrittle_offset(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal + do f = 1_pInt,lattice_maxNcleavageFamily + index_myFamily = sum(lattice_NcleavageSystem(1:f-1_pInt,phase)) ! at which index starts my family + do i = 1_pInt,source_damage_anisoBrittle_Ncleavage(f,instance) ! process each (active) cleavage system in family + traction_d = dot_product(Tstar_v,lattice_Scleavage_v(1:6,1,index_myFamily+i,phase)) + traction_t = dot_product(Tstar_v,lattice_Scleavage_v(1:6,2,index_myFamily+i,phase)) + traction_n = dot_product(Tstar_v,lattice_Scleavage_v(1:6,3,index_myFamily+i,phase)) + + traction_crit = source_damage_anisoBrittle_critLoad(f,instance)* & + damage(homog)%p(damageOffset)*damage(homog)%p(damageOffset) + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & + source_damage_anisoBrittle_sdot_0(instance)* & + ((max(0.0_pReal, abs(traction_d) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & + (max(0.0_pReal, abs(traction_t) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance) + & + (max(0.0_pReal, abs(traction_n) - traction_crit)/traction_crit)**source_damage_anisoBrittle_N(instance))/ & + source_damage_anisoBrittle_critDisp(f,instance) + + enddo + enddo + +end subroutine source_damage_anisoBrittle_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_damage_anisoBrittle_offset(phase) + + localphiDot = 1.0_pReal - & + sourceState(phase)%p(sourceOffset)%state(1,constituent)*phi + + dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_anisobrittle_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_anisoBrittle_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_anisoBrittle_sizePostResults( & + source_damage_anisoBrittle_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_anisoBrittle_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoBrittle_instance(phase) + sourceOffset = source_damage_anisoBrittle_offset(phase) + + c = 0_pInt + source_damage_anisoBrittle_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_anisoBrittle_Noutput(instance) + select case(source_damage_anisoBrittle_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_anisoBrittle_postResults(c+1_pInt) = & + sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1_pInt + + end select + enddo +end function source_damage_anisoBrittle_postResults + +end module source_damage_anisoBrittle diff --git a/src/source_damage_anisoDuctile.f90 b/src/source_damage_anisoDuctile.f90 new file mode 100644 index 000000000..028fd479a --- /dev/null +++ b/src/source_damage_anisoDuctile.f90 @@ -0,0 +1,415 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incorporating anisotropic ductile damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_anisoDuctile + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_anisoDuctile_sizePostResults, & !< cumulative size of post results + source_damage_anisoDuctile_offset, & !< which source is my current damage mechanism? + source_damage_anisoDuctile_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_anisoDuctile_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_anisoDuctile_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_anisoDuctile_Noutput !< number of outputs per instance of this damage + + integer(pInt), dimension(:), allocatable, private :: & + source_damage_anisoDuctile_totalNslip !< total number of slip systems + + integer(pInt), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_Nslip !< number of slip systems per family + + real(pReal), dimension(:), allocatable, private :: & + source_damage_anisoDuctile_aTol + + real(pReal), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_critPlasticStrain + + real(pReal), dimension(:), allocatable, private :: & + source_damage_anisoDuctile_sdot_0, & + source_damage_anisoDuctile_N + + real(pReal), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_critLoad + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_anisoDuctile_outputID !< ID of each post result output + + + public :: & + source_damage_anisoDuctile_init, & + source_damage_anisoDuctile_dotState, & + source_damage_anisoDuctile_getRateAndItsTangent, & + source_damage_anisoDuctile_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoDuctile_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_anisoDuctile_label, & + SOURCE_damage_anisoDuctile_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + use lattice, only: & + lattice_maxNslipFamily, & + lattice_NslipSystem + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + integer(pInt) :: Nchunks_SlipFamilies = 0_pInt, j + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_anisoDuctile_LABEL//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_anisoDuctile_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_anisoDuctile_offset(material_Nphase), source=0_pInt) + allocate(source_damage_anisoDuctile_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_anisoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_anisoDuctile_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_anisoDuctile_ID) & + source_damage_anisoDuctile_offset(phase) = source + enddo + enddo + + allocate(source_damage_anisoDuctile_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_damage_anisoDuctile_output(maxval(phase_Noutput),maxNinstance)) + source_damage_anisoDuctile_output = '' + allocate(source_damage_anisoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_anisoDuctile_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_critLoad(lattice_maxNslipFamily,maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoDuctile_critPlasticStrain(lattice_maxNslipFamily,maxNinstance),source=0.0_pReal) + allocate(source_damage_anisoDuctile_Nslip(lattice_maxNslipFamily,maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_totalNslip(maxNinstance), source=0_pInt) + allocate(source_damage_anisoDuctile_N(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoDuctile_sdot_0(maxNinstance), source=0.0_pReal) + allocate(source_damage_anisoDuctile_aTol(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_anisoDuctile_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('anisoductile_drivingforce') + source_damage_anisoDuctile_Noutput(instance) = source_damage_anisoDuctile_Noutput(instance) + 1_pInt + source_damage_anisoDuctile_outputID(source_damage_anisoDuctile_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_anisoDuctile_output(source_damage_anisoDuctile_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('anisoductile_atol') + source_damage_anisoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('nslip') ! + Nchunks_SlipFamilies = chunkPos(1) - 1_pInt + do j = 1_pInt, Nchunks_SlipFamilies + source_damage_anisoDuctile_Nslip(j,instance) = IO_intValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_sdot0') + source_damage_anisoDuctile_sdot_0(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalplasticstrain') + do j = 1_pInt, Nchunks_SlipFamilies + source_damage_anisoDuctile_critPlasticStrain(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + case ('anisoductile_ratesensitivity') + source_damage_anisoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('anisoductile_criticalload') + do j = 1_pInt, Nchunks_SlipFamilies + source_damage_anisoDuctile_critLoad(j,instance) = IO_floatValue(line,chunkPos,1_pInt+j) + enddo + + end select + endif; endif + enddo parsingFile + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, size(phase_source) + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then + instance = source_damage_anisoDuctile_instance(phase) + source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance) = & + min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase),& ! limit active cleavage systems per family to min of available and requested + source_damage_anisoDuctile_Nslip(1:lattice_maxNslipFamily,instance)) + source_damage_anisoDuctile_totalNslip(instance) = sum(source_damage_anisoDuctile_Nslip(:,instance)) + if (source_damage_anisoDuctile_aTol(instance) < 0.0_pReal) & + source_damage_anisoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_anisoDuctile_sdot_0(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='sdot_0 ('//SOURCE_damage_anisoDuctile_LABEL//')') + if (any(source_damage_anisoDuctile_critPlasticStrain(:,instance) < 0.0_pReal)) & + call IO_error(211_pInt,el=instance,ext_msg='criticaPlasticStrain ('//SOURCE_damage_anisoDuctile_LABEL//')') + if (source_damage_anisoDuctile_N(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='rate_sensitivity ('//SOURCE_damage_anisoDuctile_LABEL//')') + endif myPhase + enddo sanityChecks + + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_anisoDuctile_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_anisoDuctile_instance(phase) + sourceOffset = source_damage_anisoDuctile_offset(phase) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) + select case(source_damage_anisoDuctile_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_anisoDuctile_sizePostResult(o,instance) = mySize + source_damage_anisoDuctile_sizePostResults(instance) = source_damage_anisoDuctile_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +!-------------------------------------------------------------------------------------------------- +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_anisoDuctile_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_anisoDuctile_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_anisoDuctile_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoDuctile_dotState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + sourceState, & + material_homog, & + damage, & + damageMapping + use lattice, only: & + lattice_maxNslipFamily + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, & + constituent, & + sourceOffset, & + homog, damageOffset, & + instance, & + index, f, i + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoDuctile_instance(phase) + sourceOffset = source_damage_anisoDuctile_offset(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + index = 1_pInt + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal + do f = 1_pInt,lattice_maxNslipFamily + do i = 1_pInt,source_damage_anisoDuctile_Nslip(f,instance) ! process each (active) slip system in family + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) + & + plasticState(phase)%slipRate(index,constituent)/ & + ((damage(homog)%p(damageOffset))**source_damage_anisoDuctile_N(instance))/ & + source_damage_anisoDuctile_critPlasticStrain(f,instance) + + index = index + 1_pInt + enddo + enddo + +end subroutine source_damage_anisoDuctile_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_anisoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_damage_anisoDuctile_offset(phase) + + localphiDot = 1.0_pReal - & + sourceState(phase)%p(sourceOffset)%state(1,constituent)* & + phi + + dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_anisoDuctile_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_anisoDuctile_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_anisoDuctile_sizePostResults( & + source_damage_anisoDuctile_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_anisoDuctile_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_anisoDuctile_instance(phase) + sourceOffset = source_damage_anisoDuctile_offset(phase) + + c = 0_pInt + source_damage_anisoDuctile_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_anisoDuctile_Noutput(instance) + select case(source_damage_anisoDuctile_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_anisoDuctile_postResults(c+1_pInt) = & + sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1_pInt + + end select + enddo +end function source_damage_anisoDuctile_postResults + +end module source_damage_anisoDuctile diff --git a/src/source_damage_isoBrittle.f90 b/src/source_damage_isoBrittle.f90 new file mode 100644 index 000000000..c063ae86f --- /dev/null +++ b/src/source_damage_isoBrittle.f90 @@ -0,0 +1,383 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Luv Sharma, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine incoprorating isotropic brittle damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_isoBrittle + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_isoBrittle_sizePostResults, & !< cumulative size of post results + source_damage_isoBrittle_offset, & !< which source is my current damage mechanism? + source_damage_isoBrittle_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_isoBrittle_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_isoBrittle_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_isoBrittle_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_damage_isoBrittle_aTol, & + source_damage_isoBrittle_N, & + source_damage_isoBrittle_critStrainEnergy + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_isoBrittle_outputID !< ID of each post result output + + + public :: & + source_damage_isoBrittle_init, & + source_damage_isoBrittle_deltaState, & + source_damage_isoBrittle_getRateAndItsTangent, & + source_damage_isoBrittle_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoBrittle_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_isoBrittle_label, & + SOURCE_damage_isoBrittle_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoBrittle_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_isoBrittle_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_isoBrittle_offset(material_Nphase), source=0_pInt) + allocate(source_damage_isoBrittle_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_isoBrittle_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoBrittle_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_isoBrittle_ID) & + source_damage_isoBrittle_offset(phase) = source + enddo + enddo + + allocate(source_damage_isoBrittle_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_isoBrittle_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_damage_isoBrittle_output(maxval(phase_Noutput),maxNinstance)) + source_damage_isoBrittle_output = '' + allocate(source_damage_isoBrittle_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_isoBrittle_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_isoBrittle_critStrainEnergy(maxNinstance), source=0.0_pReal) + allocate(source_damage_isoBrittle_N(maxNinstance), source=1.0_pReal) + allocate(source_damage_isoBrittle_aTol(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_isoBrittle_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('isobrittle_drivingforce') + source_damage_isoBrittle_Noutput(instance) = source_damage_isoBrittle_Noutput(instance) + 1_pInt + source_damage_isoBrittle_outputID(source_damage_isoBrittle_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_isoBrittle_output(source_damage_isoBrittle_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('isobrittle_criticalstrainenergy') + source_damage_isoBrittle_critStrainEnergy(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isobrittle_n') + source_damage_isoBrittle_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isobrittle_atol') + source_damage_isoBrittle_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then + instance = source_damage_isoBrittle_instance(phase) + if (source_damage_isoBrittle_aTol(instance) < 0.0_pReal) & + source_damage_isoBrittle_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_isoBrittle_critStrainEnergy(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='criticalStrainEnergy ('//SOURCE_damage_isoBrittle_LABEL//')') + endif myPhase + enddo sanityChecks + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_isoBrittle_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_isoBrittle_instance(phase) + sourceOffset = source_damage_isoBrittle_offset(phase) +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) + select case(source_damage_isoBrittle_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_isoBrittle_sizePostResult(o,instance) = mySize + source_damage_isoBrittle_sizePostResults(instance) = source_damage_isoBrittle_sizePostResults(instance) + mySize + endif + enddo outputsLoop +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 1_pInt + sizeState = 1_pInt + + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoBrittle_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_isoBrittle_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_isoBrittle_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoBrittle_deltaState(C, Fe, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState, & + material_homog, & + phase_NstiffnessDegradations, & + phase_stiffnessDegradation, & + porosity, & + porosityMapping, & + STIFFNESS_DEGRADATION_porosity_ID + use math, only : & + math_mul33x33, & + math_mul66x6, & + math_Mandel33to6, & + math_transpose33, & + math_I3 + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(3,3) :: & + Fe + real(pReal), intent(in), dimension(6,6) :: & + C + integer(pInt) :: & + phase, constituent, instance, sourceOffset, mech + real(pReal) :: & + strain(6), & + stiffness(6,6), & + strainenergy + + phase = phaseAt(ipc,ip,el) !< phase ID at ipc,ip,el + constituent = phasememberAt(ipc,ip,el) !< state array offset for phase ID at ipc,ip,el + ! ToDo: capability for multiple instances of SAME source within given phase. Needs Ninstance loop from here on! + instance = source_damage_isoBrittle_instance(phase) !< instance of damage_isoBrittle source + sourceOffset = source_damage_isoBrittle_offset(phase) + + stiffness = C + do mech = 1_pInt, phase_NstiffnessDegradations(phase) + select case(phase_stiffnessDegradation(mech,phase)) + case (STIFFNESS_DEGRADATION_porosity_ID) + stiffness = porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & + porosity(material_homog(ip,el))%p(porosityMapping(material_homog(ip,el))%p(ip,el))* & + stiffness + end select + enddo + strain = 0.5_pReal*math_Mandel33to6(math_mul33x33(math_transpose33(Fe),Fe)-math_I3) + + strainenergy = 2.0_pReal*sum(strain*math_mul66x6(stiffness,strain))/ & + source_damage_isoBrittle_critStrainEnergy(instance) + if (strainenergy > sourceState(phase)%p(sourceOffset)%subState0(1,constituent)) then + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + strainenergy - sourceState(phase)%p(sourceOffset)%state(1,constituent) + else + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + sourceState(phase)%p(sourceOffset)%subState0(1,constituent) - & + sourceState(phase)%p(sourceOffset)%state(1,constituent) + endif + +end subroutine source_damage_isoBrittle_deltaState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoBrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, instance, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoBrittle_instance(phase) + sourceOffset = source_damage_isoBrittle_offset(phase) + + localphiDot = (1.0_pReal - phi)**(source_damage_isoBrittle_N(instance) - 1.0_pReal) - & + phi*sourceState(phase)%p(sourceOffset)%state(1,constituent) + dLocalphiDot_dPhi = - (source_damage_isoBrittle_N(instance) - 1.0_pReal)* & + (1.0_pReal - phi)**max(0.0_pReal,source_damage_isoBrittle_N(instance) - 2.0_pReal) & + - sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_isoBrittle_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_isoBrittle_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_isoBrittle_sizePostResults( & + source_damage_isoBrittle_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_isoBrittle_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoBrittle_instance(phase) + sourceOffset = source_damage_isoBrittle_offset(phase) + + c = 0_pInt + source_damage_isoBrittle_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_isoBrittle_Noutput(instance) + select case(source_damage_isoBrittle_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_isoBrittle_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1 + + end select + enddo +end function source_damage_isoBrittle_postResults + +end module source_damage_isoBrittle diff --git a/src/source_damage_isoDuctile.f90 b/src/source_damage_isoDuctile.f90 new file mode 100644 index 000000000..b0290264c --- /dev/null +++ b/src/source_damage_isoDuctile.f90 @@ -0,0 +1,350 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @author Luv Sharma, Max-Planck-Institut fŸr Eisenforschung GmbH +!> @brief material subroutine incoprorating isotropic ductile damage source mechanism +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_damage_isoDuctile + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_damage_isoDuctile_sizePostResults, & !< cumulative size of post results + source_damage_isoDuctile_offset, & !< which source is my current damage mechanism? + source_damage_isoDuctile_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_damage_isoDuctile_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_damage_isoDuctile_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_damage_isoDuctile_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_damage_isoDuctile_aTol, & + source_damage_isoDuctile_critPlasticStrain, & + source_damage_isoDuctile_N + + enum, bind(c) + enumerator :: undefined_ID, & + damage_drivingforce_ID + end enum !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 ToDo + + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + source_damage_isoDuctile_outputID !< ID of each post result output + + + public :: & + source_damage_isoDuctile_init, & + source_damage_isoDuctile_dotState, & + source_damage_isoDuctile_getRateAndItsTangent, & + source_damage_isoDuctile_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoDuctile_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_damage_isoDuctile_label, & + SOURCE_damage_isoDuctile_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,phase,instance,source,sourceOffset,o + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_damage_isoDuctile_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_damage_isoDuctile_ID),pInt) + if (maxNinstance == 0_pInt) return + + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_damage_isoDuctile_offset(material_Nphase), source=0_pInt) + allocate(source_damage_isoDuctile_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_damage_isoDuctile_instance(phase) = count(phase_source(:,1:phase) == source_damage_isoDuctile_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_damage_isoDuctile_ID) & + source_damage_isoDuctile_offset(phase) = source + enddo + enddo + + allocate(source_damage_isoDuctile_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_damage_isoDuctile_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_damage_isoDuctile_output(maxval(phase_Noutput),maxNinstance)) + source_damage_isoDuctile_output = '' + allocate(source_damage_isoDuctile_outputID(maxval(phase_Noutput),maxNinstance), source=undefined_ID) + allocate(source_damage_isoDuctile_Noutput(maxNinstance), source=0_pInt) + allocate(source_damage_isoDuctile_critPlasticStrain(maxNinstance), source=0.0_pReal) + allocate(source_damage_isoDuctile_N(maxNinstance), source=0.0_pReal) + allocate(source_damage_isoDuctile_aTol(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + instance = source_damage_isoDuctile_instance(phase) ! which instance of my damage is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('isoductile_drivingforce') + source_damage_isoDuctile_Noutput(instance) = source_damage_isoDuctile_Noutput(instance) + 1_pInt + source_damage_isoDuctile_outputID(source_damage_isoDuctile_Noutput(instance),instance) = damage_drivingforce_ID + source_damage_isoDuctile_output(source_damage_isoDuctile_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('isoductile_criticalplasticstrain') + source_damage_isoDuctile_critPlasticStrain(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isoductile_ratesensitivity') + source_damage_isoDuctile_N(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('isoductile_atol') + source_damage_isoDuctile_aTol(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + +!-------------------------------------------------------------------------------------------------- +! sanity checks + sanityChecks: do phase = 1_pInt, material_Nphase + myPhase: if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then + instance = source_damage_isoDuctile_instance(phase) + if (source_damage_isoDuctile_aTol(instance) < 0.0_pReal) & + source_damage_isoDuctile_aTol(instance) = 1.0e-3_pReal ! default absolute tolerance 1e-3 + if (source_damage_isoDuctile_critPlasticStrain(instance) <= 0.0_pReal) & + call IO_error(211_pInt,el=instance,ext_msg='critical plastic strain ('//SOURCE_damage_isoDuctile_LABEL//')') + endif myPhase + enddo sanityChecks + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_damage_isoDuctile_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_damage_isoDuctile_instance(phase) + sourceOffset = source_damage_isoDuctile_offset(phase) +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) + select case(source_damage_isoDuctile_outputID(o,instance)) + case(damage_drivingforce_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + source_damage_isoDuctile_sizePostResult(o,instance) = mySize + source_damage_isoDuctile_sizePostResults(instance) = source_damage_isoDuctile_sizePostResults(instance) + mySize + endif + enddo outputsLoop +! Determine size of state array + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_damage_isoDuctile_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), & + source=source_damage_isoDuctile_aTol(instance)) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_damage_isoDuctile_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoDuctile_dotState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + plasticState, & + sourceState, & + material_homog, & + damage, & + damageMapping + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, constituent, instance, homog, sourceOffset, damageOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoDuctile_instance(phase) + sourceOffset = source_damage_isoDuctile_offset(phase) + homog = material_homog(ip,el) + damageOffset = damageMapping(homog)%p(ip,el) + + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & + sum(plasticState(phase)%slipRate(:,constituent))/ & + ((damage(homog)%p(damageOffset))**source_damage_isoDuctile_N(instance))/ & + source_damage_isoDuctile_critPlasticStrain(instance) + +end subroutine source_damage_isoDuctile_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local part of nonlocal damage driving force +!-------------------------------------------------------------------------------------------------- +subroutine source_damage_isoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in) :: & + phi + real(pReal), intent(out) :: & + localphiDot, & + dLocalphiDot_dPhi + integer(pInt) :: & + phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_damage_isoDuctile_offset(phase) + + localphiDot = 1.0_pReal - & + sourceState(phase)%p(sourceOffset)%state(1,constituent)* & + phi + + dLocalphiDot_dPhi = -sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_damage_isoDuctile_getRateAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of local damage results +!-------------------------------------------------------------------------------------------------- +function source_damage_isoDuctile_postResults(ipc,ip,el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), dimension(source_damage_isoDuctile_sizePostResults( & + source_damage_isoDuctile_instance(phaseAt(ipc,ip,el)))) :: & + source_damage_isoDuctile_postResults + + integer(pInt) :: & + instance, phase, constituent, sourceOffset, o, c + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_damage_isoDuctile_instance(phase) + sourceOffset = source_damage_isoDuctile_offset(phase) + + c = 0_pInt + source_damage_isoDuctile_postResults = 0.0_pReal + + do o = 1_pInt,source_damage_isoDuctile_Noutput(instance) + select case(source_damage_isoDuctile_outputID(o,instance)) + case (damage_drivingforce_ID) + source_damage_isoDuctile_postResults(c+1_pInt) = sourceState(phase)%p(sourceOffset)%state(1,constituent) + c = c + 1 + + end select + enddo +end function source_damage_isoDuctile_postResults + +end module source_damage_isoDuctile diff --git a/src/source_thermal_dissipation.f90 b/src/source_thermal_dissipation.f90 new file mode 100644 index 000000000..83ad85167 --- /dev/null +++ b/src/source_thermal_dissipation.f90 @@ -0,0 +1,220 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for thermal source due to plastic dissipation +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_thermal_dissipation + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_thermal_dissipation_sizePostResults, & !< cumulative size of post results + source_thermal_dissipation_offset, & !< which source is my current thermal dissipation mechanism? + source_thermal_dissipation_instance !< instance of thermal dissipation source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_thermal_dissipation_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_thermal_dissipation_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_thermal_dissipation_Noutput !< number of outputs per instance of this source + + real(pReal), dimension(:), allocatable, private :: & + source_thermal_dissipation_coldworkCoeff + + public :: & + source_thermal_dissipation_init, & + source_thermal_dissipation_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_dissipation_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_thermal_dissipation_label, & + SOURCE_thermal_dissipation_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_dissipation_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_thermal_dissipation_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_thermal_dissipation_offset(material_Nphase), source=0_pInt) + allocate(source_thermal_dissipation_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_thermal_dissipation_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_dissipation_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == SOURCE_thermal_dissipation_ID) & + source_thermal_dissipation_offset(phase) = source + enddo + enddo + + allocate(source_thermal_dissipation_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_thermal_dissipation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_thermal_dissipation_output (maxval(phase_Noutput),maxNinstance)) + source_thermal_dissipation_output = '' + allocate(source_thermal_dissipation_Noutput(maxNinstance), source=0_pInt) + allocate(source_thermal_dissipation_coldworkCoeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_thermal_dissipation_instance(phase) ! which instance of my source is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('dissipation_coldworkcoeff') + source_thermal_dissipation_coldworkCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_thermal_dissipation_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_thermal_dissipation_instance(phase) + sourceOffset = source_thermal_dissipation_offset(phase) + + sizeDotState = 0_pInt + sizeDeltaState = 0_pInt + sizeState = 0_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_dissipation_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_thermal_dissipation_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_dissipation_getRateAndItsTangent(TDot, dTDOT_dT, Tstar_v, Lp, ipc, ip, el) + use math, only: & + math_Mandel6to33 + use material, only: & + phaseAt, phasememberAt + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(in), dimension(6) :: & + Tstar_v !< 2nd Piola Kirchhoff stress tensor (Mandel) + real(pReal), intent(in), dimension(3,3) :: & + Lp + real(pReal), intent(out) :: & + TDot, & + dTDOT_dT + integer(pInt) :: & + instance, phase, constituent + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_thermal_dissipation_instance(phase) + + TDot = source_thermal_dissipation_coldworkCoeff(instance)* & + sum(abs(math_Mandel6to33(Tstar_v)*Lp)) + dTDOT_dT = 0.0_pReal + +end subroutine source_thermal_dissipation_getRateAndItsTangent + +end module source_thermal_dissipation diff --git a/src/source_thermal_externalheat.f90 b/src/source_thermal_externalheat.f90 new file mode 100644 index 000000000..257012c06 --- /dev/null +++ b/src/source_thermal_externalheat.f90 @@ -0,0 +1,277 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for thermal source due to plastic dissipation +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_thermal_externalheat + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_thermal_externalheat_sizePostResults, & !< cumulative size of post results + source_thermal_externalheat_offset, & !< which source is my current thermal dissipation mechanism? + source_thermal_externalheat_instance !< instance of thermal dissipation source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_thermal_externalheat_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_thermal_externalheat_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_thermal_externalheat_Noutput !< number of outputs per instance of this source + + integer(pInt), dimension(:), allocatable, private :: & + source_thermal_externalheat_nIntervals + + real(pReal), dimension(:,:), allocatable, private :: & + source_thermal_externalheat_time, & + source_thermal_externalheat_rate + + public :: & + source_thermal_externalheat_init, & + source_thermal_externalheat_dotState, & + source_thermal_externalheat_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_externalheat_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_thermal_externalheat_label, & + SOURCE_thermal_externalheat_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase,interval + character(len=65536) :: & + tag = '', & + line = '' + real(pReal), allocatable, dimension(:,:) :: temp_time, temp_rate + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_thermal_externalheat_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_thermal_externalheat_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_thermal_externalheat_offset(material_Nphase), source=0_pInt) + allocate(source_thermal_externalheat_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_thermal_externalheat_instance(phase) = count(phase_source(:,1:phase) == SOURCE_thermal_externalheat_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == SOURCE_thermal_externalheat_ID) & + source_thermal_externalheat_offset(phase) = source + enddo + enddo + + allocate(source_thermal_externalheat_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_thermal_externalheat_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_thermal_externalheat_output (maxval(phase_Noutput),maxNinstance)) + source_thermal_externalheat_output = '' + allocate(source_thermal_externalheat_Noutput(maxNinstance), source=0_pInt) + allocate(source_thermal_externalheat_nIntervals(maxNinstance), source=0_pInt) + + allocate(temp_time(maxNinstance,1000), source=0.0_pReal) + allocate(temp_rate(maxNinstance,1000), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_thermal_externalheat_instance(phase) ! which instance of my source is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('externalheat_time') + if (chunkPos(1) <= 2_pInt) & + call IO_error(150_pInt,ext_msg=trim(tag)//' ('//SOURCE_thermal_externalheat_label//')') + source_thermal_externalheat_nIntervals(instance) = chunkPos(1) - 2_pInt + do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt + temp_time(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) + enddo + + case ('externalheat_rate') + do interval = 1, source_thermal_externalheat_nIntervals(instance) + 1_pInt + temp_rate(instance, interval) = IO_floatValue(line,chunkPos,1_pInt + interval) + enddo + + end select + endif; endif + enddo parsingFile + + allocate(source_thermal_externalheat_time(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) + allocate(source_thermal_externalheat_rate(maxNinstance,maxval(source_thermal_externalheat_nIntervals)+1_pInt), source=0.0_pReal) + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_thermal_externalheat_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_thermal_externalheat_instance(phase) + sourceOffset = source_thermal_externalheat_offset(phase) + source_thermal_externalheat_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & + temp_time(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) + source_thermal_externalheat_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) = & + temp_rate(instance,1:source_thermal_externalheat_nIntervals(instance)+1_pInt) + + sizeDotState = 1_pInt + sizeDeltaState = 0_pInt + sizeState = 1_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_thermal_externalheat_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.00001_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_thermal_externalheat_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_externalheat_dotState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, & + constituent, & + sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_thermal_externalheat_offset(phase) + + sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 1.0_pReal + +end subroutine source_thermal_externalheat_dotState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_thermal_externalheat_getRateAndItsTangent(TDot, dTDot_dT, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + TDot, & + dTDot_dT + integer(pInt) :: & + instance, phase, constituent, sourceOffset, interval + real(pReal) :: & + norm_time + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_thermal_externalheat_instance(phase) + sourceOffset = source_thermal_externalheat_offset(phase) + + do interval = 1, source_thermal_externalheat_nIntervals(instance) + norm_time = (sourceState(phase)%p(sourceOffset)%state(1,constituent) - & + source_thermal_externalheat_time(instance,interval)) / & + (source_thermal_externalheat_time(instance,interval+1) - & + source_thermal_externalheat_time(instance,interval)) + if (norm_time >= 0.0_pReal .and. norm_time < 1.0_pReal) & + TDot = source_thermal_externalheat_rate(instance,interval ) * (1.0_pReal - norm_time) + & + source_thermal_externalheat_rate(instance,interval+1) * norm_time + enddo + dTDot_dT = 0.0 + +end subroutine source_thermal_externalheat_getRateAndItsTangent + +end module source_thermal_externalheat diff --git a/src/source_vacancy_irradiation.f90 b/src/source_vacancy_irradiation.f90 new file mode 100644 index 000000000..c4bcfba04 --- /dev/null +++ b/src/source_vacancy_irradiation.f90 @@ -0,0 +1,253 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for vacancy generation due to irradiation +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_vacancy_irradiation + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_vacancy_irradiation_sizePostResults, & !< cumulative size of post results + source_vacancy_irradiation_offset, & !< which source is my current damage mechanism? + source_vacancy_irradiation_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_vacancy_irradiation_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_vacancy_irradiation_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_vacancy_irradiation_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_vacancy_irradiation_cascadeProb, & + source_vacancy_irradiation_cascadeVolume + + public :: & + source_vacancy_irradiation_init, & + source_vacancy_irradiation_deltaState, & + source_vacancy_irradiation_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_irradiation_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_vacancy_irradiation_label, & + SOURCE_vacancy_irradiation_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_irradiation_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_vacancy_irradiation_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_vacancy_irradiation_offset(material_Nphase), source=0_pInt) + allocate(source_vacancy_irradiation_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_vacancy_irradiation_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_irradiation_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_vacancy_irradiation_ID) & + source_vacancy_irradiation_offset(phase) = source + enddo + enddo + + allocate(source_vacancy_irradiation_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_vacancy_irradiation_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_vacancy_irradiation_output(maxval(phase_Noutput),maxNinstance)) + source_vacancy_irradiation_output = '' + allocate(source_vacancy_irradiation_Noutput(maxNinstance), source=0_pInt) + allocate(source_vacancy_irradiation_cascadeProb(maxNinstance), source=0.0_pReal) + allocate(source_vacancy_irradiation_cascadeVolume(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_vacancy_irradiation_instance(phase) ! which instance of my vacancy is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('irradiation_cascadeprobability') + source_vacancy_irradiation_cascadeProb(instance) = IO_floatValue(line,chunkPos,2_pInt) + + case ('irradiation_cascadevolume') + source_vacancy_irradiation_cascadeVolume(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_vacancy_irradiation_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_vacancy_irradiation_instance(phase) + sourceOffset = source_vacancy_irradiation_offset(phase) + + sizeDotState = 2_pInt + sizeDeltaState = 2_pInt + sizeState = 2_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_irradiation_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_vacancy_irradiation_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_irradiation_deltaState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, constituent, sourceOffset + real(pReal) :: & + randNo + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_vacancy_irradiation_offset(phase) + + call random_number(randNo) + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + randNo - sourceState(phase)%p(sourceOffset)%state(1,constituent) + call random_number(randNo) + sourceState(phase)%p(sourceOffset)%deltaState(2,constituent) = & + randNo - sourceState(phase)%p(sourceOffset)%state(2,constituent) + +end subroutine source_vacancy_irradiation_deltaState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_irradiation_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + CvDot, dCvDot_dCv + integer(pInt) :: & + instance, phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_vacancy_irradiation_instance(phase) + sourceOffset = source_vacancy_irradiation_offset(phase) + + CvDot = 0.0_pReal + dCvDot_dCv = 0.0_pReal + if (sourceState(phase)%p(sourceOffset)%state0(1,constituent) < source_vacancy_irradiation_cascadeProb(instance)) & + CvDot = sourceState(phase)%p(sourceOffset)%state0(2,constituent)*source_vacancy_irradiation_cascadeVolume(instance) + +end subroutine source_vacancy_irradiation_getRateAndItsTangent + +end module source_vacancy_irradiation diff --git a/src/source_vacancy_phenoplasticity.f90 b/src/source_vacancy_phenoplasticity.f90 new file mode 100644 index 000000000..f9e766b2c --- /dev/null +++ b/src/source_vacancy_phenoplasticity.f90 @@ -0,0 +1,215 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for vacancy generation due to plasticity +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_vacancy_phenoplasticity + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_vacancy_phenoplasticity_sizePostResults, & !< cumulative size of post results + source_vacancy_phenoplasticity_offset, & !< which source is my current damage mechanism? + source_vacancy_phenoplasticity_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_vacancy_phenoplasticity_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_vacancy_phenoplasticity_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_vacancy_phenoplasticity_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_vacancy_phenoplasticity_rateCoeff + + public :: & + source_vacancy_phenoplasticity_init, & + source_vacancy_phenoplasticity_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_phenoplasticity_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_vacancy_phenoplasticity_label, & + SOURCE_vacancy_phenoplasticity_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_phenoplasticity_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_vacancy_phenoplasticity_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_vacancy_phenoplasticity_offset(material_Nphase), source=0_pInt) + allocate(source_vacancy_phenoplasticity_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_vacancy_phenoplasticity_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_phenoplasticity_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_vacancy_phenoplasticity_ID) & + source_vacancy_phenoplasticity_offset(phase) = source + enddo + enddo + + allocate(source_vacancy_phenoplasticity_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_vacancy_phenoplasticity_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_vacancy_phenoplasticity_output(maxval(phase_Noutput),maxNinstance)) + source_vacancy_phenoplasticity_output = '' + allocate(source_vacancy_phenoplasticity_Noutput(maxNinstance), source=0_pInt) + allocate(source_vacancy_phenoplasticity_rateCoeff(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_vacancy_phenoplasticity_instance(phase) ! which instance of my vacancy is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('phenoplasticity_ratecoeff') + source_vacancy_phenoplasticity_rateCoeff(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_vacancy_phenoplasticity_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_vacancy_phenoplasticity_instance(phase) + sourceOffset = source_vacancy_phenoplasticity_offset(phase) + + sizeDotState = 0_pInt + sizeDeltaState = 0_pInt + sizeState = 0_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_phenoplasticity_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_vacancy_phenoplasticity_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_phenoplasticity_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + plasticState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + CvDot, dCvDot_dCv + integer(pInt) :: & + instance, phase, constituent + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_vacancy_phenoplasticity_instance(phase) + + CvDot = & + source_vacancy_phenoplasticity_rateCoeff(instance)* & + sum(plasticState(phase)%slipRate(:,constituent)) + dCvDot_dCv = 0.0_pReal + +end subroutine source_vacancy_phenoplasticity_getRateAndItsTangent + +end module source_vacancy_phenoplasticity diff --git a/src/source_vacancy_thermalfluc.f90 b/src/source_vacancy_thermalfluc.f90 new file mode 100644 index 000000000..c86406430 --- /dev/null +++ b/src/source_vacancy_thermalfluc.f90 @@ -0,0 +1,255 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for vacancy generation due to thermal fluctuations +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module source_vacancy_thermalfluc + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + source_vacancy_thermalfluc_sizePostResults, & !< cumulative size of post results + source_vacancy_thermalfluc_offset, & !< which source is my current damage mechanism? + source_vacancy_thermalfluc_instance !< instance of damage source mechanism + + integer(pInt), dimension(:,:), allocatable, target, public :: & + source_vacancy_thermalfluc_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + source_vacancy_thermalfluc_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + source_vacancy_thermalfluc_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + source_vacancy_thermalfluc_amplitude, & + source_vacancy_thermalfluc_normVacancyEnergy + + public :: & + source_vacancy_thermalfluc_init, & + source_vacancy_thermalfluc_deltaState, & + source_vacancy_thermalfluc_getRateAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_thermalfluc_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use debug, only: & + debug_level,& + debug_constitutive,& + debug_levelBasic + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use lattice, only: & + lattice_vacancyFormationEnergy + use material, only: & + phase_source, & + phase_Nsources, & + phase_Noutput, & + SOURCE_vacancy_thermalfluc_label, & + SOURCE_vacancy_thermalfluc_ID, & + material_Nphase, & + material_phase, & + sourceState, & + MATERIAL_partPhase + use numerics,only: & + analyticJaco, & + worldrank, & + numerics_integrator + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,phase,instance,source,sourceOffset + integer(pInt) :: sizeState, sizeDotState, sizeDeltaState + integer(pInt) :: NofMyPhase + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- source_'//SOURCE_vacancy_thermalfluc_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(phase_source == SOURCE_vacancy_thermalfluc_ID),pInt) + if (maxNinstance == 0_pInt) return + if (iand(debug_level(debug_constitutive),debug_levelBasic) /= 0_pInt) & + write(6,'(a16,1x,i5,/)') '# instances:',maxNinstance + + allocate(source_vacancy_thermalfluc_offset(material_Nphase), source=0_pInt) + allocate(source_vacancy_thermalfluc_instance(material_Nphase), source=0_pInt) + do phase = 1, material_Nphase + source_vacancy_thermalfluc_instance(phase) = count(phase_source(:,1:phase) == source_vacancy_thermalfluc_ID) + do source = 1, phase_Nsources(phase) + if (phase_source(source,phase) == source_vacancy_thermalfluc_ID) & + source_vacancy_thermalfluc_offset(phase) = source + enddo + enddo + + allocate(source_vacancy_thermalfluc_sizePostResults(maxNinstance), source=0_pInt) + allocate(source_vacancy_thermalfluc_sizePostResult(maxval(phase_Noutput),maxNinstance),source=0_pInt) + allocate(source_vacancy_thermalfluc_output(maxval(phase_Noutput),maxNinstance)) + source_vacancy_thermalfluc_output = '' + allocate(source_vacancy_thermalfluc_Noutput(maxNinstance), source=0_pInt) + allocate(source_vacancy_thermalfluc_amplitude(maxNinstance), source=0.0_pReal) + allocate(source_vacancy_thermalfluc_normVacancyEnergy(maxNinstance), source=0.0_pReal) + + rewind(fileUnit) + phase = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of phase part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next phase section + phase = phase + 1_pInt ! advance phase section counter + cycle ! skip to next line + endif + + if (phase > 0_pInt ) then; if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = source_vacancy_thermalfluc_instance(phase) ! which instance of my vacancy is present phase + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('thermalfluctuation_amplitude') + source_vacancy_thermalfluc_amplitude(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingFile + + initializeInstances: do phase = 1_pInt, material_Nphase + if (any(phase_source(:,phase) == SOURCE_vacancy_thermalfluc_ID)) then + NofMyPhase=count(material_phase==phase) + instance = source_vacancy_thermalfluc_instance(phase) + source_vacancy_thermalfluc_normVacancyEnergy(instance) = & + lattice_vacancyFormationEnergy(phase)/1.3806488e-23_pReal + sourceOffset = source_vacancy_thermalfluc_offset(phase) + + sizeDotState = 1_pInt + sizeDeltaState = 1_pInt + sizeState = 1_pInt + sourceState(phase)%p(sourceOffset)%sizeState = sizeState + sourceState(phase)%p(sourceOffset)%sizeDotState = sizeDotState + sourceState(phase)%p(sourceOffset)%sizeDeltaState = sizeDeltaState + sourceState(phase)%p(sourceOffset)%sizePostResults = source_vacancy_thermalfluc_sizePostResults(instance) + allocate(sourceState(phase)%p(sourceOffset)%aTolState (sizeState), source=0.1_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%partionedState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%subState0 (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%state (sizeState,NofMyPhase), source=0.0_pReal) + + allocate(sourceState(phase)%p(sourceOffset)%dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%deltaState (sizeDeltaState,NofMyPhase), source=0.0_pReal) + if (.not. analyticJaco) then + allocate(sourceState(phase)%p(sourceOffset)%state_backup (sizeState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%dotState_backup (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 1_pInt)) then + allocate(sourceState(phase)%p(sourceOffset)%previousDotState (sizeDotState,NofMyPhase), source=0.0_pReal) + allocate(sourceState(phase)%p(sourceOffset)%previousDotState2 (sizeDotState,NofMyPhase), source=0.0_pReal) + endif + if (any(numerics_integrator == 4_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RK4dotState (sizeDotState,NofMyPhase), source=0.0_pReal) + if (any(numerics_integrator == 5_pInt)) & + allocate(sourceState(phase)%p(sourceOffset)%RKCK45dotState (6,sizeDotState,NofMyPhase),source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine source_vacancy_thermalfluc_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates derived quantities from state +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_thermalfluc_deltaState(ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + integer(pInt) :: & + phase, constituent, sourceOffset + real(pReal) :: & + randNo + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + sourceOffset = source_vacancy_thermalfluc_offset(phase) + + call random_number(randNo) + sourceState(phase)%p(sourceOffset)%deltaState(1,constituent) = & + randNo - 0.5_pReal - sourceState(phase)%p(sourceOffset)%state(1,constituent) + +end subroutine source_vacancy_thermalfluc_deltaState + +!-------------------------------------------------------------------------------------------------- +!> @brief returns local vacancy generation rate +!-------------------------------------------------------------------------------------------------- +subroutine source_vacancy_thermalfluc_getRateAndItsTangent(CvDot, dCvDot_dCv, ipc, ip, el) + use material, only: & + phaseAt, phasememberAt, & + material_homog, & + temperature, & + thermalMapping, & + sourceState + + implicit none + integer(pInt), intent(in) :: & + ipc, & !< grain number + ip, & !< integration point number + el !< element number + real(pReal), intent(out) :: & + CvDot, dCvDot_dCv + integer(pInt) :: & + instance, phase, constituent, sourceOffset + + phase = phaseAt(ipc,ip,el) + constituent = phasememberAt(ipc,ip,el) + instance = source_vacancy_thermalfluc_instance(phase) + sourceOffset = source_vacancy_thermalfluc_offset(phase) + + CvDot = source_vacancy_thermalfluc_amplitude(instance)* & + sourceState(phase)%p(sourceOffset)%state0(2,constituent)* & + exp(-source_vacancy_thermalfluc_normVacancyEnergy(instance)/ & + temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))) + dCvDot_dCv = 0.0_pReal + +end subroutine source_vacancy_thermalfluc_getRateAndItsTangent + +end module source_vacancy_thermalfluc diff --git a/src/spectral_damage.f90 b/src/spectral_damage.f90 new file mode 100644 index 000000000..0b79d5e5d --- /dev/null +++ b/src/spectral_damage.f90 @@ -0,0 +1,414 @@ +!-------------------------------------------------------------------------------------------------- +! $Id: spectral_damage.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Shaokang Zhang, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Spectral solver for nonlocal damage +!-------------------------------------------------------------------------------------------------- +module spectral_damage + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + use numerics, only: & + worldrank, & + worldsize + + implicit none + private +#include + + character (len=*), parameter, public :: & + spectral_damage_label = 'spectraldamage' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + +!-------------------------------------------------------------------------------------------------- +! PETSc data + SNES, private :: damage_snes + Vec, private :: solution + PetscInt, private :: xstart, xend, ystart, yend, zstart, zend + real(pReal), private, dimension(:,:,:), allocatable :: & + damage_current, & !< field of current damage + damage_lastInc, & !< field of previous damage + damage_stagInc !< field of staggered damage + +!-------------------------------------------------------------------------------------------------- +! reference diffusion tensor, mobility etc. + integer(pInt), private :: totalIter = 0_pInt !< total iteration in current increment + real(pReal), dimension(3,3), private :: D_ref + real(pReal), private :: mobility_ref + character(len=1024), private :: incInfo + + public :: & + spectral_damage_init, & + spectral_damage_solution, & + spectral_damage_forward, & + spectral_damage_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use spectral_utilities, only: & + wgt + use mesh, only: & + grid, & + grid3 + use damage_nonlocal, only: & + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility + + implicit none + DM :: damage_grid + Vec :: uBound, lBound + PetscErrorCode :: ierr + PetscObject :: dummy + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + integer(pInt) :: i, j, k, cell + character(len=100) :: snes_type + + mainProcess: if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- spectral_damage init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! initialize solver specific parts of PETSc + call SNESCreate(PETSC_COMM_WORLD,damage_snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(damage_snes,'damage_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & !< cut off stencil at boundary + DMDA_STENCIL_BOX, & !< Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & !< global grid + 1, 1, worldsize, & + 1, 0, & !< #dof (damage phase field), ghost boundary width (domain overlap) + grid(1),grid(2),localK, & !< local grid + damage_grid,ierr) !< handle, error + CHKERRQ(ierr) + call SNESSetDM(damage_snes,damage_grid,ierr); CHKERRQ(ierr) !< connect snes to da + call DMCreateGlobalVector(damage_grid,solution,ierr); CHKERRQ(ierr) !< global solution vector (grid x 1, i.e. every def grad tensor) + call DMDASNESSetFunctionLocal(damage_grid,INSERT_VALUES,spectral_damage_formResidual,dummy,ierr) !< residual vector of same shape as solution vector + CHKERRQ(ierr) + call SNESSetFromOptions(damage_snes,ierr); CHKERRQ(ierr) !< pull it all together with additional cli arguments + call SNESGetType(damage_snes,snes_type,ierr); CHKERRQ(ierr) + if (trim(snes_type) == 'vinewtonrsls' .or. & + trim(snes_type) == 'vinewtonssls') then + call DMGetGlobalVector(damage_grid,lBound,ierr); CHKERRQ(ierr) + call DMGetGlobalVector(damage_grid,uBound,ierr); CHKERRQ(ierr) + call VecSet(lBound,0.0,ierr); CHKERRQ(ierr) + call VecSet(uBound,1.0,ierr); CHKERRQ(ierr) + call SNESVISetVariableBounds(damage_snes,lBound,uBound,ierr) !< variable bounds for variational inequalities like contact mechanics, damage etc. + call DMRestoreGlobalVector(damage_grid,lBound,ierr); CHKERRQ(ierr) + call DMRestoreGlobalVector(damage_grid,uBound,ierr); CHKERRQ(ierr) + endif + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAGetCorners(damage_grid,xstart,ystart,zstart,xend,yend,zend,ierr) + CHKERRQ(ierr) + xend = xstart + xend - 1 + yend = ystart + yend - 1 + zend = zstart + zend - 1 + call VecSet(solution,1.0,ierr); CHKERRQ(ierr) + allocate(damage_current(grid(1),grid(2),grid3), source=1.0_pReal) + allocate(damage_lastInc(grid(1),grid(2),grid3), source=1.0_pReal) + allocate(damage_stagInc(grid(1),grid(2),grid3), source=1.0_pReal) + +!-------------------------------------------------------------------------------------------------- +! damage reference diffusion update + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + D_ref = D_ref + damage_nonlocal_getDiffusion33(1,cell) + mobility_ref = mobility_ref + damage_nonlocal_getMobility(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + +end subroutine spectral_damage_init + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the spectral damage scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function spectral_damage_solution(guess,timeinc,timeinc_old,loadCaseTime) + use numerics, only: & + itmax, & + err_damage_tolAbs, & + err_damage_tolRel + use spectral_utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use mesh, only: & + grid, & + grid3 + use damage_nonlocal, only: & + damage_nonlocal_putNonLocalDamage + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + integer(pInt) :: i, j, k, cell + PetscInt ::position + PetscReal :: minDamage, maxDamage, stagNorm, solnNorm + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + spectral_damage_solution%converged =.false. + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + params%timeinc = timeinc + params%timeincOld = timeinc_old + + call SNESSolve(damage_snes,PETSC_NULL_OBJECT,solution,ierr); CHKERRQ(ierr) + call SNESGetConvergedReason(damage_snes,reason,ierr); CHKERRQ(ierr) + + if (reason < 1) then + spectral_damage_solution%converged = .false. + spectral_damage_solution%iterationsNeeded = itmax + else + spectral_damage_solution%converged = .true. + spectral_damage_solution%iterationsNeeded = totalIter + endif + stagNorm = maxval(abs(damage_current - damage_stagInc)) + solnNorm = maxval(abs(damage_current)) + call MPI_Allreduce(MPI_IN_PLACE,stagNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + call MPI_Allreduce(MPI_IN_PLACE,solnNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + damage_stagInc = damage_current + spectral_damage_solution%stagConverged = stagNorm < err_damage_tolAbs & + .or. stagNorm < err_damage_tolRel*solnNorm + +!-------------------------------------------------------------------------------------------------- +! updating damage state + cell = 0_pInt !< material point = 0 + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt !< material point increase + call damage_nonlocal_putNonLocalDamage(damage_current(i,j,k),1,cell) + enddo; enddo; enddo + + call VecMin(solution,position,minDamage,ierr); CHKERRQ(ierr) + call VecMax(solution,position,maxDamage,ierr); CHKERRQ(ierr) + if (worldrank == 0) then + if (spectral_damage_solution%converged) & + write(6,'(/,a)') ' ... nonlocal damage converged .....................................' + write(6,'(/,a,f8.6,2x,f8.6,2x,f8.6,/)',advance='no') ' Minimum|Maximum|Delta Damage = ',& + minDamage, maxDamage, stagNorm + write(6,'(/,a)') ' ===========================================================================' + flush(6) + endif + +end function spectral_damage_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the spectral damage residual vector +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_formResidual(in,x_scal,f_scal,dummy,ierr) + use numerics, only: & + residualStiffness + use mesh, only: & + grid, & + grid3 + use math, only: & + math_mul33x3 + use spectral_utilities, only: & + scalarField_real, & + vectorField_real, & + utilities_FFTvectorForward, & + utilities_FFTvectorBackward, & + utilities_FFTscalarForward, & + utilities_FFTscalarBackward, & + utilities_fourierGreenConvolution, & + utilities_fourierScalarGradient, & + utilities_fourierVectorDivergence + use damage_nonlocal, only: & + damage_nonlocal_getSourceAndItsTangent,& + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility + + implicit none + DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, dimension( & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, dimension( & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscObject :: dummy + PetscErrorCode :: ierr + integer(pInt) :: i, j, k, cell + real(pReal) :: phiDot, dPhiDot_dPhi, mobility + + damage_current = x_scal +!-------------------------------------------------------------------------------------------------- +! evaluate polarization field + scalarField_real = 0.0_pReal + scalarField_real(1:grid(1),1:grid(2),1:grid3) = damage_current + call utilities_FFTscalarForward() + call utilities_fourierScalarGradient() !< calculate gradient of damage field + call utilities_FFTvectorBackward() + cell = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + vectorField_real(1:3,i,j,k) = math_mul33x3(damage_nonlocal_getDiffusion33(1,cell) - D_ref, & + vectorField_real(1:3,i,j,k)) + enddo; enddo; enddo + call utilities_FFTvectorForward() + call utilities_fourierVectorDivergence() !< calculate damage divergence in fourier field + call utilities_FFTscalarBackward() + cell = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + call damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, damage_current(i,j,k), 1, cell) + mobility = damage_nonlocal_getMobility(1,cell) + scalarField_real(i,j,k) = params%timeinc*scalarField_real(i,j,k) + & + params%timeinc*phiDot + & + mobility*damage_lastInc(i,j,k) - & + mobility*damage_current(i,j,k) + & + mobility_ref*damage_current(i,j,k) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! convolution of damage field with green operator + call utilities_FFTscalarForward() + call utilities_fourierGreenConvolution(D_ref, mobility_ref, params%timeinc) + call utilities_FFTscalarBackward() + where(scalarField_real(1:grid(1),1:grid(2),1:grid3) > damage_lastInc) & + scalarField_real(1:grid(1),1:grid(2),1:grid3) = damage_lastInc + where(scalarField_real(1:grid(1),1:grid(2),1:grid3) < residualStiffness) & + scalarField_real(1:grid(1),1:grid(2),1:grid3) = residualStiffness + +!-------------------------------------------------------------------------------------------------- +! constructing residual + f_scal = scalarField_real(1:grid(1),1:grid(2),1:grid3) - damage_current + +end subroutine spectral_damage_formResidual + +!-------------------------------------------------------------------------------------------------- +!> @brief spectral damage forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_forward(guess,timeinc,timeinc_old,loadCaseTime) + use mesh, only: & + grid, & + grid3 + use spectral_utilities, only: & + cutBack, & + wgt + use damage_nonlocal, only: & + damage_nonlocal_putNonLocalDamage, & + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + PetscErrorCode :: ierr + integer(pInt) :: i, j, k, cell + DM :: dm_local + PetscScalar, dimension(:,:,:), pointer :: x_scal + + if (cutBack) then + damage_current = damage_lastInc + damage_stagInc = damage_lastInc +!-------------------------------------------------------------------------------------------------- +! reverting damage field state + cell = 0_pInt + call SNESGetDM(damage_snes,dm_local,ierr); CHKERRQ(ierr) + call DMDAVecGetArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with + x_scal(xstart:xend,ystart:yend,zstart:zend) = damage_current + call DMDAVecRestoreArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + call damage_nonlocal_putNonLocalDamage(damage_current(i,j,k),1,cell) + enddo; enddo; enddo + else +!-------------------------------------------------------------------------------------------------- +! update rate and forward last inc + damage_lastInc = damage_current + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + D_ref = D_ref + damage_nonlocal_getDiffusion33(1,cell) + mobility_ref = mobility_ref + damage_nonlocal_getMobility(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + endif + + end subroutine spectral_damage_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_destroy() + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution,ierr); CHKERRQ(ierr) + call SNESDestroy(damage_snes,ierr); CHKERRQ(ierr) + +end subroutine spectral_damage_destroy + +end module spectral_damage diff --git a/src/spectral_interface.f90 b/src/spectral_interface.f90 new file mode 100644 index 000000000..b24c5f747 --- /dev/null +++ b/src/spectral_interface.f90 @@ -0,0 +1,568 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Interfacing between the spectral solver and the material subroutines provided +!! by DAMASK +!> @details Interfacing between the spectral solver and the material subroutines provided +!> by DAMASK. Interpretating the command line arguments or, in case of called from f2py, +!> the arguments parsed to the init routine to get load case, geometry file, working +!> directory, etc. +!-------------------------------------------------------------------------------------------------- +module DAMASK_interface + use prec, only: & + pInt + + implicit none + private +#ifdef PETSc +#include +#endif + logical, public, protected :: appendToOutFile = .false. !< Append to existing spectralOut file (in case of restart, not in case of regridding) + integer(pInt), public, protected :: spectralRestartInc = 1_pInt !< Increment at which calculation starts + character(len=1024), public, protected :: & + geometryFile = '', & !< parameter given for geometry file + loadCaseFile = '' !< parameter given for load case file + character(len=1024), private :: workingDirectory !< accessed by getSolverWorkingDirectoryName for compatibility reasons + + public :: & + getSolverWorkingDirectoryName, & + getSolverJobName, & + DAMASK_interface_init + private :: & + storeWorkingDirectory, & + getGeometryFile, & + getLoadCaseFile, & + rectifyPath, & + makeRelativePath, & + getPathSep, & + IIO_stringValue, & + IIO_intValue, & + IIO_lc, & + IIO_stringPos + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief initializes the solver by interpreting the command line arguments. Also writes +!! information on computation to screen +!-------------------------------------------------------------------------------------------------- +subroutine DAMASK_interface_init(loadCaseParameterIn,geometryParameterIn) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + + implicit none + character(len=1024), optional, intent(in) :: & + loadCaseParameterIn, & !< if using the f2py variant, the -l argument of DAMASK_spectral.exe + geometryParameterIn !< if using the f2py variant, the -g argument of DAMASK_spectral.exe + character(len=1024) :: & + commandLine, & !< command line call as string + loadCaseArg ='', & !< -l argument given to DAMASK_spectral.exe + geometryArg ='', & !< -g argument given to DAMASK_spectral.exe + workingDirArg ='', & !< -w argument given to DAMASK_spectral.exe + hostName, & !< name of machine on which DAMASK_spectral.exe is execute (might require export HOSTNAME) + userName, & !< name of user calling DAMASK_spectral.exe + tag + integer :: & + i, & + worldrank = 0 + integer, allocatable, dimension(:) :: & + chunkPos + integer, dimension(8) :: & + dateAndTime ! type default integer +#ifdef PETSc + PetscErrorCode :: ierr +#endif + external :: & + quit,& + MPI_Comm_rank,& + PETScInitialize, & + MPI_abort + +!-------------------------------------------------------------------------------------------------- +! PETSc Init +#ifdef PETSc + call PetscInitialize(PETSC_NULL_CHARACTER,ierr) ! according to PETSc manual, that should be the first line in the code + CHKERRQ(ierr) ! this is a macro definition, it is case sensitive + + open(6, encoding='UTF-8') ! modern fortran compilers (gfortran >4.4, ifort >11 support it) + call MPI_Comm_rank(PETSC_COMM_WORLD,worldrank,ierr);CHKERRQ(ierr) +#endif + mainProcess: if (worldrank == 0) then + call date_and_time(values = dateAndTime) + write(6,'(/,a)') ' <<<+- DAMASK_spectral -+>>>' + write(6,'(/,a)') ' Version: '//DAMASKVERSION + write(6,'(a,2(i2.2,a),i4.4)') ' Date: ',dateAndTime(3),'/',& + dateAndTime(2),'/',& + dateAndTime(1) + write(6,'(a,2(i2.2,a),i2.2)') ' Time: ',dateAndTime(5),':',& + dateAndTime(6),':',& + dateAndTime(7) + write(6,'(/,a)') ' <<<+- DAMASK_interface init -+>>>' +#include "compilation_info.f90" + endif mainProcess + + if ( present(loadcaseParameterIn) .and. present(geometryParameterIn)) then ! both mandatory parameters given in function call + geometryArg = geometryParameterIn + loadcaseArg = loadcaseParameterIn + commandLine = 'n/a' + else if ( .not.( present(loadcaseParameterIn) .and. present(geometryParameterIn))) then ! none parameters given in function call, trying to get them from command line + call get_command(commandLine) + chunkPos = IIO_stringPos(commandLine) + do i = 1, chunkPos(1) + tag = IIO_lc(IIO_stringValue(commandLine,chunkPos,i)) ! extract key + select case(tag) + case ('-h','--help') + mainProcess2: if (worldrank == 0) then + write(6,'(a)') ' #######################################################################' + write(6,'(a)') ' DAMASK_spectral:' + write(6,'(a)') ' The spectral method boundary value problem solver for' + write(6,'(a)') ' the Düsseldorf Advanced Material Simulation Kit' + write(6,'(a,/)')' #######################################################################' + write(6,'(a,/)')' Valid command line switches:' + write(6,'(a)') ' --geom (-g, --geometry)' + write(6,'(a)') ' --load (-l, --loadcase)' + write(6,'(a)') ' --workingdir (-w, --wd, --workingdirectory, -d, --directory)' + write(6,'(a)') ' --restart (-r, --rs)' + write(6,'(a)') ' --regrid (--rg)' + write(6,'(a)') ' --help (-h)' + write(6,'(/,a)')' -----------------------------------------------------------------------' + write(6,'(a)') ' Mandatory arguments:' + write(6,'(/,a)')' --geom PathToGeomFile/NameOfGeom.geom' + write(6,'(a)') ' Specifies the location of the geometry definition file,' + write(6,'(a)') ' if no extension is given, .geom will be appended.' + write(6,'(a)') ' "PathToGeomFile" will be the working directory if not specified' + write(6,'(a)') ' via --workingdir.' + write(6,'(a)') ' Make sure the file "material.config" exists in the working' + write(6,'(a)') ' directory.' + write(6,'(a)') ' For further configuration place "numerics.config"' + write(6,'(a)')' and "numerics.config" in that directory.' + write(6,'(/,a)')' --load PathToLoadFile/NameOfLoadFile.load' + write(6,'(a)') ' Specifies the location of the load case definition file,' + write(6,'(a)') ' if no extension is given, .load will be appended.' + write(6,'(/,a)')' -----------------------------------------------------------------------' + write(6,'(a)') ' Optional arguments:' + write(6,'(/,a)')' --workingdirectory PathToWorkingDirectory' + write(6,'(a)') ' Specifies the working directory and overwrites the default' + write(6,'(a)') ' "PathToGeomFile".' + write(6,'(a)') ' Make sure the file "material.config" exists in the working' + write(6,'(a)') ' directory.' + write(6,'(a)') ' For further configuration place "numerics.config"' + write(6,'(a)')' and "numerics.config" in that directory.' + write(6,'(/,a)')' --restart XX' + write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' + write(6,'(a)') ' calculate total increment No. XX.' + write(6,'(a)') ' Appends to existing results file ' + write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' + write(6,'(a)') ' Works only if the restart information for total increment' + write(6,'(a)') ' No. XX-1 is available in the working directory.' + write(6,'(/,a)')' --regrid XX' + write(6,'(a)') ' Reads in total increment No. XX-1 and continues to' + write(6,'(a)') ' calculate total increment No. XX.' + write(6,'(a)') ' Attention: Overwrites existing results file ' + write(6,'(a)') ' "NameOfGeom_NameOfLoadFile.spectralOut".' + write(6,'(a)') ' Works only if the restart information for total increment' + write(6,'(a)') ' No. XX-1 is available in the working directory.' + write(6,'(/,a)')' -----------------------------------------------------------------------' + write(6,'(a)') ' Help:' + write(6,'(/,a)')' --help' + write(6,'(a,/)')' Prints this message and exits' + call quit(0_pInt) ! normal Termination + endif mainProcess2 + case ('-l', '--load', '--loadcase') + loadcaseArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + case ('-g', '--geom', '--geometry') + geometryArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + case ('-w', '-d', '--wd', '--directory', '--workingdir', '--workingdirectory') + workingDirArg = IIO_stringValue(commandLine,chunkPos,i+1_pInt) + case ('-r', '--rs', '--restart') + spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) + appendToOutFile = .true. + case ('--rg', '--regrid') + spectralRestartInc = IIO_IntValue(commandLine,chunkPos,i+1_pInt) + appendToOutFile = .false. + end select + enddo + endif + + if (len(trim(loadcaseArg)) == 0 .or. len(trim(geometryArg)) == 0) then + write(6,'(a)') ' Please specify geometry AND load case (-h for help)' + call quit(1_pInt) + endif + + workingDirectory = storeWorkingDirectory(trim(workingDirArg),trim(geometryArg)) + geometryFile = getGeometryFile(geometryArg) + loadCaseFile = getLoadCaseFile(loadCaseArg) + + call get_environment_variable('HOSTNAME',hostName) + call get_environment_variable('USER',userName) + mainProcess3: if (worldrank == 0) then + write(6,'(a,a)') ' Host name: ', trim(hostName) + write(6,'(a,a)') ' User name: ', trim(userName) + write(6,'(a,a)') ' Path separator: ', getPathSep() + write(6,'(a,a)') ' Command line call: ', trim(commandLine) + if (len(trim(workingDirArg))>0) & + write(6,'(a,a)') ' Working dir argument: ', trim(workingDirArg) + write(6,'(a,a)') ' Geometry argument: ', trim(geometryArg) + write(6,'(a,a)') ' Loadcase argument: ', trim(loadcaseArg) + write(6,'(a,a)') ' Working directory: ', trim(getSolverWorkingDirectoryName()) + write(6,'(a,a)') ' Geometry file: ', trim(geometryFile) + write(6,'(a,a)') ' Loadcase file: ', trim(loadCaseFile) + write(6,'(a,a)') ' Solver job name: ', trim(getSolverJobName()) + if (SpectralRestartInc > 1_pInt) & + write(6,'(a,i6.6)') ' Restart at increment: ', spectralRestartInc + write(6,'(a,l1,/)') ' Append to result file: ', appendToOutFile + endif mainProcess3 + +end subroutine DAMASK_interface_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief extract working directory from given argument or from location of geometry file, +!! possibly converting relative arguments to absolut path +!> @todo change working directory with call chdir(storeWorkingDirectory)? +!-------------------------------------------------------------------------------------------------- +character(len=1024) function storeWorkingDirectory(workingDirectoryArg,geometryArg) +#ifdef __INTEL_COMPILER + use IFPORT +#endif + + implicit none + character(len=*), intent(in) :: workingDirectoryArg !< working directory argument + character(len=*), intent(in) :: geometryArg !< geometry argument + character(len=1024) :: cwd + character :: pathSep + logical :: dirExists + external :: quit + integer :: error + + pathSep = getPathSep() + if (len(workingDirectoryArg)>0) then ! got working directory as input + if (workingDirectoryArg(1:1) == pathSep) then ! absolute path given as command line argument + storeWorkingDirectory = workingDirectoryArg + else + error = getcwd(cwd) ! relative path given as command line argument + storeWorkingDirectory = trim(cwd)//pathSep//workingDirectoryArg + endif + if (storeWorkingDirectory(len(trim(storeWorkingDirectory)):len(trim(storeWorkingDirectory))) & ! if path seperator is not given, append it + /= pathSep) storeWorkingDirectory = trim(storeWorkingDirectory)//pathSep +#ifdef __INTEL_COMPILER + inquire(directory = trim(storeWorkingDirectory)//'.', exist=dirExists) +#else + inquire(file = trim(storeWorkingDirectory), exist=dirExists) +#endif + if(.not. dirExists) then ! check if the directory exists + write(6,'(a20,a,a16)') ' working directory "',trim(storeWorkingDirectory),'" does not exist' + call quit(1_pInt) + endif + else ! using path to geometry file as working dir + if (geometryArg(1:1) == pathSep) then ! absolute path given as command line argument + storeWorkingDirectory = geometryArg(1:scan(geometryArg,pathSep,back=.true.)) + else + error = getcwd(cwd) ! relative path given as command line argument + storeWorkingDirectory = trim(cwd)//pathSep//& + geometryArg(1:scan(geometryArg,pathSep,back=.true.)) + endif + endif + storeWorkingDirectory = rectifyPath(storeWorkingDirectory) + +end function storeWorkingDirectory + + +!-------------------------------------------------------------------------------------------------- +!> @brief simply returns the private string workingDir +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getSolverWorkingDirectoryName() + + implicit none + getSolverWorkingDirectoryName = workingDirectory + +end function getSolverWorkingDirectoryName + + +!-------------------------------------------------------------------------------------------------- +!> @brief solver job name (no extension) as combination of geometry and load case name +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getSolverJobName() + + implicit none + integer :: posExt,posSep + character :: pathSep + character(len=1024) :: tempString + + pathSep = getPathSep() + + tempString = geometryFile + posExt = scan(tempString,'.',back=.true.) + posSep = scan(tempString,pathSep,back=.true.) + + getSolverJobName = tempString(posSep+1:posExt-1) + + tempString = loadCaseFile + posExt = scan(tempString,'.',back=.true.) + posSep = scan(tempString,pathSep,back=.true.) + + getSolverJobName = trim(getSolverJobName)//'_'//tempString(posSep+1:posExt-1) + +end function getSolverJobName + + +!-------------------------------------------------------------------------------------------------- +!> @brief basename of geometry file with extension from command line arguments +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getGeometryFile(geometryParameter) +#ifdef __INTEL_COMPILER + use IFPORT +#endif + + implicit none + character(len=1024), intent(in) :: & + geometryParameter + character(len=1024) :: & + cwd + integer :: posExt, posSep + character :: pathSep + integer :: error + + getGeometryFile = geometryParameter + pathSep = getPathSep() + posExt = scan(getGeometryFile,'.',back=.true.) + posSep = scan(getGeometryFile,pathSep,back=.true.) + + if (posExt <= posSep) getGeometryFile = trim(getGeometryFile)//('.geom') ! no extension present + if (scan(getGeometryFile,pathSep) /= 1) then ! relative path given as command line argument + error = getcwd(cwd) + getGeometryFile = rectifyPath(trim(cwd)//pathSep//getGeometryFile) + else + getGeometryFile = rectifyPath(getGeometryFile) + endif + + getGeometryFile = makeRelativePath(getSolverWorkingDirectoryName(), getGeometryFile) + +end function getGeometryFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief relative path of loadcase from command line arguments +!-------------------------------------------------------------------------------------------------- +character(len=1024) function getLoadCaseFile(loadCaseParameter) +#ifdef __INTEL_COMPILER + use IFPORT +#endif + + implicit none + character(len=1024), intent(in) :: & + loadCaseParameter + character(len=1024) :: & + cwd + integer :: posExt, posSep, error + character :: pathSep + + getLoadCaseFile = loadcaseParameter + pathSep = getPathSep() + posExt = scan(getLoadCaseFile,'.',back=.true.) + posSep = scan(getLoadCaseFile,pathSep,back=.true.) + + if (posExt <= posSep) getLoadCaseFile = trim(getLoadCaseFile)//('.load') ! no extension present + if (scan(getLoadCaseFile,pathSep) /= 1) then ! relative path given as command line argument + error = getcwd(cwd) + getLoadCaseFile = rectifyPath(trim(cwd)//pathSep//getLoadCaseFile) + else + getLoadCaseFile = rectifyPath(getLoadCaseFile) + endif + + getLoadCaseFile = makeRelativePath(getSolverWorkingDirectoryName(), getLoadCaseFile) + +end function getLoadCaseFile + + +!-------------------------------------------------------------------------------------------------- +!> @brief remove ../ and /./ from path +!-------------------------------------------------------------------------------------------------- +function rectifyPath(path) + + implicit none + character(len=*) :: path + character(len=len_trim(path)) :: rectifyPath + character :: pathSep + integer :: i,j,k,l ! no pInt + + pathSep = getPathSep() + +!-------------------------------------------------------------------------------------------------- +! remove /./ from path + l = len_trim(path) + rectifyPath = path + do i = l,3,-1 + if (rectifyPath(i-2:i) == pathSep//'.'//pathSep) & + rectifyPath(i-1:l) = rectifyPath(i+1:l)//' ' + enddo + +!-------------------------------------------------------------------------------------------------- +! remove ../ and corresponding directory from rectifyPath + l = len_trim(rectifyPath) + i = index(rectifyPath(i:l),'..'//pathSep) + j = 0 + do while (i > j) + j = scan(rectifyPath(1:i-2),pathSep,back=.true.) + rectifyPath(j+1:l) = rectifyPath(i+3:l)//repeat(' ',2+i-j) + if (rectifyPath(j+1:j+1) == pathSep) then !search for '//' that appear in case of XXX/../../XXX + k = len_trim(rectifyPath) + rectifyPath(j+1:k-1) = rectifyPath(j+2:k) + rectifyPath(k:k) = ' ' + endif + i = j+index(rectifyPath(j+1:l),'..'//pathSep) + enddo + if(len_trim(rectifyPath) == 0) rectifyPath = pathSep + +end function rectifyPath + + +!-------------------------------------------------------------------------------------------------- +!> @brief relative path from absolute a to absolute b +!-------------------------------------------------------------------------------------------------- +character(len=1024) function makeRelativePath(a,b) + + implicit none + character (len=*) :: a,b + character :: pathSep + integer :: i,posLastCommonSlash,remainingSlashes !no pInt + + pathSep = getPathSep() + posLastCommonSlash = 0 + remainingSlashes = 0 + + do i = 1, min(1024,len_trim(a),len_trim(b)) + if (a(i:i) /= b(i:i)) exit + if (a(i:i) == pathSep) posLastCommonSlash = i + enddo + do i = posLastCommonSlash+1,len_trim(a) + if (a(i:i) == pathSep) remainingSlashes = remainingSlashes + 1 + enddo + makeRelativePath = repeat('..'//pathSep,remainingSlashes)//b(posLastCommonSlash+1:len_trim(b)) + +end function makeRelativePath + + +!-------------------------------------------------------------------------------------------------- +!> @brief counting / and \ in $PATH System variable the character occuring more often is assumed +! to be the path separator +!-------------------------------------------------------------------------------------------------- +character function getPathSep() + + implicit none + character(len=2048) :: & + path + integer(pInt) :: & + backslash = 0_pInt, & + slash = 0_pInt + integer :: i + + call get_environment_variable('PATH',path) + do i=1, len(trim(path)) + if (path(i:i)=='/') slash = slash + 1_pInt + if (path(i:i)=='\') backslash = backslash + 1_pInt + enddo + + if (backslash>slash) then + getPathSep = '\' + else + getPathSep = '/' + endif + +end function getPathSep + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_stringValue for documentation +!-------------------------------------------------------------------------------------------------- +pure function IIO_stringValue(string,chunkPos,myChunk) + + implicit none + integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string + integer(pInt), intent(in) :: myChunk !< position number of desired chunk + character(len=1+chunkPos(myChunk*2+1)-chunkPos(myChunk*2)) :: IIO_stringValue + character(len=*), intent(in) :: string !< raw input with known start and end of each chunk + + + valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then + IIO_stringValue = '' + else valuePresent + IIO_stringValue = string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)) + endif valuePresent + +end function IIO_stringValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_intValue for documentation +!-------------------------------------------------------------------------------------------------- +integer(pInt) pure function IIO_intValue(string,chunkPos,myChunk) + + implicit none + character(len=*), intent(in) :: string !< raw input with known start and end of each chunk + integer(pInt), intent(in) :: myChunk !< position number of desired sub string + integer(pInt), dimension(:), intent(in) :: chunkPos !< positions of start and end of each tag/chunk in given string + + + valuePresent: if (myChunk > chunkPos(1) .or. myChunk < 1_pInt) then + IIO_intValue = 0_pInt + else valuePresent + read(UNIT=string(chunkPos(myChunk*2):chunkPos(myChunk*2+1)),ERR=100,FMT=*) IIO_intValue + endif valuePresent + return +100 IIO_intValue = huge(1_pInt) + +end function IIO_intValue + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_lc for documentation +!-------------------------------------------------------------------------------------------------- +pure function IIO_lc(string) + + implicit none + character(len=*), intent(in) :: string !< string to convert + character(len=len(string)) :: IIO_lc + + character(26), parameter :: LOWER = 'abcdefghijklmnopqrstuvwxyz' + character(26), parameter :: UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + + integer :: i,n ! no pInt (len returns default integer) + + IIO_lc = string + do i=1,len(string) + n = index(UPPER,IIO_lc(i:i)) + if (n/=0) IIO_lc(i:i) = LOWER(n:n) + enddo + +end function IIO_lc + + +!-------------------------------------------------------------------------------------------------- +!> @brief taken from IO, check IO_stringPos for documentation +!-------------------------------------------------------------------------------------------------- +pure function IIO_stringPos(string) + + implicit none + integer(pInt), dimension(:), allocatable :: IIO_stringPos + character(len=*), intent(in) :: string !< string in which chunks are searched for + + character(len=*), parameter :: SEP=achar(44)//achar(32)//achar(9)//achar(10)//achar(13) ! comma and whitespaces + integer :: left, right ! no pInt (verify and scan return default integer) + + allocate(IIO_stringPos(1), source=0_pInt) + right = 0 + + do while (verify(string(right+1:),SEP)>0) + left = right + verify(string(right+1:),SEP) + right = left + scan(string(left:),SEP) - 2 + if ( string(left:left) == '#' ) exit + IIO_stringPos = [IIO_stringPos,int(left, pInt), int(right, pInt)] + IIO_stringPos(1) = IIO_stringPos(1)+1_pInt + enddo + +end function IIO_stringPos + + +end module diff --git a/src/spectral_mech_AL.f90 b/src/spectral_mech_AL.f90 new file mode 100644 index 000000000..a937dcc86 --- /dev/null +++ b/src/spectral_mech_AL.f90 @@ -0,0 +1,715 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief AL scheme solver +!-------------------------------------------------------------------------------------------------- +module spectral_mech_AL + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + + implicit none + private +#include + + character (len=*), parameter, public :: & + DAMASK_spectral_solverAL_label = 'al' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! PETSc data + DM, private :: da + SNES, private :: snes + Vec, private :: solution_vec + +!-------------------------------------------------------------------------------------------------- +! common pointwise data + real(pReal), private, dimension(:,:,:,:,:), allocatable :: & + F_lastInc, & !< field of previous compatible deformation gradients + F_lambda_lastInc, & !< field of previous incompatible deformation gradient + Fdot, & !< field of assumed rate of compatible deformation gradient + F_lambdaDot !< field of assumed rate of incopatible deformation gradient + +!-------------------------------------------------------------------------------------------------- +! stress, stiffness and compliance average etc. + real(pReal), private, dimension(3,3) :: & + F_aimDot, & !< assumed rate of average deformation gradient + F_aim = math_I3, & !< current prescribed deformation gradient + F_aim_lastInc = math_I3, & !< previous average deformation gradient + F_av = 0.0_pReal, & !< average incompatible def grad field + P_av = 0.0_pReal, & !< average 1st Piola--Kirchhoff stress + P_avLastEval = 0.0_pReal !< average 1st Piola--Kirchhoff stress last call of CPFEM_general + character(len=1024), private :: incInfo !< time and increment information + real(pReal), private, dimension(3,3,3,3) :: & + C_volAvg = 0.0_pReal, & !< current volume average stiffness + C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness + C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness + S = 0.0_pReal, & !< current compliance (filled up with zeros) + C_scale = 0.0_pReal, & + S_scale = 0.0_pReal + + real(pReal), private :: & + err_BC, & !< deviation from stress BC + err_curl, & !< RMS of curl of F + err_div !< RMS of div of P + logical, private :: ForwardData + integer(pInt), private :: & + totalIter = 0_pInt !< total iteration in current increment + + public :: & + AL_init, & + AL_solution, & + AL_forward, & + AL_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!> @todo use sourced allocation, e.g. allocate(Fdot,source = F_lastInc) +!-------------------------------------------------------------------------------------------------- +subroutine AL_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRestart + use FEsolving, only: & + restartInc + use numerics, only: & + worldrank, & + worldsize + use DAMASK_interface, only: & + getSolverJobName + use spectral_utilities, only: & + Utilities_constitutiveResponse, & + Utilities_updateGamma, & + Utilities_updateIPcoords + use mesh, only: & + grid, & + grid3 + use math, only: & + math_invSym3333 + + implicit none + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P + real(pReal), dimension(3,3) :: & + temp33_Real = 0.0_pReal + + PetscErrorCode :: ierr + PetscObject :: dummy + PetscScalar, pointer, dimension(:,:,:,:) :: xx_psc, F, F_lambda + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + character(len=1024) :: rankStr + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverAL init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif + +!-------------------------------------------------------------------------------------------------- +! 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_lambda_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate (F_lambdaDot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + +!-------------------------------------------------------------------------------------------------- +! PETSc Init + call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary + DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & ! global grid + 1 , 1, worldsize, & + 18, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) + grid(1),grid(2),localK, & ! local grid + da,ierr) ! handle, error + CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) + call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) + call DMDASNESSetFunctionLocal(da,INSERT_VALUES,AL_formResidual,dummy,ierr) + CHKERRQ(ierr) + call SNESSetConvergenceTest(snes,AL_converged,dummy,PETSC_NULL_FUNCTION,ierr) + CHKERRQ(ierr) + call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! places pointer xx_psc on PETSc data + F => xx_psc(0:8,:,:,:) + F_lambda => xx_psc(9:17,:,:,:) + restart: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading values of increment ', restartInc - 1_pInt, ' from file' + flush(6) + write(rankStr,'(a1,i0)')'_',worldrank + call IO_read_realFile(777,'F'//trim(rankStr), trim(getSolverJobName()),size(F)) + read (777,rec=1) F + close (777) + call IO_read_realFile(777,'F_lastInc'//trim(rankStr), trim(getSolverJobName()),size(F_lastInc)) + read (777,rec=1) F_lastInc + close (777) + call IO_read_realFile(777,'F_lambda'//trim(rankStr),trim(getSolverJobName()),size(F_lambda)) + read (777,rec=1) F_lambda + close (777) + call IO_read_realFile(777,'F_lambda_lastInc'//trim(rankStr),& + trim(getSolverJobName()),size(F_lambda_lastInc)) + read (777,rec=1) F_lambda_lastInc + close (777) + call IO_read_realFile(777,'F_aim', trim(getSolverJobName()),size(F_aim)) + read (777,rec=1) F_aim + close (777) + call IO_read_realFile(777,'F_aim_lastInc', trim(getSolverJobName()),size(F_aim_lastInc)) + read (777,rec=1) F_aim_lastInc + close (777) + call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) + read (777,rec=1) f_aimDot + close (777) + elseif (restartInc == 1_pInt) then restart + F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity + F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) + F_lambda = F + F_lambda_lastInc = F_lastInc + endif restart + + + call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) + call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & + 0.0_pReal,P,C_volAvg,C_minMaxAvg,temp33_Real,.false.,math_I3) + nullify(F) + nullify(F_lambda) + call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! write data back to PETSc + + readRestart: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading more values of increment', restartInc - 1_pInt, 'from file' + flush(6) + call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) + read (777,rec=1) C_volAvg + close (777) + call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) + read (777,rec=1) C_volAvgLastInc + close (777) + call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) + read (777,rec=1) C_minMaxAvg + close (777) + endif readRestart + + call Utilities_updateGamma(C_minMaxAvg,.True.) + C_scale = C_minMaxAvg + S_scale = math_invSym3333(C_minMaxAvg) + +end subroutine AL_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the AL scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function & + AL_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) + use IO, only: & + IO_error + use numerics, only: & + update_gamma + use math, only: & + math_invSym3333 + use spectral_utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use FEsolving, only: & + restartWrite, & + terminallyIll + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + logical, intent(in) :: & + guess + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + character(len=*), intent(in) :: & + incInfoIn + real(pReal), dimension(3,3), intent(in) :: rotation_BC + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + incInfo = incInfoIn + +!-------------------------------------------------------------------------------------------------- +! update stiffness (and gamma operator) + S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) + if (update_gamma) then + call Utilities_updateGamma(C_minMaxAvg,restartWrite) + C_scale = C_minMaxAvg + S_scale = math_invSym3333(C_minMaxAvg) + endif + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + mask_stress = P_BC%maskFloat + params%P_BC = P_BC%values + params%rotation_BC = rotation_BC + params%timeinc = timeinc + params%timeincOld = timeinc_old + +!-------------------------------------------------------------------------------------------------- +! solve BVP + call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) + CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! check convergence + call SNESGetConvergedReason(snes,reason,ierr) + CHKERRQ(ierr) + AL_solution%termIll = terminallyIll + terminallyIll = .false. + if (reason == -4) call IO_error(893_pInt) + if (reason < 1) AL_solution%converged = .false. + AL_solution%iterationsNeeded = totalIter + +end function AL_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the AL residual vector +!-------------------------------------------------------------------------------------------------- +subroutine AL_formResidual(in,x_scal,f_scal,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + polarAlpha, & + polarBeta, & + worldrank + use mesh, only: & + grid3, & + grid + use IO, only: & + IO_intOut + use math, only: & + math_rotate_backward33, & + math_transpose33, & + math_mul3333xx33, & + math_invSym3333, & + math_mul33x33 + use spectral_utilities, only: & + wgt, & + tensorField_real, & + utilities_FFTtensorForward, & + utilities_fourierGammaConvolution, & + utilities_FFTtensorBackward, & + Utilities_constitutiveResponse, & + Utilities_divergenceRMS, & + Utilities_curlRMS + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRotation + use homogenization, only: & + materialpoint_dPdF + use FEsolving, only: & + terminallyIll + + implicit none +!-------------------------------------------------------------------------------------------------- +! strange syntax in the next line because otherwise macros expand beyond 132 character limit + DMDALocalInfo, dimension(& + DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, target, dimension(3,3,2, & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, target, dimension(3,3,2, & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscScalar, pointer, dimension(:,:,:,:,:) :: & + F, & + F_lambda, & + residual_F, & + residual_F_lambda + PetscInt :: & + PETScIter, & + nfuncs + PetscObject :: dummy + PetscErrorCode :: ierr + integer(pInt) :: & + i, j, k, e + + F => x_scal(1:3,1:3,1,& + XG_RANGE,YG_RANGE,ZG_RANGE) + F_lambda => x_scal(1:3,1:3,2,& + XG_RANGE,YG_RANGE,ZG_RANGE) + residual_F => f_scal(1:3,1:3,1,& + X_RANGE,Y_RANGE,Z_RANGE) + residual_F_lambda => f_scal(1:3,1:3,2,& + X_RANGE,Y_RANGE,Z_RANGE) + + call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) + call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) + + F_av = sum(sum(sum(F,dim=5),dim=4),dim=3) * wgt + call MPI_Allreduce(MPI_IN_PLACE,F_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + + if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment + newIteration: if(totalIter <= PETScIter) then +!-------------------------------------------------------------------------------------------------- +! report begin of new iteration + totalIter = totalIter + 1_pInt + if (worldrank == 0_pInt) then + write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & + ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax + if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & + math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & + math_transpose33(F_aim) + flush(6) + endif + endif newIteration + +!-------------------------------------------------------------------------------------------------- +! + tensorField_real = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) + tensorField_real(1:3,1:3,i,j,k) = & + polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& + polarAlpha*math_mul33x33(F(1:3,1:3,i,j,k), & + math_mul3333xx33(C_scale,F_lambda(1:3,1:3,i,j,k) - math_I3)) + + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! doing convolution in Fourier space + call utilities_FFTtensorForward() + call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) + call utilities_FFTtensorBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + residual_F_lambda = polarBeta*F - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) + +!-------------------------------------------------------------------------------------------------- +! evaluate constitutive response + P_avLastEval = P_av + call Utilities_constitutiveResponse(F_lastInc,F - residual_F_lambda/polarBeta,params%timeinc, & + residual_F,C_volAvg,C_minMaxAvg,P_av,ForwardData,params%rotation_BC) + call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) + ForwardData = .False. + +!-------------------------------------------------------------------------------------------------- +! calculate divergence + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = residual_F + call utilities_FFTtensorForward() + err_div = Utilities_divergenceRMS() + call utilities_FFTtensorBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + e = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) + e = e + 1_pInt + residual_F(1:3,1:3,i,j,k) = math_mul3333xx33(math_invSym3333(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & + residual_F(1:3,1:3,i,j,k) - & + math_mul33x33(F(1:3,1:3,i,j,k), & + math_mul3333xx33(C_scale,F_lambda(1:3,1:3,i,j,k) - math_I3))) & + + residual_F_lambda(1:3,1:3,i,j,k) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! calculating curl + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F + call utilities_FFTtensorForward() + err_curl = Utilities_curlRMS() + call utilities_FFTtensorBackward() + +end subroutine AL_formResidual + + +!-------------------------------------------------------------------------------------------------- +!> @brief convergence check +!-------------------------------------------------------------------------------------------------- +subroutine AL_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + err_div_tolRel, & + err_div_tolAbs, & + err_curl_tolRel, & + err_curl_tolAbs, & + err_stress_tolAbs, & + err_stress_tolRel, & + worldrank + use math, only: & + math_mul3333xx33 + use FEsolving, only: & + terminallyIll + + implicit none + SNES :: snes_local + PetscInt :: PETScIter + PetscReal :: & + xnorm, & + snorm, & + fnorm + SNESConvergedReason :: reason + PetscObject :: dummy + PetscErrorCode ::ierr + real(pReal) :: & + curlTol, & + divTol, & + BC_tol + +!-------------------------------------------------------------------------------------------------- +! stress BC handling + F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc + err_BC = maxval(abs((-mask_stress+1.0_pReal)*math_mul3333xx33(C_scale,F_aim-F_av) + & + mask_stress *(P_av - params%P_BC))) ! mask = 0.0 for no bc + +!-------------------------------------------------------------------------------------------------- +! error calculation + curlTol = max(maxval(abs(F_aim-math_I3))*err_curl_tolRel,err_curl_tolAbs) + divTol = max(maxval(abs(P_av)) *err_div_tolRel,err_div_tolAbs) + BC_tol = max(maxval(abs(P_av)) *err_stress_tolrel,err_stress_tolabs) + + converged: if ((totalIter >= itmin .and. & + all([ err_div/divTol, & + err_curl/curlTol, & + err_BC/BC_tol ] < 1.0_pReal)) & + .or. terminallyIll) then + reason = 1 + elseif (totalIter >= itmax) then converged + reason = -1 + else converged + reason = 0 + endif converged + +!-------------------------------------------------------------------------------------------------- +! report + if (worldrank == 0_pInt) then + write(6,'(1/,a)') ' ... reporting .............................................................' + write(6,'(/,a,f12.2,a,es8.2,a,es9.2,a)') ' error curl = ', & + err_curl/curlTol,' (',err_curl,' -, tol =',curlTol,')' + write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & + err_div/divTol, ' (',err_div, ' / m, tol =',divTol,')' + write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error BC = ', & + err_BC/BC_tol, ' (',err_BC, ' Pa, tol =',BC_tol,')' + write(6,'(/,a)') ' ===========================================================================' + flush(6) + endif + +end subroutine AL_converged + +!-------------------------------------------------------------------------------------------------- +!> @brief forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine AL_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) + use math, only: & + math_mul33x33, & + math_mul3333xx33, & + math_transpose33, & + math_rotate_backward33 + use numerics, only: & + worldrank + use mesh, only: & + grid3, & + grid + use spectral_utilities, only: & + Utilities_calculateRate, & + Utilities_forwardField, & + Utilities_updateIPcoords, & + tBoundaryCondition, & + cutBack + use IO, only: & + IO_write_JobRealFile + use FEsolving, only: & + restartWrite + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + real(pReal), dimension(3,3), intent(in) :: rotation_BC + logical, intent(in) :: & + guess + PetscErrorCode :: ierr + PetscScalar, dimension(:,:,:,:), pointer :: xx_psc, F, F_lambda + integer(pInt) :: i, j, k + real(pReal), dimension(3,3) :: F_lambda33 + character(len=1024) :: rankStr + +!-------------------------------------------------------------------------------------------------- +! update coordinates and rate and forward last inc + call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr) + F => xx_psc(0:8,:,:,:) + F_lambda => xx_psc(9:17,:,:,:) + if (restartWrite) then + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' writing converged results for restart' + flush(6) + endif + write(rankStr,'(a1,i0)')'_',worldrank + call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file + write (777,rec=1) F + close (777) + call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file + write (777,rec=1) F_lastInc + close (777) + call IO_write_jobRealFile(777,'F_lambda'//trim(rankStr),size(F_lambda)) ! writing deformation gradient field to file + write (777,rec=1) F_lambda + close (777) + call IO_write_jobRealFile(777,'F_lambda_lastInc'//trim(rankStr),size(F_lambda_lastInc)) ! writing F_lastInc field to file + write (777,rec=1) F_lambda_lastInc + close (777) + if (worldrank == 0_pInt) then + call IO_write_jobRealFile(777,'F_aim',size(F_aim)) + write (777,rec=1) F_aim + close(777) + call IO_write_jobRealFile(777,'F_aim_lastInc',size(F_aim_lastInc)) + write (777,rec=1) F_aim_lastInc + close(777) + call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) + write (777,rec=1) F_aimDot + close(777) + call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) + write (777,rec=1) C_volAvg + close(777) + call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) + write (777,rec=1) C_volAvgLastInc + close(777) + endif + endif + + call utilities_updateIPcoords(F) + + if (cutBack) then + F_aim = F_aim_lastInc + F_lambda = reshape(F_lambda_lastInc,[9,grid(1),grid(2),grid3]) + F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) + C_volAvg = C_volAvgLastInc + else + ForwardData = .True. + C_volAvgLastInc = C_volAvg +!-------------------------------------------------------------------------------------------------- +! calculate rate for aim + if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F + f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) + elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed + f_aimDot = F_BC%maskFloat * F_BC%values + elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed + f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime + endif + if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old + F_aim_lastInc = F_aim + +!-------------------------------------------------------------------------------------------------- +! update coordinates and rate and forward last inc + call utilities_updateIPcoords(F) + Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & + timeinc_old,guess,F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3])) + F_lambdaDot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & + timeinc_old,guess,F_lambda_lastInc,reshape(F_lambda,[3,3,grid(1),grid(2),grid3])) + F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) + F_lambda_lastInc = reshape(F_lambda,[3,3,grid(1),grid(2),grid3]) + endif + + F_aim = F_aim + f_aimDot * timeinc + +!-------------------------------------------------------------------------------------------------- +! update local deformation gradient + F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim + math_rotate_backward33(F_aim,rotation_BC)), & + [9,grid(1),grid(2),grid3]) + F_lambda = reshape(Utilities_forwardField(timeinc,F_lambda_lastInc,F_lambdadot), & + [9,grid(1),grid(2),grid3]) ! does not have any average value as boundary condition + if (.not. guess) then ! large strain forwarding + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) + F_lambda33 = reshape(F_lambda(1:9,i,j,k),[3,3]) + F_lambda33 = math_mul3333xx33(S_scale,math_mul33x33(F_lambda33, & + math_mul3333xx33(C_scale,& + math_mul33x33(math_transpose33(F_lambda33),& + F_lambda33) -math_I3))*0.5_pReal)& + + math_I3 + F_lambda(1:9,i,j,k) = reshape(F_lambda33,[9]) + enddo; enddo; enddo + endif + call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) + +end subroutine AL_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine AL_destroy() + use spectral_utilities, only: & + Utilities_destroy + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) + call SNESDestroy(snes,ierr); CHKERRQ(ierr) + call DMDestroy(da,ierr); CHKERRQ(ierr) + +end subroutine AL_destroy + +end module spectral_mech_AL diff --git a/src/spectral_mech_Basic.f90 b/src/spectral_mech_Basic.f90 new file mode 100644 index 000000000..a8344fabe --- /dev/null +++ b/src/spectral_mech_Basic.f90 @@ -0,0 +1,569 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Basic scheme PETSc solver +!-------------------------------------------------------------------------------------------------- +module spectral_mech_basic + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + + implicit none + private +#include + + character (len=*), parameter, public :: & + DAMASK_spectral_SolverBasicPETSC_label = 'basicpetsc' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + +!-------------------------------------------------------------------------------------------------- +! PETSc data + DM, private :: da + SNES, private :: snes + Vec, private :: solution_vec + +!-------------------------------------------------------------------------------------------------- +! common pointwise data + real(pReal), private, dimension(:,:,:,:,:), allocatable :: F_lastInc, Fdot + +!-------------------------------------------------------------------------------------------------- +! stress, stiffness and compliance average etc. + real(pReal), private, dimension(3,3) :: & + F_aim = math_I3, & + F_aim_lastIter = math_I3, & + F_aim_lastInc = math_I3, & + P_av = 0.0_pReal, & + F_aimDot=0.0_pReal + character(len=1024), private :: incInfo + real(pReal), private, dimension(3,3,3,3) :: & + C_volAvg = 0.0_pReal, & !< current volume average stiffness + C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness + C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness + S = 0.0_pReal !< current compliance (filled up with zeros) + real(pReal), private :: err_stress, err_div + logical, private :: ForwardData + integer(pInt), private :: & + totalIter = 0_pInt !< total iteration in current increment + real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal + + public :: & + basicPETSc_init, & + basicPETSc_solution, & + BasicPETSc_forward, & + basicPETSc_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!-------------------------------------------------------------------------------------------------- +subroutine basicPETSc_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRestart + use FEsolving, only: & + restartInc + use numerics, only: & + worldrank, & + worldsize + use DAMASK_interface, only: & + getSolverJobName + use spectral_utilities, only: & + Utilities_constitutiveResponse, & + Utilities_updateGamma, & + utilities_updateIPcoords, & + wgt + use mesh, only: & + grid, & + grid3 + use math, only: & + math_invSym3333 + + implicit none + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P + PetscScalar, dimension(:,:,:,:), pointer :: F + PetscErrorCode :: ierr + PetscObject :: dummy + real(pReal), dimension(3,3) :: & + temp33_Real = 0.0_pReal + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + character(len=1024) :: rankStr + + mainProcess: if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverBasicPETSc init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! 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) + +!-------------------------------------------------------------------------------------------------- +! initialize solver specific parts of PETSc + call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary + DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & ! global grid + 1, 1, worldsize, & + 9, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) + grid (1),grid (2),localK, & ! local grid + da,ierr) ! handle, error + CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) + call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) ! global solution vector (grid x 9, i.e. every def grad tensor) + call DMDASNESSetFunctionLocal(da,INSERT_VALUES,BasicPETSC_formResidual,dummy,ierr) ! residual vector of same shape as solution vector + CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) ! connect snes to da + call SNESSetConvergenceTest(snes,BasicPETSC_converged,dummy,PETSC_NULL_FUNCTION,ierr) ! specify custom convergence check function "_converged" + CHKERRQ(ierr) + call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAVecGetArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) ! get the data out of PETSc to work with + + restart: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading values of increment ', restartInc - 1_pInt, ' from file' + flush(6) + write(rankStr,'(a1,i0)')'_',worldrank + call IO_read_realFile(777,'F'//trim(rankStr),trim(getSolverJobName()),size(F)) + read (777,rec=1) F + close (777) + call IO_read_realFile(777,'F_lastInc'//trim(rankStr),trim(getSolverJobName()),size(F_lastInc)) + read (777,rec=1) F_lastInc + close (777) + call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) + read (777,rec=1) f_aimDot + close (777) + F_aim = reshape(sum(sum(sum(F,dim=4),dim=3),dim=2) * wgt, [3,3]) ! average of F + F_aim_lastInc = sum(sum(sum(F_lastInc,dim=5),dim=4),dim=3) * wgt ! average of F_lastInc + elseif (restartInc == 1_pInt) then restart + F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity + F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) + endif restart + + call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) + call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & + 0.0_pReal, & + P, & + C_volAvg,C_minMaxAvg, & ! global average of stiffness and (min+max)/2 + temp33_Real, & + .false., & + math_I3) + + call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) ! write data back to PETSc + + restartRead: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading more values of increment', restartInc - 1_pInt, 'from file' + flush(6) + call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) + read (777,rec=1) C_volAvg + close (777) + call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) + read (777,rec=1) C_volAvgLastInc + close (777) + call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) + read (777,rec=1) C_minMaxAvg + close (777) + endif restartRead + + call Utilities_updateGamma(C_minmaxAvg,.True.) + +end subroutine basicPETSc_init + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the Basic PETSC scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function & + basicPETSc_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) + use IO, only: & + IO_error + use numerics, only: & + update_gamma + use spectral_utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use FEsolving, only: & + restartWrite, & + terminallyIll + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + character(len=*), intent(in) :: & + incInfoIn + real(pReal), dimension(3,3), intent(in) :: rotation_BC + logical, intent(in) :: & + guess + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + incInfo = incInfoIn + +!-------------------------------------------------------------------------------------------------- +! update stiffness (and gamma operator) + S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) + if (update_gamma) call Utilities_updateGamma(C_minmaxAvg,restartWrite) + + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + mask_stress = P_BC%maskFloat + params%P_BC = P_BC%values + params%rotation_BC = rotation_BC + params%timeinc = timeinc + params%timeincOld = timeinc_old + +!-------------------------------------------------------------------------------------------------- +! solve BVP + call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) + CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! check convergence + call SNESGetConvergedReason(snes,reason,ierr) + CHKERRQ(ierr) + basicPETSc_solution%termIll = terminallyIll + terminallyIll = .false. + BasicPETSc_solution%converged =.true. + if (reason == -4) call IO_error(893_pInt) + if (reason < 1) basicPETSC_solution%converged = .false. + basicPETSC_solution%iterationsNeeded = totalIter + +end function BasicPETSc_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the AL residual vector +!-------------------------------------------------------------------------------------------------- +subroutine BasicPETSC_formResidual(in,x_scal,f_scal,dummy,ierr) + use numerics, only: & + itmax, & + itmin + use numerics, only: & + worldrank + use mesh, only: & + grid, & + grid3 + use math, only: & + math_rotate_backward33, & + math_transpose33, & + math_mul3333xx33 + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRotation + use spectral_utilities, only: & + tensorField_real, & + utilities_FFTtensorForward, & + utilities_FFTtensorBackward, & + utilities_fourierGammaConvolution, & + Utilities_constitutiveResponse, & + Utilities_divergenceRMS + use IO, only: & + IO_intOut + use FEsolving, only: & + terminallyIll + + implicit none + DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, dimension(3,3, & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, dimension(3,3, & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscInt :: & + PETScIter, & + nfuncs + PetscObject :: dummy + PetscErrorCode :: ierr + + call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) + call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) + + if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment + newIteration: if (totalIter <= PETScIter) then +!-------------------------------------------------------------------------------------------------- +! report begin of new iteration + totalIter = totalIter + 1_pInt + if (worldrank == 0_pInt) then + write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & + ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax + if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & + math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & + math_transpose33(F_aim) + flush(6) + endif + endif newIteration + +!-------------------------------------------------------------------------------------------------- +! evaluate constitutive response + call Utilities_constitutiveResponse(F_lastInc,x_scal,params%timeinc, & + f_scal,C_volAvg,C_minmaxAvg,P_av,ForwardData,params%rotation_BC) + call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) + ForwardData = .false. + +!-------------------------------------------------------------------------------------------------- +! stress BC handling + F_aim_lastIter = F_aim + F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc + err_stress = maxval(abs(mask_stress * (P_av - params%P_BC))) ! mask = 0.0 for no bc + +!-------------------------------------------------------------------------------------------------- +! updated deformation gradient using fix point algorithm of basic scheme + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = f_scal + call utilities_FFTtensorForward() + err_div = Utilities_divergenceRMS() + call utilities_fourierGammaConvolution(math_rotate_backward33(F_aim_lastIter-F_aim,params%rotation_BC)) + call utilities_FFTtensorBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + f_scal = tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) + +end subroutine BasicPETSc_formResidual + + +!-------------------------------------------------------------------------------------------------- +!> @brief convergence check +!-------------------------------------------------------------------------------------------------- +subroutine BasicPETSc_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + err_div_tolRel, & + err_div_tolAbs, & + err_stress_tolRel, & + err_stress_tolAbs, & + worldrank + use FEsolving, only: & + terminallyIll + + implicit none + SNES :: snes_local + PetscInt :: PETScIter + PetscReal :: & + xnorm, & + snorm, & + fnorm + SNESConvergedReason :: reason + PetscObject :: dummy + PetscErrorCode :: ierr + real(pReal) :: & + divTol, & + stressTol + + divTol = max(maxval(abs(P_av))*err_div_tolRel,err_div_tolAbs) + stressTol = max(maxval(abs(P_av))*err_stress_tolrel,err_stress_tolabs) + + converged: if ((totalIter >= itmin .and. & + all([ err_div/divTol, & + err_stress/stressTol ] < 1.0_pReal)) & + .or. terminallyIll) then + reason = 1 + elseif (totalIter >= itmax) then converged + reason = -1 + else converged + reason = 0 + endif converged + +!-------------------------------------------------------------------------------------------------- +! report + if (worldrank == 0_pInt) then + write(6,'(1/,a)') ' ... reporting .............................................................' + write(6,'(1/,a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & + err_div/divTol, ' (',err_div,' / m, tol =',divTol,')' + write(6,'(a,f12.2,a,es8.2,a,es9.2,a)') ' error stress BC = ', & + err_stress/stressTol, ' (',err_stress, ' Pa, tol =',stressTol,')' + write(6,'(/,a)') ' ===========================================================================' + flush(6) + endif + +end subroutine BasicPETSc_converged + +!-------------------------------------------------------------------------------------------------- +!> @brief forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine BasicPETSc_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) + use math, only: & + math_mul33x33 ,& + math_rotate_backward33 + use mesh, only: & + grid, & + grid3 + use spectral_utilities, only: & + Utilities_calculateRate, & + Utilities_forwardField, & + utilities_updateIPcoords, & + tBoundaryCondition, & + cutBack + use IO, only: & + IO_write_JobRealFile + use FEsolving, only: & + restartWrite + use numerics, only: & + worldrank + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + real(pReal), dimension(3,3), intent(in) :: rotation_BC + logical, intent(in) :: & + guess + PetscScalar, pointer :: F(:,:,:,:) + PetscErrorCode :: ierr + character(len=1024) :: rankStr + + call DMDAVecGetArrayF90(da,solution_vec,F,ierr) +!-------------------------------------------------------------------------------------------------- +! restart information for spectral solver + if (restartWrite) then + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' writing converged results for restart' + flush(6) + endif + write(rankStr,'(a1,i0)')'_',worldrank + call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file + write (777,rec=1) F + close (777) + call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file + write (777,rec=1) F_lastInc + close (777) + if (worldrank == 0_pInt) then + call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) + write (777,rec=1) F_aimDot + close(777) + call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) + write (777,rec=1) C_volAvg + close(777) + call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) + write (777,rec=1) C_volAvgLastInc + close(777) + endif + endif + + call utilities_updateIPcoords(F) + + if (cutBack) then + F_aim = F_aim_lastInc + F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) + C_volAvg = C_volAvgLastInc + else + ForwardData = .True. + C_volAvgLastInc = C_volAvg +!-------------------------------------------------------------------------------------------------- +! calculate rate for aim + if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F + f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) + elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed + f_aimDot = F_BC%maskFloat * F_BC%values + elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed + f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime + endif + if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old + F_aim_lastInc = F_aim + +!-------------------------------------------------------------------------------------------------- +! update coordinates and rate and forward last inc + call utilities_updateIPcoords(F) + Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & + timeinc_old,guess,F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3])) + F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) + endif + F_aim = F_aim + f_aimDot * timeinc + +!-------------------------------------------------------------------------------------------------- +! update local deformation gradient + F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim + math_rotate_backward33(F_aim,rotation_BC)),[9,grid(1),grid(2),grid3]) + call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) + +end subroutine BasicPETSc_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine BasicPETSc_destroy() + use spectral_utilities, only: & + Utilities_destroy + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) + call SNESDestroy(snes,ierr); CHKERRQ(ierr) + call DMDestroy(da,ierr); CHKERRQ(ierr) + +end subroutine BasicPETSc_destroy + +end module spectral_mech_basic diff --git a/src/spectral_mech_Polarisation.f90 b/src/spectral_mech_Polarisation.f90 new file mode 100644 index 000000000..a28eb5adb --- /dev/null +++ b/src/spectral_mech_Polarisation.f90 @@ -0,0 +1,712 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Polarisation scheme solver +!-------------------------------------------------------------------------------------------------- +module spectral_mech_Polarisation + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + + implicit none + private +#include + + character (len=*), parameter, public :: & + DAMASK_spectral_solverPolarisation_label = 'polarisation' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! PETSc data + DM, private :: da + SNES, private :: snes + Vec, private :: solution_vec + +!-------------------------------------------------------------------------------------------------- +! common pointwise data + real(pReal), private, dimension(:,:,:,:,:), allocatable :: & + F_lastInc, & !< field of previous compatible deformation gradients + F_tau_lastInc, & !< field of previous incompatible deformation gradient + Fdot, & !< field of assumed rate of compatible deformation gradient + F_tauDot !< field of assumed rate of incopatible deformation gradient + +!-------------------------------------------------------------------------------------------------- +! stress, stiffness and compliance average etc. + real(pReal), private, dimension(3,3) :: & + F_aimDot, & !< assumed rate of average deformation gradient + F_aim = math_I3, & !< current prescribed deformation gradient + F_aim_lastInc = math_I3, & !< previous average deformation gradient + F_av = 0.0_pReal, & !< average incompatible def grad field + P_av = 0.0_pReal, & !< average 1st Piola--Kirchhoff stress + P_avLastEval = 0.0_pReal !< average 1st Piola--Kirchhoff stress last call of CPFEM_general + character(len=1024), private :: incInfo !< time and increment information + real(pReal), private, dimension(3,3,3,3) :: & + C_volAvg = 0.0_pReal, & !< current volume average stiffness + C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness + C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness + S = 0.0_pReal, & !< current compliance (filled up with zeros) + C_scale = 0.0_pReal, & + S_scale = 0.0_pReal + + real(pReal), private :: & + err_BC, & !< deviation from stress BC + err_curl, & !< RMS of curl of F + err_div !< RMS of div of P + logical, private :: ForwardData + integer(pInt), private :: & + totalIter = 0_pInt !< total iteration in current increment + + public :: & + Polarisation_init, & + Polarisation_solution, & + Polarisation_forward, & + Polarisation_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!> @todo use sourced allocation, e.g. allocate(Fdot,source = F_lastInc) +!-------------------------------------------------------------------------------------------------- +subroutine Polarisation_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRestart + use FEsolving, only: & + restartInc + use numerics, only: & + worldrank, & + worldsize + use DAMASK_interface, only: & + getSolverJobName + use spectral_utilities, only: & + Utilities_constitutiveResponse, & + Utilities_updateGamma, & + Utilities_updateIPcoords + use mesh, only: & + grid, & + grid3 + use math, only: & + math_invSym3333 + + implicit none + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P + real(pReal), dimension(3,3) :: & + temp33_Real = 0.0_pReal + + PetscErrorCode :: ierr + PetscObject :: dummy + PetscScalar, pointer, dimension(:,:,:,:) :: xx_psc, F, F_tau + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + character(len=1024) :: rankStr + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverPolarisation init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif + +!-------------------------------------------------------------------------------------------------- +! 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_tau_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate (F_tauDot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + +!-------------------------------------------------------------------------------------------------- +! PETSc Init + call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary + DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & ! global grid + 1 , 1, worldsize, & + 18, 0, & ! #dof (F tensor), ghost boundary width (domain overlap) + grid (1),grid (2),localK, & ! local grid + da,ierr) ! handle, error + CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) + call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) + call DMDASNESSetFunctionLocal(da,INSERT_VALUES,Polarisation_formResidual,dummy,ierr) + CHKERRQ(ierr) + call SNESSetConvergenceTest(snes,Polarisation_converged,dummy,PETSC_NULL_FUNCTION,ierr) + CHKERRQ(ierr) + call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! places pointer xx_psc on PETSc data + F => xx_psc(0:8,:,:,:) + F_tau => xx_psc(9:17,:,:,:) + restart: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading values of increment', restartInc - 1_pInt, 'from file' + flush(6) + write(rankStr,'(a1,i0)')'_',worldrank + call IO_read_realFile(777,'F'//trim(rankStr),trim(getSolverJobName()),size(F)) + read (777,rec=1) F + close (777) + call IO_read_realFile(777,'F_lastInc'//trim(rankStr),trim(getSolverJobName()),size(F_lastInc)) + read (777,rec=1) F_lastInc + close (777) + call IO_read_realFile(777,'F_tau'//trim(rankStr),trim(getSolverJobName()),size(F_tau)) + read (777,rec=1) F_tau + close (777) + call IO_read_realFile(777,'F_tau_lastInc'//trim(rankStr),& + trim(getSolverJobName()),size(F_tau_lastInc)) + read (777,rec=1) F_tau_lastInc + close (777) + call IO_read_realFile(777,'F_aim', trim(getSolverJobName()),size(F_aim)) + read (777,rec=1) F_aim + close (777) + call IO_read_realFile(777,'F_aim_lastInc', trim(getSolverJobName()),size(F_aim_lastInc)) + read (777,rec=1) F_aim_lastInc + close (777) + call IO_read_realFile(777,'F_aimDot',trim(getSolverJobName()),size(f_aimDot)) + read (777,rec=1) f_aimDot + close (777) + elseif (restartInc == 1_pInt) then restart + F_lastInc = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) ! initialize to identity + F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) + F_tau = 2.0_pReal* F + F_tau_lastInc = 2.0_pReal*F_lastInc + endif restart + + call Utilities_updateIPcoords(reshape(F,shape(F_lastInc))) + call Utilities_constitutiveResponse(F_lastInc, reshape(F,shape(F_lastInc)), & + 0.0_pReal,P,C_volAvg,C_minMaxAvg,temp33_Real,.false.,math_I3) + nullify(F) + nullify(F_tau) + call DMDAVecRestoreArrayF90(da,solution_vec,xx_psc,ierr); CHKERRQ(ierr) ! write data back to PETSc + + readRestart: if (restartInc > 1_pInt) then + if (iand(debug_level(debug_spectral),debug_spectralRestart)/= 0 .and. worldrank == 0_pInt) & + write(6,'(/,a,'//IO_intOut(restartInc-1_pInt)//',a)') & + 'reading more values of increment', restartInc - 1_pInt, 'from file' + flush(6) + call IO_read_realFile(777,'C_volAvg',trim(getSolverJobName()),size(C_volAvg)) + read (777,rec=1) C_volAvg + close (777) + call IO_read_realFile(777,'C_volAvgLastInc',trim(getSolverJobName()),size(C_volAvgLastInc)) + read (777,rec=1) C_volAvgLastInc + close (777) + call IO_read_realFile(777,'C_ref',trim(getSolverJobName()),size(C_minMaxAvg)) + read (777,rec=1) C_minMaxAvg + close (777) + endif readRestart + + call Utilities_updateGamma(C_minMaxAvg,.True.) + C_scale = C_minMaxAvg + S_scale = math_invSym3333(C_minMaxAvg) + +end subroutine Polarisation_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the Polarisation scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function & + Polarisation_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,rotation_BC) + use IO, only: & + IO_error + use numerics, only: & + update_gamma + use math, only: & + math_invSym3333 + use spectral_utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use FEsolving, only: & + restartWrite, & + terminallyIll + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + logical, intent(in) :: & + guess + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + character(len=*), intent(in) :: & + incInfoIn + real(pReal), dimension(3,3), intent(in) :: rotation_BC + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + incInfo = incInfoIn + +!-------------------------------------------------------------------------------------------------- +! update stiffness (and gamma operator) + S = Utilities_maskedCompliance(rotation_BC,P_BC%maskLogical,C_volAvg) + if (update_gamma) then + call Utilities_updateGamma(C_minMaxAvg,restartWrite) + C_scale = C_minMaxAvg + S_scale = math_invSym3333(C_minMaxAvg) + endif + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + mask_stress = P_BC%maskFloat + params%P_BC = P_BC%values + params%rotation_BC = rotation_BC + params%timeinc = timeinc + params%timeincOld = timeinc_old + +!-------------------------------------------------------------------------------------------------- +! solve BVP + call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr) + CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! check convergence + call SNESGetConvergedReason(snes,reason,ierr) + CHKERRQ(ierr) + Polarisation_solution%termIll = terminallyIll + terminallyIll = .false. + if (reason == -4) call IO_error(893_pInt) + if (reason < 1) Polarisation_solution%converged = .false. + Polarisation_solution%iterationsNeeded = totalIter + +end function Polarisation_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the Polarisation residual vector +!-------------------------------------------------------------------------------------------------- +subroutine Polarisation_formResidual(in,x_scal,f_scal,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + polarAlpha, & + polarBeta, & + worldrank + use mesh, only: & + grid3, & + grid + use IO, only: & + IO_intOut + use math, only: & + math_rotate_backward33, & + math_transpose33, & + math_mul3333xx33, & + math_invSym3333, & + math_mul33x33 + use spectral_utilities, only: & + wgt, & + tensorField_real, & + utilities_FFTtensorForward, & + utilities_fourierGammaConvolution, & + utilities_FFTtensorBackward, & + Utilities_constitutiveResponse, & + Utilities_divergenceRMS, & + Utilities_curlRMS + use debug, only: & + debug_level, & + debug_spectral, & + debug_spectralRotation + use homogenization, only: & + materialpoint_dPdF + use FEsolving, only: & + terminallyIll + + implicit none +!-------------------------------------------------------------------------------------------------- +! strange syntax in the next line because otherwise macros expand beyond 132 character limit + DMDALocalInfo, dimension(& + DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, target, dimension(3,3,2, & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, target, dimension(3,3,2, & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscScalar, pointer, dimension(:,:,:,:,:) :: & + F, & + F_tau, & + residual_F, & + residual_F_tau + PetscInt :: & + PETScIter, & + nfuncs + PetscObject :: dummy + PetscErrorCode :: ierr + integer(pInt) :: & + i, j, k, e + + F => x_scal(1:3,1:3,1,& + XG_RANGE,YG_RANGE,ZG_RANGE) + F_tau => x_scal(1:3,1:3,2,& + XG_RANGE,YG_RANGE,ZG_RANGE) + residual_F => f_scal(1:3,1:3,1,& + X_RANGE,Y_RANGE,Z_RANGE) + residual_F_tau => f_scal(1:3,1:3,2,& + X_RANGE,Y_RANGE,Z_RANGE) + + call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) + call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) + + F_av = sum(sum(sum(F,dim=5),dim=4),dim=3) * wgt + call MPI_Allreduce(MPI_IN_PLACE,F_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + + if(nfuncs== 0 .and. PETScIter == 0) totalIter = -1_pInt ! new increment + newIteration: if(totalIter <= PETScIter) then +!-------------------------------------------------------------------------------------------------- +! report begin of new iteration + totalIter = totalIter + 1_pInt + if (worldrank == 0_pInt) then + write(6,'(1x,a,3(a,'//IO_intOut(itmax)//'))') trim(incInfo), & + ' @ Iteration ', itmin, '≤',totalIter, '≤', itmax + if (iand(debug_level(debug_spectral),debug_spectralRotation) /= 0) & + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim (lab) =', & + math_transpose33(math_rotate_backward33(F_aim,params%rotation_BC)) + write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' deformation gradient aim =', & + math_transpose33(F_aim) + flush(6) + endif + endif newIteration + +!-------------------------------------------------------------------------------------------------- +! + tensorField_real = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) + tensorField_real(1:3,1:3,i,j,k) = & + polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& + polarAlpha*math_mul33x33(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)) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! doing convolution in Fourier space + call utilities_FFTtensorForward() + call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) + call utilities_FFTtensorBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + residual_F_tau = polarBeta*F - tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) + +!-------------------------------------------------------------------------------------------------- +! evaluate constitutive response + P_avLastEval = P_av + call Utilities_constitutiveResponse(F_lastInc,F - residual_F_tau/polarBeta,params%timeinc, & + residual_F,C_volAvg,C_minMaxAvg,P_av,ForwardData,params%rotation_BC) + call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr) + ForwardData = .False. + +!-------------------------------------------------------------------------------------------------- +! calculate divergence + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = residual_F + call utilities_FFTtensorForward() + err_div = Utilities_divergenceRMS() + call utilities_FFTtensorBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + e = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid(1) + e = e + 1_pInt + residual_F(1:3,1:3,i,j,k) = & + math_mul3333xx33(math_invSym3333(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & + residual_F(1:3,1:3,i,j,k) - math_mul33x33(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) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! calculating curl + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F + call utilities_FFTtensorForward() + err_curl = Utilities_curlRMS() + call utilities_FFTtensorBackward() + +end subroutine Polarisation_formResidual + + +!-------------------------------------------------------------------------------------------------- +!> @brief convergence check +!-------------------------------------------------------------------------------------------------- +subroutine Polarisation_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dummy,ierr) + use numerics, only: & + itmax, & + itmin, & + err_div_tolRel, & + err_div_tolAbs, & + err_curl_tolRel, & + err_curl_tolAbs, & + err_stress_tolAbs, & + err_stress_tolRel, & + worldrank + use math, only: & + math_mul3333xx33 + use FEsolving, only: & + terminallyIll + + implicit none + SNES :: snes_local + PetscInt :: PETScIter + PetscReal :: & + xnorm, & + snorm, & + fnorm + SNESConvergedReason :: reason + PetscObject :: dummy + PetscErrorCode ::ierr + real(pReal) :: & + curlTol, & + divTol, & + BC_tol + +!-------------------------------------------------------------------------------------------------- +! stress BC handling + F_aim = F_aim - math_mul3333xx33(S, ((P_av - params%P_BC))) ! S = 0.0 for no bc + err_BC = maxval(abs((-mask_stress+1.0_pReal)*math_mul3333xx33(C_scale,F_aim-F_av) + & + mask_stress *(P_av - params%P_BC))) ! mask = 0.0 for no bc + +!-------------------------------------------------------------------------------------------------- +! error calculation + curlTol = max(maxval(abs(F_aim-math_I3))*err_curl_tolRel,err_curl_tolAbs) + divTol = max(maxval(abs(P_av)) *err_div_tolRel,err_div_tolAbs) + BC_tol = max(maxval(abs(P_av)) *err_stress_tolrel,err_stress_tolabs) + + converged: if ((totalIter >= itmin .and. & + all([ err_div/divTol, & + err_curl/curlTol, & + err_BC/BC_tol ] < 1.0_pReal)) & + .or. terminallyIll) then + reason = 1 + elseif (totalIter >= itmax) then converged + reason = -1 + else converged + reason = 0 + endif converged + +!-------------------------------------------------------------------------------------------------- +! report +if (worldrank == 0_pInt) then + write(6,'(1/,a)') ' ... reporting .............................................................' + write(6,'(/,a,f12.2,a,es8.2,a,es9.2,a)') ' error curl = ', & + err_curl/curlTol,' (',err_curl,' -, tol =',curlTol,')' + write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error divergence = ', & + err_div/divTol, ' (',err_div, ' / m, tol =',divTol,')' + write(6,' (a,f12.2,a,es8.2,a,es9.2,a)') ' error BC = ', & + err_BC/BC_tol, ' (',err_BC, ' Pa, tol =',BC_tol,')' + write(6,'(/,a)') ' ===========================================================================' + flush(6) +endif + +end subroutine Polarisation_converged + +!-------------------------------------------------------------------------------------------------- +!> @brief forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine Polarisation_forward(guess,timeinc,timeinc_old,loadCaseTime,F_BC,P_BC,rotation_BC) + use math, only: & + math_mul33x33, & + math_mul3333xx33, & + math_transpose33, & + math_rotate_backward33 + use numerics, only: & + worldrank + use mesh, only: & + grid3, & + grid + use spectral_utilities, only: & + Utilities_calculateRate, & + Utilities_forwardField, & + Utilities_updateIPcoords, & + tBoundaryCondition, & + cutBack + use IO, only: & + IO_write_JobRealFile + use FEsolving, only: & + restartWrite + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & + P_BC, & + F_BC + real(pReal), dimension(3,3), intent(in) :: rotation_BC + logical, intent(in) :: & + guess + PetscErrorCode :: ierr + PetscScalar, dimension(:,:,:,:), pointer :: xx_psc, F, F_tau + integer(pInt) :: i, j, k + real(pReal), dimension(3,3) :: F_lambda33 + character(len=1024) :: rankStr + +!-------------------------------------------------------------------------------------------------- +! update coordinates and rate and forward last inc + call DMDAVecGetArrayF90(da,solution_vec,xx_psc,ierr) + F => xx_psc(0:8,:,:,:) + F_tau => xx_psc(9:17,:,:,:) + if (restartWrite) then + if (worldrank == 0_pInt) write(6,'(/,a)') ' writing converged results for restart' + flush(6) + write(rankStr,'(a1,i0)')'_',worldrank + call IO_write_jobRealFile(777,'F'//trim(rankStr),size(F)) ! writing deformation gradient field to file + write (777,rec=1) F + close (777) + call IO_write_jobRealFile(777,'F_lastInc'//trim(rankStr),size(F_lastInc)) ! writing F_lastInc field to file + write (777,rec=1) F_lastInc + close (777) + call IO_write_jobRealFile(777,'F_tau'//trim(rankStr),size(F_tau)) ! writing deformation gradient field to file + write (777,rec=1) F_tau + close (777) + call IO_write_jobRealFile(777,'F_tau_lastInc'//trim(rankStr),size(F_tau_lastInc)) ! writing F_lastInc field to file + write (777,rec=1) F_tau_lastInc + close (777) + if (worldrank == 0_pInt) then + call IO_write_jobRealFile(777,'F_aim',size(F_aim)) + write (777,rec=1) F_aim + close(777) + call IO_write_jobRealFile(777,'F_aim_lastInc',size(F_aim_lastInc)) + write (777,rec=1) F_aim_lastInc + close (777) + call IO_write_jobRealFile(777,'F_aimDot',size(F_aimDot)) + write (777,rec=1) F_aimDot + close(777) + call IO_write_jobRealFile(777,'C_volAvg',size(C_volAvg)) + write (777,rec=1) C_volAvg + close(777) + call IO_write_jobRealFile(777,'C_volAvgLastInc',size(C_volAvgLastInc)) + write (777,rec=1) C_volAvgLastInc + close(777) + endif + endif + call utilities_updateIPcoords(F) + + if (cutBack) then + F_aim = F_aim_lastInc + F_tau= reshape(F_tau_lastInc,[9,grid(1),grid(2),grid3]) + F = reshape(F_lastInc, [9,grid(1),grid(2),grid3]) + C_volAvg = C_volAvgLastInc + else + ForwardData = .True. + C_volAvgLastInc = C_volAvg +!-------------------------------------------------------------------------------------------------- +! calculate rate for aim + if (F_BC%myType=='l') then ! calculate f_aimDot from given L and current F + f_aimDot = F_BC%maskFloat * math_mul33x33(F_BC%values, F_aim) + elseif(F_BC%myType=='fdot') then ! f_aimDot is prescribed + f_aimDot = F_BC%maskFloat * F_BC%values + elseif(F_BC%myType=='f') then ! aim at end of load case is prescribed + f_aimDot = F_BC%maskFloat * (F_BC%values -F_aim)/loadCaseTime + endif + if (guess) f_aimDot = f_aimDot + P_BC%maskFloat * (F_aim - F_aim_lastInc)/timeinc_old + F_aim_lastInc = F_aim + +!-------------------------------------------------------------------------------------------------- +! update coordinates and rate and forward last inc + call utilities_updateIPcoords(F) + Fdot = Utilities_calculateRate(math_rotate_backward33(f_aimDot,rotation_BC), & + timeinc_old,guess,F_lastInc, & + reshape(F,[3,3,grid(1),grid(2),grid3])) + F_tauDot = Utilities_calculateRate(math_rotate_backward33(2.0_pReal*f_aimDot,rotation_BC), & + timeinc_old,guess,F_tau_lastInc, & + reshape(F_tau,[3,3,grid(1),grid(2),grid3])) + F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) + F_tau_lastInc = reshape(F_tau,[3,3,grid(1),grid(2),grid3]) + endif + + F_aim = F_aim + f_aimDot * timeinc + +!-------------------------------------------------------------------------------------------------- +! update local deformation gradient + F = reshape(Utilities_forwardField(timeinc,F_lastInc,Fdot, & ! ensure that it matches rotated F_aim + math_rotate_backward33(F_aim,rotation_BC)), & + [9,grid(1),grid(2),grid3]) + F_tau = reshape(Utilities_forwardField(timeinc,F_tau_lastInc,F_taudot), & ! does not have any average value as boundary condition + [9,grid(1),grid(2),grid3]) + if (.not. guess) then ! large strain forwarding + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, 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,math_mul33x33(F_lambda33, & + math_mul3333xx33(C_scale,& + math_mul33x33(math_transpose33(F_lambda33),& + F_lambda33) -math_I3))*0.5_pReal)& + + 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,xx_psc,ierr); CHKERRQ(ierr) + +end subroutine Polarisation_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine Polarisation_destroy() + use spectral_utilities, only: & + Utilities_destroy + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) + call SNESDestroy(snes,ierr); CHKERRQ(ierr) + call DMDestroy(da,ierr); CHKERRQ(ierr) + +end subroutine Polarisation_destroy + +end module spectral_mech_Polarisation diff --git a/src/spectral_thermal.f90 b/src/spectral_thermal.f90 new file mode 100644 index 000000000..843642394 --- /dev/null +++ b/src/spectral_thermal.f90 @@ -0,0 +1,419 @@ +!-------------------------------------------------------------------------------------------------- +! $Id: spectral_thermal.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Shaokang Zhang, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Spectral solver for thermal conduction +!-------------------------------------------------------------------------------------------------- +module spectral_thermal + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use spectral_utilities, only: & + tSolutionState, & + tSolutionParams + use numerics, only: & + worldrank, & + worldsize + + implicit none + private +#include + + character (len=*), parameter, public :: & + spectral_thermal_label = 'spectralthermal' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + +!-------------------------------------------------------------------------------------------------- +! PETSc data + SNES, private :: thermal_snes + Vec, private :: solution + PetscInt, private :: xstart, xend, ystart, yend, zstart, zend + real(pReal), private, dimension(:,:,:), allocatable :: & + temperature_current, & !< field of current temperature + temperature_lastInc, & !< field of previous temperature + temperature_stagInc !< field of staggered temperature + +!-------------------------------------------------------------------------------------------------- +! reference diffusion tensor, mobility etc. + integer(pInt), private :: totalIter = 0_pInt !< total iteration in current increment + real(pReal), dimension(3,3), private :: D_ref + real(pReal), private :: mobility_ref + character(len=1024), private :: incInfo + + public :: & + spectral_thermal_init, & + spectral_thermal_solution, & + spectral_thermal_forward, & + spectral_thermal_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_init + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use spectral_utilities, only: & + wgt + use mesh, only: & + grid, & + grid3 + use thermal_conduction, only: & + thermal_conduction_getConductivity33, & + thermal_conduction_getMassDensity, & + thermal_conduction_getSpecificHeat + use material, only: & + mappingHomogenization, & + temperature, & + thermalMapping + + implicit none + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + integer(pInt) :: i, j, k, cell + DM :: thermal_grid + PetscScalar, pointer :: x_scal(:,:,:) + PetscErrorCode :: ierr + PetscObject :: dummy + + mainProcess: if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- spectral_thermal init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! initialize solver specific parts of PETSc + call SNESCreate(PETSC_COMM_WORLD,thermal_snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(thermal_snes,'thermal_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = grid3 + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary + DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point + grid(1),grid(2),grid(3), & ! global grid + 1, 1, worldsize, & + 1, 0, & ! #dof (temperature field), ghost boundary width (domain overlap) + grid (1),grid(2),localK, & ! local grid + thermal_grid,ierr) ! handle, error + CHKERRQ(ierr) + call SNESSetDM(thermal_snes,thermal_grid,ierr); CHKERRQ(ierr) ! connect snes to da + call DMCreateGlobalVector(thermal_grid,solution ,ierr); CHKERRQ(ierr) ! global solution vector (grid x 1, i.e. every def grad tensor) + call DMDASNESSetFunctionLocal(thermal_grid,INSERT_VALUES,spectral_thermal_formResidual,dummy,ierr) ! residual vector of same shape as solution vector + CHKERRQ(ierr) + call SNESSetFromOptions(thermal_snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAGetCorners(thermal_grid,xstart,ystart,zstart,xend,yend,zend,ierr) + CHKERRQ(ierr) + xend = xstart + xend - 1 + yend = ystart + yend - 1 + zend = zstart + zend - 1 + allocate(temperature_current(grid(1),grid(2),grid3), source=0.0_pReal) + allocate(temperature_lastInc(grid(1),grid(2),grid3), source=0.0_pReal) + allocate(temperature_stagInc(grid(1),grid(2),grid3), source=0.0_pReal) + cell = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + temperature_current(i,j,k) = temperature(mappingHomogenization(2,1,cell))% & + p(thermalMapping(mappingHomogenization(2,1,cell))%p(1,cell)) + temperature_lastInc(i,j,k) = temperature_current(i,j,k) + temperature_stagInc(i,j,k) = temperature_current(i,j,k) + enddo; enddo; enddo + call DMDAVecGetArrayF90(thermal_grid,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with + x_scal(xstart:xend,ystart:yend,zstart:zend) = temperature_current + call DMDAVecRestoreArrayF90(thermal_grid,solution,x_scal,ierr); CHKERRQ(ierr) + + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + D_ref = D_ref + thermal_conduction_getConductivity33(1,cell) + mobility_ref = mobility_ref + thermal_conduction_getMassDensity(1,cell)* & + thermal_conduction_getSpecificHeat(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + +end subroutine spectral_thermal_init + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the Basic PETSC scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function spectral_thermal_solution(guess,timeinc,timeinc_old,loadCaseTime) + use numerics, only: & + itmax, & + err_thermal_tolAbs, & + err_thermal_tolRel + use spectral_utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use mesh, only: & + grid, & + grid3 + use thermal_conduction, only: & + thermal_conduction_putTemperatureAndItsRate + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + integer(pInt) :: i, j, k, cell + PetscInt :: position + PetscReal :: minTemperature, maxTemperature, stagNorm, solnNorm + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + spectral_thermal_solution%converged =.false. + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + params%timeinc = timeinc + params%timeincOld = timeinc_old + + call SNESSolve(thermal_snes,PETSC_NULL_OBJECT,solution,ierr); CHKERRQ(ierr) + call SNESGetConvergedReason(thermal_snes,reason,ierr); CHKERRQ(ierr) + + if (reason < 1) then + spectral_thermal_solution%converged = .false. + spectral_thermal_solution%iterationsNeeded = itmax + else + spectral_thermal_solution%converged = .true. + spectral_thermal_solution%iterationsNeeded = totalIter + endif + stagNorm = maxval(abs(temperature_current - temperature_stagInc)) + solnNorm = maxval(abs(temperature_current)) + call MPI_Allreduce(MPI_IN_PLACE,stagNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + call MPI_Allreduce(MPI_IN_PLACE,solnNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + temperature_stagInc = temperature_current + spectral_thermal_solution%stagConverged = stagNorm < err_thermal_tolAbs & + .or. stagNorm < err_thermal_tolRel*solnNorm + +!-------------------------------------------------------------------------------------------------- +! updating thermal state + cell = 0_pInt !< material point = 0 + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt !< material point increase + call thermal_conduction_putTemperatureAndItsRate(temperature_current(i,j,k), & + (temperature_current(i,j,k)-temperature_lastInc(i,j,k))/params%timeinc, & + 1,cell) + enddo; enddo; enddo + + call VecMin(solution,position,minTemperature,ierr); CHKERRQ(ierr) + call VecMax(solution,position,maxTemperature,ierr); CHKERRQ(ierr) + if (worldrank == 0) then + if (spectral_thermal_solution%converged) & + write(6,'(/,a)') ' ... thermal conduction converged ..................................' + write(6,'(/,a,f8.4,2x,f8.4,2x,f8.4,/)',advance='no') ' Minimum|Maximum|Delta Temperature = ',& + minTemperature, maxTemperature, stagNorm + write(6,'(/,a)') ' ===========================================================================' + flush(6) + endif + +end function spectral_thermal_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the spectral thermal residual vector +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_formResidual(in,x_scal,f_scal,dummy,ierr) + use mesh, only: & + grid, & + grid3 + use math, only: & + math_mul33x3 + use spectral_utilities, only: & + scalarField_real, & + vectorField_real, & + utilities_FFTvectorForward, & + utilities_FFTvectorBackward, & + utilities_FFTscalarForward, & + utilities_FFTscalarBackward, & + utilities_fourierGreenConvolution, & + utilities_fourierScalarGradient, & + utilities_fourierVectorDivergence + use thermal_conduction, only: & + thermal_conduction_getSourceAndItsTangent, & + thermal_conduction_getConductivity33, & + thermal_conduction_getMassDensity, & + thermal_conduction_getSpecificHeat + + implicit none + DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, dimension( & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, dimension( & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscObject :: dummy + PetscErrorCode :: ierr + integer(pInt) :: i, j, k, cell + real(pReal) :: Tdot, dTdot_dT + + temperature_current = x_scal +!-------------------------------------------------------------------------------------------------- +! evaluate polarization field + scalarField_real = 0.0_pReal + scalarField_real(1:grid(1),1:grid(2),1:grid3) = temperature_current + call utilities_FFTscalarForward() + call utilities_fourierScalarGradient() !< calculate gradient of damage field + call utilities_FFTvectorBackward() + cell = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + vectorField_real(1:3,i,j,k) = math_mul33x3(thermal_conduction_getConductivity33(1,cell) - D_ref, & + vectorField_real(1:3,i,j,k)) + enddo; enddo; enddo + call utilities_FFTvectorForward() + call utilities_fourierVectorDivergence() !< calculate damage divergence in fourier field + call utilities_FFTscalarBackward() + cell = 0_pInt + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + call thermal_conduction_getSourceAndItsTangent(Tdot, dTdot_dT, temperature_current(i,j,k), 1, cell) + scalarField_real(i,j,k) = params%timeinc*scalarField_real(i,j,k) + & + params%timeinc*Tdot + & + thermal_conduction_getMassDensity (1,cell)* & + thermal_conduction_getSpecificHeat(1,cell)*(temperature_lastInc(i,j,k) - & + temperature_current(i,j,k)) + & + mobility_ref*temperature_current(i,j,k) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! convolution of damage field with green operator + call utilities_FFTscalarForward() + call utilities_fourierGreenConvolution(D_ref, mobility_ref, params%timeinc) + call utilities_FFTscalarBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + f_scal = temperature_current - scalarField_real(1:grid(1),1:grid(2),1:grid3) + +end subroutine spectral_thermal_formResidual + +!-------------------------------------------------------------------------------------------------- +!> @brief forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_forward(guess,timeinc,timeinc_old,loadCaseTime) + use mesh, only: & + grid, & + grid3 + use spectral_utilities, only: & + cutBack, & + wgt + use thermal_conduction, only: & + thermal_conduction_putTemperatureAndItsRate, & + thermal_conduction_getConductivity33, & + thermal_conduction_getMassDensity, & + thermal_conduction_getSpecificHeat + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + integer(pInt) :: i, j, k, cell + DM :: dm_local + PetscScalar, pointer :: x_scal(:,:,:) + PetscErrorCode :: ierr + + if (cutBack) then + temperature_current = temperature_lastInc + temperature_stagInc = temperature_lastInc + +!-------------------------------------------------------------------------------------------------- +! reverting thermal field state + cell = 0_pInt !< material point = 0 + call SNESGetDM(thermal_snes,dm_local,ierr); CHKERRQ(ierr) + call DMDAVecGetArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with + x_scal(xstart:xend,ystart:yend,zstart:zend) = temperature_current + call DMDAVecRestoreArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt !< material point increase + call thermal_conduction_putTemperatureAndItsRate(temperature_current(i,j,k), & + (temperature_current(i,j,k) - & + temperature_lastInc(i,j,k))/params%timeinc, & + 1,cell) + enddo; enddo; enddo + else +!-------------------------------------------------------------------------------------------------- +! update rate and forward last inc + temperature_lastInc = temperature_current + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid(1) + cell = cell + 1_pInt + D_ref = D_ref + thermal_conduction_getConductivity33(1,cell) + mobility_ref = mobility_ref + thermal_conduction_getMassDensity(1,cell)* & + thermal_conduction_getSpecificHeat(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + endif + + end subroutine spectral_thermal_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_destroy() + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution,ierr); CHKERRQ(ierr) + call SNESDestroy(thermal_snes,ierr); CHKERRQ(ierr) + +end subroutine spectral_thermal_destroy + +end module spectral_thermal diff --git a/src/spectral_utilities.f90 b/src/spectral_utilities.f90 new file mode 100644 index 000000000..bde088ccb --- /dev/null +++ b/src/spectral_utilities.f90 @@ -0,0 +1,1262 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH +!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Utilities used by the different spectral solver variants +!-------------------------------------------------------------------------------------------------- +module spectral_utilities + use, intrinsic :: iso_c_binding + use prec, only: & + pReal, & + pInt + use math, only: & + math_I3 + + implicit none + private +#include + include 'fftw3-mpi.f03' + + logical, public :: cutBack =.false. !< cut back of BVP solver in case convergence is not achieved or a material point is terminally ill + integer(pInt), public, parameter :: maxPhaseFields = 2_pInt + integer(pInt), public :: nActiveFields = 0_pInt + +!-------------------------------------------------------------------------------------------------- +! field labels information + enum, bind(c) + enumerator :: FIELD_UNDEFINED_ID, & + FIELD_MECH_ID, & + FIELD_THERMAL_ID, & + FIELD_DAMAGE_ID, & + FIELD_VACANCYDIFFUSION_ID + end enum + +!-------------------------------------------------------------------------------------------------- +! grid related information information + real(pReal), public :: wgt !< weighting factor 1/Nelems + +!-------------------------------------------------------------------------------------------------- +! variables storing information for spectral method and FFTW + integer(pInt), public :: grid1Red !< grid(1)/2 + real (C_DOUBLE), public, dimension(:,:,:,:,:), pointer :: tensorField_real !< real representation (some stress or deformation) of field_fourier + complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:,:), pointer :: tensorField_fourier !< field on which the Fourier transform operates + real(C_DOUBLE), public, dimension(:,:,:,:), pointer :: vectorField_real !< vector field real representation for fftw + complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:), pointer :: vectorField_fourier !< vector field fourier representation for fftw + real(C_DOUBLE), public, dimension(:,:,:), pointer :: scalarField_real !< scalar field real representation for fftw + complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:), pointer :: scalarField_fourier !< scalar field fourier representation for fftw + complex(pReal), private, dimension(:,:,:,:,:,:,:), allocatable :: gamma_hat !< gamma operator (field) for spectral method + complex(pReal), private, dimension(:,:,:,:), allocatable :: xi1st !< wave vector field for first derivatives + complex(pReal), private, dimension(:,:,:,:), allocatable :: xi2nd !< wave vector field for second derivatives + real(pReal), private, dimension(3,3,3,3) :: C_ref !< mechanic reference stiffness + real(pReal), protected, public, dimension(3) :: scaledGeomSize !< scaled geometry size for calculation of divergence (Basic, Basic PETSc) + +!-------------------------------------------------------------------------------------------------- +! plans for FFTW + type(C_PTR), private :: & + planTensorForth, & !< FFTW MPI plan P(x) to P(k) + planTensorBack, & !< FFTW MPI plan F(k) to F(x) + planVectorForth, & !< FFTW MPI plan v(x) to v(k) + planVectorBack, & !< FFTW MPI plan v(k) to v(x) + planScalarForth, & !< FFTW MPI plan s(x) to s(k) + planScalarBack !< FFTW MPI plan s(k) to s(x) + +!-------------------------------------------------------------------------------------------------- +! variables controlling debugging + logical, private :: & + debugGeneral, & !< general debugging of spectral solver + debugRotation, & !< also printing out results in lab frame + debugPETSc !< use some in debug defined options for more verbose PETSc solution + +!-------------------------------------------------------------------------------------------------- +! derived types + type, public :: tSolutionState !< return type of solution from spectral solver variants + logical :: converged = .true. + logical :: regrid = .false. + logical :: stagConverged = .true. + logical :: termIll = .false. + integer(pInt) :: iterationsNeeded = 0_pInt + end type tSolutionState + + type, public :: tBoundaryCondition !< set of parameters defining a boundary condition + real(pReal), dimension(3,3) :: values = 0.0_pReal + real(pReal), dimension(3,3) :: maskFloat = 0.0_pReal + logical, dimension(3,3) :: maskLogical = .false. + character(len=64) :: myType = 'None' + end type tBoundaryCondition + + type, public :: tLoadCase + real(pReal), dimension (3,3) :: rotation = math_I3 !< rotation of BC + type(tBoundaryCondition) :: P, & !< stress BC + deformation !< deformation BC (Fdot or L) + real(pReal) :: time = 0.0_pReal !< length of increment + integer(pInt) :: incs = 0_pInt, & !< number of increments + outputfrequency = 1_pInt, & !< frequency of result writes + restartfrequency = 0_pInt, & !< frequency of restart writes + logscale = 0_pInt !< linear/logarithmic time inc flag + logical :: followFormerTrajectory = .true. !< follow trajectory of former loadcase + integer(kind(FIELD_UNDEFINED_ID)), allocatable :: ID(:) + end type tLoadCase + + type, public :: tSolutionParams !< @todo use here the type definition for a full loadcase including mask + real(pReal), dimension(3,3) :: P_BC, rotation_BC + real(pReal) :: timeinc + real(pReal) :: timeincOld + real(pReal) :: density + end type tSolutionParams + + type(tSolutionParams), private :: params + + type, public :: phaseFieldDataBin !< set of parameters defining a phase field + real(pReal) :: diffusion = 0.0_pReal, & !< thermal conductivity + mobility = 0.0_pReal, & !< thermal mobility + phaseField0 = 0.0_pReal !< homogeneous damage field starting condition + logical :: active = .false. + character(len=64) :: label = '' + end type phaseFieldDataBin + + enum, bind(c) + enumerator :: DERIVATIVE_CONTINUOUS_ID, & + DERIVATIVE_CENTRAL_DIFF_ID, & + DERIVATIVE_FWBW_DIFF_ID + end enum + integer(kind(DERIVATIVE_CONTINUOUS_ID)) :: & + spectral_derivative_ID + + public :: & + utilities_init, & + utilities_updateGamma, & + utilities_FFTtensorForward, & + utilities_FFTtensorBackward, & + utilities_FFTvectorForward, & + utilities_FFTvectorBackward, & + utilities_FFTscalarForward, & + utilities_FFTscalarBackward, & + utilities_fourierGammaConvolution, & + utilities_fourierGreenConvolution, & + utilities_divergenceRMS, & + utilities_curlRMS, & + utilities_fourierScalarGradient, & + utilities_fourierVectorDivergence, & + utilities_fourierVectorGradient, & + utilities_fourierTensorDivergence, & + utilities_maskedCompliance, & + utilities_constitutiveResponse, & + utilities_calculateRate, & + utilities_forwardField, & + utilities_destroy, & + utilities_updateIPcoords, & + FIELD_UNDEFINED_ID, & + FIELD_MECH_ID, & + FIELD_THERMAL_ID, & + FIELD_DAMAGE_ID + private :: & + utilities_getFreqDerivative + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, sets debug flags, create plans for FFTW +!> @details Sets the debug levels for general, divergence, restart and FFTW from the biwise coding +!> provided by the debug module to logicals. +!> Allocates all fields used by FFTW and create the corresponding plans depending on the debug +!> level chosen. +!> Initializes FFTW. +!-------------------------------------------------------------------------------------------------- +subroutine utilities_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_error, & + IO_warning, & + IO_timeStamp, & + IO_open_file + use numerics, only: & + spectral_derivative, & + fftw_planner_flag, & + fftw_timelimit, & + memory_efficient, & + petsc_defaultOptions, & + petsc_options, & + divergence_correction, & + worldrank + use debug, only: & + debug_level, & + debug_SPECTRAL, & + debug_LEVELBASIC, & + debug_SPECTRALDIVERGENCE, & + debug_SPECTRALFFTW, & + debug_SPECTRALPETSC, & + debug_SPECTRALROTATION + use debug, only: & + PETSCDEBUG + use math + use mesh, only: & + grid, & + grid3, & + grid3Offset, & + geomSize + + implicit none + + external :: & + PETScOptionsClear, & + PETScOptionsInsertString, & + MPI_Abort + + PetscErrorCode :: ierr + integer(pInt) :: i, j, k + integer(pInt), dimension(3) :: k_s + type(C_PTR) :: & + tensorField, & !< field containing data for FFTW in real and fourier space (in place) + vectorField, & !< field containing data for FFTW in real space when debugging FFTW (no in place) + scalarField !< field containing data for FFTW in real space when debugging FFTW (no in place) + integer(C_INTPTR_T), dimension(3) :: gridFFTW + integer(C_INTPTR_T) :: alloc_local, local_K, local_K_offset + integer(C_INTPTR_T), parameter :: & + scalarSize = 1_C_INTPTR_T, & + vecSize = 3_C_INTPTR_T, & + tensorSize = 9_C_INTPTR_T + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- spectral_utilities init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! set debugging parameters + debugGeneral = iand(debug_level(debug_SPECTRAL),debug_LEVELBASIC) /= 0 + debugRotation = iand(debug_level(debug_SPECTRAL),debug_SPECTRALROTATION) /= 0 + debugPETSc = iand(debug_level(debug_SPECTRAL),debug_SPECTRALPETSC) /= 0 + + if(debugPETSc .and. worldrank == 0_pInt) write(6,'(3(/,a),/)') & + ' Initializing PETSc with debug options: ', & + trim(PETScDebug), & + ' add more using the PETSc_Options keyword in numerics.config ' + flush(6) + call PetscOptionsClear(ierr); CHKERRQ(ierr) + if(debugPETSc) call PetscOptionsInsertString(trim(PETSCDEBUG),ierr); CHKERRQ(ierr) + call PetscOptionsInsertString(trim(petsc_defaultOptions),ierr); CHKERRQ(ierr) + call PetscOptionsInsertString(trim(petsc_options),ierr); CHKERRQ(ierr) + + grid1Red = grid(1)/2_pInt + 1_pInt + wgt = 1.0/real(product(grid),pReal) + + if (worldrank == 0) then + write(6,'(a,3(i12 ))') ' grid a b c: ', grid + write(6,'(a,3(es12.5))') ' size x y z: ', geomSize + endif + + select case (spectral_derivative) + case ('continuous') ! default, no weighting + spectral_derivative_ID = DERIVATIVE_CONTINUOUS_ID + case ('central_difference') ! cosine curve with 1 for avg and zero for highest freq + spectral_derivative_ID = DERIVATIVE_CENTRAL_DIFF_ID + case ('fwbw_difference') ! gradient, might need grid scaling as for cosine filter + spectral_derivative_ID = DERIVATIVE_FWBW_DIFF_ID + case default + call IO_error(892_pInt,ext_msg=trim(spectral_derivative)) + end select + +!-------------------------------------------------------------------------------------------------- +! scale dimension to calculate either uncorrected, dimension-independent, or dimension- and +! resolution-independent divergence + if (divergence_correction == 1_pInt) then + do j = 1_pInt, 3_pInt + if (j /= minloc(geomSize,1) .and. j /= maxloc(geomSize,1)) & + scaledGeomSize = geomSize/geomSize(j) + enddo + elseif (divergence_correction == 2_pInt) then + do j = 1_pInt, 3_pInt + if (j /= minloc(geomSize/grid,1) .and. j /= maxloc(geomSize/grid,1)) & + scaledGeomSize = geomSize/geomSize(j)*grid(j) + enddo + else + scaledGeomSize = geomSize + endif + + +!-------------------------------------------------------------------------------------------------- +! MPI allocation + gridFFTW = int(grid,C_INTPTR_T) + alloc_local = fftw_mpi_local_size_3d(gridFFTW(3), gridFFTW(2), gridFFTW(1)/2 +1, & + MPI_COMM_WORLD, local_K, local_K_offset) + allocate (xi1st (3,grid1Red,grid(2),grid3),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies, only half the size for first dimension + allocate (xi2nd (3,grid1Red,grid(2),grid3),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies, only half the size for first dimension + + tensorField = fftw_alloc_complex(tensorSize*alloc_local) + call c_f_pointer(tensorField, tensorField_real, [3_C_INTPTR_T,3_C_INTPTR_T, & + 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real tensor representation + call c_f_pointer(tensorField, tensorField_fourier, [3_C_INTPTR_T,3_C_INTPTR_T, & + gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T , gridFFTW(2),local_K]) ! place a pointer for a fourier tensor representation + + vectorField = fftw_alloc_complex(vecSize*alloc_local) + call c_f_pointer(vectorField, vectorField_real, [3_C_INTPTR_T,& + 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real vector representation + call c_f_pointer(vectorField, vectorField_fourier,[3_C_INTPTR_T,& + gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T, gridFFTW(2),local_K]) ! place a pointer for a fourier vector representation + + scalarField = fftw_alloc_complex(scalarSize*alloc_local) ! allocate data for real representation (no in place transform) + call c_f_pointer(scalarField, scalarField_real, & + [2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1),gridFFTW(2),local_K]) ! place a pointer for a real scalar representation + call c_f_pointer(scalarField, scalarField_fourier, & + [ gridFFTW(1)/2_C_INTPTR_T + 1 ,gridFFTW(2),local_K]) ! place a pointer for a fourier scarlar representation + +!-------------------------------------------------------------------------------------------------- +! tensor MPI fftw plans + planTensorForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock + tensorField_real, tensorField_fourier, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + if (.not. C_ASSOCIATED(planTensorForth)) call IO_error(810, ext_msg='planTensorForth') + planTensorBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock + tensorField_fourier,tensorField_real, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision + if (.not. C_ASSOCIATED(planTensorBack)) call IO_error(810, ext_msg='planTensorBack') + +!-------------------------------------------------------------------------------------------------- +! vector MPI fftw plans + planVectorForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock + vectorField_real, vectorField_fourier, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + if (.not. C_ASSOCIATED(planVectorForth)) call IO_error(810, ext_msg='planVectorForth') + planVectorBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock + vectorField_fourier,vectorField_real, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision + if (.not. C_ASSOCIATED(planVectorBack)) call IO_error(810, ext_msg='planVectorBack') + +!-------------------------------------------------------------------------------------------------- +! scalar MPI fftw plans + planScalarForth = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock + scalarField_real, scalarField_fourier, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + if (.not. C_ASSOCIATED(planScalarForth)) call IO_error(810, ext_msg='planScalarForth') + planScalarBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order, no. of transforms + scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock + scalarField_fourier,scalarField_real, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + if (.not. C_ASSOCIATED(planScalarBack)) call IO_error(810, ext_msg='planScalarBack') + +!-------------------------------------------------------------------------------------------------- +! general initialization of FFTW (see manual on fftw.org for more details) + if (pReal /= C_DOUBLE .or. pInt /= C_INT) call IO_error(0_pInt,ext_msg='Fortran to C') ! check for correct precision in C + call fftw_set_timelimit(fftw_timelimit) ! set timelimit for plan creation + + if (debugGeneral .and. worldrank == 0_pInt) write(6,'(/,a)') ' FFTW initialized' + flush(6) + +!-------------------------------------------------------------------------------------------------- +! calculation of discrete angular frequencies, ordered as in FFTW (wrap around) + do k = grid3Offset+1_pInt, grid3Offset+grid3 + k_s(3) = k - 1_pInt + if(k > grid(3)/2_pInt + 1_pInt) k_s(3) = k_s(3) - grid(3) ! running from 0,1,...,N/2,N/2+1,-N/2,-N/2+1,...,-1 + do j = 1_pInt, grid(2) + k_s(2) = j - 1_pInt + if(j > grid(2)/2_pInt + 1_pInt) k_s(2) = k_s(2) - grid(2) ! running from 0,1,...,N/2,N/2+1,-N/2,-N/2+1,...,-1 + do i = 1_pInt, grid1Red + k_s(1) = i - 1_pInt ! symmetry, junst running from 0,1,...,N/2,N/2+1 + xi2nd(1:3,i,j,k-grid3Offset) = utilities_getFreqDerivative(k_s) ! if divergence_correction is set, frequencies are calculated on unit length + where(mod(grid,2)==0 .and. [i,j,k] == grid/2+1 .and. & + spectral_derivative_ID == DERIVATIVE_CONTINUOUS_ID) ! for even grids, set the Nyquist Freq component to 0.0 + xi1st(1:3,i,j,k-grid3Offset) = cmplx(0.0_pReal,0.0_pReal,pReal) + elsewhere + xi1st(1:3,i,j,k-grid3Offset) = xi2nd(1:3,i,j,k-grid3Offset) + endwhere + enddo; enddo; enddo + + if(memory_efficient) then ! allocate just single fourth order tensor + allocate (gamma_hat(3,3,3,3,1,1,1), source = cmplx(0.0_pReal,0.0_pReal,pReal)) + else ! precalculation of gamma_hat field + allocate (gamma_hat(3,3,3,3,grid1Red,grid(2),grid3), source = cmplx(0.0_pReal,0.0_pReal,pReal)) + endif + +end subroutine utilities_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief updates references stiffness and potentially precalculated gamma operator +!> @details Sets the current reference stiffness to the stiffness given as an argument. +!> If the gamma operator is precalculated, it is calculated with this stiffness. +!> In case of a on-the-fly calculation, only the reference stiffness is updated. +!> Also writes out the current reference stiffness for restart. +!-------------------------------------------------------------------------------------------------- +subroutine utilities_updateGamma(C,saveReference) + use IO, only: & + IO_write_jobRealFile + use numerics, only: & + memory_efficient, & + worldrank + use mesh, only: & + grid3Offset, & + grid3,& + grid + use math, only: & + math_det33, & + math_invert + + implicit none + real(pReal), intent(in), dimension(3,3,3,3) :: C !< input stiffness to store as reference stiffness + logical , intent(in) :: saveReference !< save reference stiffness to file for restart + complex(pReal), dimension(3,3) :: temp33_complex, xiDyad_cmplx + real(pReal), dimension(6,6) :: matA, matInvA + integer(pInt) :: & + i, j, k, & + l, m, n, o + logical :: ierr + + C_ref = C + if (saveReference) then + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' writing reference stiffness to file' + flush(6) + call IO_write_jobRealFile(777,'C_ref',size(C_ref)) + write (777,rec=1) C_ref + close(777) + endif + endif + + if(.not. memory_efficient) then + gamma_hat = cmplx(0.0_pReal,0.0_pReal,pReal) ! for the singular point and any non invertible A + do k = grid3Offset+1_pInt, grid3Offset+grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid1Red + if (any([i,j,k] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + xiDyad_cmplx(l,m) = conjg(-xi1st(l,i,j,k-grid3Offset))*xi1st(m,i,j,k-grid3Offset) + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_complex(l,m) = sum(C_ref(l,1:3,m,1:3)*xiDyad_cmplx) + matA(1:3,1:3) = real(temp33_complex); matA(4:6,4:6) = real(temp33_complex) + matA(1:3,4:6) = aimag(temp33_complex); matA(4:6,1:3) = -aimag(temp33_complex) + if (abs(math_det33(matA(1:3,1:3))) > 1e-16) then + call math_invert(6_pInt, matA, matInvA, ierr) + temp33_complex = cmplx(matInvA(1:3,1:3),matInvA(1:3,4:6),pReal) + forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, o=1_pInt:3_pInt) & + gamma_hat(l,m,n,o,i,j,k-grid3Offset) = temp33_complex(l,n)* & + conjg(-xi1st(o,i,j,k-grid3Offset))*xi1st(m,i,j,k-grid3Offset) + endif + endif + enddo; enddo; enddo + endif + +end subroutine utilities_updateGamma + +!-------------------------------------------------------------------------------------------------- +!> @brief forward FFT of data in field_real to field_fourier +!> @details Does an unweighted filtered FFT transform from real to complex +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTtensorForward() + implicit none + +!-------------------------------------------------------------------------------------------------- +! doing the tensor FFT + call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) + +end subroutine utilities_FFTtensorForward + + +!-------------------------------------------------------------------------------------------------- +!> @brief backward FFT of data in field_fourier to field_real +!> @details Does an weighted inverse FFT transform from complex to real +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTtensorBackward() + implicit none + + call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real) + tensorField_real = tensorField_real * wgt ! normalize the result by number of elements + +end subroutine utilities_FFTtensorBackward + +!-------------------------------------------------------------------------------------------------- +!> @brief forward FFT of data in scalarField_real to scalarField_fourier +!> @details Does an unweighted filtered FFT transform from real to complex +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTscalarForward() + implicit none + +!-------------------------------------------------------------------------------------------------- +! doing the scalar FFT + call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier) + +end subroutine utilities_FFTscalarForward + + +!-------------------------------------------------------------------------------------------------- +!> @brief backward FFT of data in scalarField_fourier to scalarField_real +!> @details Does an weighted inverse FFT transform from complex to real +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTscalarBackward() + implicit none + + call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) + scalarField_real = scalarField_real * wgt ! normalize the result by number of elements + +end subroutine utilities_FFTscalarBackward + + +!-------------------------------------------------------------------------------------------------- +!> @brief forward FFT of data in field_real to field_fourier with highest freqs. removed +!> @details Does an unweighted filtered FFT transform from real to complex. +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTvectorForward() + implicit none + +!-------------------------------------------------------------------------------------------------- +! doing the vector FFT + call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier) + +end subroutine utilities_FFTvectorForward + + +!-------------------------------------------------------------------------------------------------- +!> @brief backward FFT of data in field_fourier to field_real +!> @details Does an weighted inverse FFT transform from complex to real +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTvectorBackward() + implicit none + + call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) + vectorField_real = vectorField_real * wgt ! normalize the result by number of elements + +end subroutine utilities_FFTvectorBackward + + +!-------------------------------------------------------------------------------------------------- +!> @brief doing convolution gamma_hat * field_real, ensuring that average value = fieldAim +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierGammaConvolution(fieldAim) + use numerics, only: & + memory_efficient + use math, only: & + math_det33, & + math_invert + use numerics, only: & + worldrank + use mesh, only: & + grid3, & + grid, & + grid3Offset + + implicit none + real(pReal), intent(in), dimension(3,3) :: fieldAim !< desired average value of the field after convolution + complex(pReal), dimension(3,3) :: temp33_complex, xiDyad_cmplx + real(pReal) :: matA(6,6), matInvA(6,6) + + integer(pInt) :: & + i, j, k, & + l, m, n, o + logical :: ierr + + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' ... doing gamma convolution ...............................................' + flush(6) + endif + +!-------------------------------------------------------------------------------------------------- +! do the actual spectral method calculation (mechanical equilibrium) + memoryEfficient: if(memory_efficient) then + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt, grid1Red + if (any([i,j,k+grid3Offset] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + xiDyad_cmplx(l,m) = conjg(-xi1st(l,i,j,k))*xi1st(m,i,j,k) + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_complex(l,m) = sum(C_ref(l,1:3,m,1:3)*xiDyad_cmplx) + matA(1:3,1:3) = real(temp33_complex); matA(4:6,4:6) = real(temp33_complex) + matA(1:3,4:6) = aimag(temp33_complex); matA(4:6,1:3) = -aimag(temp33_complex) + if (abs(math_det33(matA(1:3,1:3))) > 1e-16) then + call math_invert(6_pInt, matA, matInvA, ierr) + temp33_complex = cmplx(matInvA(1:3,1:3),matInvA(1:3,4:6),pReal) + forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, o=1_pInt:3_pInt) & + gamma_hat(l,m,n,o,1,1,1) = temp33_complex(l,n)*conjg(-xi1st(o,i,j,k))*xi1st(m,i,j,k) + else + gamma_hat(1:3,1:3,1:3,1:3,1,1,1) = cmplx(0.0_pReal,0.0_pReal,pReal) + endif + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3,1,1,1)*tensorField_fourier(1:3,1:3,i,j,k)) + tensorField_fourier(1:3,1:3,i,j,k) = temp33_Complex + endif + enddo; enddo; enddo + else memoryEfficient + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3,i,j,k) * tensorField_fourier(1:3,1:3,i,j,k)) + tensorField_fourier(1:3,1:3,i,j,k) = temp33_Complex + enddo; enddo; enddo + endif memoryEfficient + + if (grid3Offset == 0_pInt) & + tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim/wgt,0.0_pReal,pReal) + +end subroutine utilities_fourierGammaConvolution + + +!-------------------------------------------------------------------------------------------------- +!> @brief doing convolution DamageGreenOp_hat * field_real +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierGreenConvolution(D_ref, mobility_ref, deltaT) + + use math, only: & + math_mul33x3, & + PI + use mesh, only: & + grid, & + grid3 + + implicit none + real(pReal), dimension(3,3), intent(in) :: D_ref !< desired average value of the field after convolution + real(pReal), intent(in) :: mobility_ref, deltaT !< desired average value of the field after convolution + complex(pReal) :: GreenOp_hat + integer(pInt) :: i, j, k + +!-------------------------------------------------------------------------------------------------- +! do the actual spectral method calculation + do k = 1_pInt, grid3; do j = 1_pInt, grid(2) ;do i = 1_pInt, grid1Red + GreenOp_hat = cmplx(1.0_pReal,0.0_pReal,pReal)/ & + (cmplx(mobility_ref,0.0_pReal,pReal) + & + deltaT*sum(conjg(xi1st(1:3,i,j,k))*matmul(D_ref,xi1st(1:3,i,j,k)))) ! why not use dot_product + scalarField_fourier(i,j,k) = scalarField_fourier(i,j,k)*GreenOp_hat + enddo; enddo; enddo + +end subroutine utilities_fourierGreenConvolution + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate root mean square of divergence of field_fourier +!-------------------------------------------------------------------------------------------------- +real(pReal) function utilities_divergenceRMS() + use numerics, only: & + worldrank + use mesh, only: & + geomSize, & + grid, & + grid3 + + implicit none + integer(pInt) :: i, j, k + PetscErrorCode :: ierr + + external :: & + MPI_Allreduce + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' ... calculating divergence ................................................' + flush(6) + endif + +!-------------------------------------------------------------------------------------------------- +! calculating RMS divergence criterion in Fourier space + utilities_divergenceRMS = 0.0_pReal + do k = 1_pInt, grid3; do j = 1_pInt, grid(2) + do i = 2_pInt, grid1Red -1_pInt ! Has somewhere a conj. complex counterpart. Therefore count it twice. + utilities_divergenceRMS = utilities_divergenceRMS & + + 2.0_pReal*(sum (real(matmul(tensorField_fourier(1:3,1:3,i,j,k),& ! (sqrt(real(a)**2 + aimag(a)**2))**2 = real(a)**2 + aimag(a)**2. do not take square root and square again + conjg(-xi1st(1:3,i,j,k))*geomSize/scaledGeomSize))**2.0_pReal)& ! --> sum squared L_2 norm of vector + +sum(aimag(matmul(tensorField_fourier(1:3,1:3,i,j,k),& + conjg(-xi1st(1:3,i,j,k))*geomSize/scaledGeomSize))**2.0_pReal)) + enddo + utilities_divergenceRMS = utilities_divergenceRMS & ! these two layers (DC and Nyquist) do not have a conjugate complex counterpart (if grid(1) /= 1) + + sum( real(matmul(tensorField_fourier(1:3,1:3,1 ,j,k), & + conjg(-xi1st(1:3,1,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & + + sum(aimag(matmul(tensorField_fourier(1:3,1:3,1 ,j,k), & + conjg(-xi1st(1:3,1,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & + + sum( real(matmul(tensorField_fourier(1:3,1:3,grid1Red,j,k), & + conjg(-xi1st(1:3,grid1Red,j,k))*geomSize/scaledGeomSize))**2.0_pReal) & + + sum(aimag(matmul(tensorField_fourier(1:3,1:3,grid1Red,j,k), & + conjg(-xi1st(1:3,grid1Red,j,k))*geomSize/scaledGeomSize))**2.0_pReal) + enddo; enddo + if(grid(1) == 1_pInt) utilities_divergenceRMS = utilities_divergenceRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 + call MPI_Allreduce(MPI_IN_PLACE,utilities_divergenceRMS,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + utilities_divergenceRMS = sqrt(utilities_divergenceRMS) * wgt ! RMS in real space calculated with Parsevals theorem from Fourier space + + +end function utilities_divergenceRMS + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate max of curl of field_fourier +!-------------------------------------------------------------------------------------------------- +real(pReal) function utilities_curlRMS() + use numerics, only: & + worldrank + use mesh, only: & + geomSize, & + grid, & + grid3 + + implicit none + integer(pInt) :: i, j, k, l + complex(pReal), dimension(3,3) :: curl_fourier + PetscErrorCode :: ierr + + external :: & + MPI_Reduce, & + MPI_Allreduce + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' ... calculating curl ......................................................' + flush(6) + endif + + !-------------------------------------------------------------------------------------------------- +! calculating max curl criterion in Fourier space + utilities_curlRMS = 0.0_pReal + + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); + do i = 2_pInt, grid1Red - 1_pInt + do l = 1_pInt, 3_pInt + curl_fourier(l,1) = (+tensorField_fourier(l,3,i,j,k)*xi1st(2,i,j,k)*geomSize(2)/scaledGeomSize(2) & + -tensorField_fourier(l,2,i,j,k)*xi1st(3,i,j,k)*geomSize(3)/scaledGeomSize(3)) + curl_fourier(l,2) = (+tensorField_fourier(l,1,i,j,k)*xi1st(3,i,j,k)*geomSize(3)/scaledGeomSize(3) & + -tensorField_fourier(l,3,i,j,k)*xi1st(1,i,j,k)*geomSize(1)/scaledGeomSize(1)) + curl_fourier(l,3) = (+tensorField_fourier(l,2,i,j,k)*xi1st(1,i,j,k)*geomSize(1)/scaledGeomSize(1) & + -tensorField_fourier(l,1,i,j,k)*xi1st(2,i,j,k)*geomSize(2)/scaledGeomSize(2)) + enddo + utilities_curlRMS = utilities_curlRMS + & + 2.0_pReal*sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! Has somewhere a conj. complex counterpart. Therefore count it twice. + enddo + do l = 1_pInt, 3_pInt + curl_fourier = (+tensorField_fourier(l,3,1,j,k)*xi1st(2,1,j,k)*geomSize(2)/scaledGeomSize(2) & + -tensorField_fourier(l,2,1,j,k)*xi1st(3,1,j,k)*geomSize(3)/scaledGeomSize(3)) + curl_fourier = (+tensorField_fourier(l,1,1,j,k)*xi1st(3,1,j,k)*geomSize(3)/scaledGeomSize(3) & + -tensorField_fourier(l,3,1,j,k)*xi1st(1,1,j,k)*geomSize(1)/scaledGeomSize(1)) + curl_fourier = (+tensorField_fourier(l,2,1,j,k)*xi1st(1,1,j,k)*geomSize(1)/scaledGeomSize(1) & + -tensorField_fourier(l,1,1,j,k)*xi1st(2,1,j,k)*geomSize(2)/scaledGeomSize(2)) + enddo + utilities_curlRMS = utilities_curlRMS + & + sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! this layer (DC) does not have a conjugate complex counterpart (if grid(1) /= 1) + do l = 1_pInt, 3_pInt + curl_fourier = (+tensorField_fourier(l,3,grid1Red,j,k)*xi1st(2,grid1Red,j,k)*geomSize(2)/scaledGeomSize(2) & + -tensorField_fourier(l,2,grid1Red,j,k)*xi1st(3,grid1Red,j,k)*geomSize(3)/scaledGeomSize(3)) + curl_fourier = (+tensorField_fourier(l,1,grid1Red,j,k)*xi1st(3,grid1Red,j,k)*geomSize(3)/scaledGeomSize(3) & + -tensorField_fourier(l,3,grid1Red,j,k)*xi1st(1,grid1Red,j,k)*geomSize(1)/scaledGeomSize(1)) + curl_fourier = (+tensorField_fourier(l,2,grid1Red,j,k)*xi1st(1,grid1Red,j,k)*geomSize(1)/scaledGeomSize(1) & + -tensorField_fourier(l,1,grid1Red,j,k)*xi1st(2,grid1Red,j,k)*geomSize(2)/scaledGeomSize(2)) + enddo + utilities_curlRMS = utilities_curlRMS + & + sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal)! this layer (Nyquist) does not have a conjugate complex counterpart (if grid(1) /= 1) + enddo; enddo + + call MPI_Allreduce(MPI_IN_PLACE,utilities_curlRMS,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + utilities_curlRMS = sqrt(utilities_curlRMS) * wgt + if(grid(1) == 1_pInt) utilities_curlRMS = utilities_curlRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 + +end function utilities_curlRMS + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates mask compliance tensor used to adjust F to fullfill stress BC +!-------------------------------------------------------------------------------------------------- +function utilities_maskedCompliance(rot_BC,mask_stress,C) + use prec, only: & + prec_isNaN + use IO, only: & + IO_error + use numerics, only: & + worldrank + use math, only: & + math_Plain3333to99, & + math_plain99to3333, & + math_rotate_forward3333, & + math_rotate_forward33, & + math_invert + + implicit none + real(pReal), dimension(3,3,3,3) :: utilities_maskedCompliance !< masked compliance + real(pReal), intent(in) , dimension(3,3,3,3) :: C !< current average stiffness + real(pReal), intent(in) , dimension(3,3) :: rot_BC !< rotation of load frame + logical, intent(in), dimension(3,3) :: mask_stress !< mask of stress BC + integer(pInt) :: j, k, m, n + logical, dimension(9) :: mask_stressVector + real(pReal), dimension(9,9) :: temp99_Real + integer(pInt) :: size_reduced = 0_pInt + real(pReal), dimension(:,:), allocatable :: & + s_reduced, & !< reduced compliance matrix (depending on number of stress BC) + c_reduced, & !< reduced stiffness (depending on number of stress BC) + sTimesC !< temp variable to check inversion + logical :: errmatinv + character(len=1024):: formatString + + mask_stressVector = reshape(transpose(mask_stress), [9]) + size_reduced = int(count(mask_stressVector), pInt) + if(size_reduced > 0_pInt )then + allocate (c_reduced(size_reduced,size_reduced), source =0.0_pReal) + allocate (s_reduced(size_reduced,size_reduced), source =0.0_pReal) + allocate (sTimesC(size_reduced,size_reduced), source =0.0_pReal) + temp99_Real = math_Plain3333to99(math_rotate_forward3333(C,rot_BC)) + + if(debugGeneral .and. worldrank == 0_pInt) then + write(6,'(/,a)') ' ... updating masked compliance ............................................' + write(6,'(/,a,/,9(9(2x,f12.7,1x)/))',advance='no') ' Stiffness C (load) / GPa =',& + transpose(temp99_Real)/1.e9_pReal + flush(6) + endif + k = 0_pInt ! calculate reduced stiffness + do n = 1_pInt,9_pInt + if(mask_stressVector(n)) then + k = k + 1_pInt + j = 0_pInt + do m = 1_pInt,9_pInt + if(mask_stressVector(m)) then + j = j + 1_pInt + c_reduced(k,j) = temp99_Real(n,m) + endif; enddo; endif; enddo + + call math_invert(size_reduced, c_reduced, s_reduced, errmatinv) ! invert reduced stiffness + if (any(prec_isNaN(s_reduced))) errmatinv = .true. + if(errmatinv) call IO_error(error_ID=400_pInt,ext_msg='utilities_maskedCompliance') + temp99_Real = 0.0_pReal ! fill up compliance with zeros + k = 0_pInt + do n = 1_pInt,9_pInt + if(mask_stressVector(n)) then + k = k + 1_pInt + j = 0_pInt + do m = 1_pInt,9_pInt + if(mask_stressVector(m)) then + j = j + 1_pInt + temp99_Real(n,m) = s_reduced(k,j) + endif; enddo; endif; enddo + +!-------------------------------------------------------------------------------------------------- +! check if inversion was successful + sTimesC = matmul(c_reduced,s_reduced) + do m=1_pInt, size_reduced + do n=1_pInt, size_reduced + if(m==n .and. abs(sTimesC(m,n)) > (1.0_pReal + 10.0e-12_pReal)) errmatinv = .true. ! diagonal elements of S*C should be 1 + if(m/=n .and. abs(sTimesC(m,n)) > (0.0_pReal + 10.0e-12_pReal)) errmatinv = .true. ! off diagonal elements of S*C should be 0 + enddo + enddo + if((debugGeneral .or. errmatinv) .and. (worldrank == 0_pInt)) then ! report + write(formatString, '(I16.16)') size_reduced + formatString = '(/,a,/,'//trim(formatString)//'('//trim(formatString)//'(2x,es9.2,1x)/))' + write(6,trim(formatString),advance='no') ' C * S (load) ', & + transpose(matmul(c_reduced,s_reduced)) + write(6,trim(formatString),advance='no') ' S (load) ', transpose(s_reduced) + endif + if(errmatinv) call IO_error(error_ID=400_pInt,ext_msg='utilities_maskedCompliance') + deallocate(c_reduced) + deallocate(s_reduced) + deallocate(sTimesC) + else + temp99_real = 0.0_pReal + endif + if(debugGeneral .and. worldrank == 0_pInt) & ! report + write(6,'(/,a,/,9(9(2x,f12.7,1x)/),/)',advance='no') ' Masked Compliance (load) * GPa =', & + transpose(temp99_Real*1.e9_pReal) + flush(6) + utilities_maskedCompliance = math_Plain99to3333(temp99_Real) + +end function utilities_maskedCompliance + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate scalar gradient in fourier field +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierScalarGradient() + use mesh, only: & + grid3, & + grid + + implicit none + integer(pInt) :: i, j, k + + vectorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) + forall(k = 1_pInt:grid3, j = 1_pInt:grid(2), i = 1_pInt:grid1Red) & + vectorField_fourier(1:3,i,j,k) = scalarField_fourier(i,j,k)*xi1st(1:3,i,j,k) + +end subroutine utilities_fourierScalarGradient + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate vector divergence in fourier field +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierVectorDivergence() + use mesh, only: & + grid3, & + grid + + implicit none + integer(pInt) :: i, j, k + + scalarField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) + forall(k = 1_pInt:grid3, j = 1_pInt:grid(2), i = 1_pInt:grid1Red) & + scalarField_fourier(i,j,k) = scalarField_fourier(i,j,k) + & + sum(vectorField_fourier(1:3,i,j,k)*conjg(-xi1st(1:3,i,j,k))) + +end subroutine utilities_fourierVectorDivergence + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate vector gradient in fourier field +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierVectorGradient() + use mesh, only: & + grid3, & + grid + + implicit none + integer(pInt) :: i, j, k, m, n + + tensorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red + do m = 1_pInt, 3_pInt; do n = 1_pInt, 3_pInt + tensorField_fourier(m,n,i,j,k) = vectorField_fourier(m,i,j,k)*xi1st(n,i,j,k) + enddo; enddo + enddo; enddo; enddo +end subroutine utilities_fourierVectorGradient + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate tensor divergence in fourier field +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierTensorDivergence() + use mesh, only: & + grid3, & + grid + + implicit none + integer(pInt) :: i, j, k, m, n + + vectorField_fourier = cmplx(0.0_pReal,0.0_pReal,pReal) + do k = 1_pInt, grid3; do j = 1_pInt, grid(2); do i = 1_pInt,grid1Red + do m = 1_pInt, 3_pInt; do n = 1_pInt, 3_pInt + vectorField_fourier(m,i,j,k) = & + vectorField_fourier(m,i,j,k) + & + tensorField_fourier(m,n,i,j,k)*conjg(-xi1st(n,i,j,k)) + enddo; enddo + enddo; enddo; enddo +end subroutine utilities_fourierTensorDivergence + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates constitutive response +!-------------------------------------------------------------------------------------------------- +subroutine utilities_constitutiveResponse(F_lastInc,F,timeinc, & + P,C_volAvg,C_minmaxAvg,P_av,forwardData,rotation_BC) + use debug, only: & + debug_reset, & + debug_info + use numerics, only: & + worldrank + use math, only: & + math_transpose33, & + math_rotate_forward33, & + math_det33 + use mesh, only: & + grid,& + grid3 + use FEsolving, only: & + restartWrite + use CPFEM2, only: & + CPFEM_general + use homogenization, only: & + materialpoint_F0, & + materialpoint_F, & + materialpoint_P, & + materialpoint_dPdF + + implicit none + real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & + F_lastInc, & !< target deformation gradient + F !< previous deformation gradient + real(pReal), intent(in) :: timeinc !< loading time + logical, intent(in) :: forwardData !< age results + real(pReal), intent(in), dimension(3,3) :: rotation_BC !< rotation of load frame + + real(pReal),intent(out), dimension(3,3,3,3) :: C_volAvg, C_minmaxAvg !< average stiffness + real(pReal),intent(out), dimension(3,3) :: P_av !< average PK stress + real(pReal),intent(out), dimension(3,3,grid(1),grid(2),grid3) :: P !< PK stress + + logical :: & + age + + integer(pInt) :: & + j,k + real(pReal), dimension(3,3,3,3) :: max_dPdF, min_dPdF + real(pReal) :: max_dPdF_norm, min_dPdF_norm, defgradDetMin, defgradDetMax, defgradDet + PetscErrorCode :: ierr + + external :: & + MPI_Reduce, & + MPI_Allreduce + + if (worldrank == 0_pInt) then + write(6,'(/,a)') ' ... evaluating constitutive response ......................................' + flush(6) + endif + age = .False. + + if (forwardData) then ! aging results + age = .True. + materialpoint_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) + endif + if (cutBack) then ! restore saved variables + age = .False. + endif + + materialpoint_F = reshape(F,[3,3,1,product(grid(1:2))*grid3]) + call debug_reset() + +!-------------------------------------------------------------------------------------------------- +! calculate bounds of det(F) and report + if(debugGeneral) then + defgradDetMax = -huge(1.0_pReal) + defgradDetMin = +huge(1.0_pReal) + do j = 1_pInt, product(grid(1:2))*grid3 + defgradDet = math_det33(materialpoint_F(1:3,1:3,1,j)) + defgradDetMax = max(defgradDetMax,defgradDet) + defgradDetMin = min(defgradDetMin,defgradDet) + end do + call MPI_reduce(MPI_IN_PLACE,defgradDetMax,1,MPI_DOUBLE,MPI_MAX,0,PETSC_COMM_WORLD,ierr) + call MPI_reduce(MPI_IN_PLACE,defgradDetMin,1,MPI_DOUBLE,MPI_MIN,0,PETSC_COMM_WORLD,ierr) + if (worldrank == 0_pInt) then + write(6,'(a,1x,es11.4)') ' max determinant of deformation =', defgradDetMax + write(6,'(a,1x,es11.4)') ' min determinant of deformation =', defgradDetMin + flush(6) + endif + endif + + call CPFEM_general(age,timeinc) + + max_dPdF = 0.0_pReal + max_dPdF_norm = 0.0_pReal + min_dPdF = huge(1.0_pReal) + min_dPdF_norm = huge(1.0_pReal) + do k = 1_pInt, product(grid(1:2))*grid3 + if (max_dPdF_norm < sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal)) then + max_dPdF = materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k) + max_dPdF_norm = sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal) + endif + if (min_dPdF_norm > sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal)) then + min_dPdF = materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k) + min_dPdF_norm = sum(materialpoint_dPdF(1:3,1:3,1:3,1:3,1,k)**2.0_pReal) + endif + end do + + call MPI_Allreduce(MPI_IN_PLACE,max_dPdF,81,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + call MPI_Allreduce(MPI_IN_PLACE,min_dPdF,81,MPI_DOUBLE,MPI_MIN,PETSC_COMM_WORLD,ierr) + + C_minmaxAvg = 0.5_pReal*(max_dPdF + min_dPdF) + C_volAvg = sum(sum(materialpoint_dPdF,dim=6),dim=5) * wgt + + call MPI_Allreduce(MPI_IN_PLACE,C_volAvg,81,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + + call debug_info() + + restartWrite = .false. ! reset restartWrite status + cutBack = .false. ! reset cutBack status + + P = reshape(materialpoint_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 .and. worldrank == 0_pInt) & + write(6,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress (lab) / MPa =',& + math_transpose33(P_av)*1.e-6_pReal + P_av = math_rotate_forward33(P_av,rotation_BC) + if (worldrank == 0_pInt) then + write(6,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress / MPa =',& + math_transpose33(P_av)*1.e-6_pReal + flush(6) + endif + +end subroutine utilities_constitutiveResponse + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates forward rate, either guessing or just add delta/timeinc +!-------------------------------------------------------------------------------------------------- +pure function utilities_calculateRate(avRate,timeinc_old,guess,field_lastInc,field) + use mesh, only: & + grid3, & + grid + + implicit none + real(pReal), intent(in), dimension(3,3) :: avRate !< homogeneous addon + real(pReal), intent(in) :: & + timeinc_old !< timeinc of last step + logical, intent(in) :: & + guess !< guess along former trajectory + real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & + field_lastInc, & !< data of previous step + field !< data of current step + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: & + utilities_calculateRate + + if (guess) then + utilities_calculateRate = (field-field_lastInc) / timeinc_old + else + utilities_calculateRate = spread(spread(spread(avRate,3,grid(1)),4,grid(2)),5,grid3) + endif + +end function utilities_calculateRate + + +!-------------------------------------------------------------------------------------------------- +!> @brief forwards a field with a pointwise given rate, if aim is given, +!> ensures that the average matches the aim +!-------------------------------------------------------------------------------------------------- +function utilities_forwardField(timeinc,field_lastInc,rate,aim) + use mesh, only: & + grid3, & + grid + + implicit none + real(pReal), intent(in) :: & + timeinc !< timeinc of current step + real(pReal), intent(in), dimension(3,3,grid(1),grid(2),grid3) :: & + field_lastInc, & !< initial field + rate !< rate by which to forward + real(pReal), intent(in), optional, dimension(3,3) :: & + aim !< average field value aim + real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: & + utilities_forwardField + real(pReal), dimension(3,3) :: fieldDiff !< - aim + PetscErrorCode :: ierr + + external :: & + MPI_Allreduce + + utilities_forwardField = field_lastInc + rate*timeinc + if (present(aim)) then !< correct to match average + fieldDiff = sum(sum(sum(utilities_forwardField,dim=5),dim=4),dim=3)*wgt + call MPI_Allreduce(MPI_IN_PLACE,fieldDiff,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + fieldDiff = fieldDiff - aim + utilities_forwardField = utilities_forwardField - & + spread(spread(spread(fieldDiff,3,grid(1)),4,grid(2)),5,grid3) + endif + +end function utilities_forwardField + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates filter for fourier convolution depending on type given in numerics.config +!-------------------------------------------------------------------------------------------------- +pure function utilities_getFreqDerivative(k_s) + use math, only: & + PI + use mesh, only: & + geomSize, & + grid + + implicit none + integer(pInt), intent(in), dimension(3) :: k_s !< indices of frequency + complex(pReal), dimension(3) :: utilities_getFreqDerivative + + select case (spectral_derivative_ID) + case (DERIVATIVE_CONTINUOUS_ID) + utilities_getFreqDerivative = cmplx(0.0_pReal, 2.0_pReal*PI*real(k_s,pReal)/geomSize,pReal) + + case (DERIVATIVE_CENTRAL_DIFF_ID) + utilities_getFreqDerivative = cmplx(0.0_pReal, sin(2.0_pReal*PI*real(k_s,pReal)/real(grid,pReal)), pReal)/ & + cmplx(2.0_pReal*geomSize/real(grid,pReal), 0.0_pReal, pReal) + + case (DERIVATIVE_FWBW_DIFF_ID) + utilities_getFreqDerivative(1) = & + cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) - 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & + cmplx(4.0_pReal*geomSize(1)/real(grid(1),pReal), 0.0_pReal, pReal) + utilities_getFreqDerivative(2) = & + cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) - 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & + cmplx(4.0_pReal*geomSize(2)/real(grid(2),pReal), 0.0_pReal, pReal) + utilities_getFreqDerivative(3) = & + cmplx(cos(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(1),pReal)/real(grid(1),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)) + 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(2),pReal)/real(grid(2),pReal)), pReal)* & + cmplx(cos(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)) - 1.0_pReal, & + sin(2.0_pReal*PI*real(k_s(3),pReal)/real(grid(3),pReal)), pReal)/ & + cmplx(4.0_pReal*geomSize(3)/real(grid(3),pReal), 0.0_pReal, pReal) + + end select + +end function utilities_getFreqDerivative + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate coordinates in current configuration for given defgrad field +! using integration in Fourier space. Similar as in mesh.f90, but using data already defined for +! convolution +!-------------------------------------------------------------------------------------------------- +subroutine utilities_updateIPcoords(F) + use math, only: & + math_mul33x3 + use mesh, only: & + grid, & + grid3, & + grid3Offset, & + geomSize, & + mesh_ipCoordinates + implicit none + + real(pReal), dimension(3,3,grid(1),grid(2),grid3), intent(in) :: F + integer(pInt) :: i, j, k, m + real(pReal), dimension(3) :: step, offset_coords + real(pReal), dimension(3,3) :: Favg + PetscErrorCode :: ierr + external & + MPI_Bcast + +!-------------------------------------------------------------------------------------------------- +! integration in Fourier space + tensorField_real = 0.0_pReal + tensorField_real(1:3,1:3,1:grid(1),1:grid(2),1:grid3) = F + call utilities_FFTtensorForward() + call utilities_fourierTensorDivergence() + + do k = 1_pInt, grid3; do j = 1_pInt, grid(2) ;do i = 1_pInt, grid1Red + if (any(abs(xi1st(1:3,i,j,k)) > tiny(0.0_pReal))) & + vectorField_fourier(1:3,i,j,k) = vectorField_fourier(1:3,i,j,k)/ & + sum(conjg(-xi1st(1:3,i,j,k))*xi1st(1:3,i,j,k)) + enddo; enddo; enddo + call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) + +!-------------------------------------------------------------------------------------------------- +! average F + if (grid3Offset == 0_pInt) Favg = real(tensorField_fourier(1:3,1:3,1,1,1),pReal)*wgt + call MPI_Bcast(Favg,9,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) + +!-------------------------------------------------------------------------------------------------- +! add average to fluctuation and put (0,0,0) on (0,0,0) + step = geomSize/real(grid, pReal) + if (grid3Offset == 0_pInt) offset_coords = vectorField_real(1:3,1,1,1) + call MPI_Bcast(offset_coords,3,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) + offset_coords = math_mul33x3(Favg,step/2.0_pReal) - offset_coords + m = 1_pInt + do k = 1_pInt,grid3; do j = 1_pInt,grid(2); do i = 1_pInt,grid(1) + mesh_ipCoordinates(1:3,1,m) = vectorField_real(1:3,i,j,k) & + + offset_coords & + + math_mul33x3(Favg,step*real([i,j,k+grid3Offset]-1_pInt,pReal)) + m = m+1_pInt + enddo; enddo; enddo + +end subroutine utilities_updateIPcoords + + +!-------------------------------------------------------------------------------------------------- +!> @brief cleans up +!-------------------------------------------------------------------------------------------------- +subroutine utilities_destroy() + implicit none + + call fftw_destroy_plan(planTensorForth) + call fftw_destroy_plan(planTensorBack) + call fftw_destroy_plan(planVectorForth) + call fftw_destroy_plan(planVectorBack) + call fftw_destroy_plan(planScalarForth) + call fftw_destroy_plan(planScalarBack) + +end subroutine utilities_destroy + + +end module spectral_utilities diff --git a/src/thermal_adiabatic.f90 b/src/thermal_adiabatic.f90 new file mode 100644 index 000000000..7bb8620e7 --- /dev/null +++ b/src/thermal_adiabatic.f90 @@ -0,0 +1,422 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for adiabatic temperature evolution +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module thermal_adiabatic + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + thermal_adiabatic_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + thermal_adiabatic_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + thermal_adiabatic_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + thermal_adiabatic_Noutput !< number of outputs per instance of this thermal model + + enum, bind(c) + enumerator :: undefined_ID, & + temperature_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + thermal_adiabatic_outputID !< ID of each post result output + + + public :: & + thermal_adiabatic_init, & + thermal_adiabatic_updateState, & + thermal_adiabatic_getSourceAndItsTangent, & + thermal_adiabatic_getSpecificHeat, & + thermal_adiabatic_getMassDensity, & + thermal_adiabatic_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine thermal_adiabatic_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + thermal_type, & + thermal_typeInstance, & + homogenization_Noutput, & + THERMAL_ADIABATIC_label, & + THERMAL_adiabatic_ID, & + material_homog, & + mappingHomogenization, & + thermalState, & + thermalMapping, & + thermal_initialT, & + temperature, & + temperatureRate, & + material_partHomogenization + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_ADIABATIC_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(thermal_type == THERMAL_adiabatic_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(thermal_adiabatic_sizePostResults(maxNinstance), source=0_pInt) + allocate(thermal_adiabatic_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(thermal_adiabatic_output (maxval(homogenization_Noutput),maxNinstance)) + thermal_adiabatic_output = '' + allocate(thermal_adiabatic_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(thermal_adiabatic_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (thermal_type(section) == THERMAL_adiabatic_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = thermal_typeInstance(section) ! which instance of my thermal is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('temperature') + thermal_adiabatic_Noutput(instance) = thermal_adiabatic_Noutput(instance) + 1_pInt + thermal_adiabatic_outputID(thermal_adiabatic_Noutput(instance),instance) = temperature_ID + thermal_adiabatic_output(thermal_adiabatic_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingFile + + initializeInstances: do section = 1_pInt, size(thermal_type) + if (thermal_type(section) == THERMAL_adiabatic_ID) then + NofMyHomog=count(material_homog==section) + instance = thermal_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,thermal_adiabatic_Noutput(instance) + select case(thermal_adiabatic_outputID(o,instance)) + case(temperature_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + thermal_adiabatic_sizePostResult(o,instance) = mySize + thermal_adiabatic_sizePostResults(instance) = thermal_adiabatic_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 1_pInt + thermalState(section)%sizeState = sizeState + thermalState(section)%sizePostResults = thermal_adiabatic_sizePostResults(instance) + allocate(thermalState(section)%state0 (sizeState,NofMyHomog), source=thermal_initialT(section)) + allocate(thermalState(section)%subState0(sizeState,NofMyHomog), source=thermal_initialT(section)) + allocate(thermalState(section)%state (sizeState,NofMyHomog), source=thermal_initialT(section)) + + nullify(thermalMapping(section)%p) + thermalMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(temperature(section)%p) + temperature(section)%p => thermalState(section)%state(1,:) + deallocate(temperatureRate(section)%p) + allocate (temperatureRate(section)%p(NofMyHomog), source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine thermal_adiabatic_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates adiabatic change in temperature based on local heat generation model +!-------------------------------------------------------------------------------------------------- +function thermal_adiabatic_updateState(subdt, ip, el) + use numerics, only: & + err_thermal_tolAbs, & + err_thermal_tolRel + use material, only: & + mappingHomogenization, & + thermalState, & + temperature, & + temperatureRate, & + thermalMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + subdt + logical, dimension(2) :: & + thermal_adiabatic_updateState + integer(pInt) :: & + homog, & + offset + real(pReal) :: & + T, Tdot, dTdot_dT + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,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)) & + <= err_thermal_tolAbs & + .or. abs(T - thermalState(homog)%state(1,offset)) & + <= err_thermal_tolRel*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) + use math, only: & + math_Mandel6to33 + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + thermal_typeInstance, & + phase_Nsources, & + phase_source, & + SOURCE_thermal_dissipation_ID, & + SOURCE_thermal_externalheat_ID + use source_thermal_dissipation, only: & + source_thermal_dissipation_getRateAndItsTangent + use source_thermal_externalheat, only: & + source_thermal_externalheat_getRateAndItsTangent + use crystallite, only: & + crystallite_Tstar_v, & + crystallite_Lp + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + T + real(pReal), intent(out) :: & + Tdot, dTdot_dT + real(pReal) :: & + my_Tdot, my_dTdot_dT + integer(pInt) :: & + phase, & + homog, & + offset, & + instance, & + grain, & + source + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + instance = thermal_typeInstance(homog) + + Tdot = 0.0_pReal + dTdot_dT = 0.0_pReal + do grain = 1, homogenization_Ngrains(homog) + phase = phaseAt(grain,ip,el) + do source = 1, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_thermal_dissipation_ID) + call source_thermal_dissipation_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & + crystallite_Tstar_v(1:6,grain,ip,el), & + crystallite_Lp(1:3,1:3,grain,ip,el), & + grain, ip, el) + + case (SOURCE_thermal_externalheat_ID) + call source_thermal_externalheat_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & + grain, ip, el) + + case default + my_Tdot = 0.0_pReal + my_dTdot_dT = 0.0_pReal + end select + Tdot = Tdot + my_Tdot + dTdot_dT = dTdot_dT + my_dTdot_dT + enddo + enddo + + Tdot = Tdot/homogenization_Ngrains(homog) + dTdot_dT = dTdot_dT/homogenization_Ngrains(homog) + +end subroutine thermal_adiabatic_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized specific heat capacity +!-------------------------------------------------------------------------------------------------- +function thermal_adiabatic_getSpecificHeat(ip,el) + use lattice, only: & + lattice_specificHeat + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + thermal_adiabatic_getSpecificHeat + integer(pInt) :: & + homog, grain + + thermal_adiabatic_getSpecificHeat = 0.0_pReal + + homog = mappingHomogenization(2,ip,el) + + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + thermal_adiabatic_getSpecificHeat = thermal_adiabatic_getSpecificHeat + & + lattice_specificHeat(material_phase(grain,ip,el)) + enddo + + thermal_adiabatic_getSpecificHeat = & + thermal_adiabatic_getSpecificHeat/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function thermal_adiabatic_getSpecificHeat + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized mass density +!-------------------------------------------------------------------------------------------------- +function thermal_adiabatic_getMassDensity(ip,el) + use lattice, only: & + lattice_massDensity + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + thermal_adiabatic_getMassDensity + integer(pInt) :: & + homog, grain + + thermal_adiabatic_getMassDensity = 0.0_pReal + + homog = mappingHomogenization(2,ip,el) + + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + thermal_adiabatic_getMassDensity = thermal_adiabatic_getMassDensity + & + lattice_massDensity(material_phase(grain,ip,el)) + enddo + + thermal_adiabatic_getMassDensity = & + thermal_adiabatic_getMassDensity/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function thermal_adiabatic_getMassDensity + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of thermal results +!-------------------------------------------------------------------------------------------------- +function thermal_adiabatic_postResults(ip,el) + use material, only: & + mappingHomogenization, & + thermal_typeInstance, & + thermalMapping, & + temperature + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(thermal_adiabatic_sizePostResults(thermal_typeInstance(mappingHomogenization(2,ip,el)))) :: & + thermal_adiabatic_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = thermalMapping(homog)%p(ip,el) + instance = thermal_typeInstance(homog) + + c = 0_pInt + thermal_adiabatic_postResults = 0.0_pReal + + do o = 1_pInt,thermal_adiabatic_Noutput(instance) + select case(thermal_adiabatic_outputID(o,instance)) + + case (temperature_ID) + thermal_adiabatic_postResults(c+1_pInt) = temperature(homog)%p(offset) + c = c + 1 + end select + enddo +end function thermal_adiabatic_postResults + +end module thermal_adiabatic diff --git a/src/thermal_conduction.f90 b/src/thermal_conduction.f90 new file mode 100644 index 000000000..2f9b766eb --- /dev/null +++ b/src/thermal_conduction.f90 @@ -0,0 +1,444 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for temperature evolution from heat conduction +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module thermal_conduction + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + thermal_conduction_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + thermal_conduction_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + thermal_conduction_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + thermal_conduction_Noutput !< number of outputs per instance of this damage + + enum, bind(c) + enumerator :: undefined_ID, & + temperature_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + thermal_conduction_outputID !< ID of each post result output + + + public :: & + thermal_conduction_init, & + thermal_conduction_getSourceAndItsTangent, & + thermal_conduction_getConductivity33, & + thermal_conduction_getSpecificHeat, & + thermal_conduction_getMassDensity, & + thermal_conduction_putTemperatureAndItsRate, & + thermal_conduction_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine thermal_conduction_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + thermal_type, & + thermal_typeInstance, & + homogenization_Noutput, & + THERMAL_conduction_label, & + THERMAL_conduction_ID, & + material_homog, & + mappingHomogenization, & + thermalState, & + thermalMapping, & + thermal_initialT, & + temperature, & + temperatureRate, & + material_partHomogenization + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_CONDUCTION_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(thermal_type == THERMAL_conduction_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(thermal_conduction_sizePostResults(maxNinstance), source=0_pInt) + allocate(thermal_conduction_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(thermal_conduction_output (maxval(homogenization_Noutput),maxNinstance)) + thermal_conduction_output = '' + allocate(thermal_conduction_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(thermal_conduction_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (thermal_type(section) == THERMAL_conduction_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = thermal_typeInstance(section) ! which instance of my thermal is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('temperature') + thermal_conduction_Noutput(instance) = thermal_conduction_Noutput(instance) + 1_pInt + thermal_conduction_outputID(thermal_conduction_Noutput(instance),instance) = temperature_ID + thermal_conduction_output(thermal_conduction_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingFile + + initializeInstances: do section = 1_pInt, size(thermal_type) + if (thermal_type(section) == THERMAL_conduction_ID) then + NofMyHomog=count(material_homog==section) + instance = thermal_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,thermal_conduction_Noutput(instance) + select case(thermal_conduction_outputID(o,instance)) + case(temperature_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + thermal_conduction_sizePostResult(o,instance) = mySize + thermal_conduction_sizePostResults(instance) = thermal_conduction_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 0_pInt + thermalState(section)%sizeState = sizeState + thermalState(section)%sizePostResults = thermal_conduction_sizePostResults(instance) + allocate(thermalState(section)%state0 (sizeState,NofMyHomog)) + allocate(thermalState(section)%subState0(sizeState,NofMyHomog)) + allocate(thermalState(section)%state (sizeState,NofMyHomog)) + + nullify(thermalMapping(section)%p) + thermalMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(temperature (section)%p) + allocate (temperature (section)%p(NofMyHomog), source=thermal_initialT(section)) + deallocate(temperatureRate(section)%p) + allocate (temperatureRate(section)%p(NofMyHomog), source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine thermal_conduction_init + +!-------------------------------------------------------------------------------------------------- +!> @brief returns heat generation rate +!-------------------------------------------------------------------------------------------------- +subroutine thermal_conduction_getSourceAndItsTangent(Tdot, dTdot_dT, T, ip, el) + use math, only: & + math_Mandel6to33 + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + thermal_typeInstance, & + phase_Nsources, & + phase_source, & + SOURCE_thermal_dissipation_ID, & + SOURCE_thermal_externalheat_ID + use source_thermal_dissipation, only: & + source_thermal_dissipation_getRateAndItsTangent + use source_thermal_externalheat, only: & + source_thermal_externalheat_getRateAndItsTangent + use crystallite, only: & + crystallite_Tstar_v, & + crystallite_Lp + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + T + real(pReal), intent(out) :: & + Tdot, dTdot_dT + real(pReal) :: & + my_Tdot, my_dTdot_dT + integer(pInt) :: & + phase, & + homog, & + offset, & + instance, & + grain, & + source + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + instance = thermal_typeInstance(homog) + + Tdot = 0.0_pReal + dTdot_dT = 0.0_pReal + do grain = 1, homogenization_Ngrains(homog) + phase = phaseAt(grain,ip,el) + do source = 1, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_thermal_dissipation_ID) + call source_thermal_dissipation_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & + crystallite_Tstar_v(1:6,grain,ip,el), & + crystallite_Lp(1:3,1:3,grain,ip,el), & + grain, ip, el) + + case (SOURCE_thermal_externalheat_ID) + call source_thermal_externalheat_getRateAndItsTangent(my_Tdot, my_dTdot_dT, & + grain, ip, el) + + case default + my_Tdot = 0.0_pReal + my_dTdot_dT = 0.0_pReal + + end select + Tdot = Tdot + my_Tdot + dTdot_dT = dTdot_dT + my_dTdot_dT + enddo + enddo + + Tdot = Tdot/homogenization_Ngrains(homog) + dTdot_dT = dTdot_dT/homogenization_Ngrains(homog) + +end subroutine thermal_conduction_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized thermal conductivity in reference configuration +!-------------------------------------------------------------------------------------------------- +function thermal_conduction_getConductivity33(ip,el) + use lattice, only: & + lattice_thermalConductivity33 + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + thermal_conduction_getConductivity33 + integer(pInt) :: & + homog, & + grain + + homog = mappingHomogenization(2,ip,el) + + thermal_conduction_getConductivity33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + thermal_conduction_getConductivity33 = thermal_conduction_getConductivity33 + & + crystallite_push33ToRef(grain,ip,el,lattice_thermalConductivity33(:,:,material_phase(grain,ip,el))) + enddo + + thermal_conduction_getConductivity33 = & + thermal_conduction_getConductivity33/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function thermal_conduction_getConductivity33 + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized specific heat capacity +!-------------------------------------------------------------------------------------------------- +function thermal_conduction_getSpecificHeat(ip,el) + use lattice, only: & + lattice_specificHeat + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + thermal_conduction_getSpecificHeat + integer(pInt) :: & + homog, grain + + thermal_conduction_getSpecificHeat = 0.0_pReal + + homog = mappingHomogenization(2,ip,el) + + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + thermal_conduction_getSpecificHeat = thermal_conduction_getSpecificHeat + & + lattice_specificHeat(material_phase(grain,ip,el)) + enddo + + thermal_conduction_getSpecificHeat = & + thermal_conduction_getSpecificHeat/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function thermal_conduction_getSpecificHeat + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized mass density +!-------------------------------------------------------------------------------------------------- +function thermal_conduction_getMassDensity(ip,el) + use lattice, only: & + lattice_massDensity + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal) :: & + thermal_conduction_getMassDensity + integer(pInt) :: & + homog, grain + + thermal_conduction_getMassDensity = 0.0_pReal + + homog = mappingHomogenization(2,ip,el) + + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + thermal_conduction_getMassDensity = thermal_conduction_getMassDensity + & + lattice_massDensity(material_phase(grain,ip,el)) + enddo + + thermal_conduction_getMassDensity = & + thermal_conduction_getMassDensity/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function thermal_conduction_getMassDensity + +!-------------------------------------------------------------------------------------------------- +!> @brief updates thermal state with solution from heat conduction PDE +!-------------------------------------------------------------------------------------------------- +subroutine thermal_conduction_putTemperatureAndItsRate(T,Tdot,ip,el) + use material, only: & + mappingHomogenization, & + temperature, & + temperatureRate, & + thermalMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + T, & + Tdot + integer(pInt) :: & + homog, & + offset + + homog = mappingHomogenization(2,ip,el) + offset = thermalMapping(homog)%p(ip,el) + temperature (homog)%p(offset) = T + temperatureRate(homog)%p(offset) = Tdot + +end subroutine thermal_conduction_putTemperatureAndItsRate + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of thermal results +!-------------------------------------------------------------------------------------------------- +function thermal_conduction_postResults(ip,el) + use material, only: & + mappingHomogenization, & + thermal_typeInstance, & + temperature, & + thermalMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(thermal_conduction_sizePostResults(thermal_typeInstance(mappingHomogenization(2,ip,el)))) :: & + thermal_conduction_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = thermalMapping(homog)%p(ip,el) + instance = thermal_typeInstance(homog) + + c = 0_pInt + thermal_conduction_postResults = 0.0_pReal + + do o = 1_pInt,thermal_conduction_Noutput(instance) + select case(thermal_conduction_outputID(o,instance)) + + case (temperature_ID) + thermal_conduction_postResults(c+1_pInt) = temperature(homog)%p(offset) + c = c + 1 + end select + enddo +end function thermal_conduction_postResults + +end module thermal_conduction diff --git a/src/thermal_isothermal.f90 b/src/thermal_isothermal.f90 new file mode 100644 index 000000000..8c9d3a782 --- /dev/null +++ b/src/thermal_isothermal.f90 @@ -0,0 +1,65 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for isothermal temperature field +!-------------------------------------------------------------------------------------------------- +module thermal_isothermal + + implicit none + private + + public :: & + thermal_isothermal_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine thermal_isothermal_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog, & + sizeState + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- thermal_'//THERMAL_isothermal_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (thermal_type(homog) == THERMAL_isothermal_ID) then + NofMyHomog = count(material_homog == homog) + sizeState = 0_pInt + thermalState(homog)%sizeState = sizeState + thermalState(homog)%sizePostResults = sizeState + allocate(thermalState(homog)%state0 (sizeState,NofMyHomog), source=0.0_pReal) + allocate(thermalState(homog)%subState0(sizeState,NofMyHomog), source=0.0_pReal) + allocate(thermalState(homog)%state (sizeState,NofMyHomog), source=0.0_pReal) + + deallocate(temperature (homog)%p) + allocate (temperature (homog)%p(1), source=thermal_initialT(homog)) + deallocate(temperatureRate(homog)%p) + allocate (temperatureRate(homog)%p(1), source=0.0_pReal) + + endif myhomog + enddo initializeInstances + + +end subroutine thermal_isothermal_init + +end module thermal_isothermal diff --git a/src/vacancyflux_cahnhilliard.f90 b/src/vacancyflux_cahnhilliard.f90 new file mode 100644 index 000000000..16a380ffc --- /dev/null +++ b/src/vacancyflux_cahnhilliard.f90 @@ -0,0 +1,606 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for conservative transport of vacancy concentration field +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module vacancyflux_cahnhilliard + use prec, only: & + pReal, & + pInt, & + p_vec + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + vacancyflux_cahnhilliard_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + vacancyflux_cahnhilliard_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + vacancyflux_cahnhilliard_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + vacancyflux_cahnhilliard_Noutput !< number of outputs per instance of this damage + + real(pReal), dimension(:), allocatable, private :: & + vacancyflux_cahnhilliard_flucAmplitude + + type(p_vec), dimension(:), allocatable, private :: & + vacancyflux_cahnhilliard_thermalFluc + + real(pReal), parameter, private :: & + kB = 1.3806488e-23_pReal !< Boltzmann constant in J/Kelvin + + enum, bind(c) + enumerator :: undefined_ID, & + vacancyConc_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + vacancyflux_cahnhilliard_outputID !< ID of each post result output + + + public :: & + vacancyflux_cahnhilliard_init, & + vacancyflux_cahnhilliard_getSourceAndItsTangent, & + vacancyflux_cahnhilliard_getMobility33, & + vacancyflux_cahnhilliard_getDiffusion33, & + vacancyflux_cahnhilliard_getChemPotAndItsTangent, & + vacancyflux_cahnhilliard_putVacancyConcAndItsRate, & + vacancyflux_cahnhilliard_postResults + private :: & + vacancyflux_cahnhilliard_getFormationEnergy, & + vacancyflux_cahnhilliard_getEntropicCoeff, & + vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_cahnhilliard_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + vacancyflux_type, & + vacancyflux_typeInstance, & + homogenization_Noutput, & + VACANCYFLUX_cahnhilliard_label, & + VACANCYFLUX_cahnhilliard_ID, & + material_homog, & + mappingHomogenization, & + vacancyfluxState, & + vacancyfluxMapping, & + vacancyConc, & + vacancyConcRate, & + vacancyflux_initialCv, & + material_partHomogenization, & + material_partPhase + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o,offset + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_cahnhilliard_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(vacancyflux_type == VACANCYFLUX_cahnhilliard_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(vacancyflux_cahnhilliard_sizePostResults(maxNinstance), source=0_pInt) + allocate(vacancyflux_cahnhilliard_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(vacancyflux_cahnhilliard_output (maxval(homogenization_Noutput),maxNinstance)) + vacancyflux_cahnhilliard_output = '' + allocate(vacancyflux_cahnhilliard_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(vacancyflux_cahnhilliard_Noutput (maxNinstance), source=0_pInt) + + allocate(vacancyflux_cahnhilliard_flucAmplitude (maxNinstance)) + allocate(vacancyflux_cahnhilliard_thermalFluc (maxNinstance)) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingHomog: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (vacancyflux_type(section) == VACANCYFLUX_cahnhilliard_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = vacancyflux_typeInstance(section) ! which instance of my vacancyflux is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('vacancyconc') + vacancyflux_cahnhilliard_Noutput(instance) = vacancyflux_cahnhilliard_Noutput(instance) + 1_pInt + vacancyflux_cahnhilliard_outputID(vacancyflux_cahnhilliard_Noutput(instance),instance) = vacancyConc_ID + vacancyflux_cahnhilliard_output(vacancyflux_cahnhilliard_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + case ('vacancyflux_flucamplitude') + vacancyflux_cahnhilliard_flucAmplitude(instance) = IO_floatValue(line,chunkPos,2_pInt) + + end select + endif; endif + enddo parsingHomog + + initializeInstances: do section = 1_pInt, size(vacancyflux_type) + if (vacancyflux_type(section) == VACANCYFLUX_cahnhilliard_ID) then + NofMyHomog=count(material_homog==section) + instance = vacancyflux_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,vacancyflux_cahnhilliard_Noutput(instance) + select case(vacancyflux_cahnhilliard_outputID(o,instance)) + case(vacancyConc_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + vacancyflux_cahnhilliard_sizePostResult(o,instance) = mySize + vacancyflux_cahnhilliard_sizePostResults(instance) = vacancyflux_cahnhilliard_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 0_pInt + vacancyfluxState(section)%sizeState = sizeState + vacancyfluxState(section)%sizePostResults = vacancyflux_cahnhilliard_sizePostResults(instance) + allocate(vacancyfluxState(section)%state0 (sizeState,NofMyHomog)) + allocate(vacancyfluxState(section)%subState0(sizeState,NofMyHomog)) + allocate(vacancyfluxState(section)%state (sizeState,NofMyHomog)) + + allocate(vacancyflux_cahnhilliard_thermalFluc(instance)%p(NofMyHomog)) + do offset = 1_pInt, NofMyHomog + call random_number(vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset)) + vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset) = & + 1.0_pReal - & + vacancyflux_cahnhilliard_flucAmplitude(instance)* & + (vacancyflux_cahnhilliard_thermalFluc(instance)%p(offset) - 0.5_pReal) + enddo + + nullify(vacancyfluxMapping(section)%p) + vacancyfluxMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(vacancyConc (section)%p) + allocate (vacancyConc (section)%p(NofMyHomog), source=vacancyflux_initialCv(section)) + deallocate(vacancyConcRate(section)%p) + allocate (vacancyConcRate(section)%p(NofMyHomog), source=0.0_pReal) + + endif + + enddo initializeInstances + +end subroutine vacancyflux_cahnhilliard_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates homogenized vacancy driving forces +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_cahnhilliard_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + phase_source, & + phase_Nsources, & + SOURCE_vacancy_phenoplasticity_ID, & + SOURCE_vacancy_irradiation_ID, & + SOURCE_vacancy_thermalfluc_ID + use source_vacancy_phenoplasticity, only: & + source_vacancy_phenoplasticity_getRateAndItsTangent + use source_vacancy_irradiation, only: & + source_vacancy_irradiation_getRateAndItsTangent + use source_vacancy_thermalfluc, only: & + source_vacancy_thermalfluc_getRateAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Cv + integer(pInt) :: & + phase, & + grain, & + source + real(pReal) :: & + CvDot, dCvDot_dCv, localCvDot, dLocalCvDot_dCv + + CvDot = 0.0_pReal + dCvDot_dCv = 0.0_pReal + do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) + phase = phaseAt(grain,ip,el) + do source = 1_pInt, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_vacancy_phenoplasticity_ID) + call source_vacancy_phenoplasticity_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) + + case (SOURCE_vacancy_irradiation_ID) + call source_vacancy_irradiation_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) + + case (SOURCE_vacancy_thermalfluc_ID) + call source_vacancy_thermalfluc_getRateAndItsTangent(localCvDot, dLocalCvDot_dCv, grain, ip, el) + + end select + CvDot = CvDot + localCvDot + dCvDot_dCv = dCvDot_dCv + dLocalCvDot_dCv + enddo + enddo + + CvDot = CvDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + dCvDot_dCv = dCvDot_dCv/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + +end subroutine vacancyflux_cahnhilliard_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized vacancy mobility tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function vacancyflux_cahnhilliard_getMobility33(ip,el) + use lattice, only: & + lattice_vacancyfluxMobility33 + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + vacancyflux_cahnhilliard_getMobility33 + integer(pInt) :: & + grain + + vacancyflux_cahnhilliard_getMobility33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + vacancyflux_cahnhilliard_getMobility33 = vacancyflux_cahnhilliard_getMobility33 + & + crystallite_push33ToRef(grain,ip,el,lattice_vacancyfluxMobility33(:,:,material_phase(grain,ip,el))) + enddo + + vacancyflux_cahnhilliard_getMobility33 = & + vacancyflux_cahnhilliard_getMobility33/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function vacancyflux_cahnhilliard_getMobility33 + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized vacancy diffusion tensor in reference configuration +!-------------------------------------------------------------------------------------------------- +function vacancyflux_cahnhilliard_getDiffusion33(ip,el) + use lattice, only: & + lattice_vacancyfluxDiffusion33 + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + use crystallite, only: & + crystallite_push33ToRef + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), dimension(3,3) :: & + vacancyflux_cahnhilliard_getDiffusion33 + integer(pInt) :: & + grain + + vacancyflux_cahnhilliard_getDiffusion33 = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + vacancyflux_cahnhilliard_getDiffusion33 = vacancyflux_cahnhilliard_getDiffusion33 + & + crystallite_push33ToRef(grain,ip,el,lattice_vacancyfluxDiffusion33(:,:,material_phase(grain,ip,el))) + enddo + + vacancyflux_cahnhilliard_getDiffusion33 = & + vacancyflux_cahnhilliard_getDiffusion33/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function vacancyflux_cahnhilliard_getDiffusion33 + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized vacancy formation energy +!-------------------------------------------------------------------------------------------------- +real(pReal) function vacancyflux_cahnhilliard_getFormationEnergy(ip,el) + use lattice, only: & + lattice_vacancyFormationEnergy, & + lattice_vacancyVol, & + lattice_vacancySurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_phase + use mesh, only: & + mesh_element + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + integer(pInt) :: & + grain + + vacancyflux_cahnhilliard_getFormationEnergy = 0.0_pReal + do grain = 1, homogenization_Ngrains(mesh_element(3,el)) + vacancyflux_cahnhilliard_getFormationEnergy = vacancyflux_cahnhilliard_getFormationEnergy + & + lattice_vacancyFormationEnergy(material_phase(grain,ip,el))/ & + lattice_vacancyVol(material_phase(grain,ip,el))/ & + lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) + enddo + + vacancyflux_cahnhilliard_getFormationEnergy = & + vacancyflux_cahnhilliard_getFormationEnergy/ & + homogenization_Ngrains(mesh_element(3,el)) + +end function vacancyflux_cahnhilliard_getFormationEnergy + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized vacancy entropy coefficient +!-------------------------------------------------------------------------------------------------- +real(pReal) function vacancyflux_cahnhilliard_getEntropicCoeff(ip,el) + use lattice, only: & + lattice_vacancyVol, & + lattice_vacancySurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_homog, & + material_phase, & + temperature, & + thermalMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + integer(pInt) :: & + grain + + vacancyflux_cahnhilliard_getEntropicCoeff = 0.0_pReal + do grain = 1, homogenization_Ngrains(material_homog(ip,el)) + vacancyflux_cahnhilliard_getEntropicCoeff = vacancyflux_cahnhilliard_getEntropicCoeff + & + kB/ & + lattice_vacancyVol(material_phase(grain,ip,el))/ & + lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) + enddo + + vacancyflux_cahnhilliard_getEntropicCoeff = & + vacancyflux_cahnhilliard_getEntropicCoeff* & + temperature(material_homog(ip,el))%p(thermalMapping(material_homog(ip,el))%p(ip,el))/ & + homogenization_Ngrains(material_homog(ip,el)) + +end function vacancyflux_cahnhilliard_getEntropicCoeff + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized kinematic contribution to chemical potential +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCv, Cv, ip, el) + use lattice, only: & + lattice_vacancySurfaceEnergy + use material, only: & + homogenization_Ngrains, & + material_homog, & + phase_kinematics, & + phase_Nkinematics, & + material_phase, & + KINEMATICS_vacancy_strain_ID + use crystallite, only: & + crystallite_Tstar_v, & + crystallite_Fi0, & + crystallite_Fi + use kinematics_vacancy_strain, only: & + kinematics_vacancy_strain_ChemPotAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Cv + real(pReal), intent(out) :: & + KPot, dKPot_dCv + real(pReal) :: & + my_KPot, my_dKPot_dCv + integer(pInt) :: & + grain, kinematics + + KPot = 0.0_pReal + dKPot_dCv = 0.0_pReal + do grain = 1_pInt,homogenization_Ngrains(material_homog(ip,el)) + do kinematics = 1_pInt, phase_Nkinematics(material_phase(grain,ip,el)) + select case (phase_kinematics(kinematics,material_phase(grain,ip,el))) + case (KINEMATICS_vacancy_strain_ID) + call kinematics_vacancy_strain_ChemPotAndItsTangent(my_KPot, my_dKPot_dCv, & + crystallite_Tstar_v(1:6,grain,ip,el), & + crystallite_Fi0(1:3,1:3,grain,ip,el), & + crystallite_Fi (1:3,1:3,grain,ip,el), & + grain,ip, el) + + case default + my_KPot = 0.0_pReal + my_dKPot_dCv = 0.0_pReal + + end select + KPot = KPot + my_KPot/lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) + dKPot_dCv = dKPot_dCv + my_dKPot_dCv/lattice_vacancySurfaceEnergy(material_phase(grain,ip,el)) + enddo + enddo + + KPot = KPot/homogenization_Ngrains(material_homog(ip,el)) + dKPot_dCv = dKPot_dCv/homogenization_Ngrains(material_homog(ip,el)) + +end subroutine vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief returns homogenized chemical potential and its tangent +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_cahnhilliard_getChemPotAndItsTangent(ChemPot,dChemPot_dCv,Cv,ip,el) + use numerics, only: & + vacancyBoundPenalty, & + vacancyPolyOrder + use material, only: & + mappingHomogenization, & + vacancyflux_typeInstance, & + porosity, & + porosityMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Cv + real(pReal), intent(out) :: & + ChemPot, & + dChemPot_dCv + real(pReal) :: & + VoidPhaseFrac, kBT, KPot, dKPot_dCv + integer(pInt) :: & + homog, o + + homog = mappingHomogenization(2,ip,el) + VoidPhaseFrac = porosity(homog)%p(porosityMapping(homog)%p(ip,el)) + kBT = vacancyflux_cahnhilliard_getEntropicCoeff(ip,el) + + ChemPot = vacancyflux_cahnhilliard_getFormationEnergy(ip,el) + dChemPot_dCv = 0.0_pReal + do o = 1_pInt, vacancyPolyOrder + ChemPot = ChemPot + kBT*((2.0_pReal*Cv - 1.0_pReal)**real(2_pInt*o-1_pInt,pReal))/ & + real(2_pInt*o-1_pInt,pReal) + dChemPot_dCv = dChemPot_dCv + 2.0_pReal*kBT*(2.0_pReal*Cv - 1.0_pReal)**real(2_pInt*o-2_pInt,pReal) + enddo + + ChemPot = VoidPhaseFrac*VoidPhaseFrac*ChemPot & + - 2.0_pReal*(1.0_pReal - Cv)*(1.0_pReal - VoidPhaseFrac)*(1.0_pReal - VoidPhaseFrac) + + dChemPot_dCv = VoidPhaseFrac*VoidPhaseFrac*dChemPot_dCv & + + 2.0_pReal*(1.0_pReal - VoidPhaseFrac)*(1.0_pReal - VoidPhaseFrac) + + call vacancyflux_cahnhilliard_KinematicChemPotAndItsTangent(KPot, dKPot_dCv, Cv, ip, el) + ChemPot = ChemPot + KPot + dChemPot_dCv = dChemPot_dCv + dKPot_dCv + + if (Cv < 0.0_pReal) then + ChemPot = ChemPot - 3.0_pReal*vacancyBoundPenalty*Cv*Cv + dChemPot_dCv = dChemPot_dCv - 6.0_pReal*vacancyBoundPenalty*Cv + elseif (Cv > 1.0_pReal) then + ChemPot = ChemPot + 3.0_pReal*vacancyBoundPenalty*(1.0_pReal - Cv)*(1.0_pReal - Cv) + dChemPot_dCv = dChemPot_dCv - 6.0_pReal*vacancyBoundPenalty*(1.0_pReal - Cv) + endif + + ChemPot = ChemPot* & + vacancyflux_cahnhilliard_thermalFluc(vacancyflux_typeInstance(homog))%p(mappingHomogenization(1,ip,el)) + dChemPot_dCv = dChemPot_dCv* & + vacancyflux_cahnhilliard_thermalFluc(vacancyflux_typeInstance(homog))%p(mappingHomogenization(1,ip,el)) + +end subroutine vacancyflux_cahnhilliard_getChemPotAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief updated vacancy concentration and its rate with solution from transport PDE +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_cahnhilliard_putVacancyConcAndItsRate(Cv,Cvdot,ip,el) + use material, only: & + mappingHomogenization, & + vacancyConc, & + vacancyConcRate, & + vacancyfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Cv, & + Cvdot + integer(pInt) :: & + homog, & + offset + + homog = mappingHomogenization(2,ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + vacancyConc (homog)%p(offset) = Cv + vacancyConcRate(homog)%p(offset) = Cvdot + +end subroutine vacancyflux_cahnhilliard_putVacancyConcAndItsRate + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of vacancy transport results +!-------------------------------------------------------------------------------------------------- +function vacancyflux_cahnhilliard_postResults(ip,el) + use material, only: & + mappingHomogenization, & + vacancyflux_typeInstance, & + vacancyConc, & + vacancyfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(vacancyflux_cahnhilliard_sizePostResults(vacancyflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & + vacancyflux_cahnhilliard_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + instance = vacancyflux_typeInstance(homog) + + c = 0_pInt + vacancyflux_cahnhilliard_postResults = 0.0_pReal + + do o = 1_pInt,vacancyflux_cahnhilliard_Noutput(instance) + select case(vacancyflux_cahnhilliard_outputID(o,instance)) + + case (vacancyConc_ID) + vacancyflux_cahnhilliard_postResults(c+1_pInt) = vacancyConc(homog)%p(offset) + c = c + 1 + end select + enddo +end function vacancyflux_cahnhilliard_postResults + +end module vacancyflux_cahnhilliard diff --git a/src/vacancyflux_isochempot.f90 b/src/vacancyflux_isochempot.f90 new file mode 100644 index 000000000..35db8d159 --- /dev/null +++ b/src/vacancyflux_isochempot.f90 @@ -0,0 +1,329 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for locally evolving vacancy concentration +!> @details to be done +!-------------------------------------------------------------------------------------------------- +module vacancyflux_isochempot + use prec, only: & + pReal, & + pInt + + implicit none + private + integer(pInt), dimension(:), allocatable, public, protected :: & + vacancyflux_isochempot_sizePostResults !< cumulative size of post results + + integer(pInt), dimension(:,:), allocatable, target, public :: & + vacancyflux_isochempot_sizePostResult !< size of each post result output + + character(len=64), dimension(:,:), allocatable, target, public :: & + vacancyflux_isochempot_output !< name of each post result output + + integer(pInt), dimension(:), allocatable, target, public :: & + vacancyflux_isochempot_Noutput !< number of outputs per instance of this damage + + enum, bind(c) + enumerator :: undefined_ID, & + vacancyconc_ID + end enum + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + vacancyflux_isochempot_outputID !< ID of each post result output + + + public :: & + vacancyflux_isochempot_init, & + vacancyflux_isochempot_updateState, & + vacancyflux_isochempot_getSourceAndItsTangent, & + vacancyflux_isochempot_postResults + +contains + + +!-------------------------------------------------------------------------------------------------- +!> @brief module initialization +!> @details reads in material parameters, allocates arrays, and does sanity checks +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_isochempot_init(fileUnit) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use IO, only: & + IO_read, & + IO_lc, & + IO_getTag, & + IO_isBlank, & + IO_stringPos, & + IO_stringValue, & + IO_floatValue, & + IO_intValue, & + IO_warning, & + IO_error, & + IO_timeStamp, & + IO_EOF + use material, only: & + vacancyflux_type, & + vacancyflux_typeInstance, & + homogenization_Noutput, & + VACANCYFLUX_isochempot_label, & + VACANCYFLUX_isochempot_ID, & + material_homog, & + mappingHomogenization, & + vacancyfluxState, & + vacancyfluxMapping, & + vacancyConc, & + vacancyConcRate, & + vacancyflux_initialCv, & + material_partHomogenization + use numerics,only: & + worldrank + + implicit none + integer(pInt), intent(in) :: fileUnit + + integer(pInt), allocatable, dimension(:) :: chunkPos + integer(pInt) :: maxNinstance,mySize=0_pInt,section,instance,o + integer(pInt) :: sizeState + integer(pInt) :: NofMyHomog + character(len=65536) :: & + tag = '', & + line = '' + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_isochempot_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + maxNinstance = int(count(vacancyflux_type == VACANCYFLUX_isochempot_ID),pInt) + if (maxNinstance == 0_pInt) return + + allocate(vacancyflux_isochempot_sizePostResults(maxNinstance), source=0_pInt) + allocate(vacancyflux_isochempot_sizePostResult (maxval(homogenization_Noutput),maxNinstance),source=0_pInt) + allocate(vacancyflux_isochempot_output (maxval(homogenization_Noutput),maxNinstance)) + vacancyflux_isochempot_output = '' + allocate(vacancyflux_isochempot_outputID (maxval(homogenization_Noutput),maxNinstance),source=undefined_ID) + allocate(vacancyflux_isochempot_Noutput (maxNinstance), source=0_pInt) + + rewind(fileUnit) + section = 0_pInt + do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= material_partHomogenization)! wind forward to + line = IO_read(fileUnit) + enddo + + parsingFile: do while (trim(line) /= IO_EOF) ! read through sections of homog part + line = IO_read(fileUnit) + if (IO_isBlank(line)) cycle ! skip empty lines + if (IO_getTag(line,'<','>') /= '') then ! stop at next part + line = IO_read(fileUnit, .true.) ! reset IO_read + exit + endif + if (IO_getTag(line,'[',']') /= '') then ! next homog section + section = section + 1_pInt ! advance homog section counter + cycle ! skip to next line + endif + + if (section > 0_pInt ) then; if (vacancyflux_type(section) == VACANCYFLUX_isochempot_ID) then ! do not short-circuit here (.and. with next if statemen). It's not safe in Fortran + + instance = vacancyflux_typeInstance(section) ! which instance of my vacancyflux is present homog + chunkPos = IO_stringPos(line) + tag = IO_lc(IO_stringValue(line,chunkPos,1_pInt)) ! extract key + select case(tag) + case ('(output)') + select case(IO_lc(IO_stringValue(line,chunkPos,2_pInt))) + case ('vacancyconc') + vacancyflux_isochempot_Noutput(instance) = vacancyflux_isochempot_Noutput(instance) + 1_pInt + vacancyflux_isochempot_outputID(vacancyflux_isochempot_Noutput(instance),instance) = vacancyconc_ID + vacancyflux_isochempot_output(vacancyflux_isochempot_Noutput(instance),instance) = & + IO_lc(IO_stringValue(line,chunkPos,2_pInt)) + end select + + end select + endif; endif + enddo parsingFile + + initializeInstances: do section = 1_pInt, size(vacancyflux_type) + if (vacancyflux_type(section) == VACANCYFLUX_isochempot_ID) then + NofMyHomog=count(material_homog==section) + instance = vacancyflux_typeInstance(section) + +!-------------------------------------------------------------------------------------------------- +! Determine size of postResults array + outputsLoop: do o = 1_pInt,vacancyflux_isochempot_Noutput(instance) + select case(vacancyflux_isochempot_outputID(o,instance)) + case(vacancyconc_ID) + mySize = 1_pInt + end select + + if (mySize > 0_pInt) then ! any meaningful output found + vacancyflux_isochempot_sizePostResult(o,instance) = mySize + vacancyflux_isochempot_sizePostResults(instance) = vacancyflux_isochempot_sizePostResults(instance) + mySize + endif + enddo outputsLoop + +! allocate state arrays + sizeState = 1_pInt + vacancyfluxState(section)%sizeState = sizeState + vacancyfluxState(section)%sizePostResults = vacancyflux_isochempot_sizePostResults(instance) + allocate(vacancyfluxState(section)%state0 (sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) + allocate(vacancyfluxState(section)%subState0(sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) + allocate(vacancyfluxState(section)%state (sizeState,NofMyHomog), source=vacancyflux_initialCv(section)) + + nullify(vacancyfluxMapping(section)%p) + vacancyfluxMapping(section)%p => mappingHomogenization(1,:,:) + deallocate(vacancyConc(section)%p) + vacancyConc(section)%p => vacancyfluxState(section)%state(1,:) + deallocate(vacancyConcRate(section)%p) + allocate(vacancyConcRate(section)%p(NofMyHomog), source=0.0_pReal) + + endif + + enddo initializeInstances +end subroutine vacancyflux_isochempot_init + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates change in vacancy concentration based on local vacancy generation model +!-------------------------------------------------------------------------------------------------- +function vacancyflux_isochempot_updateState(subdt, ip, el) + use numerics, only: & + err_vacancyflux_tolAbs, & + err_vacancyflux_tolRel + use material, only: & + mappingHomogenization, & + vacancyflux_typeInstance, & + vacancyfluxState, & + vacancyConc, & + vacancyConcRate, & + vacancyfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + subdt + logical, dimension(2) :: & + vacancyflux_isochempot_updateState + integer(pInt) :: & + homog, & + offset, & + instance + real(pReal) :: & + Cv, Cvdot, dCvDot_dCv + + homog = mappingHomogenization(2,ip,el) + offset = mappingHomogenization(1,ip,el) + instance = vacancyflux_typeInstance(homog) + + Cv = vacancyfluxState(homog)%subState0(1,offset) + call vacancyflux_isochempot_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) + Cv = Cv + subdt*Cvdot + + vacancyflux_isochempot_updateState = [ abs(Cv - vacancyfluxState(homog)%state(1,offset)) & + <= err_vacancyflux_tolAbs & + .or. abs(Cv - vacancyfluxState(homog)%state(1,offset)) & + <= err_vacancyflux_tolRel*abs(vacancyfluxState(homog)%state(1,offset)), & + .true.] + + vacancyConc (homog)%p(vacancyfluxMapping(homog)%p(ip,el)) = Cv + vacancyConcRate(homog)%p(vacancyfluxMapping(homog)%p(ip,el)) = & + (vacancyfluxState(homog)%state(1,offset) - vacancyfluxState(homog)%subState0(1,offset))/(subdt+tiny(0.0_pReal)) + +end function vacancyflux_isochempot_updateState + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates homogenized vacancy driving forces +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_isochempot_getSourceAndItsTangent(CvDot, dCvDot_dCv, Cv, ip, el) + use material, only: & + homogenization_Ngrains, & + mappingHomogenization, & + phaseAt, phasememberAt, & + phase_source, & + phase_Nsources, & + SOURCE_vacancy_phenoplasticity_ID, & + SOURCE_vacancy_irradiation_ID, & + SOURCE_vacancy_thermalfluc_ID + use source_vacancy_phenoplasticity, only: & + source_vacancy_phenoplasticity_getRateAndItsTangent + use source_vacancy_irradiation, only: & + source_vacancy_irradiation_getRateAndItsTangent + use source_vacancy_thermalfluc, only: & + source_vacancy_thermalfluc_getRateAndItsTangent + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point number + el !< element number + real(pReal), intent(in) :: & + Cv + integer(pInt) :: & + phase, & + grain, & + source + real(pReal) :: & + CvDot, dCvDot_dCv, localCvDot, dLocalCvDot_dCv + + CvDot = 0.0_pReal + dCvDot_dCv = 0.0_pReal + do grain = 1, homogenization_Ngrains(mappingHomogenization(2,ip,el)) + phase = phaseAt(grain,ip,el) + do source = 1_pInt, phase_Nsources(phase) + select case(phase_source(source,phase)) + case (SOURCE_vacancy_phenoplasticity_ID) + call source_vacancy_phenoplasticity_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) + + case (SOURCE_vacancy_irradiation_ID) + call source_vacancy_irradiation_getRateAndItsTangent (localCvDot, dLocalCvDot_dCv, grain, ip, el) + + case (SOURCE_vacancy_thermalfluc_ID) + call source_vacancy_thermalfluc_getRateAndItsTangent(localCvDot, dLocalCvDot_dCv, grain, ip, el) + + end select + CvDot = CvDot + localCvDot + dCvDot_dCv = dCvDot_dCv + dLocalCvDot_dCv + enddo + enddo + + CvDot = CvDot/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + dCvDot_dCv = dCvDot_dCv/homogenization_Ngrains(mappingHomogenization(2,ip,el)) + +end subroutine vacancyflux_isochempot_getSourceAndItsTangent + +!-------------------------------------------------------------------------------------------------- +!> @brief return array of vacancy transport results +!-------------------------------------------------------------------------------------------------- +function vacancyflux_isochempot_postResults(ip,el) + use material, only: & + mappingHomogenization, & + vacancyflux_typeInstance, & + vacancyConc, & + vacancyfluxMapping + + implicit none + integer(pInt), intent(in) :: & + ip, & !< integration point + el !< element + real(pReal), dimension(vacancyflux_isochempot_sizePostResults(vacancyflux_typeInstance(mappingHomogenization(2,ip,el)))) :: & + vacancyflux_isochempot_postResults + + integer(pInt) :: & + instance, homog, offset, o, c + + homog = mappingHomogenization(2,ip,el) + offset = vacancyfluxMapping(homog)%p(ip,el) + instance = vacancyflux_typeInstance(homog) + + c = 0_pInt + vacancyflux_isochempot_postResults = 0.0_pReal + + do o = 1_pInt,vacancyflux_isochempot_Noutput(instance) + select case(vacancyflux_isochempot_outputID(o,instance)) + + case (vacancyconc_ID) + vacancyflux_isochempot_postResults(c+1_pInt) = vacancyConc(homog)%p(offset) + c = c + 1 + end select + enddo +end function vacancyflux_isochempot_postResults + +end module vacancyflux_isochempot diff --git a/src/vacancyflux_isoconc.f90 b/src/vacancyflux_isoconc.f90 new file mode 100644 index 000000000..63cfb1b62 --- /dev/null +++ b/src/vacancyflux_isoconc.f90 @@ -0,0 +1,63 @@ +!-------------------------------------------------------------------------------------------------- +! $Id$ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @brief material subroutine for constant vacancy concentration +!-------------------------------------------------------------------------------------------------- +module vacancyflux_isoconc + + implicit none + private + + public :: & + vacancyflux_isoconc_init + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields, reads information from material configuration file +!-------------------------------------------------------------------------------------------------- +subroutine vacancyflux_isoconc_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) + use prec, only: & + pReal, & + pInt + use IO, only: & + IO_timeStamp + use material + use numerics, only: & + worldrank + + implicit none + integer(pInt) :: & + homog, & + NofMyHomog + + mainProcess: if (worldrank == 0) then + write(6,'(/,a)') ' <<<+- vacancyflux_'//VACANCYFLUX_isoconc_label//' init -+>>>' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + + initializeInstances: do homog = 1_pInt, material_Nhomogenization + + myhomog: if (vacancyflux_type(homog) == VACANCYFLUX_isoconc_ID) then + NofMyHomog = count(material_homog == homog) + vacancyfluxState(homog)%sizeState = 0_pInt + vacancyfluxState(homog)%sizePostResults = 0_pInt + allocate(vacancyfluxState(homog)%state0 (0_pInt,NofMyHomog)) + allocate(vacancyfluxState(homog)%subState0(0_pInt,NofMyHomog)) + allocate(vacancyfluxState(homog)%state (0_pInt,NofMyHomog)) + + deallocate(vacancyConc (homog)%p) + allocate (vacancyConc (homog)%p(1), source=vacancyflux_initialCv(homog)) + deallocate(vacancyConcRate(homog)%p) + allocate (vacancyConcRate(homog)%p(1), source=0.0_pReal) + + endif myhomog + enddo initializeInstances + + +end subroutine vacancyflux_isoconc_init + +end module vacancyflux_isoconc From 06865df87e679a12d6ab34f267d9b6e4bb970084 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Fri, 4 Mar 2016 15:57:24 -0500 Subject: [PATCH 038/183] switching development back to HPCC --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 27dc46e0f..f6350a8e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -317,7 +317,7 @@ set (LINK_OPTIONS_ifort "-shared-intel") # --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) ################################################################################################### set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -xf95-cpp-input" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -ffree-line-length-240" ) +set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -ffree-line-length-132" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fimplicit-none" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fmodule-private" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wall" ) From ef45d440d97745cc20b85f0d628b390bb4262043 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Fri, 4 Mar 2016 16:43:51 -0500 Subject: [PATCH 039/183] now support old version of CMake --- CMakeLists.txt | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6350a8e7..e4af65880 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ ######################################################################################## # CMAKE for build the Material subroutine for BVP solution ######################################################################################## -cmake_minimum_required (VERSION 3.1.0 FATAL_ERROR) +cmake_minimum_required (VERSION 2.8.0 FATAL_ERROR) project (DAMASK Fortran) # THE VERSION NUMBER. @@ -24,13 +24,22 @@ message("\n***The binary will be installed at\n${CMAKE_INSTALL_PREFIX}\n") # DAMASK DRIVER SELECTION set (SPECTRAL OFF) set (FEM OFF) -if (DAMASK_DRIVER STREQUAL "SPECTRAL") +if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") set (SPECTRAL ON ) -elseif (DAMASK_DRIVER STREQUAL "FEM") +endif("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") +# +if ("${DAMASK_DRIVER}" STREQUAL "FEM") set (FEM ON ) -else (DAMASK_DRIVER STREQUAL "SPECTRAL") - message (FATAL_ERROR "!?driver?!, check build script!") -endif (DAMASK_DRIVER STREQUAL "SPECTRAL") +endif("${DAMASK_DRIVER}" STREQUAL "FEM") + +# if (DAMASK_DRIVER STREQUAL "SPECTRAL") +# set (SPECTRAL ON ) +# message('set to spectral solver') +# endif() +# if (DAMASK_DRIVER STREQUAL "FEM") +# set (FEM ON ) +# message('set to FEM solver') +# endif() # COMPILE VARIABLES add_definitions(-DDAMASKVERSION="${DAMASK_V}") @@ -129,22 +138,22 @@ else (OPENMP) set (OPENMP_FLAG_gfortran "") endif (OPENMP) -if (OPTIMIZATION STREQUAL "OFF") +if ("${OPTIMIZATION}" STREQUAL "OFF") set (OPTIMIZATION_ifort "-O0 -no-ip") set (OPTIMIZATION_gfortran "-O0" ) -elseif (OPTIMIZATION STREQUAL "DEFENSIVE") +elseif ("${OPTIMIZATION}" STREQUAL "DEFENSIVE") set (OPTIMIZATION_ifort "-O2") set (OPTIMIZATION_gfortran "-O2") -elseif (OPTIMIZATION STREQUAL "AGGRESSIVE") +elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") -elseif (OPTIMIZATION STREQUAL "ULTRA") +elseif ("${OPTIMIZATION}" STREQUAL "ULTRA") set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") -else (OPTIMIZATION STREQUAL "OFF") +else ("${OPTIMIZATION}" STREQUAL "OFF") set (OPTIMIZATION_ifort "-O2") set (OPTIMIZATION_gfortran "-O2") -endif (OPTIMIZATION STREQUAL "OFF") +endif ("${OPTIMIZATION}" STREQUAL "OFF") set (STANDARD_CHECK_ifort "-stand f08 -standard-semantics") set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) @@ -425,13 +434,13 @@ set (CMAKE_Fortran_COMPILER "${MPIEXEC}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") set (CMAKE_LINKER "${PETSC_LINKER}") -if (CMAKE_BUILD_TYPE STREQUAL "RELEASE") +if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB}") -else(CMAKE_BUILD_TYPE STREQUAL "RELEASE") +else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") -endif(CMAKE_BUILD_TYPE STREQUAL "RELEASE") +endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") message("***LINK FLAGS:\n${CMAKE_EXE_LINKER_FLAGS_RELEASE}\n") From 81ac9aefa178f2a6cc147029680d56d71ddd5756 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Fri, 4 Mar 2016 17:32:26 -0500 Subject: [PATCH 040/183] support special compile flags for single file --- CMakeLists.txt | 26 -------------------------- src/CMakeLists.txt | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4af65880..4e646897c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,15 +32,6 @@ if ("${DAMASK_DRIVER}" STREQUAL "FEM") set (FEM ON ) endif("${DAMASK_DRIVER}" STREQUAL "FEM") -# if (DAMASK_DRIVER STREQUAL "SPECTRAL") -# set (SPECTRAL ON ) -# message('set to spectral solver') -# endif() -# if (DAMASK_DRIVER STREQUAL "FEM") -# set (FEM ON ) -# message('set to FEM solver') -# endif() - # COMPILE VARIABLES add_definitions(-DDAMASKVERSION="${DAMASK_V}") add_definitions(-DPETSc) @@ -186,9 +177,6 @@ set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) # all: # -name as_is: case sensitive Fortran! ################################################################################################### -# -diag-disable 7410 should disable warning about directory statement in inquire function, -# but does not work. hence the other 2 statements -################################################################################################### set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -fpp" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -ftz" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -assume byterecl,fpe_summary") @@ -200,8 +188,6 @@ set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn interfaces" set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn ignore_loc" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn alignments" ) set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn unused" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -diag-remark 7410" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn nostderrors" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING # -g: Generate symbolic debugging information in the object file @@ -240,7 +226,6 @@ set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -warn stderrors" set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -debug-parameters all" ) set (LINK_OPTIONS_ifort "-shared-intel") -# set (LINK_OPTIONS_ifort "-static-intel") ################################################################################################### # COMPILE SWITCHES # -shared @@ -317,14 +302,6 @@ set (LINK_OPTIONS_ifort "-shared-intel") # -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. # -Wstrict-overflow: ################################################################################################### -# fno-range-check: Disable range checking on results of simplification of constant expressions during compilation -# --> allows the definition of DAMASK_NaN -#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored -# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external -# --> allows the use of 'isnan' -#-fno-fast-math: -# --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) -################################################################################################### set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -xf95-cpp-input" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -ffree-line-length-132" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fimplicit-none" ) @@ -339,9 +316,6 @@ set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wconversion-extra" set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wimplicit-procedure" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wno-unused-parameter" ) set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fno-range-check" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fall-intrinsics" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fno-fast-math" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fall-intrinsics" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING # -ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c1abf4d4e..d461eb294 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,32 @@ # The dependency detection in CMake is not functioning for Fortran # !!! EXPLICIT DEPENDENCY DECLARATION !!! +# SOME FILES REQUIRE SPECIAL FLAGS +if (INTEL_FORTRAN) + # -diag-disable 7410 should disable warning about directory statement + # in inquire function, but does not work. hence the other 2 statements + SET_SOURCE_FILES_PROPERTIES( "spectral_interface.f90" PROPERTIES + COMPILE_FLAGS "-diag-remark 7410 -stand none -warn nostderrors" ) +elseif (GNU_FORTRAN) + # fno-range-check: Disable range checking on results of simplification of constant expressions during compilation + # --> allows the definition of DAMASK_NaN + #-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored + # and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external + # --> allows the use of 'isnan' + #-fno-fast-math: + # --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) + SET_SOURCE_FILES_PROPERTIES( "prec.f90" PROPERTIES + COMPILE_FLAGS "-fno-range-check -fall-intrinsics -fno-fast-math") + #-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored + # and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external + # --> allows the use of 'getcwd' + SET_SOURCE_FILES_PROPERTIES( "spectral_interface.f90" PROPERTIES + COMPILE_FLAGS "-fall-intrinsics") + # long lines for interaction matrix + SET_SOURCE_FILES_PROPERTIES( "lattice.f90" PROPERTIES + COMPILE_FLAGS "-ffree-line-length-240") +endif(INTEL_FORTRAN) + add_library(DAMASK_PREC "prec.f90") if (SPECTRAL) From c7046634762f5b09ad1467632a460101d9a56dcc Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Sat, 5 Mar 2016 15:44:30 -0500 Subject: [PATCH 041/183] final test before pushing to central --- Makefile | 84 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/Makefile b/Makefile index 8be738090..4e7286eff 100755 --- a/Makefile +++ b/Makefile @@ -1,42 +1,42 @@ -SHELL = /bin/sh -######################################################################################## -# Makefile for the installation of DAMASK -######################################################################################## -.PHONY: all -all: spectral marc processing - -.PHONY: spectral -spectral: - $(MAKE) DAMASK_spectral.exe -C code - -.PHONY: FEM -FEM: - $(MAKE) DAMASK_FEM.exe -C code - -.PHONY: marc -marc: - @./installation/mods_MarcMentat/apply_DAMASK_modifications.sh ${MAKEFLAGS} - -.PHONY: processing -processing: - @if hash cython 2>/dev/null; then \ - cd ./lib/damask; \ - CC=gcc python setup_corientation.py build_ext --inplace; \ - rm -rv build; \ - rm *.c; \ - fi - @./installation/compile_CoreModule.py ${MAKEFLAGS} - -.PHONY: tidy -tidy: - @$(MAKE) tidy -C code >/dev/null - -.PHONY: clean -clean: - @$(MAKE) cleanDAMASK -C code >/dev/null - -.PHONY: install -install: - @./installation/symlink_Code.py ${MAKEFLAGS} - @./installation/symlink_Processing.py ${MAKEFLAGS} - +SHELL = /bin/sh +######################################################################################## +# Makefile for the installation of DAMASK +######################################################################################## +.PHONY: all +all: spectral marc processing + +.PHONY: spectral +spectral: + $(MAKE) DAMASK_spectral.exe -C src + +.PHONY: FEM +FEM: + $(MAKE) DAMASK_FEM.exe -C src + +.PHONY: marc +marc: + @./installation/mods_MarcMentat/apply_DAMASK_modifications.sh ${MAKEFLAGS} + +.PHONY: processing +processing: + @if hash cython 2>/dev/null; then \ + cd ./lib/damask; \ + CC=gcc python setup_corientation.py build_ext --inplace; \ + rm -rv build; \ + rm *.c; \ + fi + @./installation/compile_CoreModule.py ${MAKEFLAGS} + +.PHONY: tidy +tidy: + @$(MAKE) tidy -C src >/dev/null + +.PHONY: clean +clean: + @$(MAKE) cleanDAMASK -C src >/dev/null + +.PHONY: install +install: + @./installation/symlink_Code.py ${MAKEFLAGS} + @./installation/symlink_Processing.py ${MAKEFLAGS} + From 3d6a034c9e2a1b53f2d28221aded346fd36b1134 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 5 Mar 2016 22:17:59 +0100 Subject: [PATCH 042/183] added build directory to ignore list and simplified dir layout --- .gitignore | 1 + build_FEM.sh | 8 ++++---- build_spectral.sh | 12 ++++++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index ea92bb425..c5b6e9866 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ *.bak *~ PRIVATE +build diff --git a/build_FEM.sh b/build_FEM.sh index 0def3760a..9c154670b 100755 --- a/build_FEM.sh +++ b/build_FEM.sh @@ -16,10 +16,10 @@ if [ ! -d build ]; then fi cd build if [ -d build_FEM ] ; then - rm -rf build_FEM + rm -rf FEM fi -mkdir build_FEM -cd build_FEM +mkdir FEM +cd FEM ## # CMake call @@ -43,4 +43,4 @@ echo echo "Please move to the build directory using" echo " cd build/build_spectral" echo "Using the following command to build DAMASK spectral solver" -echo " make clean all install" \ No newline at end of file +echo " make clean all install" diff --git a/build_spectral.sh b/build_spectral.sh index a48d8d360..a26175b65 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -15,11 +15,11 @@ if [ ! -d build ]; then mkdir build fi cd build -if [ -d build_spectral ] ; then - rm -rf build_spectral +if [ -d build ] ; then + rm -rf build fi -mkdir build_spectral -cd build_spectral +mkdir build +cd build ## # CMake call @@ -41,6 +41,6 @@ cmake -D PETSC_DIR=${PETSC_DIR} \ echo echo "Please move to the build directory using" -echo " cd build/build_spectral" +echo " cd build/spectral" echo "Using the following command to build DAMASK spectral solver" -echo " make clean all install" \ No newline at end of file +echo " make clean all install" From f276c61c33c4500b32667f4fa235e272803d6d9f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 5 Mar 2016 22:31:33 +0100 Subject: [PATCH 043/183] hickup in dirs in last commit --- build_FEM.sh | 4 ++-- build_spectral.sh | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build_FEM.sh b/build_FEM.sh index 9c154670b..a8326a07e 100755 --- a/build_FEM.sh +++ b/build_FEM.sh @@ -15,7 +15,7 @@ if [ ! -d build ]; then mkdir build fi cd build -if [ -d build_FEM ] ; then +if [ -d FEM ] ; then rm -rf FEM fi mkdir FEM @@ -41,6 +41,6 @@ cmake -D PETSC_DIR=${PETSC_DIR} \ echo echo "Please move to the build directory using" -echo " cd build/build_spectral" +echo " cd build/FEM" echo "Using the following command to build DAMASK spectral solver" echo " make clean all install" diff --git a/build_spectral.sh b/build_spectral.sh index a26175b65..51a6fcd74 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -15,11 +15,11 @@ if [ ! -d build ]; then mkdir build fi cd build -if [ -d build ] ; then - rm -rf build +if [ -d spectral ] ; then + rm -rf spectral fi -mkdir build -cd build +mkdir spectral +cd spectral ## # CMake call From 89a1e2deb1a9a5f46c4695f2d29d3748adc9afa5 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Sat, 5 Mar 2016 17:35:34 -0500 Subject: [PATCH 044/183] detect compiler from MPIF90 --- CMakeLists.txt | 19 ++++++++++++------- build_spectral.sh | 28 ++++++++++++++-------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e646897c..9b20a6188 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,7 @@ compiler: linker: \t@echo \${LINKERNAME} + ") find_program (MAKE_EXECUTABLE NAMES make gmake) @@ -93,6 +94,10 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compiler RESULT_VARIABLE MPIEXEC_RETURN OUTPUT_VARIABLE MPIEXEC OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process(COMMAND ${MPIEXEC} -v OUTPUT_QUIET + RESULT_VARIABLE MPINAME_RETURN + OUTPUT_VARIABLE MPINAME + OUTPUT_STRIP_TRAILING_WHITESPACE) file (REMOVE ${petsc_config_makefile}) # REMOVE DUPLICATE FLAGS FOR COMPILER AND LINKING @@ -355,10 +360,9 @@ set (PRECISION_ifort "-real-size 64 -integer-size 32") ################################################################################################### set (PRECISION_gfortran "-fdefault-real-8 -fdefault-double-8") -# set FLAGS -get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) -if (Fortran_COMPILER_NAME MATCHES "ifort.*") +if (MPINAME MATCHES "(^ifort)*") + message("Intel fortran used for MPIF90\n") set (INTEL_FORTRAN ON) # for RELEASE set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) @@ -378,7 +382,8 @@ if (Fortran_COMPILER_NAME MATCHES "ifort.*") set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DEBUG_OPTIONS_ifort}" ) # -elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") +elseif (MPINAME MATCHES "(^gfortran)*") + message("GNU fortran used for MPIF90\n") set (GNU_FORTRAN ON) # for RELEASE set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_gfortran}" ) @@ -397,11 +402,11 @@ elseif (Fortran_COMPILER_NAME MATCHES "gfortran.*") set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DEBUG_OPTIONS_gfortran}") # -elseif (Fortran_COMPILER_NAME MATCHES "g77") +elseif (MPINAME MATCHES "(^g77)*") message (FATAL_ERROR "Fortran 77 is not supported.") -else (Fortran_COMPILER_NAME MATCHES "ifort.*") +else (MPINAME MATCHES "(^ifort)*") message (FATAL_ERROR "Require Fortran90 from GNU or Intel.") -endif (Fortran_COMPILER_NAME MATCHES "ifort.*") +endif (MPINAME MATCHES "(^ifort)*") # Finalizing set (CMAKE_Fortran_COMPILER "${MPIEXEC}") diff --git a/build_spectral.sh b/build_spectral.sh index a48d8d360..49a7da429 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -23,20 +23,20 @@ cd build_spectral ## # CMake call -# PETSC_DIR | PETSC directory -# DAMASK_V | DAMASK current revision -# CMAKE_BUILD_TYPE | Default set to release (no debugging output) -# OPENMP | [ON/OFF] -# OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] -# DAMASK_DRIVER | [SPECTRAL, FEM] -# DAMASK_INSTALL | Directory to install binary output -cmake -D PETSC_DIR=${PETSC_DIR} \ - -D DAMASK_V=${DAMASKVERSION} \ - -D CMAKE_BUILD_TYPE=RELEASE \ - -D OPENMP=ON \ - -D OPTIMIZATION=DEFENSIVE \ - -D DAMASK_DRIVER=SPECTRAL \ - -D DAMASK_INSTALL=${HOME}/bin \ +# PETSC_DIR | PETSC directory +# DAMASK_V | DAMASK current revision +# CMAKE_BUILD_TYPE | Default set to release (no debugging output) +# OPENMP | [ON/OFF] +# OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] +# DAMASK_DRIVER | [SPECTRAL, FEM] +# DAMASK_INSTALL | Directory to install binary output +cmake -D PETSC_DIR=${PETSC_DIR} \ + -D DAMASK_V=${DAMASKVERSION} \ + -D CMAKE_BUILD_TYPE=RELEASE \ + -D OPENMP=ON \ + -D OPTIMIZATION=DEFENSIVE \ + -D DAMASK_DRIVER=SPECTRAL \ + -D DAMASK_INSTALL=${HOME}/bin \ ../.. echo From 939e0e372e44944afd91ef0ad430cf5ea3f315c1 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 6 Mar 2016 09:28:20 +0100 Subject: [PATCH 045/183] changed order: first find PETSc, than determine the compiler abilities --- CMakeLists.txt | 82 +++++++++++++++++++++++++---------------------- build_spectral.sh | 26 ++++++++++----- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b20a6188..7da86d6e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,55 +2,20 @@ # CMAKE for build the Material subroutine for BVP solution ######################################################################################## cmake_minimum_required (VERSION 2.8.0 FATAL_ERROR) -project (DAMASK Fortran) -# THE VERSION NUMBER. -set (DAMASK_VERSION_MAJOR 1) -set (DAMASK_VERSION_MINOR ${DAMASK_V}) - -# PETSC IS REQUIRED +#--------------------------------------------------------------------------------------- +# Find PETSc because the entire build will rely on it if (NOT DEFINED PETSC_DIR) message (FATAL_ERROR "PETSC_DIR is not found!") endif (NOT DEFINED PETSC_DIR) -# Setting installation prefix -if (NOT DEFINED DAMASK_INSTALL) - set (CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/bin") -elseif(DEFINED DAMASK_INSTALL) - set (CMAKE_INSTALL_PREFIX "${DAMASK_INSTALL}") -endif(NOT DEFINED DAMASK_INSTALL) -message("\n***The binary will be installed at\n${CMAKE_INSTALL_PREFIX}\n") - -# DAMASK DRIVER SELECTION -set (SPECTRAL OFF) -set (FEM OFF) -if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") - set (SPECTRAL ON ) -endif("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") -# -if ("${DAMASK_DRIVER}" STREQUAL "FEM") - set (FEM ON ) -endif("${DAMASK_DRIVER}" STREQUAL "FEM") - -# COMPILE VARIABLES -add_definitions(-DDAMASKVERSION="${DAMASK_V}") -add_definitions(-DPETSc) -add_definitions(-DFLOAT=8) -add_definitions(-DINT=4) -if (SPECTRAL) - add_definitions(-DSpectral) -endif(SPECTRAL) -if (FEM) - add_definitions(-DFEM) -endif(FEM) - # BRUTAL FORCE TO FIND THE VARIABLES DEFINED IN PETSC # ref: # https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake set(petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") set(petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) # A temporary makefile to probe the PETSc configuration -set (petsc_config_makefile "${PROJECT_BINARY_DIR}/Makefile.petsc") +set (petsc_config_makefile "/home/m/DAMASK/build/Makefile.petsc") #MD: don't know how get the path here file (WRITE "${petsc_config_makefile}" "## This file was auto generated by CMake # PETSC_DIR = ${PETSC_DIR} @@ -76,6 +41,45 @@ linker: \t@echo \${LINKERNAME} ") +# https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F +set(CMAKE_Fortran_COMPILER "/opt/petsc/gfortran/bin/mpif90") #MD: https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake might help +set(CMAKE_C_COMPILER "/opt/petsc/gfortran/bin/mpicc") #MD: https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake might help +#--------------------------------------------------------------------------------------- +# Now start to care about DAMASK + +# THE VERSION NUMBER. +set (DAMASK_VERSION_MAJOR 1) +set (DAMASK_VERSION_MINOR ${DAMASK_V}) + +project (DAMASK Fortran C) + +# COMPILE VARIABLES +add_definitions(-DDAMASKVERSION="${DAMASK_V}") +add_definitions(-DPETSc) +add_definitions(-DFLOAT=8) +add_definitions(-DINT=4) + +# Setting installation prefix +if (NOT DEFINED DAMASK_INSTALL) + set (CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/bin") +elseif(DEFINED DAMASK_INSTALL) + set (CMAKE_INSTALL_PREFIX "${DAMASK_INSTALL}") +endif(NOT DEFINED DAMASK_INSTALL) +message("\n***The binary will be installed at\n${CMAKE_INSTALL_PREFIX}\n") + +# DAMASK DRIVER SELECTION +set (SPECTRAL OFF) +set (FEM OFF) +if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") + set (SPECTRAL ON ) + add_definitions(-DSpectral) +endif("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") +# +if ("${DAMASK_DRIVER}" STREQUAL "FEM") + set (FEM ON ) + add_definitions(-DFEM) +endif("${DAMASK_DRIVER}" STREQUAL "FEM") + find_program (MAKE_EXECUTABLE NAMES make gmake) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "includes" @@ -443,4 +447,4 @@ endif(SPECTRAL) # Enable Dashboard scripting # include (CTest) -# set (CTEST_PROJECT_NAME "DAMASK") \ No newline at end of file +# set (CTEST_PROJECT_NAME "DAMASK") diff --git a/build_spectral.sh b/build_spectral.sh index dd1164558..e40700566 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -2,8 +2,18 @@ cat README echo -echo "Building spectral solver with ${FC}" + +if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == 'linux' ]; then + DAMASK_ROOT=$(readlink -f "`dirname $BASH_SOURCE`") +else + [[ "${BASH_SOURCE::1}" == "/" ]] && BASE="" || BASE="`pwd`/" + STAT=$(stat "`dirname $BASE$BASH_SOURCE`") + DAMASK_ROOT=${STAT##* } +fi + DAMASKVERSION=$(cat VERSION) +BUILDROOT=$DAMASK_ROOT/build +BUILDDIR=spectral # prepare building directory # structure: @@ -11,15 +21,15 @@ DAMASKVERSION=$(cat VERSION) # |-BUILD_SPECTRAL # |-BUILD_FEM # |-BUILD_MARC -if [ ! -d build ]; then - mkdir build +if [ ! -d $BUILDROOT ]; then + mkdir $BUILDROOT fi -cd build -if [ -d spectral ] ; then - rm -rf spectral +cd $BUILDROOT +if [ -d $BUILDDIR ] ; then + rm -rf $BUILDDIR fi -mkdir spectral -cd spectral +mkdir $BUILDDIR +cd $BUILDDIR ## # CMake call From a4225de91d923eb1e2b39764039d6b2cc3b16fb4 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Sun, 6 Mar 2016 09:30:16 -0500 Subject: [PATCH 046/183] reorder the CMake configuration and add more comments --- CMakeLists.txt | 149 +++++++++++++++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 61 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7da86d6e8..a0f754b61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,9 @@ # CMAKE for build the Material subroutine for BVP solution ######################################################################################## cmake_minimum_required (VERSION 2.8.0 FATAL_ERROR) +# PROJECT DEFINITION HAS TO BE ON TOP +# //The rest of the script relies on it to figure out relative position +project (DAMASK Fortran C) #--------------------------------------------------------------------------------------- # Find PETSc because the entire build will rely on it @@ -14,8 +17,10 @@ endif (NOT DEFINED PETSC_DIR) # https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake set(petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") set(petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) -# A temporary makefile to probe the PETSc configuration -set (petsc_config_makefile "/home/m/DAMASK/build/Makefile.petsc") #MD: don't know how get the path here +# Generate a temporary makerfile to probe the PETSc configuration +# This file will be deleted once the setting from PETSc is parsed +# into CMake +set (petsc_config_makefile "${PROJECT_SOURCE_DIR}/Makefile.petsc") file (WRITE "${petsc_config_makefile}" "## This file was auto generated by CMake # PETSC_DIR = ${PETSC_DIR} @@ -23,10 +28,11 @@ file (WRITE "${petsc_config_makefile}" SHELL = /bin/sh include ${petsc_conf_rules} include ${petsc_conf_variables} -INCLUDE_DIRS := \${PETSC_FC_INCLUDES} -LIBRARIES := \${PETSC_WITH_EXTERNAL_LIB} -COMPILERNAME ?= \${FC} -LINKERNAME ?= \${FLINKER} +INCLUDE_DIRS := \${PETSC_FC_INCLUDES} +LIBRARIES := \${PETSC_WITH_EXTERNAL_LIB} +COMPILERF ?= \${FC} +LINKERNAME ?= \${FLINKER} +COMPILERC ?= \${CC} includes: \t@echo \${INCLUDE_DIRS} @@ -34,16 +40,84 @@ includes: extlibs: \t@echo \${LIBRARIES} -compiler: -\t@echo \${COMPILERNAME} +compilerf: +\t@echo \${COMPILERF} + +compilerc: +\t@echo \${COMPILERC} linker: -\t@echo \${LINKERNAME} +\t@echo \${LINKERNAME}") -") -# https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F -set(CMAKE_Fortran_COMPILER "/opt/petsc/gfortran/bin/mpif90") #MD: https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake might help -set(CMAKE_C_COMPILER "/opt/petsc/gfortran/bin/mpicc") #MD: https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake might help +# CMake will execute each target in the ${petsc_config_makefile} +# to acquire corresponding PETSc Variables. +# The include path and linking libraries in PETSc usually contains +# duplicated entries, which is cleaned up later using CMake list. +find_program (MAKE_EXECUTABLE NAMES make gmake) +# Find the PETSc includes directory settings +execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "includes" + RESULT_VARIABLE PETSC_INCLUDES_RETURN + 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} -f ${petsc_config_makefile} "extlibs" + RESULT_VARIABLE PETSC_EXTERNAL_LIB_RETURN + OUTPUT_VARIABLE petsc_external_lib + OUTPUT_STRIP_TRAILING_WHITESPACE) +# The MPI compiler specified in PETSc +# //its version information is used to identify whether it is INTEL FORTRAN +# //or GNU FORTRAN, +# //e.g. for PETSc configured with INTEL FORTRAN compiler +# // >>${MPIEXEC} -v +# // ifort version 14.0.3 --> This line is captured and parsed by CMake +execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compilerf" + RESULT_VARIABLE MPIEXEC_RETURN + OUTPUT_VARIABLE MPIEXEC + OUTPUT_STRIP_TRAILING_WHITESPACE) +# The option OUTPUT_QUIET sometimes fails to suppress the output from +# ${MPIEXEC} -v, thus the MPIF90 version information may show up in the terminal. +execute_process(COMMAND ${MPIEXEC} --version OUTPUT_QUIET + RESULT_VARIABLE MPINAME_RETURN + OUTPUT_VARIABLE MPINAME + OUTPUT_STRIP_TRAILING_WHITESPACE) +# PETSc specified linker (MPIF90 + PETSc linking flags) +execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "linker" + RESULT_VARIABLE PETSC_LINKER_RETURN + OUTPUT_VARIABLE PETSC_LINKER + OUTPUT_STRIP_TRAILING_WHITESPACE) +# Get MPI C compiler name from PETSc +execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compilerc" + RESULT_VARIABLE CMPIEXEC_RETURN + OUTPUT_VARIABLE CMPIEXEC + OUTPUT_STRIP_TRAILING_WHITESPACE) +# Remove temporary makefile, no need to keep it anymore. +file (REMOVE ${petsc_config_makefile}) + +# REMOVE DUPLICATE FLAGS FOR COMPILER AND LINKING +string( REGEX MATCHALL "-I([^\" ]+)" TMP_LIST "${petsc_includes}") +list(REMOVE_DUPLICATES TMP_LIST) +foreach (dir ${TMP_LIST}) + set(PETSC_INCLUDES "${PETSC_INCLUDES} ${dir}") +endforeach(dir) +string( REGEX MATCHALL "-[lLW]([^\" ]+)" TMP_LIST "${petsc_external_lib}") +list(REMOVE_DUPLICATES TMP_LIST) +foreach (exlib ${TMP_LIST}) + set(PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} ${exlib}") +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 FORTRAN MPI COMPILER:\n${MPIEXEC}\n" ) +message("***Found C MPI COMPILER:\n${CMPIEXEC}\n" ) + +set (CMAKE_Fortran_COMPILER "${MPIEXEC}" ) +set (CMAKE_C_COMPILER "${CMPIEXEC}") +# # https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F +# set(CMAKE_Fortran_COMPILER "/opt/petsc/gfortran/bin/mpif90") #MD: https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake might help +# set(CMAKE_C_COMPILER "/opt/petsc/gfortran/bin/mpicc") #MD: https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake might help #--------------------------------------------------------------------------------------- # Now start to care about DAMASK @@ -51,8 +125,6 @@ set(CMAKE_C_COMPILER "/opt/petsc/gfortran/bin/mpicc") #MD: set (DAMASK_VERSION_MAJOR 1) set (DAMASK_VERSION_MINOR ${DAMASK_V}) -project (DAMASK Fortran C) - # COMPILE VARIABLES add_definitions(-DDAMASKVERSION="${DAMASK_V}") add_definitions(-DPETSc) @@ -80,50 +152,6 @@ if ("${DAMASK_DRIVER}" STREQUAL "FEM") add_definitions(-DFEM) endif("${DAMASK_DRIVER}" STREQUAL "FEM") - -find_program (MAKE_EXECUTABLE NAMES make gmake) -execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "includes" - RESULT_VARIABLE PETSC_INCLUDES_RETURN - OUTPUT_VARIABLE petsc_includes - OUTPUT_STRIP_TRAILING_WHITESPACE) -execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "extlibs" - RESULT_VARIABLE PETSC_EXTERNAL_LIB_RETURN - OUTPUT_VARIABLE petsc_external_lib - OUTPUT_STRIP_TRAILING_WHITESPACE) -execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "linker" - RESULT_VARIABLE PETSC_LINKER_RETURN - OUTPUT_VARIABLE PETSC_LINKER - OUTPUT_STRIP_TRAILING_WHITESPACE) -execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compiler" - RESULT_VARIABLE MPIEXEC_RETURN - OUTPUT_VARIABLE MPIEXEC - OUTPUT_STRIP_TRAILING_WHITESPACE) -execute_process(COMMAND ${MPIEXEC} -v OUTPUT_QUIET - RESULT_VARIABLE MPINAME_RETURN - OUTPUT_VARIABLE MPINAME - OUTPUT_STRIP_TRAILING_WHITESPACE) -file (REMOVE ${petsc_config_makefile}) - -# REMOVE DUPLICATE FLAGS FOR COMPILER AND LINKING -string( REGEX MATCHALL "-I([^\" ]+)" TMP_LIST "${petsc_includes}") -list(REMOVE_DUPLICATES TMP_LIST) -foreach (dir ${TMP_LIST}) - set(PETSC_INCLUDES "${PETSC_INCLUDES} ${dir}") -endforeach(dir) -string( REGEX MATCHALL "-[lLW]([^\" ]+)" TMP_LIST "${petsc_external_lib}") -list(REMOVE_DUPLICATES TMP_LIST) -foreach (exlib ${TMP_LIST}) - set(PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} ${exlib}") -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 PETSC_MPIEXEC:\n${MPIEXEC}\n") - - set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") @@ -386,7 +414,7 @@ if (MPINAME MATCHES "(^ifort)*") set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DEBUG_OPTIONS_ifort}" ) # -elseif (MPINAME MATCHES "(^gfortran)*") +elseif (MPINAME MATCHES "(^GNU)*") message("GNU fortran used for MPIF90\n") set (GNU_FORTRAN ON) # for RELEASE @@ -413,7 +441,6 @@ else (MPINAME MATCHES "(^ifort)*") endif (MPINAME MATCHES "(^ifort)*") # Finalizing -set (CMAKE_Fortran_COMPILER "${MPIEXEC}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") set (CMAKE_LINKER "${PETSC_LINKER}") From c22b73c8035728dfe7dfcf5933682e4f8e8684cc Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 7 Mar 2016 11:54:36 -0500 Subject: [PATCH 047/183] fix mpif90 compiler type detection --- CMakeLists.txt | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0f754b61..4c89b8e62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,12 +75,6 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compiler RESULT_VARIABLE MPIEXEC_RETURN OUTPUT_VARIABLE MPIEXEC OUTPUT_STRIP_TRAILING_WHITESPACE) -# The option OUTPUT_QUIET sometimes fails to suppress the output from -# ${MPIEXEC} -v, thus the MPIF90 version information may show up in the terminal. -execute_process(COMMAND ${MPIEXEC} --version OUTPUT_QUIET - RESULT_VARIABLE MPINAME_RETURN - OUTPUT_VARIABLE MPINAME - OUTPUT_STRIP_TRAILING_WHITESPACE) # PETSc specified linker (MPIF90 + PETSc linking flags) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "linker" RESULT_VARIABLE PETSC_LINKER_RETURN @@ -115,6 +109,8 @@ message("***Found C MPI COMPILER:\n${CMPIEXEC}\n" ) set (CMAKE_Fortran_COMPILER "${MPIEXEC}" ) set (CMAKE_C_COMPILER "${CMPIEXEC}") + + # # https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F # set(CMAKE_Fortran_COMPILER "/opt/petsc/gfortran/bin/mpif90") #MD: https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake might help # set(CMAKE_C_COMPILER "/opt/petsc/gfortran/bin/mpicc") #MD: https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake might help @@ -392,10 +388,23 @@ set (PRECISION_ifort "-real-size 64 -integer-size 32") ################################################################################################### set (PRECISION_gfortran "-fdefault-real-8 -fdefault-double-8") - -if (MPINAME MATCHES "(^ifort)*") - message("Intel fortran used for MPIF90\n") +# DETECT MPI COMPILER TYPE +message("\n***DETECTING MPI COMPILER TYPE") +execute_process(COMMAND ${MPIEXEC} --version + RESULT_VARIABLE MPINAME_RETURN + OUTPUT_VARIABLE MPINAME + OUTPUT_STRIP_TRAILING_WHITESPACE) +if (MPINAME MATCHES "(ifort)") + message(" [OK]INTEL FORTRAN DETECTED FOR MPI\n") set (INTEL_FORTRAN ON) +elseif(MPINAME MATCHES "(GNU)") + message(" [OK]GNU fortran used for MPIF90\n") + set (GNU_FORTRAN ON) +else(MPINAME MATCHES "(ifort)") + message(FATAL_ERROR "[ERROR]Unknown compiler type!!!") +endif(MPINAME MATCHES "(ifort)") + +if (INTEL_FORTRAN) # for RELEASE set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}" ) @@ -414,9 +423,7 @@ if (MPINAME MATCHES "(^ifort)*") set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DEBUG_OPTIONS_ifort}" ) # -elseif (MPINAME MATCHES "(^GNU)*") - message("GNU fortran used for MPIF90\n") - set (GNU_FORTRAN ON) +elseif (GNU_FORTRAN) # for RELEASE set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_gfortran}" ) set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_gfortran}" ) @@ -434,11 +441,9 @@ elseif (MPINAME MATCHES "(^GNU)*") set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DEBUG_OPTIONS_gfortran}") # -elseif (MPINAME MATCHES "(^g77)*") - message (FATAL_ERROR "Fortran 77 is not supported.") -else (MPINAME MATCHES "(^ifort)*") +else (INTEL_FORTRAN) message (FATAL_ERROR "Require Fortran90 from GNU or Intel.") -endif (MPINAME MATCHES "(^ifort)*") +endif (INTEL_FORTRAN) # Finalizing set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") From ff92d228f41673f9d6a60f51be016ba3f23155f0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 7 Mar 2016 18:43:07 +0100 Subject: [PATCH 048/183] reordering --- CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c89b8e62..b90f79afd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,6 @@ cmake_minimum_required (VERSION 2.8.0 FATAL_ERROR) # PROJECT DEFINITION HAS TO BE ON TOP # //The rest of the script relies on it to figure out relative position -project (DAMASK Fortran C) #--------------------------------------------------------------------------------------- # Find PETSc because the entire build will rely on it @@ -12,6 +11,8 @@ if (NOT DEFINED PETSC_DIR) message (FATAL_ERROR "PETSC_DIR is not found!") endif (NOT DEFINED PETSC_DIR) +exec_program(mktemp ARGS -d OUTPUT_VARIABLE PETSC_TEMP) + # BRUTAL FORCE TO FIND THE VARIABLES DEFINED IN PETSC # ref: # https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake @@ -20,7 +21,7 @@ set(petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) # Generate a temporary makerfile to probe the PETSc configuration # This file will be deleted once the setting from PETSc is parsed # into CMake -set (petsc_config_makefile "${PROJECT_SOURCE_DIR}/Makefile.petsc") +set (petsc_config_makefile "${PETSC_TEMP}/Makefile.petsc") file (WRITE "${petsc_config_makefile}" "## This file was auto generated by CMake # PETSC_DIR = ${PETSC_DIR} @@ -49,6 +50,7 @@ compilerc: linker: \t@echo \${LINKERNAME}") + # CMake will execute each target in the ${petsc_config_makefile} # to acquire corresponding PETSc Variables. # The include path and linking libraries in PETSc usually contains @@ -100,6 +102,10 @@ foreach (exlib ${TMP_LIST}) set(PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} ${exlib}") endforeach(exlib) +set(CMAKE_Fortran_COMPILER "${MPIEXEC}") +set(CMAKE_C_COMPILER "${COMPILERC}") +project (DAMASK Fortran C) + 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") From 1935d00e05416e78224ae095be5280cdeee13108 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 8 Mar 2016 00:00:12 +0100 Subject: [PATCH 049/183] cleaned --- CMakeLists.txt | 257 ++++++++++++++++++++------------------------- src/CMakeLists.txt | 8 +- 2 files changed, 116 insertions(+), 149 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b90f79afd..05b9d9320 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,6 @@ INCLUDE_DIRS := \${PETSC_FC_INCLUDES} LIBRARIES := \${PETSC_WITH_EXTERNAL_LIB} COMPILERF ?= \${FC} LINKERNAME ?= \${FLINKER} -COMPILERC ?= \${CC} includes: \t@echo \${INCLUDE_DIRS} @@ -82,11 +81,6 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "linker" RESULT_VARIABLE PETSC_LINKER_RETURN OUTPUT_VARIABLE PETSC_LINKER OUTPUT_STRIP_TRAILING_WHITESPACE) -# Get MPI C compiler name from PETSc -execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compilerc" - RESULT_VARIABLE CMPIEXEC_RETURN - OUTPUT_VARIABLE CMPIEXEC - OUTPUT_STRIP_TRAILING_WHITESPACE) # Remove temporary makefile, no need to keep it anymore. file (REMOVE ${petsc_config_makefile}) @@ -103,23 +97,16 @@ foreach (exlib ${TMP_LIST}) endforeach(exlib) set(CMAKE_Fortran_COMPILER "${MPIEXEC}") -set(CMAKE_C_COMPILER "${COMPILERC}") -project (DAMASK Fortran C) +project (DAMASK Fortran) 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 FORTRAN MPI COMPILER:\n${MPIEXEC}\n" ) -message("***Found C MPI COMPILER:\n${CMPIEXEC}\n" ) - -set (CMAKE_Fortran_COMPILER "${MPIEXEC}" ) -set (CMAKE_C_COMPILER "${CMPIEXEC}") # # https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F -# set(CMAKE_Fortran_COMPILER "/opt/petsc/gfortran/bin/mpif90") #MD: https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake might help -# set(CMAKE_C_COMPILER "/opt/petsc/gfortran/bin/mpicc") #MD: https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake might help #--------------------------------------------------------------------------------------- # Now start to care about DAMASK @@ -134,59 +121,44 @@ add_definitions(-DFLOAT=8) add_definitions(-DINT=4) # Setting installation prefix -if (NOT DEFINED DAMASK_INSTALL) - set (CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/bin") -elseif(DEFINED DAMASK_INSTALL) +if (DEFINED DAMASK_INSTALL) set (CMAKE_INSTALL_PREFIX "${DAMASK_INSTALL}") -endif(NOT DEFINED DAMASK_INSTALL) +else(DEFINED DAMASK_INSTALL) + set (CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/bin") +endif(DEFINED DAMASK_INSTALL) message("\n***The binary will be installed at\n${CMAKE_INSTALL_PREFIX}\n") # DAMASK DRIVER SELECTION -set (SPECTRAL OFF) -set (FEM OFF) if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") set (SPECTRAL ON ) add_definitions(-DSpectral) -endif("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") -# -if ("${DAMASK_DRIVER}" STREQUAL "FEM") + set (FEM OFF) +elseif ("${DAMASK_DRIVER}" STREQUAL "FEM") set (FEM ON ) add_definitions(-DFEM) -endif("${DAMASK_DRIVER}" STREQUAL "FEM") + set (SPECTRAL OFF) +endif() set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") -## -# set compile and debug flags -if (OPENMP) - set (OPENMP_FLAG_ifort "-openmp -openmp-report0 -parallel") - set (OPENMP_FLAG_gfortran "-fopenmp") -else (OPENMP) - message("No openmp support specified") - set (OPENMP_FLAG_ifort "") - set (OPENMP_FLAG_gfortran "") -endif (OPENMP) - if ("${OPTIMIZATION}" STREQUAL "OFF") set (OPTIMIZATION_ifort "-O0 -no-ip") set (OPTIMIZATION_gfortran "-O0" ) elseif ("${OPTIMIZATION}" STREQUAL "DEFENSIVE") set (OPTIMIZATION_ifort "-O2") set (OPTIMIZATION_gfortran "-O2") -elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") +elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") #ToDo: this is not fully correct here, check old makefile set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") elseif ("${OPTIMIZATION}" STREQUAL "ULTRA") set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") -else ("${OPTIMIZATION}" STREQUAL "OFF") +else() set (OPTIMIZATION_ifort "-O2") set (OPTIMIZATION_gfortran "-O2") -endif ("${OPTIMIZATION}" STREQUAL "OFF") +endif() -set (STANDARD_CHECK_ifort "-stand f08 -standard-semantics") -set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) ################################################################################################### # COMPILE SWITCHES @@ -216,17 +188,35 @@ set (STANDARD_CHECK_gfortran "-std=f2008ts -pedantic-errors" ) # all: # -name as_is: case sensitive Fortran! ################################################################################################### -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -fpp" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -ftz" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -assume byterecl,fpe_summary") -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -diag-disable 5268" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn declarations" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn general" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn usage" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn interfaces" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn ignore_loc" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn alignments" ) -set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn unused" ) +if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") + + if (OPENMP) + set (OPENMP_FLAG "-openmp -openmp-report0 -parallel") + endif() + + if ("${OPTIMIZATION}" STREQUAL "OFF") + set (OPTIMIZATION_FLAG "-O0 -no-ip") + elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") #ToDo: this is not fully correct here, check old makefile + set (OPTIMIZATION_FLAG "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" + elseif ("${OPTIMIZATION}" STREQUAL "ULTRA") + set (OPTIMIZATION_FLAG "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" + else() # this is the default + set (OPTIMIZATION_FLAG "-O2") + endif() + + set (STANDARD_CHECK "-stand f08 -standard-semantics") + + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -assume byterecl,fpe_summary") + set (COMPILE_FLAGS "${COMPILE_FLAGS} -diag-disable 5268" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn declarations" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn general" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn usage" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn interfaces" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn ignore_loc" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn alignments" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn unused" ) ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING # -g: Generate symbolic debugging information in the object file @@ -252,19 +242,25 @@ set (COMPILE_OPTIONS_ifort "${COMPILE_OPTIONS_ifort} -warn unused" # arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) # stack: ################################################################################################### -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -g" ) -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -traceback" ) -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -gen-interfaces" ) -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -fp-stack-check" ) -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -fp-model strict" ) -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -check bounds,format,output_conversion,pointers,uninit" ) -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -ftrapuv" ) -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -fpe-all0" ) -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -warn errors" ) -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -warn stderrors" ) -set (DEBUG_OPTIONS_ifort "${DEBUG_OPTIONS_ifort} -debug-parameters all" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -g" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -traceback" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -gen-interfaces" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-stack-check" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-model strict" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -check bounds,format,output_conversion,pointers,uninit" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -ftrapuv" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all0" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn errors" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn stderrors" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -debug-parameters all" ) -set (LINK_OPTIONS_ifort "-shared-intel") + set (LINKER_FLAG " -shared-intel") + +################################################################################################### +#-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) +#-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) +################################################################################################### + set (PRECISION "-real-size 64 -integer-size 32") ################################################################################################### # COMPILE SWITCHES # -shared @@ -341,20 +337,41 @@ set (LINK_OPTIONS_ifort "-shared-intel") # -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. # -Wstrict-overflow: ################################################################################################### -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -xf95-cpp-input" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -ffree-line-length-132" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fimplicit-none" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fmodule-private" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wall" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wextra" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wcharacter-truncation" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wunderflow" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wsuggest-attribute=pure" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wsuggest-attribute=noreturn" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wconversion-extra" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wimplicit-procedure" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -Wno-unused-parameter" ) -set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fno-range-check" ) +elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") + + if (OPENMP) + set (OPENMP_FLAG "-fopenmp") + endif() + + if ("${OPTIMIZATION}" STREQUAL "OFF") + set (OPTIMIZATION_FLAG "-O0" ) + elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") #ToDo: this is not fully correct here, check old makefile + set (OPTIMIZATION_FLAG "-O3 -ffast-math -funroll-loops -ftree-vectorize") + elseif ("${OPTIMIZATION}" STREQUAL "ULTRA") + set (OPTIMIZATION_FLAG "-O3 -ffast-math -funroll-loops -ftree-vectorize") + else() # this is the default + set (OPTIMIZATION_FLAG "-O2") + endif() + + set (STANDARD_CHECK "-std=f2008ts -pedantic-errors" ) + + set (COMPILE_FLAGS "${COMPILE_FLAGS} -xf95-cpp-input" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffree-line-length-132" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fimplicit-none" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fmodule-private" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wall" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wextra" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wcharacter-truncation" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wunderflow" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=pure" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=noreturn") + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wconversion-extra" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wimplicit-procedure" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-unused-parameter" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fno-range-check" ) + + set (LINKER_FLAG " -Wl,-undefined,dynamic_lookup") + ################################################################################################### # COMPILE SWITCHES FOR RUNTIME DEBUGGING # -ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) @@ -373,83 +390,33 @@ set (COMPILE_OPTIONS_gfortran "${COMPILE_OPTIONS_gfortran} -fno-range-check" # denormal, \ # underflow ################################################################################################### -set (DEBUG_OPTIONS_gfortran "${DEBUG_OPTIONS_gfortran} -g" ) -set (DEBUG_OPTIONS_gfortran "${DEBUG_OPTIONS_gfortran} -fbacktrace" ) -set (DEBUG_OPTIONS_gfortran "${DEBUG_OPTIONS_gfortran} -fdump-core" ) -set (DEBUG_OPTIONS_gfortran "${DEBUG_OPTIONS_gfortran} -fcheck=all" ) -set (DEBUG_OPTIONS_gfortran "${DEBUG_OPTIONS_gfortran} -ffpe-trap=invalid,zero,overflow") - -set (LINK_OPTIONS_gfortran "-Wl,-undefined,dynamic_lookup") - -################################################################################################### -#-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) -#-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) -################################################################################################### -set (PRECISION_ifort "-real-size 64 -integer-size 32") + set (DEBUG_FLAGS "${DEBUG_FLAGS} -g" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fbacktrace" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fdump-core" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fcheck=all" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -ffpe-trap=invalid,zero,overflow") ################################################################################################### #-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set #-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used #-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) ################################################################################################### -set (PRECISION_gfortran "-fdefault-real-8 -fdefault-double-8") + set (PRECISION "-fdefault-real-8 -fdefault-double-8") +endif() -# DETECT MPI COMPILER TYPE -message("\n***DETECTING MPI COMPILER TYPE") -execute_process(COMMAND ${MPIEXEC} --version - RESULT_VARIABLE MPINAME_RETURN - OUTPUT_VARIABLE MPINAME - OUTPUT_STRIP_TRAILING_WHITESPACE) -if (MPINAME MATCHES "(ifort)") - message(" [OK]INTEL FORTRAN DETECTED FOR MPI\n") - set (INTEL_FORTRAN ON) -elseif(MPINAME MATCHES "(GNU)") - message(" [OK]GNU fortran used for MPIF90\n") - set (GNU_FORTRAN ON) -else(MPINAME MATCHES "(ifort)") - message(FATAL_ERROR "[ERROR]Unknown compiler type!!!") -endif(MPINAME MATCHES "(ifort)") +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG}" ) +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK}" ) +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPTIMIZATION_FLAG}" ) +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_FLAGS}") +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION}" ) -if (INTEL_FORTRAN) - # for RELEASE - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}" ) - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPTIMIZATION_ifort}" ) - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_OPTIONS_ifort}") - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_ifort}" ) +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAG}" ) +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK}") +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_FLAG}" ) +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_FLAG}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAG_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_ifort}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_ifort}") - - # for DEBUG - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_ifort}" ) - - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DEBUG_OPTIONS_ifort}" ) - # -elseif (GNU_FORTRAN) - # for RELEASE - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG_gfortran}" ) - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK_gfortran}" ) - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPTIMIZATION_gfortran}" ) - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_OPTIONS_gfortran}") - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_gfortran}" ) - - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAG_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_OPTIONS_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_gfortran}" ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK_gfortran}") - # for DEBUG - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_OPTIONS_gfortran}" ) - - set (CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${DEBUG_OPTIONS_gfortran}") - # -else (INTEL_FORTRAN) - message (FATAL_ERROR "Require Fortran90 from GNU or Intel.") -endif (INTEL_FORTRAN) +set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") +set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_FLAGS}" ) # Finalizing set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d461eb294..60f8336a1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,12 +2,12 @@ # !!! EXPLICIT DEPENDENCY DECLARATION !!! # SOME FILES REQUIRE SPECIAL FLAGS -if (INTEL_FORTRAN) +if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") # -diag-disable 7410 should disable warning about directory statement # in inquire function, but does not work. hence the other 2 statements SET_SOURCE_FILES_PROPERTIES( "spectral_interface.f90" PROPERTIES COMPILE_FLAGS "-diag-remark 7410 -stand none -warn nostderrors" ) -elseif (GNU_FORTRAN) +elseif (${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # fno-range-check: Disable range checking on results of simplification of constant expressions during compilation # --> allows the definition of DAMASK_NaN #-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored @@ -25,7 +25,7 @@ elseif (GNU_FORTRAN) # long lines for interaction matrix SET_SOURCE_FILES_PROPERTIES( "lattice.f90" PROPERTIES COMPILE_FLAGS "-ffree-line-length-240") -endif(INTEL_FORTRAN) +endif() add_library(DAMASK_PREC "prec.f90") @@ -195,4 +195,4 @@ if (SPECTRAL) add_executable(DAMASKSpectral.exe "DAMASK_spectral.f90") target_link_libraries(DAMASKSpectral.exe DAMASK_EXE) -endif(SPECTRAL) \ No newline at end of file +endif(SPECTRAL) From cfddba930b1dc63154b1afa1dfb491fd57020f48 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 8 Mar 2016 13:54:40 -0500 Subject: [PATCH 050/183] add missing linker flags --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05b9d9320..59b7ec382 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -413,7 +413,7 @@ set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAG}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK}") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_FLAG}" ) -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINK_FLAG}" ) +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER_FLAG}" ) set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_FLAGS}" ) From 7aadfd56cacc4ebc232428384c096015d0d35a2c Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 14 Mar 2016 15:57:19 -0400 Subject: [PATCH 051/183] use options for future cross-platform support --- CMakeLists.txt | 26 +++++++++++++++++++++++-- build_FEM.sh | 16 +++++++++------- build_spectral.sh | 15 ++++++++------- src/CMakeLists.txt | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59b7ec382..0b4d7916d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,6 @@ set (petsc_config_makefile "${PETSC_TEMP}/Makefile.petsc") file (WRITE "${petsc_config_makefile}" "## This file was auto generated by CMake # PETSC_DIR = ${PETSC_DIR} -# PETSC_ARCH = ${PETSC_ARCH} SHELL = /bin/sh include ${petsc_conf_rules} include ${petsc_conf_variables} @@ -99,11 +98,21 @@ endforeach(exlib) set(CMAKE_Fortran_COMPILER "${MPIEXEC}") project (DAMASK Fortran) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") + +find_package(FFTW REQUIRED) +find_package(PythonInterp REQUIRED) +find_program(F2PY_EXECUTABLE NAMES "f2py${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" + "f2py-${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" + "f2py${PYTHON_VERSION_MAJOR}" + "f2py") + 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 FORTRAN MPI COMPILER:\n${MPIEXEC}\n" ) +message("***Found FFTW_LIB:\n${FFTW_LIBRARIES}") # # https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F @@ -114,6 +123,14 @@ message("***Found FORTRAN MPI COMPILER:\n${MPIEXEC}\n" ) set (DAMASK_VERSION_MAJOR 1) set (DAMASK_VERSION_MINOR ${DAMASK_V}) +# Built-in options for DAMASK build system +# -> can be overwritten from commandline/install_script +option(OPENMP "Use OpenMP libaries for DAMASK" ON ) +option(DAMASK_PROCESSING "Build pre/post processing modules for DAMASK" OFF ) +option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE,ULTRA]" NONE) +option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) +option(FEM "Builb FEM solver for DAMASK" OFF ) + # COMPILE VARIABLES add_definitions(-DDAMASKVERSION="${DAMASK_V}") add_definitions(-DPETSc) @@ -142,7 +159,7 @@ endif() set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") -if ("${OPTIMIZATION}" STREQUAL "OFF") +if ("${OPTIMIZATION}" STREQUAL "NONE") set (OPTIMIZATION_ifort "-O0 -no-ip") set (OPTIMIZATION_gfortran "-O0" ) elseif ("${OPTIMIZATION}" STREQUAL "DEFENSIVE") @@ -445,6 +462,11 @@ elseif (FEM) DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(SPECTRAL) +if (DAMASK_PROCESSING) + INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/core.so + DESTINATION ${PROJECT_SOURCE_DIR}/lib/damask) +endif(DAMASK_PROCESSING) + ## # ADD TESTING CASES # add_test (SmokeTestRun diff --git a/build_FEM.sh b/build_FEM.sh index a8326a07e..b6ad6c67e 100755 --- a/build_FEM.sh +++ b/build_FEM.sh @@ -23,13 +23,14 @@ cd FEM ## # CMake call -# PETSC_DIR | PETSC directory -# DAMASK_V | DAMASK current revision -# CMAKE_BUILD_TYPE | Default set to release (no debugging output) -# OPENMP | [ON/OFF] -# OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] -# DAMASK_DRIVER | [SPECTRAL, FEM] -# DAMASK_INSTALL | Directory to install binary output +# PETSC_DIR | PETSC directory +# DAMASK_V | DAMASK current revision +# CMAKE_BUILD_TYPE | Default set to release (no debugging output) +# OPENMP | [ON/OFF] +# OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] +# DAMASK_DRIVER | [SPECTRAL, FEM] +# DAMASK_INSTALL | Directory to install binary output +# INSTALL_PROCESSING | Build supporting pre/post processing scripts cmake -D PETSC_DIR=${PETSC_DIR} \ -D DAMASK_V=${DAMASKVERSION} \ -D CMAKE_BUILD_TYPE=RELEASE \ @@ -37,6 +38,7 @@ cmake -D PETSC_DIR=${PETSC_DIR} \ -D OPTIMIZATION=DEFENSIVE \ -D DAMASK_DRIVER=FEM \ -D DAMASK_INSTALL=${HOME}/bin \ + -D INSTALL_PROCESSING=YES \ ../.. echo diff --git a/build_spectral.sh b/build_spectral.sh index e40700566..669ef18bc 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -40,13 +40,14 @@ cd $BUILDDIR # OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] # DAMASK_DRIVER | [SPECTRAL, FEM] # DAMASK_INSTALL | Directory to install binary output -cmake -D PETSC_DIR=${PETSC_DIR} \ - -D DAMASK_V=${DAMASKVERSION} \ - -D CMAKE_BUILD_TYPE=RELEASE \ - -D OPENMP=ON \ - -D OPTIMIZATION=DEFENSIVE \ - -D DAMASK_DRIVER=SPECTRAL \ - -D DAMASK_INSTALL=${HOME}/bin \ +cmake -D PETSC_DIR=${PETSC_DIR} \ + -D DAMASK_V=${DAMASKVERSION} \ + -D CMAKE_BUILD_TYPE=RELEASE \ + -D OPENMP=ON \ + -D DAMASK_PROCESSING=ON \ + -D OPTIMIZATION=DEFENSIVE \ + -D DAMASK_DRIVER=SPECTRAL \ + -D DAMASK_INSTALL=${HOME}/bin \ ../.. echo diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 60f8336a1..8d5f5296a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -196,3 +196,51 @@ if (SPECTRAL) add_executable(DAMASKSpectral.exe "DAMASK_spectral.f90") target_link_libraries(DAMASKSpectral.exe DAMASK_EXE) endif(SPECTRAL) + +if (DAMASK_PROCESSING) + # set compiler flags based on type of compiler used + if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") + set(CORECOMPILER "${CORECOMPILER} --fcompiler=intelem") + set(CORECOMPILER "${CORECOMPILER} --f90flags=\"-fPIC -fpp -stand f08 -diag-disable 5268 -assume byterecl -real-size 64 -integer-size 32 -shared-intel\"") + elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") + set(CORECOMPILER "${CORECOMPILER} --fcompiler=gnu95") + set(CORECOMPILER "${CORECOMPILER} --f90flags=\"-fPIC -fno-range-check -xf95-cpp-input -std=f2008 -fall-intrinsics -fdefault-real-8 -fdefault-double-8\"") + endif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") + # set CORE compiler options + set(CORE_COMPILE_OPTIONS "${COMPILEROPTIONS} -DSpectral -DFLOAT=8 -DINT=4") + set(CORE_COMPILE_OPTIONS "${COMPILEROPTIONS} -I${PROJECT_SOURCE_DIR}/lib") + set(CORE_COMPILE_OPTIONS "${COMPILEROPTIONS} -DDAMASKVERSION=\\\"${DAMASK_V}\\\"") + # set CORE link flags + if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") + set(CORE_LDFLAGS "${CORE_LDFLAGS} -openmp -Wl") + elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") + set(CORE_LDFLAGS "${CORE_LDFLAGS} -shared -Wl,-undefined,dynamic_lookup") + endif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") + + # source file for building core + set(COREFILES "${COREFILES} prec.f90" ) + set(COREFILES "${COREFILES} spectral_interface.f90") + set(COREFILES "${COREFILES} IO.f90" ) + set(COREFILES "${COREFILES} libs.f90" ) + set(COREFILES "${COREFILES} numerics.f90" ) + set(COREFILES "${COREFILES} debug.f90" ) + set(COREFILES "${COREFILES} math.f90" ) + set(COREFILES "${COREFILES} FEsolving.f90" ) + set(COREFILES "${COREFILES} mesh.f90" ) + set(COREFILES "${COREFILES} core_quit.f90" ) + + execute_process(COMMAND F2PY_EXECUTABLE damask.core.pyf ) +endif(DAMASK_PROCESSING) + + + + + + + + + + + + + From 610a54c04824dc25eb24d98f5bce3bd5f3b0e476 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Mon, 14 Mar 2016 17:49:36 -0400 Subject: [PATCH 052/183] remove options for building core module, which will be implemted in python --- CMakeLists.txt | 24 ++++------------------ build_FEM.sh | 1 - build_spectral.sh | 1 - src/CMakeLists.txt | 50 +--------------------------------------------- 4 files changed, 5 insertions(+), 71 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b4d7916d..f76631a61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,21 +98,11 @@ endforeach(exlib) set(CMAKE_Fortran_COMPILER "${MPIEXEC}") project (DAMASK Fortran) -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") - -find_package(FFTW REQUIRED) -find_package(PythonInterp REQUIRED) -find_program(F2PY_EXECUTABLE NAMES "f2py${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" - "f2py-${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" - "f2py${PYTHON_VERSION_MAJOR}" - "f2py") - 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 FORTRAN MPI COMPILER:\n${MPIEXEC}\n" ) -message("***Found FFTW_LIB:\n${FFTW_LIBRARIES}") # # https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F @@ -125,11 +115,10 @@ set (DAMASK_VERSION_MINOR ${DAMASK_V}) # Built-in options for DAMASK build system # -> can be overwritten from commandline/install_script -option(OPENMP "Use OpenMP libaries for DAMASK" ON ) -option(DAMASK_PROCESSING "Build pre/post processing modules for DAMASK" OFF ) -option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE,ULTRA]" NONE) -option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) -option(FEM "Builb FEM solver for DAMASK" OFF ) +option(OPENMP "Use OpenMP libaries for DAMASK" ON ) +option(OPTIMIZATION "DAMASK optimization level[NONE,DEFENSIVE,AGGRESSIVE,ULTRA]" "NONE") +option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) +option(FEM "Builb FEM solver for DAMASK" OFF ) # COMPILE VARIABLES add_definitions(-DDAMASKVERSION="${DAMASK_V}") @@ -462,11 +451,6 @@ elseif (FEM) DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(SPECTRAL) -if (DAMASK_PROCESSING) - INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/core.so - DESTINATION ${PROJECT_SOURCE_DIR}/lib/damask) -endif(DAMASK_PROCESSING) - ## # ADD TESTING CASES # add_test (SmokeTestRun diff --git a/build_FEM.sh b/build_FEM.sh index b6ad6c67e..56e26c45b 100755 --- a/build_FEM.sh +++ b/build_FEM.sh @@ -38,7 +38,6 @@ cmake -D PETSC_DIR=${PETSC_DIR} \ -D OPTIMIZATION=DEFENSIVE \ -D DAMASK_DRIVER=FEM \ -D DAMASK_INSTALL=${HOME}/bin \ - -D INSTALL_PROCESSING=YES \ ../.. echo diff --git a/build_spectral.sh b/build_spectral.sh index 669ef18bc..eb614f41c 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -44,7 +44,6 @@ cmake -D PETSC_DIR=${PETSC_DIR} \ -D DAMASK_V=${DAMASKVERSION} \ -D CMAKE_BUILD_TYPE=RELEASE \ -D OPENMP=ON \ - -D DAMASK_PROCESSING=ON \ -D OPTIMIZATION=DEFENSIVE \ -D DAMASK_DRIVER=SPECTRAL \ -D DAMASK_INSTALL=${HOME}/bin \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8d5f5296a..553ad3836 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -195,52 +195,4 @@ if (SPECTRAL) add_executable(DAMASKSpectral.exe "DAMASK_spectral.f90") target_link_libraries(DAMASKSpectral.exe DAMASK_EXE) -endif(SPECTRAL) - -if (DAMASK_PROCESSING) - # set compiler flags based on type of compiler used - if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") - set(CORECOMPILER "${CORECOMPILER} --fcompiler=intelem") - set(CORECOMPILER "${CORECOMPILER} --f90flags=\"-fPIC -fpp -stand f08 -diag-disable 5268 -assume byterecl -real-size 64 -integer-size 32 -shared-intel\"") - elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") - set(CORECOMPILER "${CORECOMPILER} --fcompiler=gnu95") - set(CORECOMPILER "${CORECOMPILER} --f90flags=\"-fPIC -fno-range-check -xf95-cpp-input -std=f2008 -fall-intrinsics -fdefault-real-8 -fdefault-double-8\"") - endif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") - # set CORE compiler options - set(CORE_COMPILE_OPTIONS "${COMPILEROPTIONS} -DSpectral -DFLOAT=8 -DINT=4") - set(CORE_COMPILE_OPTIONS "${COMPILEROPTIONS} -I${PROJECT_SOURCE_DIR}/lib") - set(CORE_COMPILE_OPTIONS "${COMPILEROPTIONS} -DDAMASKVERSION=\\\"${DAMASK_V}\\\"") - # set CORE link flags - if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") - set(CORE_LDFLAGS "${CORE_LDFLAGS} -openmp -Wl") - elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") - set(CORE_LDFLAGS "${CORE_LDFLAGS} -shared -Wl,-undefined,dynamic_lookup") - endif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") - - # source file for building core - set(COREFILES "${COREFILES} prec.f90" ) - set(COREFILES "${COREFILES} spectral_interface.f90") - set(COREFILES "${COREFILES} IO.f90" ) - set(COREFILES "${COREFILES} libs.f90" ) - set(COREFILES "${COREFILES} numerics.f90" ) - set(COREFILES "${COREFILES} debug.f90" ) - set(COREFILES "${COREFILES} math.f90" ) - set(COREFILES "${COREFILES} FEsolving.f90" ) - set(COREFILES "${COREFILES} mesh.f90" ) - set(COREFILES "${COREFILES} core_quit.f90" ) - - execute_process(COMMAND F2PY_EXECUTABLE damask.core.pyf ) -endif(DAMASK_PROCESSING) - - - - - - - - - - - - - +endif(SPECTRAL) \ No newline at end of file From 5cbd98edba1ae25635001764e1b09f0d6acd5ecf Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 23 Mar 2016 14:48:37 -0400 Subject: [PATCH 053/183] remove --standard-senmantics flag from ifort to avoid HDF5 linking error --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f76631a61..dcc000b2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,7 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") set (OPTIMIZATION_FLAG "-O2") endif() - set (STANDARD_CHECK "-stand f08 -standard-semantics") + set (STANDARD_CHECK "-stand f08") set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz" ) From 5c5b8ee36a2c76a9d36a684016287619f46fce96 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Fri, 25 Mar 2016 17:27:00 -0400 Subject: [PATCH 054/183] fortran 2003 is the default for DAMASK --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dcc000b2a..f76631a61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,7 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") set (OPTIMIZATION_FLAG "-O2") endif() - set (STANDARD_CHECK "-stand f08") + set (STANDARD_CHECK "-stand f08 -standard-semantics") set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz" ) From 30f4a5a70f48850221f3932659921a585f9681cc Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 13 Apr 2016 08:53:13 -0400 Subject: [PATCH 055/183] get F from crystallite module --- code/constitutive.f90 | 4 +- code/plastic_nonlocal.f90 | 624 ++++++++++++++++++------------------- code/plastic_phenoplus.f90 | 309 ++++++++++-------- 3 files changed, 489 insertions(+), 448 deletions(-) diff --git a/code/constitutive.f90 b/code/constitutive.f90 index 93fb9f577..63ae9a1a5 100644 --- a/code/constitutive.f90 +++ b/code/constitutive.f90 @@ -211,7 +211,7 @@ subroutine constitutive_init() outputName = PLASTICITY_NONE_label thisNoutput => null() thisOutput => null() - thisSize => null() + thisSize => null() case (PLASTICITY_ISOTROPIC_ID) plasticityType outputName = PLASTICITY_ISOTROPIC_label thisNoutput => plastic_isotropic_Noutput @@ -488,7 +488,7 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el) case (PLASTICITY_NONLOCAL_ID) plasticityType call plastic_nonlocal_microstructure (Fe,Fp,ip,el) case (PLASTICITY_PHENOPLUS_ID) plasticityType - call plastic_phenoplus_microstructure(orientations,ipc,ip,el) + call plastic_phenoplus_microstructure(orientations,ipc,ip,el,Fe,Fp) end select plasticityType end subroutine constitutive_microstructure diff --git a/code/plastic_nonlocal.f90 b/code/plastic_nonlocal.f90 index b699c57ed..98e6af226 100644 --- a/code/plastic_nonlocal.f90 +++ b/code/plastic_nonlocal.f90 @@ -8,7 +8,7 @@ module plastic_nonlocal use prec, only: & pReal, & pInt - + implicit none private character(len=22), dimension(11), parameter, private :: & @@ -23,20 +23,20 @@ module plastic_nonlocal 'rhoDipEdge ', & 'rhoDipScrew ', & 'accumulatedshear ' ] !< list of "basic" microstructural state variables that are independent from other state variables - + character(len=16), dimension(3), parameter, private :: & - DEPENDENTSTATES = ['rhoForest ', & - 'tauThreshold ', & + DEPENDENTSTATES = ['rhoForest ', & + 'tauThreshold ', & 'tauBack ' ] !< list of microstructural state variables that depend on other state variables - + character(len=20), dimension(6), parameter, private :: & - OTHERSTATES = ['velocityEdgePos ', & - 'velocityEdgeNeg ', & + OTHERSTATES = ['velocityEdgePos ', & + 'velocityEdgeNeg ', & 'velocityScrewPos ', & 'velocityScrewNeg ', & 'maxDipoleHeightEdge ', & 'maxDipoleHeightScrew' ] !< list of other dependent state variables that are not updated by microstructure - + real(pReal), parameter, private :: & KB = 1.38e-23_pReal !< Physical parameter, Boltzmann constant in J/Kelvin @@ -48,13 +48,13 @@ module plastic_nonlocal integer(pInt), dimension(:,:), allocatable, target, public :: & plastic_nonlocal_sizePostResult !< size of each post result output - + character(len=64), dimension(:,:), allocatable, target, public :: & plastic_nonlocal_output !< name of each post result output - + integer(pInt), dimension(:), allocatable, target, public :: & - plastic_nonlocal_Noutput !< number of outputs per instance of this plasticity - + plastic_nonlocal_Noutput !< number of outputs per instance of this plasticity + integer(pInt), dimension(:,:), allocatable, private :: & iGamma, & !< state indices for accumulated shear iRhoF, & !< state indices for forest density @@ -66,16 +66,16 @@ module plastic_nonlocal iRhoD, & !< state indices for dipole density iV, & !< state indices for dislcation velocities iD !< state indices for stable dipole height - + integer(pInt), dimension(:), allocatable, public, protected :: & totalNslip !< total number of active slip systems for each instance - + integer(pInt), dimension(:,:), allocatable, private :: & Nslip, & !< number of active slip systems for each family and instance slipFamily, & !< lookup table relating active slip system to slip family for each instance slipSystemLattice, & !< lookup table relating active slip system index to lattice slip system index for each instance colinearSystem !< colinear system to the active slip system (only valid for fcc!) - + real(pReal), dimension(:), allocatable, private :: & atomicVolume, & !< atomic volume Dsd0, & !< prefactor for self-diffusion coefficient @@ -102,7 +102,7 @@ module plastic_nonlocal rhoSglRandomBinning, & linetensionEffect, & edgeJogFactor - + real(pReal), dimension(:,:), allocatable, private :: & rhoSglEdgePos0, & !< initial edge_pos dislocation density per slip system for each family and instance rhoSglEdgeNeg0, & !< initial edge_neg dislocation density per slip system for each family and instance @@ -115,40 +115,40 @@ module plastic_nonlocal burgersPerSlipFamily, & !< absolute length of burgers vector [m] for each family and instance burgers, & !< absolute length of burgers vector [m] for each slip system and instance interactionSlipSlip !< coefficients for slip-slip interaction for each interaction type and instance - + real(pReal), dimension(:,:,:), allocatable, private :: & minDipoleHeightPerSlipFamily, & !< minimum stable edge/screw dipole height for each family and instance minDipoleHeight, & !< minimum stable edge/screw dipole height for each slip system and instance - peierlsStressPerSlipFamily, & !< Peierls stress (edge and screw) - peierlsStress, & !< Peierls stress (edge and screw) + peierlsStressPerSlipFamily, & !< Peierls stress (edge and screw) + peierlsStress, & !< Peierls stress (edge and screw) forestProjectionEdge, & !< matrix of forest projections of edge dislocations for each instance forestProjectionScrew, & !< matrix of forest projections of screw dislocations for each instance interactionMatrixSlipSlip !< interaction matrix of the different slip systems for each instance - + real(pReal), dimension(:,:,:,:), allocatable, private :: & lattice2slip, & !< orthogonal transformation matrix from lattice coordinate system to slip coordinate system (passive rotation !!!) rhoDotEdgeJogsOutput, & sourceProbability - + real(pReal), dimension(:,:,:,:,:), allocatable, private :: & - rhoDotFluxOutput, & + rhoDotFluxOutput, & rhoDotMultiplicationOutput, & rhoDotSingle2DipoleGlideOutput, & rhoDotAthermalAnnihilationOutput, & rhoDotThermalAnnihilationOutput, & nonSchmidProjection !< combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) - + real(pReal), dimension(:,:,:,:,:,:), allocatable, private :: & compatibility !< slip system compatibility between me and my neighbors - + real(pReal), dimension(:,:), allocatable, private :: & nonSchmidCoeff - + logical, dimension(:), allocatable, private :: & shortRangeStressCorrection, & !< flag indicating the use of the short range stress correction by a excess density gradient term probabilisticMultiplication - - enum, bind(c) + + enum, bind(c) enumerator :: undefined_ID, & rho_ID, & delta_ID, & @@ -235,9 +235,9 @@ module plastic_nonlocal accumulatedshear_ID, & dislocationstress_ID end enum - integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & + integer(kind(undefined_ID)), dimension(:,:), allocatable, private :: & plastic_nonlocal_outputID !< ID of each post result output - + public :: & plastic_nonlocal_init, & plastic_nonlocal_stateInit, & @@ -248,11 +248,11 @@ module plastic_nonlocal plastic_nonlocal_deltaState, & plastic_nonlocal_updateCompatibility, & plastic_nonlocal_postResults - + private :: & plastic_nonlocal_kinetics, & plastic_nonlocal_dislocationstress - + contains @@ -262,8 +262,8 @@ contains !-------------------------------------------------------------------------------------------------- subroutine plastic_nonlocal_init(fileUnit) use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran 4.6 at the moment) -use math, only: math_Mandel3333to66, & - math_Voigt66to3333, & +use math, only: math_Mandel3333to66, & + math_Voigt66to3333, & math_mul3x3, & math_transpose33 use IO, only: IO_read, & @@ -330,9 +330,9 @@ integer(pInt) :: phase, & integer(pInt) :: sizeState, sizeDotState,sizeDependentState, sizeDeltaState - integer(pInt) :: NofMyPhase - - mainProcess: if (worldrank == 0) then + integer(pInt) :: NofMyPhase + + mainProcess: if (worldrank == 0) then write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_NONLOCAL_label//' init -+>>>' write(6,'(a15,a)') ' Current time: ',IO_timeStamp() #include "compilation_info.f90" @@ -406,11 +406,11 @@ allocate(nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstances), s do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= MATERIAL_partPhase) ! wind forward to line = IO_read(fileUnit) enddo - + parsingFile: do while (trim(line) /= IO_EOF) ! read through phases of phase part line = IO_read(fileUnit) if (IO_isBlank(line)) cycle ! skip empty lines - if (IO_getTag(line,'<','>') /= '') then ! stop at next part + if (IO_getTag(line,'<','>') /= '') then ! stop at next part line = IO_read(fileUnit, .true.) ! reset IO_read exit endif @@ -978,7 +978,7 @@ allocate(nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstances), s sanityChecks: do phase = 1_pInt, size(phase_plasticity) myPhase: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID) then - instance = phase_plasticityInstance(phase) + instance = phase_plasticityInstance(phase) if (sum(Nslip(:,instance)) <= 0_pInt) & call IO_error(211_pInt,ext_msg='Nslip ('//PLASTICITY_NONLOCAL_label//')') do o = 1_pInt,maxval(phase_Noutput) @@ -1065,13 +1065,13 @@ allocate(nonSchmidCoeff(lattice_maxNnonSchmid,maxNinstances), s call IO_error(211_pInt,ext_msg='CFLfactor ('//PLASTICITY_NONLOCAL_label//')') if (fEdgeMultiplication(instance) < 0.0_pReal .or. fEdgeMultiplication(instance) > 1.0_pReal) & call IO_error(211_pInt,ext_msg='edgemultiplicationfactor ('//PLASTICITY_NONLOCAL_label//')') - - + + !*** determine total number of active slip systems Nslip(1:lattice_maxNslipFamily,instance) = min(lattice_NslipSystem(1:lattice_maxNslipFamily,phase), & Nslip(1:lattice_maxNslipFamily,instance) ) ! we can't use more slip systems per family than specified in lattice totalNslip(instance) = sum(Nslip(1:lattice_maxNslipFamily,instance)) - endif myPhase + endif myPhase enddo sanityChecks @@ -1116,13 +1116,13 @@ allocate(compatibility(2,maxTotalNslip,maxTotalNslip,mesh_maxNipNeighbors,mesh_m allocate(peierlsStress(maxTotalNslip,2,maxNinstances), source=0.0_pReal) allocate(colinearSystem(maxTotalNslip,maxNinstances), source=0_pInt) allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), source=0.0_pReal) - + initializeInstances: do phase = 1_pInt, size(phase_plasticity) NofMyPhase=count(material_phase==phase) myPhase2: if (phase_plasticity(phase) == PLASTICITY_NONLOCAL_ID .and. NofMyPhase/=0) then instance = phase_plasticityInstance(phase) !*** Inverse lookup of my slip system family and the slip system in lattice - + l = 0_pInt do f = 1_pInt,lattice_maxNslipFamily do s = 1_pInt,Nslip(f,instance) @@ -1130,10 +1130,10 @@ allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), slipFamily(l,instance) = f slipSystemLattice(l,instance) = sum(lattice_NslipSystem(1:f-1_pInt, phase)) + s enddo; enddo - - + + !*** determine size of state array - + ns = totalNslip(instance) sizeDotState = int(size(BASICSTATES),pInt) * ns @@ -1193,10 +1193,10 @@ allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), enddo if (iD(ns,2,instance) /= sizeState) & ! check if last index is equal to size of state call IO_error(0_pInt, ext_msg = 'state indices not properly set ('//PLASTICITY_NONLOCAL_label//')') - - + + !*** determine size of postResults array - + outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) select case(plastic_nonlocal_outputID(o,instance)) case( rho_ID, & @@ -1287,13 +1287,13 @@ allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), mySize = 6_pInt case default end select - - if (mySize > 0_pInt) then ! any meaningful output found + + if (mySize > 0_pInt) then ! any meaningful output found plastic_nonlocal_sizePostResult(o,instance) = mySize plastic_nonlocal_sizePostResults(instance) = plastic_nonlocal_sizePostResults(instance) + mySize endif enddo outputsLoop - + plasticState(phase)%sizeState = sizeState plasticState(phase)%sizeDotState = sizeDotState plasticState(phase)%sizeDeltaState = sizeDeltaState @@ -1326,63 +1326,63 @@ allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), plasticState(phase)%dotState(iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) plasticState(phase)%accumulatedSlip => & plasticState(phase)%state (iGamma(1,instance):iGamma(ns,instance),1:NofMyPhase) - - do s1 = 1_pInt,ns + + do s1 = 1_pInt,ns f = slipFamily(s1,instance) - + !*** burgers vector, mean free path prefactor and minimum dipole distance for each slip system - + burgers(s1,instance) = burgersPerSlipFamily(f,instance) lambda0(s1,instance) = lambda0PerSlipFamily(f,instance) minDipoleHeight(s1,1:2,instance) = minDipoleHeightPerSlipFamily(f,1:2,instance) peierlsStress(s1,1:2,instance) = peierlsStressPerSlipFamily(f,1:2,instance) - + do s2 = 1_pInt,ns - + !*** calculation of forest projections for edge and screw dislocations. s2 acts as forest for s1 - + forestProjectionEdge(s1,s2,instance) & = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & lattice_st(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of edge dislocations is the projection of (t = b x n) onto the slip normal of the respective slip plane - + forestProjectionScrew(s1,s2,instance) & = abs(math_mul3x3(lattice_sn(1:3,slipSystemLattice(s1,instance),phase), & lattice_sd(1:3,slipSystemLattice(s2,instance),phase))) ! forest projection of screw dislocations is the projection of b onto the slip normal of the respective splip plane - + !*** calculation of interaction matrices - + interactionMatrixSlipSlip(s1,s2,instance) & = interactionSlipSlip(lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & slipSystemLattice(s2,instance), & phase), instance) - + !*** colinear slip system (only makes sense for fcc like it is defined here) - + if (lattice_interactionSlipSlip(slipSystemLattice(s1,instance), & slipSystemLattice(s2,instance), & phase) == 3_pInt) then colinearSystem(s1,instance) = s2 endif - + enddo - + !*** rotation matrix from lattice configuration to slip system - + lattice2slip(1:3,1:3,s1,instance) & = math_transpose33( reshape([ lattice_sd(1:3, slipSystemLattice(s1,instance), phase), & -lattice_st(1:3, slipSystemLattice(s1,instance), phase), & lattice_sn(1:3, slipSystemLattice(s1,instance), phase)], [3,3])) enddo - - + + !*** combined projection of Schmid and non-Schmid contributions to the resolved shear stress (only for screws) - !* four types t: + !* four types t: !* 1) positive screw at positive resolved stress !* 2) positive screw at negative resolved stress !* 3) negative screw at positive resolved stress !* 4) negative screw at negative resolved stress - - do s = 1_pInt,ns + + do s = 1_pInt,ns do l = 1_pInt,lattice_NnonSchmid(phase) nonSchmidProjection(1:3,1:3,1,s,instance) = nonSchmidProjection(1:3,1:3,1,s,instance) & + nonSchmidCoeff(l,instance) * lattice_Sslip(1:3,1:3,2*l,slipSystemLattice(s,instance),phase) @@ -1398,7 +1398,7 @@ allocate(nonSchmidProjection(3,3,4,maxTotalNslip,maxNinstances), call plastic_nonlocal_aTolState(phase,instance) endif myPhase2 - + enddo initializeInstances end subroutine plastic_nonlocal_init @@ -1426,7 +1426,7 @@ implicit none integer(pInt) :: e, & i, & - ns, & ! short notation for total number of active slip systems + ns, & ! short notation for total number of active slip systems f, & ! index of lattice family from, & upto, & @@ -1436,7 +1436,7 @@ integer(pInt) :: e, & instance, & maxNinstances real(pReal), dimension(2) :: noise -real(pReal), dimension(4) :: rnd +real(pReal), dimension(4) :: rnd real(pReal) meanDensity, & totalVolume, & densityBinning, & @@ -1447,7 +1447,7 @@ maxNinstances = int(count(phase_plasticity == PLASTICITY_NONLOCAL_ID),pInt) do instance = 1_pInt,maxNinstances ns = totalNslip(instance) - ! randomly distribute dislocation segments on random slip system and of random type in the volume + ! randomly distribute dislocation segments on random slip system and of random type in the volume if (rhoSglRandom(instance) > 0.0_pReal) then ! get the total volume of the instance @@ -1526,7 +1526,7 @@ subroutine plastic_nonlocal_aTolState(ph,instance) plasticState implicit none - integer(pInt), intent(in) :: & + integer(pInt), intent(in) :: & instance, & !< number specifying the instance of the plasticity ph integer(pInt) :: & @@ -1540,7 +1540,7 @@ subroutine plastic_nonlocal_aTolState(ph,instance) end forall forall (c = 1_pInt:2_pInt) & plasticState(ph)%aTolState(iRhoD(1:ns,c,instance)) = aTolRho(instance) - + plasticState(ph)%aTolState(iGamma(1:ns,instance)) = aTolShear(instance) end subroutine plastic_nonlocal_aTolState @@ -1606,8 +1606,8 @@ real(pReal), dimension(3,3), intent(in) :: & integer(pInt) neighbor_el, & ! element number of neighboring material point neighbor_ip, & ! integration point of neighboring material point - instance, & ! my instance of this plasticity - neighbor_instance, & ! instance of this plasticity of neighboring material point + instance, & ! my instance of this plasticity + neighbor_instance, & ! instance of this plasticity of neighboring material point neighbor_phase, & ns, & ! total number of active slip systems at my material point neighbor_ns, & ! total number of active slip systems at neighboring material point @@ -1678,25 +1678,25 @@ where (abs(rhoDip) * mesh_ipVolume(ip,el) ** 0.667_pReal < significantN(instance forall (s = 1_pInt:ns) & rhoForest(s) = dot_product((sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1)), & - forestProjectionEdge(s,1:ns,instance)) & + forestProjectionEdge(s,1:ns,instance)) & + dot_product((sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2)), & forestProjectionScrew(s,1:ns,instance)) -!*** calculate the threshold shear stress for dislocation slip -!*** coefficients are corrected for the line tension effect +!*** calculate the threshold shear stress for dislocation slip +!*** coefficients are corrected for the line tension effect !*** (see Kubin,Devincre,Hoc; 2008; Modeling dislocation storage rates and mean free paths in face-centered cubic crystals) myInteractionMatrix = 0.0_pReal myInteractionMatrix(1:ns,1:ns) = interactionMatrixSlipSlip(1:ns,1:ns,instance) if (lattice_structure(ph) == LATTICE_bcc_ID .or. lattice_structure(ph) == LATTICE_fcc_ID) then ! only fcc and bcc - do s = 1_pInt,ns + do s = 1_pInt,ns myRhoForest = max(rhoForest(s),significantRho(instance)) correction = ( 1.0_pReal - linetensionEffect(instance) & + linetensionEffect(instance) & * log(0.35_pReal * burgers(s,instance) * sqrt(myRhoForest)) & / log(0.35_pReal * burgers(s,instance) * 1e6_pReal)) ** 2.0_pReal - myInteractionMatrix(s,1:ns) = correction * myInteractionMatrix(s,1:ns) + myInteractionMatrix(s,1:ns) = correction * myInteractionMatrix(s,1:ns) enddo endif forall (s = 1_pInt:ns) & @@ -1715,9 +1715,9 @@ if (.not. phase_localPlasticity(ph) .and. shortRangeStressCorrection(instance)) rhoExcess(1,1:ns) = rhoSgl(1:ns,1) - rhoSgl(1:ns,2) rhoExcess(2,1:ns) = rhoSgl(1:ns,3) - rhoSgl(1:ns,4) FVsize = mesh_ipVolume(ip,el) ** (1.0_pReal/3.0_pReal) - + !* loop through my neighborhood and get the connection vectors (in lattice frame) and the excess densities - + nRealNeighbors = 0_pInt neighbor_rhoTotal = 0.0_pReal do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) @@ -1769,17 +1769,17 @@ if (.not. phase_localPlasticity(ph) .and. shortRangeStressCorrection(instance)) neighbor_rhoExcess(1:2,1:ns,n) = rhoExcess endif enddo - + !* loop through the slip systems and calculate the dislocation gradient by !* 1. interpolation of the excess density in the neighorhood !* 2. interpolation of the dead dislocation density in the central volume - + m(1:3,1:ns,1) = lattice_sd(1:3,slipSystemLattice(1:ns,instance),ph) m(1:3,1:ns,2) = -lattice_st(1:3,slipSystemLattice(1:ns,instance),ph) do s = 1_pInt,ns - + !* gradient from interpolation of neighboring excess density do c = 1_pInt,2_pInt @@ -1797,23 +1797,23 @@ if (.not. phase_localPlasticity(ph) .and. shortRangeStressCorrection(instance)) rhoExcessGradient(c) = math_mul3x3(m(1:3,s,c), & math_mul33x3(invConnections,rhoExcessDifferences)) enddo - + !* plus gradient from deads - + do t = 1_pInt,4_pInt c = (t - 1_pInt) / 2_pInt + 1_pInt rhoExcessGradient(c) = rhoExcessGradient(c) + rhoSgl(s,t+4_pInt) / FVsize enddo !* normalized with the total density - + rhoExcessGradient_over_rho = 0.0_pReal forall (c = 1_pInt:2_pInt) & rhoTotal(c) = (sum(abs(rhoSgl(s,[2*c-1,2*c,2*c+3,2*c+4]))) + rhoDip(s,c) & + sum(neighbor_rhoTotal(c,s,:))) / real(1_pInt + nRealNeighbors,pReal) forall (c = 1_pInt:2_pInt, rhoTotal(c) > 0.0_pReal) & rhoExcessGradient_over_rho(c) = rhoExcessGradient(c) / rhoTotal(c) - + !* gives the local stress correction when multiplied with a factor tauBack(s) = - lattice_mu(ph) * burgers(s,instance) / (2.0_pReal * pi) & @@ -1844,7 +1844,7 @@ end subroutine plastic_nonlocal_microstructure !-------------------------------------------------------------------------------------------------- -!> @brief calculates kinetics +!> @brief calculates kinetics !-------------------------------------------------------------------------------------------------- subroutine plastic_nonlocal_kinetics(v, dv_dtau, dv_dtauNS, tau, tauNS, & tauThreshold, c, Temperature, ip, el) @@ -1880,7 +1880,7 @@ real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt integer(pInt) :: instance, & !< current instance of this plasticity ns, & !< short notation for the total number of active slip systems s !< index of my current slip system -real(pReal) tauRel_P, & +real(pReal) tauRel_P, & tauRel_S, & tauEff, & !< effective shear stress tPeierls, & !< waiting time in front of a peierls barriers @@ -1918,7 +1918,7 @@ if (Temperature > 0.0_pReal) then !* Peierls contribution !* Effective stress includes non Schmid constributions !* The derivative only gives absolute values; the correct sign is taken care of in the formula for the derivative of the velocity - + tauEff = max(0.0_pReal, abs(tauNS(s)) - tauThreshold(s)) ! ensure that the effective stress is positive meanfreepath_P = burgers(s,instance) jumpWidth_P = burgers(s,instance) @@ -1933,7 +1933,7 @@ if (Temperature > 0.0_pReal) then if (tauEff < criticalStress_P) then dtPeierls_dtau = tPeierls * pParam(instance) * qParam(instance) * activationVolume_P / (KB * Temperature) & * (1.0_pReal - tauRel_P**pParam(instance))**(qParam(instance)-1.0_pReal) & - * tauRel_P**(pParam(instance)-1.0_pReal) + * tauRel_P**(pParam(instance)-1.0_pReal) else dtPeierls_dtau = 0.0_pReal endif @@ -1957,32 +1957,32 @@ if (Temperature > 0.0_pReal) then dtSolidSolution_dtau = tSolidSolution * pParam(instance) * qParam(instance) & * activationVolume_S / (KB * Temperature) & * (1.0_pReal - tauRel_S**pParam(instance))**(qParam(instance)-1.0_pReal) & - * tauRel_S**(pParam(instance)-1.0_pReal) + * tauRel_S**(pParam(instance)-1.0_pReal) else dtSolidSolution_dtau = 0.0_pReal endif !* viscous glide velocity - + tauEff = abs(tau(s)) - tauThreshold(s) mobility = burgers(s,instance) / viscosity(instance) vViscous = mobility * tauEff - !* Mean velocity results from waiting time at peierls barriers and solid solution obstacles with respective meanfreepath of - !* free flight at glide velocity in between. + !* Mean velocity results from waiting time at peierls barriers and solid solution obstacles with respective meanfreepath of + !* free flight at glide velocity in between. !* adopt sign from resolved stress v(s) = sign(1.0_pReal,tau(s)) & / (tPeierls / meanfreepath_P + tSolidSolution / meanfreepath_S + 1.0_pReal / vViscous) dv_dtau(s) = v(s) * v(s) * (dtSolidSolution_dtau / meanfreepath_S & + mobility / (vViscous * vViscous)) - dv_dtauNS(s) = v(s) * v(s) * dtPeierls_dtau / meanfreepath_P + dv_dtauNS(s) = v(s) * v(s) * dtPeierls_dtau / meanfreepath_P endif enddo endif - + #ifndef _OPENMP if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt & @@ -2051,7 +2051,7 @@ integer(pInt) instance, & sLattice !< index of my current slip system according to lattice order real(pReal), dimension(3,3,3,3) :: dLp_dTstar3333 !< derivative of Lp with respect to Tstar (3x3x3x3 matrix) real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),8) :: & - rhoSgl !< single dislocation densities (including blocked) + rhoSgl !< single dislocation densities (including blocked) real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & v, & !< velocity tauNS, & !< resolved shear stress including non Schmid and backstress terms @@ -2075,7 +2075,7 @@ instance = phase_plasticityInstance(ph) ns = totalNslip(instance) -!*** shortcut to state variables +!*** shortcut to state variables forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) @@ -2114,7 +2114,7 @@ tau = tau + tauBack !*** get dislocation velocity and its tangent and store the velocity in the state array -! edges +! edges call plastic_nonlocal_kinetics(v(1:ns,1), dv_dtau(1:ns,1), dv_dtauNS(1:ns,1), & tau(1:ns), tauNS(1:ns,1), tauThreshold(1:ns), & 1_pInt, Temperature, ip, el) @@ -2153,7 +2153,7 @@ forall (s = 1_pInt:ns, t = 5_pInt:8_pInt, rhoSgl(s,t) * v(s,t-4_pInt) < 0.0_pRea gdotTotal = sum(rhoSgl(1:ns,1:4) * v, 2) * burgers(1:ns,instance) do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) + sLattice = slipSystemLattice(s,instance) Lp = Lp + gdotTotal(s) * lattice_Sslip(1:3,1:3,1,sLattice,ph) ! Schmid contributions to tangent @@ -2167,14 +2167,14 @@ do s = 1_pInt,ns forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + lattice_Sslip(i,j,1,sLattice,ph) & - * ( nonSchmidProjection(k,l,1,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & + * ( nonSchmidProjection(k,l,1,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & + nonSchmidProjection(k,l,3,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & * burgers(s,instance) else forall (i=1_pInt:3_pInt,j=1_pInt:3_pInt,k=1_pInt:3_pInt,l=1_pInt:3_pInt) & dLp_dTstar3333(i,j,k,l) = dLp_dTstar3333(i,j,k,l) & + lattice_Sslip(i,j,1,sLattice,ph) & - * ( nonSchmidProjection(k,l,2,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & + * ( nonSchmidProjection(k,l,2,s,instance) * rhoSgl(s,3) * dv_dtauNS(s,3) & + nonSchmidProjection(k,l,4,s,instance) * rhoSgl(s,4) * dv_dtauNS(s,4) ) & * burgers(s,instance) endif @@ -2265,7 +2265,7 @@ real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1,ip,e ns = totalNslip(instance) -!*** shortcut to state variables +!*** shortcut to state variables forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) rhoSgl(s,t) = max(plasticState(ph)%state(iRhoU(s,t,instance),of), 0.0_pReal) ! ensure positive single mobile densities @@ -2311,7 +2311,7 @@ enddo !*** calculate limits for stable dipole height do s = 1_pInt,ns - sLattice = slipSystemLattice(s,instance) + sLattice = slipSystemLattice(s,instance) tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal enddo @@ -2324,7 +2324,7 @@ dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) / (4.0_pReal * pi * abs forall (c = 1_pInt:2_pInt) where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & dUpper(1:ns,c)) end forall @@ -2347,7 +2347,7 @@ forall (t=1_pInt:4_pInt) & !*** store new maximum dipole height in state forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - plasticState(ph)%state(iD(s,c,instance),of) = dUpper(s,c) + plasticState(ph)%state(iD(s,c,instance),of) = dUpper(s,c) @@ -2400,7 +2400,7 @@ use math, only: math_mul6x6, & math_mul33x33, & math_inv33, & math_det33, & - math_transpose33, & + math_transpose33, & pi use mesh, only: mesh_NcpElems, & mesh_maxNips, & @@ -2426,7 +2426,7 @@ use lattice, only: lattice_Sslip_v, & lattice_mu, & lattice_nu, & lattice_structure, & - LATTICE_bcc_ID, & + LATTICE_bcc_ID, & LATTICE_fcc_ID implicit none @@ -2438,14 +2438,14 @@ real(pReal), intent(in) :: Temperature, & timestep !< substepped crystallite time increment real(pReal), dimension(6), intent(in) :: Tstar_v !< current 2nd Piola-Kirchhoff stress in Mandel notation real(pReal), dimension(homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - subfrac !< fraction of timestep at the beginning of the substepped crystallite time increment + subfrac !< fraction of timestep at the beginning of the substepped crystallite time increment real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & Fe, & !< elastic deformation gradient Fp !< plastic deformation gradient - + !*** local variables -integer(pInt) :: ph, & +integer(pInt) :: ph, & instance, & !< current instance of this plasticity neighbor_instance, & !< instance of my neighbor's plasticity ns, & !< short notation for the total number of active slip systems @@ -2494,7 +2494,7 @@ real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt nSources real(pReal), dimension(totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),2) :: & rhoDip, & !< current dipole dislocation densities (screw and edge dipoles) - rhoDipOriginal, & + rhoDipOriginal, & dLower, & !< minimum stable dipole distance for edges and screws dUpper !< current maximum stable dipole distance for edges and screws real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1_pInt,ip,el))),4) :: & @@ -2512,11 +2512,11 @@ real(pReal) area, & transmissivity, & !< overall transmissivity of dislocation flux to neighboring material point lineLength, & !< dislocation line length leaving the current interface selfDiffusion, & !< self diffusion - rnd, & + rnd, & meshlength logical considerEnteringFlux, & considerLeavingFlux - + p = phaseAt(1,ip,el) o = phasememberAt(1,ip,el) @@ -2538,7 +2538,7 @@ tau = 0.0_pReal gdot = 0.0_pReal -!*** shortcut to state variables +!*** shortcut to state variables forall (s = 1_pInt:ns, t = 1_pInt:4_pInt) @@ -2572,7 +2572,7 @@ if (numerics_timeSyncing) then .or. abs(rhoSgl0) < significantRho(instance)) & rhoSgl0 = 0.0_pReal endif - + !*** sanity check for timestep @@ -2605,7 +2605,7 @@ forall (t = 1_pInt:4_pInt) & !*** calculate limits for stable dipole height do s = 1_pInt,ns ! loop over slip systems - sLattice = slipSystemLattice(s,instance) + sLattice = slipSystemLattice(s,instance) tau(s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) + tauBack(s) if (abs(tau(s)) < 1.0e-15_pReal) tau(s) = 1.0e-15_pReal enddo @@ -2618,7 +2618,7 @@ dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & forall (c = 1_pInt:2_pInt) where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & dUpper(1:ns,c)) end forall @@ -2692,7 +2692,7 @@ if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then .and. CFLfactor(instance) * abs(v) * timestep & > mesh_ipVolume(ip,el) / maxval(mesh_ipArea(:,ip,el)))) then ! ...with velocity above critical value (we use the reference volume and area for simplicity here) #ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then write(6,'(a,i5,a,i2)') '<< CONST >> CFL condition not fullfilled at el ',el,' ip ',ip write(6,'(a,e10.3,a,e10.3)') '<< CONST >> velocity is at ', & maxval(abs(v), abs(gdot) > 0.0_pReal & @@ -2709,15 +2709,15 @@ if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then !*** be aware of the definition of lattice_st = lattice_sd x lattice_sn !!! !*** opposite sign to our p vector in the (s,p,n) triplet !!! - + m(1:3,1:ns,1) = lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) m(1:3,1:ns,2) = -lattice_sd(1:3, slipSystemLattice(1:ns,instance), ph) m(1:3,1:ns,3) = -lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) m(1:3,1:ns,4) = lattice_st(1:3, slipSystemLattice(1:ns,instance), ph) - + my_Fe = Fe(1:3,1:3,1_pInt,ip,el) my_F = math_mul33x33(my_Fe, Fp(1:3,1:3,1_pInt,ip,el)) - + do n = 1_pInt,FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) ! loop through my neighbors ! write(6,*) 'c' neighbor_el = mesh_ipNeighborhood(1,n,ip,el) @@ -2730,7 +2730,7 @@ if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then opposite_el = mesh_ipNeighborhood(1,opposite_neighbor,ip,el) opposite_ip = mesh_ipNeighborhood(2,opposite_neighbor,ip,el) opposite_n = mesh_ipNeighborhood(3,opposite_neighbor,ip,el) - + if (neighbor_n > 0_pInt) then ! if neighbor exists, average deformation gradient neighbor_instance = phase_plasticityInstance(material_phase(1_pInt,neighbor_ip,neighbor_el)) neighbor_Fe = Fe(1:3,1:3,1_pInt,neighbor_ip,neighbor_el) @@ -2739,26 +2739,26 @@ if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then else ! if no neighbor, take my value as average Favg = my_F endif - + !* FLUX FROM MY NEIGHBOR TO ME - !* This is only considered, if I have a neighbor of nonlocal plasticity - !* (also nonlocal constitutive law with local properties) that is at least a little bit + !* This is only considered, if I have a neighbor of nonlocal plasticity + !* (also nonlocal constitutive law with local properties) that is at least a little bit !* compatible. !* If it's not at all compatible, no flux is arriving, because everything is dammed in front of !* my neighbor's interface. - !* The entering flux from my neighbor will be distributed on my slip systems according to the + !* The entering flux from my neighbor will be distributed on my slip systems according to the !*compatibility - + considerEnteringFlux = .false. - neighbor_v = 0.0_pReal ! needed for check of sign change in flux density below + neighbor_v = 0.0_pReal ! needed for check of sign change in flux density below neighbor_rhoSgl = 0.0_pReal if (neighbor_n > 0_pInt) then if (phase_plasticity(material_phase(1,neighbor_ip,neighbor_el)) == PLASTICITY_NONLOCAL_ID & .and. any(compatibility(:,:,:,n,ip,el) > 0.0_pReal)) & considerEnteringFlux = .true. endif - + if (considerEnteringFlux) then if(numerics_timeSyncing .and. (subfrac(1_pInt,neighbor_ip,neighbor_el) /= subfrac(1_pInt,ip,el))) & then ! for timesyncing: in case of a timestep at the interface we have to use "state0" to make sure that fluxes n both sides are equal @@ -2790,7 +2790,7 @@ if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then c = (t + 1_pInt) / 2 topp = t + mod(t,2_pInt) - mod(t+1_pInt,2_pInt) if (neighbor_v(s,t) * math_mul3x3(m(1:3,s,t), normal_neighbor2me) > 0.0_pReal & ! flux from my neighbor to me == entering flux for me - .and. v(s,t) * neighbor_v(s,t) >= 0.0_pReal ) then ! ... only if no sign change in flux density + .and. v(s,t) * neighbor_v(s,t) >= 0.0_pReal ) then ! ... only if no sign change in flux density lineLength = neighbor_rhoSgl(s,t) * neighbor_v(s,t) & * math_mul3x3(m(1:3,s,t), normal_neighbor2me) * area ! positive line length that wants to enter through this interface where (compatibility(c,1_pInt:ns,s,n,ip,el) > 0.0_pReal) & ! positive compatibility... @@ -2805,16 +2805,16 @@ if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then enddo enddo endif - - + + !* FLUX FROM ME TO MY NEIGHBOR - !* This is not considered, if my opposite neighbor has a different constitutive law than nonlocal (still considered for nonlocal law with lcal properties). + !* This is not considered, if my opposite neighbor has a different constitutive law than nonlocal (still considered for nonlocal law with lcal properties). !* Then, we assume, that the opposite(!) neighbor sends an equal amount of dislocations to me. !* So the net flux in the direction of my neighbor is equal to zero: !* leaving flux to neighbor == entering flux from opposite neighbor !* In case of reduced transmissivity, part of the leaving flux is stored as dead dislocation density. !* That means for an interface of zero transmissivity the leaving flux is fully converted to dead dislocations. - + considerLeavingFlux = .true. if (opposite_n > 0_pInt) then if (phase_plasticity(material_phase(1,opposite_ip,opposite_el)) /= PLASTICITY_NONLOCAL_ID) & @@ -2822,10 +2822,10 @@ if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then endif if (considerLeavingFlux) then - - !* timeSyncing mode: If the central ip has zero subfraction, always use "state0". This is needed in case of + + !* timeSyncing mode: If the central ip has zero subfraction, always use "state0". This is needed in case of !* a synchronization step for the central ip, because then "state" contains the values at the end of the - !* previously converged full time step. Also, if either me or my neighbor has zero subfraction, we have to + !* previously converged full time step. Also, if either me or my neighbor has zero subfraction, we have to !* use "state0" to make sure that fluxes on both sides of the (potential) timestep are equal. my_rhoSgl = rhoSgl my_v = v @@ -2840,14 +2840,14 @@ if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then endif endif endif - + normal_me2neighbor_defConf = math_det33(Favg) & - * math_mul33x3(math_inv33(math_transpose33(Favg)), & + * math_mul33x3(math_inv33(math_transpose33(Favg)), & mesh_ipAreaNormal(1:3,n,ip,el)) ! calculate the normal of the interface in (average) deformed configuration (pointing from me to my neighbor!!!) normal_me2neighbor = math_mul33x3(math_transpose33(my_Fe), normal_me2neighbor_defConf) & / math_det33(my_Fe) ! interface normal in my lattice configuration area = mesh_ipArea(n,ip,el) * norm2(normal_me2neighbor) - normal_me2neighbor = normal_me2neighbor / norm2(normal_me2neighbor) ! normalize the surface normal to unit length + normal_me2neighbor = normal_me2neighbor / norm2(normal_me2neighbor) ! normalize the surface normal to unit length do s = 1_pInt,ns do t = 1_pInt,4_pInt c = (t + 1_pInt) / 2_pInt @@ -2866,9 +2866,9 @@ if (.not. phase_localPlasticity(material_phase(1_pInt,ip,el))) then endif enddo enddo - endif - - enddo ! neighbor loop + endif + + enddo ! neighbor loop endif @@ -2906,7 +2906,7 @@ enddo rhoDotAthermalAnnihilation = 0.0_pReal -forall (c=1_pInt:2_pInt) & +forall (c=1_pInt:2_pInt) & rhoDotAthermalAnnihilation(1:ns,c+8_pInt) = -2.0_pReal * dLower(1:ns,c) / burgers(1:ns,instance) & * ( 2.0_pReal * (rhoSgl(1:ns,2*c-1) * abs(gdot(1:ns,2*c)) + rhoSgl(1:ns,2*c) * abs(gdot(1:ns,2*c-1))) & ! was single hitting single + 2.0_pReal * (abs(rhoSgl(1:ns,2*c+3)) * abs(gdot(1:ns,2*c)) + abs(rhoSgl(1:ns,2*c+4)) * abs(gdot(1:ns,2*c-1))) & ! was single hitting immobile single or was immobile single hit by single @@ -2917,8 +2917,8 @@ if (lattice_structure(ph) == LATTICE_fcc_ID) & ! only fcc rhoDotAthermalAnnihilation(colinearSystem(s,instance),1:2) = - rhoDotAthermalAnnihilation(s,10) & * 0.25_pReal * sqrt(rhoForest(s)) * (dUpper(s,2) + dLower(s,2)) * edgeJogFactor(instance) - - + + !*** thermally activated annihilation of edge dipoles by climb rhoDotThermalAnnihilation = 0.0_pReal @@ -2942,7 +2942,7 @@ rhoDot = rhoDotFlux & + rhoDotMultiplication & + rhoDotSingle2DipoleGlide & + rhoDotAthermalAnnihilation & - + rhoDotThermalAnnihilation + + rhoDotThermalAnnihilation if (numerics_integrationMode == 1_pInt) then ! save rates for output if in central integration mode rhoDotFluxOutput(1:ns,1:8,1_pInt,ip,el) = rhoDotFlux(1:ns,1:8) @@ -2981,7 +2981,7 @@ endif if ( any(rhoSglOriginal(1:ns,1:4) + rhoDot(1:ns,1:4) * timestep < -aTolRho(instance)) & .or. any(rhoDipOriginal(1:ns,1:2) + rhoDot(1:ns,9:10) * timestep < -aTolRho(instance))) then #ifndef _OPENMP - if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then + if (iand(debug_level(debug_constitutive),debug_levelExtensive) /= 0_pInt) then write(6,'(a,i5,a,i2)') '<< CONST >> evolution rate leads to negative density at el ',el,' ip ',ip write(6,'(a)') '<< CONST >> enforcing cutback !!!' endif @@ -2989,7 +2989,7 @@ if ( any(rhoSglOriginal(1:ns,1:4) + rhoDot(1:ns,1:4) * timestep < -aTolRho(in plasticState(p)%dotState = DAMASK_NaN return else - forall (s = 1:ns, t = 1_pInt:4_pInt) + forall (s = 1:ns, t = 1_pInt:4_pInt) plasticState(p)%dotState(iRhoU(s,t,instance),o) = rhoDot(s,t) plasticState(p)%dotState(iRhoB(s,t,instance),o) = rhoDot(s,t+4_pInt) endforall @@ -3037,10 +3037,10 @@ integer(pInt), intent(in) :: i, & e ! element index real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & orientation ! crystal orientation in quaternions - + !* local variables integer(pInt) Nneighbors, & ! number of neighbors - n, & ! neighbor index + n, & ! neighbor index neighbor_e, & ! element index of my neighbor neighbor_i, & ! integration point index of my neighbor ph, & @@ -3054,15 +3054,15 @@ integer(pInt) Nneighbors, & real(pReal), dimension(4) :: absoluteMisorientation ! absolute misorientation (without symmetry) between me and my neighbor real(pReal), dimension(2,totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& totalNslip(phase_plasticityInstance(material_phase(1,i,e))),& - FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e))))) :: & + FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,e))))) :: & my_compatibility ! my_compatibility for current element and ip -real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & +real(pReal), dimension(3,totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & slipNormal, & slipDirection real(pReal) my_compatibilitySum, & thresholdValue, & nThresholdValues -logical, dimension(totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & +logical, dimension(totalNslip(phase_plasticityInstance(material_phase(1,i,e)))) :: & belowThreshold @@ -3087,24 +3087,24 @@ forall(s1 = 1_pInt:ns) & do n = 1_pInt,Nneighbors neighbor_e = mesh_ipNeighborhood(1,n,i,e) neighbor_i = mesh_ipNeighborhood(2,n,i,e) - - + + !* FREE SURFACE !* Set surface transmissivity to the value specified in the material.config - + if (neighbor_e <= 0_pInt .or. neighbor_i <= 0_pInt) then forall(s1 = 1_pInt:ns) & my_compatibility(1:2,s1,s1,n) = sqrt(surfaceTransmissivity(instance)) cycle endif - - + + !* PHASE BOUNDARY - !* If we encounter a different nonlocal "cpfem" phase at the neighbor, + !* If we encounter a different nonlocal "cpfem" phase at the neighbor, !* we consider this to be a real "physical" phase boundary, so completely incompatible. - !* If one of the two "CPFEM" phases has a local plasticity law, + !* If one of the two "CPFEM" phases has a local plasticity law, !* we do not consider this to be a phase boundary, so completely compatible. - + neighbor_phase = material_phase(1,neighbor_i,neighbor_e) if (neighbor_phase /= ph) then if (.not. phase_localPlasticity(neighbor_phase) .and. .not. phase_localPlasticity(ph)) then @@ -3114,7 +3114,7 @@ do n = 1_pInt,Nneighbors cycle endif - + !* GRAIN BOUNDARY ! !* fixed transmissivity for adjacent ips with different texture (only if explicitly given in material.config) @@ -3127,16 +3127,16 @@ do n = 1_pInt,Nneighbors endif cycle endif - + !* GRAIN BOUNDARY ? !* Compatibility defined by relative orientation of slip systems: !* The my_compatibility value is defined as the product of the slip normal projection and the slip direction projection. - !* Its sign is always positive for screws, for edges it has the same sign as the slip normal projection. - !* Since the sum for each slip system can easily exceed one (which would result in a transmissivity larger than one), + !* Its sign is always positive for screws, for edges it has the same sign as the slip normal projection. + !* Since the sum for each slip system can easily exceed one (which would result in a transmissivity larger than one), !* only values above or equal to a certain threshold value are considered. This threshold value is chosen, such that - !* the number of compatible slip systems is minimized with the sum of the original my_compatibility values exceeding one. - !* Finally the smallest my_compatibility value is decreased until the sum is exactly equal to one. + !* the number of compatible slip systems is minimized with the sum of the original my_compatibility values exceeding one. + !* Finally the smallest my_compatibility value is decreased until the sum is exactly equal to one. !* All values below the threshold are set to zero. else absoluteMisorientation = lattice_qDisorientation(orientation(1:4,1,i,e), & @@ -3148,7 +3148,7 @@ do n = 1_pInt,Nneighbors my_compatibility(2,s2,s1,n) = abs(math_mul3x3(slipNormal(1:3,s1), math_qRot(absoluteMisorientation, slipNormal(1:3,s2)))) & * abs(math_mul3x3(slipDirection(1:3,s1), math_qRot(absoluteMisorientation, slipDirection(1:3,s2)))) enddo - + my_compatibilitySum = 0.0_pReal belowThreshold = .true. do while (my_compatibilitySum < 1.0_pReal .and. any(belowThreshold(1:ns))) @@ -3284,7 +3284,7 @@ if (.not. phase_localPlasticity(ph)) then invFe = math_inv33(Fe(1:3,1:3,1_pInt,ip,el)) !* in case of periodic surfaces we have to find out how many periodic images in each direction we need - + do dir = 1_pInt,3_pInt maxCoord(dir) = maxval(mesh_node0(dir,:)) minCoord(dir) = minval(mesh_node0(dir,:)) @@ -3299,10 +3299,10 @@ if (.not. phase_localPlasticity(ph)) then endif enddo - - !* loop through all material points (also through their periodic images if present), + + !* loop through all material points (also through their periodic images if present), !* but only consider nonlocal neighbors within a certain cutoff radius R - + do neighbor_el = 1_pInt,mesh_NcpElems ipLoop: do neighbor_ip = 1_pInt,FE_Nips(FE_geomtype(mesh_element(2,neighbor_el))) neighbor_phase = material_phase(1_pInt,neighbor_ip,neighbor_el) @@ -3314,7 +3314,7 @@ if (.not. phase_localPlasticity(ph)) then neighbor_ns = totalNslip(neighbor_instance) neighbor_invFe = math_inv33(Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) neighbor_ipVolumeSideLength = mesh_ipVolume(neighbor_ip,neighbor_el) ** (1.0_pReal/3.0_pReal) ! reference volume used here - + forall (s = 1_pInt:neighbor_ns, c = 1_pInt:2_pInt) neighbor_rhoExcess(c,1,s) = plasticState(np)%state(iRhoU(s,2*c-1,neighbor_instance),no) & ! positive mobiles - plasticState(np)%state(iRhoU(s,2*c,neighbor_instance),no) ! negative mobiles @@ -3326,43 +3326,43 @@ if (.not. phase_localPlasticity(ph)) then do deltaX = periodicImages(1,1),periodicImages(2,1) do deltaY = periodicImages(1,2),periodicImages(2,2) do deltaZ = periodicImages(1,3),periodicImages(2,3) - - + + !* regular case - + if (neighbor_el /= el .or. neighbor_ip /= ip & .or. deltaX /= 0_pInt .or. deltaY /= 0_pInt .or. deltaZ /= 0_pInt) then - + neighbor_coords = mesh_cellCenterCoordinates(neighbor_ip,neighbor_el) & + [real(deltaX,pReal), real(deltaY,pReal), real(deltaZ,pReal)] * meshSize connection = neighbor_coords - coords distance = sqrt(sum(connection * connection)) if (distance > cutoffRadius(instance)) cycle - + !* the segment length is the minimum of the third root of the control volume and the ip distance !* this ensures, that the central MP never sits on a neighbor dislocation segment - + connection_neighborLattice = math_mul33x3(neighbor_invFe, connection) segmentLength = min(neighbor_ipVolumeSideLength, distance) - + !* loop through all slip systems of the neighbor material point !* and add up the stress contributions from egde and screw excess on these slip systems (if significant) - + do s = 1_pInt,neighbor_ns if (all(abs(neighbor_rhoExcess(:,:,s)) < significantRho(instance))) cycle ! not significant - - + + !* map the connection vector from the lattice into the slip system frame - + connection_neighborSlip = math_mul33x3(lattice2slip(1:3,1:3,s,neighbor_instance), & connection_neighborLattice) - - + + !* edge contribution to stress sigma = 0.0_pReal - + x = connection_neighborSlip(1) y = connection_neighborSlip(2) z = connection_neighborSlip(3) @@ -3372,7 +3372,7 @@ if (.not. phase_localPlasticity(ph)) then do j = 1_pInt,2_pInt if (abs(neighbor_rhoExcess(1,j,s)) < significantRho(instance)) then - cycle + cycle elseif (j > 1_pInt) then x = connection_neighborSlip(1) & + sign(0.5_pReal * segmentLength, & @@ -3381,16 +3381,16 @@ if (.not. phase_localPlasticity(ph)) then xsquare = x * x endif - + flipSign = sign(1.0_pReal, -y) do side = 1_pInt,-1_pInt,-2_pInt lambda = real(side,pReal) * 0.5_pReal * segmentLength - y R = sqrt(xsquare + zsquare + lambda * lambda) Rsquare = R * R - Rcube = Rsquare * R + Rcube = Rsquare * R denominator = R * (R + flipSign * lambda) if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop - + sigma(1,1) = sigma(1,1) - real(side,pReal) & * flipSign * z / denominator & * (1.0_pReal + xsquare / Rsquare + xsquare / denominator) & @@ -3411,14 +3411,14 @@ if (.not. phase_localPlasticity(ph)) then sigma(2,3) = sigma(2,3) - real(side,pReal) & * (lattice_nu(ph) / R - zsquare / Rcube) * neighbor_rhoExcess(1,j,s) enddo - enddo - + enddo + !* screw contribution to stress - + x = connection_neighborSlip(1) ! have to restore this value, because position might have been adapted for edge deads before do j = 1_pInt,2_pInt if (abs(neighbor_rhoExcess(2,j,s)) < significantRho(instance)) then - cycle + cycle elseif (j > 1_pInt) then y = connection_neighborSlip(2) & + sign(0.5_pReal * segmentLength, & @@ -3432,10 +3432,10 @@ if (.not. phase_localPlasticity(ph)) then lambda = x + real(side,pReal) * 0.5_pReal * segmentLength R = sqrt(ysquare + zsquare + lambda * lambda) Rsquare = R * R - Rcube = Rsquare * R + Rcube = Rsquare * R denominator = R * (R + flipSign * lambda) if (abs(denominator)<= tiny(0.0_pReal)) exit ipLoop - + sigma(1,2) = sigma(1,2) - real(side,pReal) * flipSign * z & * (1.0_pReal - lattice_nu(ph)) / denominator & * neighbor_rhoExcess(2,j,s) @@ -3444,25 +3444,25 @@ if (.not. phase_localPlasticity(ph)) then * neighbor_rhoExcess(2,j,s) enddo enddo - + if (all(abs(sigma) < 1.0e-10_pReal)) cycle ! SIGMA IS NOT A REAL STRESS, THATS WHY WE NEED A REALLY SMALL VALUE HERE !* copy symmetric parts - + sigma(2,1) = sigma(1,2) sigma(3,1) = sigma(1,3) sigma(3,2) = sigma(2,3) - + !* scale stresses and map them into the neighbor material point's lattice configuration - + sigma = sigma * lattice_mu(neighbor_phase) * burgers(s,neighbor_instance) & / (4.0_pReal * pi * (1.0_pReal - lattice_nu(neighbor_phase))) & * mesh_ipVolume(neighbor_ip,neighbor_el) / segmentLength ! reference volume is used here (according to the segment length calculation) Tdislo_neighborLattice = Tdislo_neighborLattice & + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,neighbor_instance)), & math_mul33x33(sigma, lattice2slip(1:3,1:3,s,neighbor_instance))) - + enddo ! slip system loop @@ -3470,16 +3470,16 @@ if (.not. phase_localPlasticity(ph)) then !* only consider dead dislocations !* we assume that they all sit at a distance equal to half the third root of V !* in direction of the according slip direction - + else - + forall (s = 1_pInt:ns, c = 1_pInt:2_pInt) & - rhoExcessDead(c,s) = plasticState(p)%state(iRhoB(s,2*c-1,instance),o) & ! positive deads (here we use symmetry: if this has negative sign it is - !treated as negative density at positive position instead of positive + rhoExcessDead(c,s) = plasticState(p)%state(iRhoB(s,2*c-1,instance),o) & ! positive deads (here we use symmetry: if this has negative sign it is + !treated as negative density at positive position instead of positive !density at negative position) - + plasticState(p)%state(iRhoB(s,2*c,instance),o) ! negative deads (here we use symmetry: if this has negative sign it is - !treated as positive density at positive position instead of negative + + plasticState(p)%state(iRhoB(s,2*c,instance),o) ! negative deads (here we use symmetry: if this has negative sign it is + !treated as positive density at positive position instead of negative !density at negative position) do s = 1_pInt,ns if (all(abs(rhoExcessDead(:,s)) < significantRho(instance))) cycle ! not significant @@ -3488,11 +3488,11 @@ if (.not. phase_localPlasticity(ph)) then * neighbor_ipVolumeSideLength * lattice_mu(ph) * burgers(s,instance) & / (sqrt(2.0_pReal) * pi * (1.0_pReal - lattice_nu(ph))) sigma(3,1) = sigma(1,3) - + Tdislo_neighborLattice = Tdislo_neighborLattice & + math_mul33x33(math_transpose33(lattice2slip(1:3,1:3,s,instance)), & math_mul33x33(sigma, lattice2slip(1:3,1:3,s,instance))) - + enddo ! slip system loop endif @@ -3502,7 +3502,7 @@ if (.not. phase_localPlasticity(ph)) then enddo ! deltaX loop - !* map the stress from the neighbor MP's lattice configuration into the deformed configuration + !* map the stress from the neighbor MP's lattice configuration into the deformed configuration !* and back into my lattice configuration neighborLattice2myLattice = math_mul33x33(invFe, Fe(1:3,1:3,1,neighbor_ip,neighbor_el)) @@ -3510,15 +3510,15 @@ if (.not. phase_localPlasticity(ph)) then + math_mul33x33(neighborLattice2myLattice, & math_mul33x33(Tdislo_neighborLattice, & math_transpose33(neighborLattice2myLattice))) - + enddo ipLoop enddo ! element loop - + endif end function plastic_nonlocal_dislocationstress - + !-------------------------------------------------------------------------------------------------- !> @brief return array of constitutive results !-------------------------------------------------------------------------------------------------- @@ -3553,11 +3553,11 @@ function plastic_nonlocal_postResults(Tstar_v,Fe,ip,el) integer(pInt), intent(in) :: & ip, & !< integration point el !< element - + real(pReal), dimension(plastic_nonlocal_sizePostResults(& phase_plasticityInstance(material_phase(1_pInt,ip,el)))) :: & plastic_nonlocal_postResults - + integer(pInt) :: & ph, & instance, & !< current instance of this plasticity @@ -3623,7 +3623,7 @@ tauBack = plasticState(ph)%State(iTauB(1:ns,instance),of) forall (t = 1_pInt:4_pInt) & gdot(1:ns,t) = rhoSgl(1:ns,t) * burgers(1:ns,instance) * v(1:ns,t) - + !* calculate limits for stable dipole height @@ -3641,7 +3641,7 @@ dUpper(1:ns,2) = lattice_mu(ph) * burgers(1:ns,instance) & forall (c = 1_pInt:2_pInt) where(sqrt(rhoSgl(1:ns,2*c-1)+rhoSgl(1:ns,2*c)+& abs(rhoSgl(1:ns,2*c+3))+abs(rhoSgl(1:ns,2*c+4))+rhoDip(1:ns,c)) >= tiny(0.0_pReal)) & - dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + dUpper(1:ns,c) = min(1.0_pReal / sqrt(rhoSgl(1:ns,2*c-1) + rhoSgl(1:ns,2*c) & + abs(rhoSgl(1:ns,2*c+3)) + abs(rhoSgl(1:ns,2*c+4)) + rhoDip(1:ns,c)), & dUpper(1:ns,c)) end forall @@ -3664,95 +3664,95 @@ outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) case (rho_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) + sum(rhoDip,2) cs = cs + ns - + case (rho_sgl_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl),2) cs = cs + ns - + case (rho_sgl_mobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,1:4)),2) cs = cs + ns - + case (rho_sgl_immobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:8),2) cs = cs + ns - + case (rho_dip_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDip,2) cs = cs + ns - + case (rho_edge_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) + rhoDip(1:ns,1) cs = cs + ns - + case (rho_sgl_edge_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[1,2,5,6])),2) cs = cs + ns - + case (rho_sgl_edge_mobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,1:2),2) cs = cs + ns - + case (rho_sgl_edge_immobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,5:6),2) cs = cs + ns - + case (rho_sgl_edge_pos_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5)) cs = cs + ns - + case (rho_sgl_edge_pos_mobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) cs = cs + ns - + case (rho_sgl_edge_pos_immobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,5) cs = cs + ns - + case (rho_sgl_edge_neg_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6)) cs = cs + ns - + case (rho_sgl_edge_neg_mobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,2) cs = cs + ns - + case (rho_sgl_edge_neg_immobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,6) cs = cs + ns - + case (rho_dip_edge_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,1) cs = cs + ns - + case (rho_screw_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) + rhoDip(1:ns,2) cs = cs + ns - + case (rho_sgl_screw_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(abs(rhoSgl(1:ns,[3,4,7,8])),2) cs = cs + ns - + case (rho_sgl_screw_mobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,3:4),2) cs = cs + ns - + case (rho_sgl_screw_immobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoSgl(1:ns,7:8),2) cs = cs + ns - + case (rho_sgl_screw_pos_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7)) cs = cs + ns - + case (rho_sgl_screw_pos_mobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) cs = cs + ns - + case (rho_sgl_screw_pos_immobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,7) cs = cs + ns - + case (rho_sgl_screw_neg_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8)) cs = cs + ns @@ -3768,82 +3768,82 @@ outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) case (rho_dip_screw_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDip(1:ns,2) cs = cs + ns - + case (excess_rho_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) & + (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) cs = cs + ns - + case (excess_rho_edge_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,1) + abs(rhoSgl(1:ns,5))) & - (rhoSgl(1:ns,2) + abs(rhoSgl(1:ns,6))) cs = cs + ns - + case (excess_rho_screw_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = (rhoSgl(1:ns,3) + abs(rhoSgl(1:ns,7))) & - (rhoSgl(1:ns,4) + abs(rhoSgl(1:ns,8))) cs = cs + ns - + case (rho_forest_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoForest cs = cs + ns - + case (delta_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2) + sum(rhoDip,2)) cs = cs + ns - + case (delta_sgl_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(abs(rhoSgl),2)) cs = cs + ns - + case (delta_dip_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = 1.0_pReal / sqrt(sum(rhoDip,2)) cs = cs + ns - + case (shearrate_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(gdot,2) cs = cs + ns - + case (resolvedstress_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tau cs = cs + ns - + case (resolvedstress_back_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauBack cs = cs + ns - + case (resolvedstress_external_ID) - do s = 1_pInt,ns + do s = 1_pInt,ns sLattice = slipSystemLattice(s,instance) plastic_nonlocal_postResults(cs+s) = math_mul6x6(Tstar_v, lattice_Sslip_v(1:6,1,sLattice,ph)) enddo cs = cs + ns - + case (resistance_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = tauThreshold cs = cs + ns - + case (rho_dot_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) & + sum(rhoDotDip,2) cs = cs + ns - + case (rho_dot_sgl_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) & + sum(rhoDotSgl(1:ns,5:8)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) cs = cs + ns - + case (rho_dot_sgl_mobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotSgl(1:ns,1:4),2) cs = cs + ns - + case (rho_dot_dip_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotDip,2) cs = cs + ns - + case (rho_dot_gen_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,1,1_pInt,ip,el) & + rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) @@ -3856,157 +3856,157 @@ outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) case (rho_dot_gen_screw_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotMultiplicationOutput(1:ns,2,1_pInt,ip,el) cs = cs + ns - + case (rho_dot_sgl2dip_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) & + rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) cs = cs + ns - + case (rho_dot_sgl2dip_edge_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,1,1_pInt,ip,el) cs = cs + ns - + case (rho_dot_sgl2dip_screw_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotSingle2DipoleGlideOutput(1:ns,2,1_pInt,ip,el) cs = cs + ns - + case (rho_dot_ann_ath_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotAthermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotAthermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & + rhoDotAthermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) cs = cs + ns - - case (rho_dot_ann_the_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & + + case (rho_dot_ann_the_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) & + rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) cs = cs + ns - case (rho_dot_ann_the_edge_ID) - plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) + case (rho_dot_ann_the_edge_ID) + plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,1,1_pInt,ip,el) cs = cs + ns - case (rho_dot_ann_the_screw_ID) + case (rho_dot_ann_the_screw_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotThermalAnnihilationOutput(1:ns,2,1_pInt,ip,el) cs = cs + ns - case (rho_dot_edgejogs_ID) + case (rho_dot_edgejogs_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoDotEdgeJogsOutput(1:ns,1_pInt,ip,el) cs = cs + ns case (rho_dot_flux_mobile_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) cs = cs + ns - + case (rho_dot_flux_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:4,1_pInt,ip,el),2) & + sum(rhoDotFluxOutput(1:ns,5:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:8)),2) cs = cs + ns - + case (rho_dot_flux_edge_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,1:2,1_pInt,ip,el),2) & + sum(rhoDotFluxOutput(1:ns,5:6,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,5:6)),2) cs = cs + ns - + case (rho_dot_flux_screw_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = sum(rhoDotFluxOutput(1:ns,3:4,1_pInt,ip,el),2) & + sum(rhoDotFluxOutput(1:ns,7:8,1_pInt,ip,el)*sign(1.0_pReal,rhoSgl(1:ns,7:8)),2) cs = cs + ns - + case (velocity_edge_pos_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,1) cs = cs + ns - + case (velocity_edge_neg_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,2) cs = cs + ns - + case (velocity_screw_pos_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,3) cs = cs + ns - + case (velocity_screw_neg_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = v(1:ns,4) cs = cs + ns - + case (slipdirectionx_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(1,1:ns,1) cs = cs + ns - + case (slipdirectiony_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(2,1:ns,1) cs = cs + ns - + case (slipdirectionz_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = m_currentconf(3,1:ns,1) cs = cs + ns - + case (slipnormalx_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(1,1:ns) cs = cs + ns - + case (slipnormaly_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(2,1:ns) cs = cs + ns - + case (slipnormalz_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = n_currentconf(3,1:ns) cs = cs + ns - + case (fluxdensity_edge_posx_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(1,1:ns,1) cs = cs + ns - + case (fluxdensity_edge_posy_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(2,1:ns,1) cs = cs + ns - + case (fluxdensity_edge_posz_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,1) * v(1:ns,1) * m_currentconf(3,1:ns,1) cs = cs + ns - + case (fluxdensity_edge_negx_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(1,1:ns,1) cs = cs + ns - + case (fluxdensity_edge_negy_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(2,1:ns,1) cs = cs + ns - + case (fluxdensity_edge_negz_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,2) * v(1:ns,2) * m_currentconf(3,1:ns,1) cs = cs + ns - + case (fluxdensity_screw_posx_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(1,1:ns,2) cs = cs + ns - + case (fluxdensity_screw_posy_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(2,1:ns,2) cs = cs + ns - + case (fluxdensity_screw_posz_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = rhoSgl(1:ns,3) * v(1:ns,3) * m_currentconf(3,1:ns,2) cs = cs + ns - + case (fluxdensity_screw_negx_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(1,1:ns,2) cs = cs + ns - + case (fluxdensity_screw_negy_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(2,1:ns,2) cs = cs + ns - + case (fluxdensity_screw_negz_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = - rhoSgl(1:ns,4) * v(1:ns,4) * m_currentconf(3,1:ns,2) cs = cs + ns - + case (maximumdipoleheight_edge_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,1) cs = cs + ns - + case (maximumdipoleheight_screw_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = dUpper(1:ns,2) cs = cs + ns - + case(dislocationstress_ID) sigma = plastic_nonlocal_dislocationstress(Fe, ip, el) plastic_nonlocal_postResults(cs+1_pInt) = sigma(1,1) @@ -4016,11 +4016,11 @@ outputsLoop: do o = 1_pInt,plastic_nonlocal_Noutput(instance) plastic_nonlocal_postResults(cs+5_pInt) = sigma(2,3) plastic_nonlocal_postResults(cs+6_pInt) = sigma(3,1) cs = cs + 6_pInt - + case(accumulatedshear_ID) plastic_nonlocal_postResults(cs+1_pInt:cs+ns) = plasticState(ph)%state(iGamma(1:ns,instance),of) cs = cs + ns - + end select enddo outputsLoop diff --git a/code/plastic_phenoplus.f90 b/code/plastic_phenoplus.f90 index 0887da239..9c125db04 100644 --- a/code/plastic_phenoplus.f90 +++ b/code/plastic_phenoplus.f90 @@ -557,7 +557,7 @@ subroutine plastic_phenoplus_init(fileUnit) ! allocate state arrays sizeState = plastic_phenoplus_totalNslip(instance) & ! s_slip + plastic_phenoplus_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) + + 2_pInt & ! sum(gamma) + sum(twinVolFrac) + plastic_phenoplus_totalNslip(instance) & ! accshear_slip + plastic_phenoplus_totalNtwin(instance) & ! accshear_twin + plastic_phenoplus_totalNslip(instance) ! kappa @@ -568,7 +568,7 @@ subroutine plastic_phenoplus_init(fileUnit) ! memory leak issue. sizeDotState = plastic_phenoplus_totalNslip(instance) & ! s_slip + plastic_phenoplus_totalNtwin(instance) & ! s_twin - + 2_pInt & ! sum(gamma) + sum(f) + + 2_pInt & ! sum(gamma) + sum(twinVolFrac) + plastic_phenoplus_totalNslip(instance) & ! accshear_slip + plastic_phenoplus_totalNtwin(instance) ! accshear_twin @@ -739,73 +739,84 @@ end subroutine plastic_phenoplus_aTolState !-------------------------------------------------------------------------------------------------- !> @brief calculate push-up factors (kappa) for each voxel based on its neighbors !-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el) - use math, only: pi, & - math_mul33x33, & - math_mul3x3, & - math_transpose33, & - math_qDot, & - math_qRot, & - indeg +subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,Fe,Fp) + use math, only: pi, & + math_mul33x33, & + math_mul3x3, & + math_transpose33, & + math_qDot, & + math_qRot, & + indeg - use mesh, only: mesh_element, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype, & - mesh_maxNips, & - mesh_NcpElems, & - mesh_ipNeighborhood + use mesh, only: mesh_element, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype, & + mesh_maxNips, & + mesh_NcpElems, & + mesh_ipNeighborhood - use material, only: material_phase, & - material_texture, & - phase_plasticityInstance, & - phaseAt, phasememberAt, & - homogenization_maxNgrains, & - plasticState + use material, only: material_phase, & + material_texture, & + phase_plasticityInstance, & + phaseAt, phasememberAt, & + homogenization_maxNgrains, & + plasticState - use lattice, only: lattice_sn, & - lattice_sd, & - lattice_qDisorientation + use lattice, only: lattice_sn, & + lattice_sd, & + lattice_qDisorientation !***input variables implicit none integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element + ipc, & !< component-ID of integration point + ip, & !< integration point + el + real(pReal), dimension(3,3), intent(in) :: & + Fe, & ! elastic deformation gradient + Fp ! elastic deformation gradient !< element real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - orientation ! crystal orientation in quaternions + orientation ! crystal orientation in quaternions !***local variables - integer(pInt) instance, & !my instance of this plasticity - ph, & !my phase - of, & !my spatial position in memory (offset) - textureID, & !my texture - Nneighbors, & !number of neighbors (<= 6) - vld_Nneighbors, & !number of my valid neighbors - n, & !neighbor index (for iterating through all neighbors) - ns, & !number of slip system - nt, & !number of twin system - me_slip, & !my slip system index - neighbor_el, & !element number of neighboring material point - neighbor_ip, & !integration point of neighboring material point - neighbor_n, & !I have no idea what is this - neighbor_of, & !spatial position in memory for this neighbor (offset) - neighbor_ph, & !neighbor's phase - neighbor_tex, & !neighbor's texture ID - ne_slip_ac, & !loop to find neighbor shear - ne_slip, & !slip system index for neighbor - index_kappa, & !index of pushup factors in plasticState - offset_acshear_slip, & !offset in PlasticState for the accumulative shear - j !quickly loop through slip families + integer(pInt) instance, & !my instance of this plasticity + ph, & !my phase + of, & !my spatial position in memory (offset) + textureID, & !my texture + Nneighbors, & !number of neighbors (<= 6) + vld_Nneighbors, & !number of my valid neighbors + n, & !neighbor index (for iterating through all neighbors) + ns, & !number of slip system + nt, & !number of twin system + me_slip, & !my slip system index + neighbor_el, & !element number of neighboring material point + neighbor_ip, & !integration point of neighboring material point + neighbor_n, & !I have no idea what is this + neighbor_of, & !spatial position in memory for this neighbor (offset) + neighbor_ph, & !neighbor's phase + neighbor_tex, & !neighbor's texture ID + ne_slip_ac, & !loop to find neighbor shear + ne_slip, & !slip system index for neighbor + index_kappa, & !index of pushup factors in plasticState + offset_acshear_slip, & !offset in PlasticState for the accumulative shear + j !quickly loop through slip families - real(pReal) kappa_max, & ! - tmp_myshear_slip, & !temp storage for accumulative shear for me - mprime_cut, & !m' cutoff to consider neighboring effect - avg_acshear_ne, & !the average accumulative shear from my neighbor - tmp_mprime, & !temp holder for m' value - tmp_acshear !temp holder for accumulative shear for m' + real(pReal) kappa_max, & ! + tmp_myshear_slip, & !temp storage for accumulative shear for me + mprime_cut, & !m' cutoff to consider neighboring effect + dtaylor_cut, & !threshold for determine high contrast interface using Taylor factor + avg_acshear_ne, & !the average accumulative shear from my neighbor + taylor_me, & !Taylor factor for me + taylor_ne, & !Taylor factor for my current neighbor + tmp_mprime, & !temp holder for m' value + tmp_acshear !temp holder for accumulative shear for m' + real(pReal), dimension(3,3) :: & + Fe_me, & !my elastic deformation gradient + Fp_me, & !my plastic deformation gradient + Fe_ne, & !elastic deformation gradient of my current neighbor + Fp_ne !plastic deformation gradient of my current neighbor real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & m_primes, & !m' between me_alpha(one) and neighbor beta(all) @@ -824,97 +835,127 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el) ne_mprimes !m' between each neighbor !***Get my properties + !@TODO + ! still need to know how to access the total strain for current material point + ! also, need to figure out an efficient way to calculate gamma_dot for the material + ! point and its neighbors Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) ph = phaseAt(ipc,ip,el) !get my phase - of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory - textureID = material_texture(1,ip,el) !get my texture ID - instance = phase_plasticityInstance(ph) !get my instance based on phase ID + of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory + textureID = material_texture(1,ip,el) !get my texture ID + instance = phase_plasticityInstance(ph) !get my instance based on phase ID ns = plastic_phenoplus_totalNslip(instance) nt = plastic_phenoplus_totalNtwin(instance) offset_acshear_slip = ns + nt + 2_pInt - index_kappa = ns + nt + 2_pInt + ns + nt !location of kappa in plasticState - mprime_cut = 0.7_pReal !set by Dr.Bieler + index_kappa = ns + nt + 2_pInt + ns + nt !location of kappa in plasticState - !***gather my accumulative shear from palsticState - FINDMYSHEAR: do j = 1_pInt,ns - me_acshear(j) = plasticState(ph)%state(offset_acshear_slip+j, of) - enddo FINDMYSHEAR + !***init calculation for given voxel + mprime_cut = 0.7_pReal !set by Dr.Bieler + dtaylor_cut = 1.0_pReal !set by Chen, quick test only + !***calculate my Taylor factor !***gather my orientation and slip systems - my_orientation = orientation(1:4, ipc, ip, el) + my_orientation = orientation(1:4, ipc, ip, el) + Fe_me = Fe(ipc,ip,el) + Fp_me = Fp(ipc,ip,el) slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) - kappa_max = plastic_phenoplus_kappa_max(instance) !maximum pushups allowed (READIN) - !***calculate kappa between me and all my neighbors - LOOPMYSLIP: DO me_slip=1_pInt,ns - vld_Nneighbors = Nneighbors - tmp_myshear_slip = me_acshear(me_slip) - tmp_mprime = 0.0_pReal !highest m' from all neighbors - tmp_acshear = 0.0_pReal !accumulative shear from highest m' - - !***go through my neighbors to find highest m' - LOOPNEIGHBORS: DO n=1_pInt,Nneighbors - neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - neighbor_n = 1 !It is ipc - neighbor_of = phasememberAt( neighbor_n, neighbor_ip, neighbor_el) - neighbor_ph = phaseAt( neighbor_n, neighbor_ip, neighbor_el) - neighbor_tex = material_texture(1,neighbor_ip,neighbor_el) - neighbor_orientation = orientation(1:4, neighbor_n, neighbor_ip, neighbor_el) !ipc is always 1. - absMisorientation = lattice_qDisorientation(my_orientation, & - neighbor_orientation, & - 0_pInt) !no need for explicit calculation of symmetry - - !***find the accumulative shear for this neighbor - LOOPFINDNEISHEAR: DO ne_slip_ac=1_pInt, ns - ne_acshear(ne_slip_ac) = plasticState(ph)%state(offset_acshear_slip+ne_slip_ac, & - neighbor_of) - ENDDO LOOPFINDNEISHEAR - - !***calculate the average accumulative shear and use it as cutoff - avg_acshear_ne = SUM(ne_acshear)/ns - - !*** - IF (ph==neighbor_ph) THEN - !***walk through all the - LOOPNEIGHBORSLIP: DO ne_slip=1_pInt,ns - !***only consider slip system that is active (above average accumulative shear) - IF (ne_acshear(ne_slip) > avg_acshear_ne) THEN - m_primes(ne_slip) = abs(math_mul3x3(slipNormal(1:3,me_slip), & - math_qRot(absMisorientation, slipNormal(1:3,ne_slip)))) & - *abs(math_mul3x3(slipDirect(1:3,me_slip), & - math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) - !***find the highest m' and corresponding accumulative shear - IF (m_primes(ne_slip) > tmp_mprime) THEN - tmp_mprime = m_primes(ne_slip) - tmp_acshear = ne_acshear(ne_slip) - ENDIF - ENDIF - ENDDO LOOPNEIGHBORSLIP - - ELSE - ne_mprimes(n) = 0.0_pReal - vld_Nneighbors = vld_Nneighbors - 1_pInt - ENDIF - - ENDDO LOOPNEIGHBORS - - !***check if this element close to rim - IF (vld_Nneighbors < Nneighbors) THEN - !***rim voxel, no modification allowed - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal + !***loop into the geometry to figure out who is my closest neighbor + LOOPNEIGHBORS: DO n=1_pInt, Nneighbors + !******for each of my neighbor, calculate the Taylor factor + ne_taylor = 1.0 + !*********for the high contrast interface + IF (abs(taylor_ne - taylor_me) > dtaylor_cut) THEN + !********* gather neighbor orientation and slip systems + !********* calculate m' (need to loop through all my slip systems as well) + !********* if m'>mprime_cut kappa=1.5 else 1.0 + !****** ELSE - !***patch voxel, started to calculate push up factor for gamma_dot - IF ((tmp_mprime > mprime_cut) .AND. (tmp_acshear > tmp_myshear_slip)) THEN - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal / tmp_mprime - ELSE - !***minimum damping factor is 0.5 - plasticState(ph)%state(index_kappa+me_slip, of) = 0.5_pReal + tmp_mprime * 0.5_pReal - ENDIF ENDIF + !***end of search + ENDDO LOOPNEIGHBORS - ENDDO LOOPMYSLIP + ! !***gather my accumulative shear from palsticState + ! FINDMYSHEAR: do j = 1_pInt,ns + ! me_acshear(j) = plasticState(ph)%state(offset_acshear_slip+j, of) + ! enddo FINDMYSHEAR + + ! !***gather my orientation and slip systems + ! my_orientation = orientation(1:4, ipc, ip, el) + ! slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) + ! slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) + ! kappa_max = plastic_phenoplus_kappa_max(instance) !maximum pushups allowed (READIN) + + ! !***calculate kappa between me and all my neighbors + ! LOOPMYSLIP: DO me_slip=1_pInt,ns + ! vld_Nneighbors = Nneighbors + ! tmp_myshear_slip = me_acshear(me_slip) + ! tmp_mprime = 0.0_pReal !highest m' from all neighbors + ! tmp_acshear = 0.0_pReal !accumulative shear from highest m' + + ! !***go through my neighbors to find highest m' + ! LOOPNEIGHBORS: DO n=1_pInt,Nneighbors + ! neighbor_el = mesh_ipNeighborhood(1,n,ip,el) + ! neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) + ! neighbor_n = 1 !It is ipc + ! neighbor_of = phasememberAt( neighbor_n, neighbor_ip, neighbor_el) + ! neighbor_ph = phaseAt( neighbor_n, neighbor_ip, neighbor_el) + ! neighbor_tex = material_texture(1,neighbor_ip,neighbor_el) + ! neighbor_orientation = orientation(1:4, neighbor_n, neighbor_ip, neighbor_el) !ipc is always 1. + ! absMisorientation = lattice_qDisorientation(my_orientation, & + ! neighbor_orientation, & + ! 0_pInt) !no need for explicit calculation of symmetry + + ! !***find the accumulative shear for this neighbor + ! LOOPFINDNEISHEAR: DO ne_slip_ac=1_pInt, ns + ! ne_acshear(ne_slip_ac) = plasticState(ph)%state(offset_acshear_slip+ne_slip_ac, & + ! neighbor_of) + ! ENDDO LOOPFINDNEISHEAR + + ! !***calculate the average accumulative shear and use it as cutoff + ! avg_acshear_ne = SUM(ne_acshear)/ns + + ! !*** + ! IF (ph==neighbor_ph) THEN + ! !***walk through all the + ! LOOPNEIGHBORSLIP: DO ne_slip=1_pInt,ns + ! !***only consider slip system that is active (above average accumulative shear) + ! IF (ne_acshear(ne_slip) > avg_acshear_ne) THEN + ! m_primes(ne_slip) = abs(math_mul3x3(slipNormal(1:3,me_slip), & + ! math_qRot(absMisorientation, slipNormal(1:3,ne_slip)))) & + ! *abs(math_mul3x3(slipDirect(1:3,me_slip), & + ! math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) + ! !***find the highest m' and corresponding accumulative shear + ! IF (m_primes(ne_slip) > tmp_mprime) THEN + ! tmp_mprime = m_primes(ne_slip) + ! tmp_acshear = ne_acshear(ne_slip) + ! ENDIF + ! ENDIF + ! ENDDO LOOPNEIGHBORSLIP + + ! ELSE + ! ne_mprimes(n) = 0.0_pReal + ! vld_Nneighbors = vld_Nneighbors - 1_pInt + ! ENDIF + + ! ENDDO LOOPNEIGHBORS + + ! !***check if this element close to rim + ! IF (vld_Nneighbors < Nneighbors) THEN + ! !***rim voxel, no modification allowed + ! plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal + ! ELSE + ! !***patch voxel, started to calculate push up factor for gamma_dot + ! IF ((tmp_mprime > mprime_cut) .AND. (tmp_acshear > tmp_myshear_slip)) THEN + ! plasticState(ph)%state(index_kappa+me_slip, of) = 1.5_pReal + ! ELSE + ! !***minimum damping factor is 0.5 + ! plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal + ! ENDIF + ! ENDIF + + ! ENDDO LOOPMYSLIP end subroutine plastic_phenoplus_microstructure From de6b712b09d8a3397ce402c25c0cd43476c0fb13 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 13 Apr 2016 14:06:04 -0400 Subject: [PATCH 056/183] passing the entire defomration gradient information through microstructure --- code/constitutive.f90 | 9 ++++++--- code/crystallite.f90 | 37 +++++++++++++++++++++++++++++-------- code/plastic_phenoplus.f90 | 31 ++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/code/constitutive.f90 b/code/constitutive.f90 index 63ae9a1a5..34328d300 100644 --- a/code/constitutive.f90 +++ b/code/constitutive.f90 @@ -436,7 +436,7 @@ end function constitutive_homogenizedC !-------------------------------------------------------------------------------------------------- !> @brief calls microstructure function of the different constitutive models !-------------------------------------------------------------------------------------------------- -subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el) +subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el, F0s,Fes,Fps) use prec, only: & pReal use material, only: & @@ -473,7 +473,10 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el) ho, & !< homogenization tme !< thermal member position real(pReal), intent(in), dimension(:,:,:,:) :: & - orientations !< crystal orientations as quaternions + orientations, & + F0s, & + Fes, & + Fps !< crystal orientations as quaternions ho = material_homog(ip,el) tme = thermalMapping(ho)%p(ip,el) @@ -488,7 +491,7 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el) case (PLASTICITY_NONLOCAL_ID) plasticityType call plastic_nonlocal_microstructure (Fe,Fp,ip,el) case (PLASTICITY_PHENOPLUS_ID) plasticityType - call plastic_phenoplus_microstructure(orientations,ipc,ip,el,Fe,Fp) + call plastic_phenoplus_microstructure(orientations,ipc,ip,el,F0s,Fes,Fps) end select plasticityType end subroutine constitutive_microstructure diff --git a/code/crystallite.f90 b/code/crystallite.f90 index 71a5e4743..271fd2300 100644 --- a/code/crystallite.f90 +++ b/code/crystallite.f90 @@ -424,7 +424,7 @@ subroutine crystallite_init crystallite_partionedFp0 = crystallite_Fp0 crystallite_partionedFi0 = crystallite_Fi0 crystallite_partionedF0 = crystallite_F0 - crystallite_partionedF = crystallite_F0 + crystallite_partionedF = crystallite_F0 call crystallite_orientations() crystallite_orientation0 = crystallite_orientation ! store initial orientations for calculation of grain rotations @@ -437,7 +437,10 @@ subroutine crystallite_init call constitutive_microstructure(crystallite_orientation, & ! pass orientation to constitutive module crystallite_Fe(1:3,1:3,c,i,e), & crystallite_Fp(1:3,1:3,c,i,e), & - c,i,e) ! update dependent state variables to be consistent with basic states + c,i,e, + crystallite_F0, + crystallite_Fe, + crystallite_Fp) ! update dependent state variables to be consistent with basic states enddo enddo enddo @@ -1714,7 +1717,10 @@ subroutine crystallite_integrateStateRK4() call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states + g, i, e, + crystallite_F0, + crystallite_Fe, + crystallite_Fp) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2040,7 +2046,10 @@ subroutine crystallite_integrateStateRKCK45() call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states + g, i, e, + crystallite_F0, + crystallite_Fe, + crystallite_Fp) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2260,7 +2269,10 @@ subroutine crystallite_integrateStateRKCK45() call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states + g, i, e, + crystallite_F0, + crystallite_Fe, + crystallite_Fp) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2495,7 +2507,10 @@ subroutine crystallite_integrateStateAdaptiveEuler() call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states + g, i, e, + crystallite_F0, + crystallite_Fe, + crystallite_Fp) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO !$OMP END PARALLEL @@ -2839,7 +2854,10 @@ eIter = FEsolving_execElem(1:2) call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states + g, i, e, + crystallite_F0, + crystallite_Fe, + crystallite_Fp) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO !$OMP END PARALLEL @@ -3084,7 +3102,10 @@ subroutine crystallite_integrateStateFPI() call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e) ! update dependent state variables to be consistent with basic states + g, i, e, + crystallite_F0, + crystallite_Fe, + crystallite_Fp) ! update dependent state variables to be consistent with basic states p = phaseAt(g,i,e) c = phasememberAt(g,i,e) plasticState(p)%previousDotState2(:,c) = plasticState(p)%previousDotState(:,c) diff --git a/code/plastic_phenoplus.f90 b/code/plastic_phenoplus.f90 index 9c125db04..b2a366dd3 100644 --- a/code/plastic_phenoplus.f90 +++ b/code/plastic_phenoplus.f90 @@ -739,9 +739,11 @@ end subroutine plastic_phenoplus_aTolState !-------------------------------------------------------------------------------------------------- !> @brief calculate push-up factors (kappa) for each voxel based on its neighbors !-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,Fe,Fp) +subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp) use math, only: pi, & + math_identity2nd, & math_mul33x33, & + math_mul33xx33, & math_mul3x3, & math_transpose33, & math_qDot, & @@ -773,7 +775,8 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,Fe,Fp) ipc, & !< component-ID of integration point ip, & !< integration point el - real(pReal), dimension(3,3), intent(in) :: & + real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + F0, & ! deformation gradient from last increment Fe, & ! elastic deformation gradient Fp ! elastic deformation gradient !< element real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & @@ -813,10 +816,15 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,Fe,Fp) tmp_acshear !temp holder for accumulative shear for m' real(pReal), dimension(3,3) :: & + F0_me, & !my deformation gradient from last converged increment Fe_me, & !my elastic deformation gradient Fp_me, & !my plastic deformation gradient + dF_me, & !my deformation gradient change (delta) + dE_me, & !my Green Lagrangian strain tensor (delta) Fe_ne, & !elastic deformation gradient of my current neighbor - Fp_ne !plastic deformation gradient of my current neighbor + Fp_ne, & !plastic deformation gradient of my current neighbor + dF_ne, & !deformation gradient of my current neighbor + dE_ne !delta Green Lagrangian strain tensor real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & m_primes, & !m' between me_alpha(one) and neighbor beta(all) @@ -835,10 +843,6 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,Fe,Fp) ne_mprimes !m' between each neighbor !***Get my properties - !@TODO - ! still need to know how to access the total strain for current material point - ! also, need to figure out an efficient way to calculate gamma_dot for the material - ! point and its neighbors Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) ph = phaseAt(ipc,ip,el) !get my phase of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory @@ -853,13 +857,18 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,Fe,Fp) mprime_cut = 0.7_pReal !set by Dr.Bieler dtaylor_cut = 1.0_pReal !set by Chen, quick test only - !***calculate my Taylor factor - !***gather my orientation and slip systems + !***gather my orientation, F and slip systems my_orientation = orientation(1:4, ipc, ip, el) - Fe_me = Fe(ipc,ip,el) - Fp_me = Fp(ipc,ip,el) + F0_me = F0(1:3, 1:3, ipc, ip, el) + Fe_me = Fe(1:3, 1:3, ipc, ip, el) + Fp_me = Fp(1:3, 1:3, ipc, ip, el) slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) + !******calculate Taylor factor for me + !@note: we need teh + F_me = math_mul33x33(Fe_me,Fp_me) + E_me = 0.5*(math_mul33x33(math_transpose33(F_me), F_me) - math_identity2nd) !E = 0.5(F^tF-I) + vonStrain !***loop into the geometry to figure out who is my closest neighbor LOOPNEIGHBORS: DO n=1_pInt, Nneighbors From 00abdc34c1b20bfb3eea321b3bd688739154425e Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 13 Apr 2016 16:38:22 -0400 Subject: [PATCH 057/183] new formular for kappa is done, time for debugging --- code/constitutive.f90 | 13 +- code/crystallite.f90 | 21 ++- code/plastic_phenoplus.f90 | 371 +++++++++++++++++++++++-------------- 3 files changed, 255 insertions(+), 150 deletions(-) diff --git a/code/constitutive.f90 b/code/constitutive.f90 index 34328d300..6280ae457 100644 --- a/code/constitutive.f90 +++ b/code/constitutive.f90 @@ -436,7 +436,7 @@ end function constitutive_homogenizedC !-------------------------------------------------------------------------------------------------- !> @brief calls microstructure function of the different constitutive models !-------------------------------------------------------------------------------------------------- -subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el, F0s,Fes,Fps) +subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el, F0s,Fes,Fps,Tstar_vs) use prec, only: & pReal use material, only: & @@ -473,10 +473,15 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el, F0s,Fe ho, & !< homogenization tme !< thermal member position real(pReal), intent(in), dimension(:,:,:,:) :: & - orientations, & + orientations + + real(pReal), intent(in), dimension(:,:,:,:,:) :: & F0s, & Fes, & - Fps !< crystal orientations as quaternions + Fps + + real(pReal), intent(in), dimension(6,:,:,:) :: & + Tstar_vs !< crystal orientations as quaternions ho = material_homog(ip,el) tme = thermalMapping(ho)%p(ip,el) @@ -491,7 +496,7 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el, F0s,Fe case (PLASTICITY_NONLOCAL_ID) plasticityType call plastic_nonlocal_microstructure (Fe,Fp,ip,el) case (PLASTICITY_PHENOPLUS_ID) plasticityType - call plastic_phenoplus_microstructure(orientations,ipc,ip,el,F0s,Fes,Fps) + call plastic_phenoplus_microstructure(orientations,ipc,ip,el,F0s,Fes,Fps,Tstar_vs) end select plasticityType end subroutine constitutive_microstructure diff --git a/code/crystallite.f90 b/code/crystallite.f90 index 271fd2300..187eba697 100644 --- a/code/crystallite.f90 +++ b/code/crystallite.f90 @@ -440,7 +440,8 @@ subroutine crystallite_init c,i,e, crystallite_F0, crystallite_Fe, - crystallite_Fp) ! update dependent state variables to be consistent with basic states + crystallite_Fp, + crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo enddo enddo @@ -1720,7 +1721,8 @@ subroutine crystallite_integrateStateRK4() g, i, e, crystallite_F0, crystallite_Fe, - crystallite_Fp) ! update dependent state variables to be consistent with basic states + crystallite_Fp, + crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2049,7 +2051,8 @@ subroutine crystallite_integrateStateRKCK45() g, i, e, crystallite_F0, crystallite_Fe, - crystallite_Fp) ! update dependent state variables to be consistent with basic states + crystallite_Fp, + crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2272,7 +2275,8 @@ subroutine crystallite_integrateStateRKCK45() g, i, e, crystallite_F0, crystallite_Fe, - crystallite_Fp) ! update dependent state variables to be consistent with basic states + crystallite_Fp, + crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2510,7 +2514,8 @@ subroutine crystallite_integrateStateAdaptiveEuler() g, i, e, crystallite_F0, crystallite_Fe, - crystallite_Fp) ! update dependent state variables to be consistent with basic states + crystallite_Fp, + crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO !$OMP END PARALLEL @@ -2857,7 +2862,8 @@ eIter = FEsolving_execElem(1:2) g, i, e, crystallite_F0, crystallite_Fe, - crystallite_Fp) ! update dependent state variables to be consistent with basic states + crystallite_Fp, + crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO !$OMP END PARALLEL @@ -3105,7 +3111,8 @@ subroutine crystallite_integrateStateFPI() g, i, e, crystallite_F0, crystallite_Fe, - crystallite_Fp) ! update dependent state variables to be consistent with basic states + crystallite_Fp, + crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states p = phaseAt(g,i,e) c = phasememberAt(g,i,e) plasticState(p)%previousDotState2(:,c) = plasticState(p)%previousDotState(:,c) diff --git a/code/plastic_phenoplus.f90 b/code/plastic_phenoplus.f90 index b2a366dd3..cf0cdd424 100644 --- a/code/plastic_phenoplus.f90 +++ b/code/plastic_phenoplus.f90 @@ -739,162 +739,255 @@ end subroutine plastic_phenoplus_aTolState !-------------------------------------------------------------------------------------------------- !> @brief calculate push-up factors (kappa) for each voxel based on its neighbors !-------------------------------------------------------------------------------------------------- -subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp) - use math, only: pi, & - math_identity2nd, & - math_mul33x33, & - math_mul33xx33, & - math_mul3x3, & - math_transpose33, & - math_qDot, & - math_qRot, & - indeg +subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar_v) + use math, only: pi, & + math_identity2nd, & + math_mul33x33, & + math_mul33xx33, & + math_mul3x3, & + math_transpose33, & + math_qDot, & + math_qRot, & + indeg - use mesh, only: mesh_element, & - FE_NipNeighbors, & - FE_geomtype, & - FE_celltype, & - mesh_maxNips, & - mesh_NcpElems, & - mesh_ipNeighborhood + use mesh, only: mesh_element, & + FE_NipNeighbors, & + FE_geomtype, & + FE_celltype, & + mesh_maxNips, & + mesh_NcpElems, & + mesh_ipNeighborhood - use material, only: material_phase, & - material_texture, & - phase_plasticityInstance, & - phaseAt, phasememberAt, & - homogenization_maxNgrains, & - plasticState + use material, only: material_phase, & + material_texture, & + phase_plasticityInstance, & + phaseAt, phasememberAt, & + homogenization_maxNgrains, & + plasticState - use lattice, only: lattice_sn, & - lattice_sd, & - lattice_qDisorientation + use lattice, only: lattice_Sslip_v, & + lattice_maxNslipFamily, & + lattice_NslipSystem, & + lattice_NslipSystem, & + lattice_sn, & + lattice_sd, & + lattice_qDisorientation - !***input variables - implicit none - integer(pInt), intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el - real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - F0, & ! deformation gradient from last increment - Fe, & ! elastic deformation gradient - Fp ! elastic deformation gradient !< element - real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & - orientation ! crystal orientation in quaternions + !***input variables + implicit none + integer(pInt), intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el + real(pReal), dimension(3,3,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + F0, & !< deformation gradient from last increment + Fe, & !< elastic deformation gradient + Fp !< elastic deformation gradient !< element + real(pReal), dimension(4,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + orientation !< crystal orientation in quaternions + real(pReal), dimension(6,homogenization_maxNgrains,mesh_maxNips,mesh_NcpElems), intent(in) :: & + Tstar_v !< for calculation of gdot - !***local variables - integer(pInt) instance, & !my instance of this plasticity - ph, & !my phase - of, & !my spatial position in memory (offset) - textureID, & !my texture - Nneighbors, & !number of neighbors (<= 6) - vld_Nneighbors, & !number of my valid neighbors - n, & !neighbor index (for iterating through all neighbors) - ns, & !number of slip system - nt, & !number of twin system - me_slip, & !my slip system index - neighbor_el, & !element number of neighboring material point - neighbor_ip, & !integration point of neighboring material point - neighbor_n, & !I have no idea what is this - neighbor_of, & !spatial position in memory for this neighbor (offset) - neighbor_ph, & !neighbor's phase - neighbor_tex, & !neighbor's texture ID - ne_slip_ac, & !loop to find neighbor shear - ne_slip, & !slip system index for neighbor - index_kappa, & !index of pushup factors in plasticState - offset_acshear_slip, & !offset in PlasticState for the accumulative shear - j !quickly loop through slip families + !***local variables + integer(pInt) instance, & !my instance of this plasticity + ph, & !my phase + of, & !my spatial position in memory (offset) + textureID, & !my texture + Nneighbors, & !number of neighbors (<= 6) + vld_Nneighbors, & !number of my valid neighbors + n, & !neighbor index (for iterating through all neighbors) + n_calcTaylor, & ! + n_phasecheck, & ! + ns, & !number of slip system + nt, & !number of twin system + me_slip, & !my slip system index + neighbor_el, & !element number of neighboring material point + neighbor_ip, & !integration point of neighboring material point + neighbor_ipc, & !I have no idea what is this + neighbor_of, & !spatial position in memory for this neighbor (offset) + neighbor_ph, & !neighbor's phase + neighbor_instance, & !neighbor's instance of this plasticity + neighbor_tex, & !neighbor's texture ID + ne_slip, & !slip system index for neighbor + index_kappa, & !index of pushup factors in plasticState + j, & !quickly loop through slip families + f,i,& !loop counter for me + f_ne, i_ne !loop counter for neighbor - real(pReal) kappa_max, & ! - tmp_myshear_slip, & !temp storage for accumulative shear for me - mprime_cut, & !m' cutoff to consider neighboring effect - dtaylor_cut, & !threshold for determine high contrast interface using Taylor factor - avg_acshear_ne, & !the average accumulative shear from my neighbor - taylor_me, & !Taylor factor for me - taylor_ne, & !Taylor factor for my current neighbor - tmp_mprime, & !temp holder for m' value - tmp_acshear !temp holder for accumulative shear for m' + real(pReal) kappa_max, & ! + tmp_myshear_slip, & !temp storage for accumulative shear for me + mprime_cut, & !m' cutoff to consider neighboring effect + dtaylor_cut, & !threshold for determine high contrast interface using Taylor factor + avg_acshear_ne, & !the average accumulative shear from my neighbor + taylor_me, & !Taylor factor for me + taylor_ne, & !Taylor factor for my current neighbor + d_vonstrain !von Mises delta strain (temp container) - real(pReal), dimension(3,3) :: & - F0_me, & !my deformation gradient from last converged increment - Fe_me, & !my elastic deformation gradient - Fp_me, & !my plastic deformation gradient - dF_me, & !my deformation gradient change (delta) - dE_me, & !my Green Lagrangian strain tensor (delta) - Fe_ne, & !elastic deformation gradient of my current neighbor - Fp_ne, & !plastic deformation gradient of my current neighbor - dF_ne, & !deformation gradient of my current neighbor - dE_ne !delta Green Lagrangian strain tensor + real(pReal), dimension(3,3) :: & + F0_me, & !my deformation gradient from last converged increment + Fe_me, & !my elastic deformation gradient + Fp_me, & !my plastic deformation gradient + dF_me, & !my deformation gradient change (delta) + dE_me, & !my Green Lagrangian strain tensor (delta) + Fe_ne, & !elastic deformation gradient of my current neighbor + Fp_ne, & !plastic deformation gradient of my current neighbor + dF_ne, & !deformation gradient of my current neighbor + dE_ne !delta Green Lagrangian strain tensor - real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - m_primes, & !m' between me_alpha(one) and neighbor beta(all) - me_acshear, & !temp storage for ac_shear of one particular system for me - ne_acshear !temp storage for ac_shear of one particular system for one of my neighbor + real(pReal), dimension(plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + m_primes !m' between me_alpha(one) and neighbor beta(all) - real(pReal), dimension(3,plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & - slipNormal, & - slipDirect + real(pReal), dimension(3,plastic_phenoplus_totalNslip(phase_plasticityInstance(material_phase(1,ip,el)))) :: & + slipNormal, & + slipDirect - real(pReal), dimension(4) :: my_orientation, & !store my orientation - neighbor_orientation, & !store my neighbor orientation - absMisorientation + real(pReal), dimension(4) :: & + my_orientation, & !store my orientation + neighbor_orientation, & !store my neighbor orientation + absMisorientation - real(pReal), dimension(FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) :: & - ne_mprimes !m' between each neighbor + real(pReal), dimension(FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el))))) :: & + ne_mprimes, & !m' between each neighbor + d_taylors !store (taylor_ne-taylor_me) for each neighbor - !***Get my properties - Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) - ph = phaseAt(ipc,ip,el) !get my phase - of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory - textureID = material_texture(1,ip,el) !get my texture ID - instance = phase_plasticityInstance(ph) !get my instance based on phase ID - ns = plastic_phenoplus_totalNslip(instance) - nt = plastic_phenoplus_totalNtwin(instance) - offset_acshear_slip = ns + nt + 2_pInt - index_kappa = ns + nt + 2_pInt + ns + nt !location of kappa in plasticState + !***Get my properties + Nneighbors = FE_NipNeighbors(FE_celltype(FE_geomtype(mesh_element(2,el)))) + ph = phaseAt(ipc,ip,el) !get my phase + of = phasememberAt(ipc,ip,el) !get my spatial location offset in memory + textureID = material_texture(1,ip,el) !get my texture ID + instance = phase_plasticityInstance(ph) !get my instance based on phase ID + ns = plastic_phenoplus_totalNslip(instance) + nt = plastic_phenoplus_totalNtwin(instance) + index_kappa = ns + nt + 2_pInt + ns + nt !location of kappa in plasticState - !***init calculation for given voxel - mprime_cut = 0.7_pReal !set by Dr.Bieler - dtaylor_cut = 1.0_pReal !set by Chen, quick test only + !***init calculation for given voxel + mprime_cut = 0.7_pReal !set by Dr.Bieler + dtaylor_cut = 1.0_pReal !set by Chen, quick test only - !***gather my orientation, F and slip systems - my_orientation = orientation(1:4, ipc, ip, el) - F0_me = F0(1:3, 1:3, ipc, ip, el) - Fe_me = Fe(1:3, 1:3, ipc, ip, el) - Fp_me = Fp(1:3, 1:3, ipc, ip, el) - slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) - slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) - !******calculate Taylor factor for me - !@note: we need teh - F_me = math_mul33x33(Fe_me,Fp_me) - E_me = 0.5*(math_mul33x33(math_transpose33(F_me), F_me) - math_identity2nd) !E = 0.5(F^tF-I) - vonStrain + !***gather my orientation, F and slip systems + my_orientation = orientation(1:4, ipc, ip, el) + F0_me = F0(1:3, 1:3, ipc, ip, el) + Fe_me = Fe(1:3, 1:3, ipc, ip, el) + Fp_me = Fp(1:3, 1:3, ipc, ip, el) + slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) + slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) + + !***check if all my neighbors have the same phase as me + vld_Nneighbors = 0 + PHASECHECK DO n_phasecheck = 1_pInt, Nneighbors + !******for each of my neighbor + neighbor_el = mesh_ipNeighborhood( 1, n_phasecheck, ip, el ) + neighbor_ip = mesh_ipNeighborhood( 2, n_phasecheck, ip, el ) + neighbor_ipc = 1 + neighbor_of = phasememberAt( neighbor_ipc, neighbor_ip, neighbor_el ) + neighbor_ph = phaseAt( neighbor_ipc, neighbor_ip, neighbor_el ) + IF (neighbor_ph == ph) THEN + vld_Nneighbors = vld_Nneighbors + 1_pInt + ENDIF + ENDDO PHASECHECK + + !***initialize kappa with 1.0 (assume no push-up) + plasticState(ph)%state(index_kappa+1_pInt:index_kappa+ns, of) = 1.0_pReal + + !***only calculate kappa for those inside the main phase + IF (vld_Nneighbors == Nneighbors) THEN + !******calculate Taylor factor for me + dF_me = math_mul33x33(Fe_me,Fp_me) - F0_me + dE_me = 0.5*(math_mul33x33(math_transpose33(dF_me), dF_me) - math_identity2nd(3)) !dE = 0.5(dF^tdF-I) + d_vonstrain = SQRT(2.0_pReal/3.0_pReal * math_mul33xx33(dE_me, dE_me)) + sum_gdot = 0.0_pReal + !go through my slip system to find the sum of gamma_dot + j = 0_pInt + slipFamilies: DO f = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f-1_pInt,ph)) !at which index starts my family + slipSystems: DO i = 1_pInt,plastic_phenoplus_Nslip(f,instance) + j = j+1_pInt + tau_slip = dot_product(Tstar_v(1:6, ipc, ip, el),lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) + sum_gdot = sum_gdot + & + plastic_phenoplus_gdot0_slip(instance)* & + ((abs(tau_slip)/(state(instance)%s_slip(j,of))) & + **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip) + ENDDO slipSystems + ENDDO slipFamilies + taylor_me = d_vonstrain/sum_gdot + + !***calculate delta_M (Taylor factor) between each neighbor and me + LOOPCALCTAYLOR: DO n_calcTaylor=1_pInt, Nneighbors + !******for each of my neighbor + neighbor_el = mesh_ipNeighborhood( 1, n_calcTaylor, ip, el ) + neighbor_ip = mesh_ipNeighborhood( 2, n_calcTaylor, ip, el ) + neighbor_ipc = 1 !It is ipc + neighbor_of = phasememberAt( neighbor_ipc, neighbor_ip, neighbor_el ) + neighbor_ph = phaseAt( neighbor_ipc, neighbor_ip, neighbor_el ) + neighbor_instance = phase_plasticityInstance( neighbor_ph ) + neighbor_tex = material_texture( 1,neighbor_ip, neighbor_el ) + neighbor_orientation = orientation( 1:4, neighbor_ipc, neighbor_ip, neighbor_el ) !ipc is always 1. + Fe_ne = Fe( 1:3, 1:3, neighbor_ipc, neighbor_ip, neighbor_el ) + Fp_ne = Fp( 1:3, 1:3, neighbor_ipc, neighbor_ip, neighbor_el ) + F0_ne = F0( 1:3, 1:3, neighbor_ipc, neighbor_ip, neighbor_el ) + !******calculate the Taylor factor + dF_ne = math_mul33x33(Fe_ne, Fp_ne) - F0_ne + dE_ne = 0.5*(math_mul33x33(math_transpose33(dF_ne), dF_ne) - math_identity2nd(3)) !dE = 0.5(dF^tdF-I) + d_vonstrain = SQRT(2.0_pReal/3.0_pReal * math_mul33xx33(dE_ne, dE_ne)) + sum_gdot = 0.0_pReal + !go through my neighbor slip system to calculate sum_gdot + j = 0_pInt + slipFamiliesNeighbor: DO f_ne = 1_pInt,lattice_maxNslipFamily + index_myFamily = sum(lattice_NslipSystem(1:f_ne-1_pInt,neighbor_ph)) ! at which index starts my family + slipSystemsNeighbor: DO i_ne = 1_pInt,plastic_phenopowerlaw_Nslip(f_ne,neighbor_instance) + j = j+1_pInt + tau_slip = dot_product(Tstar_v(1:6, neighbor_ipc, neighbor_ip, neighbor_el), + lattice_Sslip_v(1:6,1,index_myFamily+i_ne,neighbor_ph)) + sum_gdot = sum_gdot & + +plastic_phenopowerlaw_gdot0_slip(neighbor_instance) & + *((abs(tau_slip)/(state(neighbor_instance)%s_slip(j,neighbor_of))) & + **plastic_phenopowerlaw_n_slip(neighbor_instance))*sign(1.0_pReal,tau_slip) + ENDDO slipSystemsNeighbor + ENDDO slipFamiliesNeighbor + taylor_ne = d_vonstrain / sum_gdot + !******calculate Taylor difference + d_taylors(n_calcTaylor) = taylor_ne - taylor_me + ENDDO LOOPCALCTAYLOR + + !***Only perform necessary calculation if high contrast interface is detected + IF (max(d_taylors) > dtaylor_cut) THEN + !*****calculate kappa per slip system base + LOOPMYSLIP DO me_slip = 1_pInt, ns + ne_mprimes = 0.0_pReal !initialize max m' to 0 for all neighbors + LOOPMYNEIGHBORS DO n=1_pInt, Nneighbors + !*******only consider neighbor at the high contrast interface + IF (d_taylors(n) > dtaylor_cut) THEN + neighbor_el = mesh_ipNeighborhood( 1, n_calcTaylor, ip, el ) + neighbor_ip = mesh_ipNeighborhood( 2, n_calcTaylor, ip, el ) + neighbor_ipc = 1 !It is ipc + neighbor_of = phasememberAt( neighbor_ipc, neighbor_ip, neighbor_el ) + neighbor_ph = phaseAt( neighbor_ipc, neighbor_ip, neighbor_el ) + neighbor_instance = phase_plasticityInstance( neighbor_ph ) + neighbor_tex = material_texture( 1,neighbor_ip, neighbor_el ) + neighbor_orientation = orientation( 1:4, neighbor_ipc, neighbor_ip, neighbor_el ) !ipc is always 1. + absMisorientation = lattice_qDisorientation( my_orientation, & + neighbor_orientation, & + 0_pInt ) !no need for explicit calculation of symmetry + !*********go through neighbor slip system to calculate m' + LOOPNEIGHBORSLIP: DO ne_slip=1_pInt,ns + m_primes(ne_slip) = abs(math_mul3x3(slipNormal(1:3,me_slip), & + math_qRot(absMisorientation, slipNormal(1:3,ne_slip)))) & + *abs(math_mul3x3(slipDirect(1:3,me_slip), & + math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) + ENDDO LOOPNEIGHBORSLIP + ne_mprimes(n) = max(m_primes) + ENDIF + !*******check if one of the neighbor already can provide a kick for this slip system + IF ( max(ne_mprimes) > mprime_cut ) THEN + plasticState(ph)%state(index_kappa+me_slip, of) = 1.5_pReal + EXIT + ENDIF + ENDDO LOOPMYNEIGHBORS + ENDDO LOOPMYSLIP + ENDIF - !***loop into the geometry to figure out who is my closest neighbor - LOOPNEIGHBORS: DO n=1_pInt, Nneighbors - !******for each of my neighbor, calculate the Taylor factor - ne_taylor = 1.0 - !*********for the high contrast interface - IF (abs(taylor_ne - taylor_me) > dtaylor_cut) THEN - !********* gather neighbor orientation and slip systems - !********* calculate m' (need to loop through all my slip systems as well) - !********* if m'>mprime_cut kappa=1.5 else 1.0 - !****** - ELSE ENDIF - !***end of search - ENDDO LOOPNEIGHBORS - ! !***gather my accumulative shear from palsticState - ! FINDMYSHEAR: do j = 1_pInt,ns - ! me_acshear(j) = plasticState(ph)%state(offset_acshear_slip+j, of) - ! enddo FINDMYSHEAR - - ! !***gather my orientation and slip systems - ! my_orientation = orientation(1:4, ipc, ip, el) - ! slipNormal(1:3, 1:ns) = lattice_sn(1:3, 1:ns, ph) - ! slipDirect(1:3, 1:ns) = lattice_sd(1:3, 1:ns, ph) - ! kappa_max = plastic_phenoplus_kappa_max(instance) !maximum pushups allowed (READIN) ! !***calculate kappa between me and all my neighbors ! LOOPMYSLIP: DO me_slip=1_pInt,ns From 1e406169ec37620fc08f27428254cd8461c5a09c Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Fri, 15 Apr 2016 10:28:02 -0400 Subject: [PATCH 058/183] adding damping mechanism --- code/constitutive.f90 | 2 +- code/crystallite.f90 | 56 +++++++++++++++++++------------------- code/plastic_phenoplus.f90 | 48 ++++++++++++++++---------------- 3 files changed, 54 insertions(+), 52 deletions(-) diff --git a/code/constitutive.f90 b/code/constitutive.f90 index 6280ae457..7c1bf18b2 100644 --- a/code/constitutive.f90 +++ b/code/constitutive.f90 @@ -480,7 +480,7 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el, F0s,Fe Fes, & Fps - real(pReal), intent(in), dimension(6,:,:,:) :: & + real(pReal), intent(in), dimension(:,:,:,:) :: & Tstar_vs !< crystal orientations as quaternions ho = material_homog(ip,el) diff --git a/code/crystallite.f90 b/code/crystallite.f90 index 187eba697..f5e66b1c8 100644 --- a/code/crystallite.f90 +++ b/code/crystallite.f90 @@ -437,10 +437,10 @@ subroutine crystallite_init call constitutive_microstructure(crystallite_orientation, & ! pass orientation to constitutive module crystallite_Fe(1:3,1:3,c,i,e), & crystallite_Fp(1:3,1:3,c,i,e), & - c,i,e, - crystallite_F0, - crystallite_Fe, - crystallite_Fp, + c,i,e, & + crystallite_F0, & + crystallite_Fe, & + crystallite_Fp, & crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo enddo @@ -1718,10 +1718,10 @@ subroutine crystallite_integrateStateRK4() call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, - crystallite_F0, - crystallite_Fe, - crystallite_Fp, + g, i, e, & + crystallite_F0, & + crystallite_Fe, & + crystallite_Fp, & crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2048,10 +2048,10 @@ subroutine crystallite_integrateStateRKCK45() call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, - crystallite_F0, - crystallite_Fe, - crystallite_Fp, + g, i, e, & + crystallite_F0, & + crystallite_Fe, & + crystallite_Fp, & crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2272,10 +2272,10 @@ subroutine crystallite_integrateStateRKCK45() call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, - crystallite_F0, - crystallite_Fe, - crystallite_Fp, + g, i, e, & + crystallite_F0, & + crystallite_Fe, & + crystallite_Fp, & crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2511,10 +2511,10 @@ subroutine crystallite_integrateStateAdaptiveEuler() call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, - crystallite_F0, - crystallite_Fe, - crystallite_Fp, + g, i, e, & + crystallite_F0, & + crystallite_Fe, & + crystallite_Fp, & crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2859,10 +2859,10 @@ eIter = FEsolving_execElem(1:2) call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, - crystallite_F0, - crystallite_Fe, - crystallite_Fp, + g, i, e, & + crystallite_F0, & + crystallite_Fe, & + crystallite_Fp, & crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -3108,10 +3108,10 @@ subroutine crystallite_integrateStateFPI() call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, - crystallite_F0, - crystallite_Fe, - crystallite_Fp, + g, i, e, & + crystallite_F0, & + crystallite_Fe, & + crystallite_Fp, & crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states p = phaseAt(g,i,e) c = phasememberAt(g,i,e) diff --git a/code/plastic_phenoplus.f90 b/code/plastic_phenoplus.f90 index cf0cdd424..6e87b4160 100644 --- a/code/plastic_phenoplus.f90 +++ b/code/plastic_phenoplus.f90 @@ -793,6 +793,7 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar ph, & !my phase of, & !my spatial position in memory (offset) textureID, & !my texture + index_myFamily, & Nneighbors, & !number of neighbors (<= 6) vld_Nneighbors, & !number of my valid neighbors n, & !neighbor index (for iterating through all neighbors) @@ -814,21 +815,21 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar f,i,& !loop counter for me f_ne, i_ne !loop counter for neighbor - real(pReal) kappa_max, & ! - tmp_myshear_slip, & !temp storage for accumulative shear for me - mprime_cut, & !m' cutoff to consider neighboring effect + real(pReal) mprime_cut, & !m' cutoff to consider neighboring effect dtaylor_cut, & !threshold for determine high contrast interface using Taylor factor - avg_acshear_ne, & !the average accumulative shear from my neighbor + tau_slip, & !the average accumulative shear from my neighbor taylor_me, & !Taylor factor for me taylor_ne, & !Taylor factor for my current neighbor - d_vonstrain !von Mises delta strain (temp container) + d_vonstrain, & !von Mises delta strain (temp container) + sum_gdot !total shear rate for given material point real(pReal), dimension(3,3) :: & F0_me, & !my deformation gradient from last converged increment Fe_me, & !my elastic deformation gradient Fp_me, & !my plastic deformation gradient - dF_me, & !my deformation gradient change (delta) - dE_me, & !my Green Lagrangian strain tensor (delta) + dF_me, & !my deformation gradient change (delta) + dE_me, & !my Green Lagrangian strain tensor (delta) + F0_ne, & ! Fe_ne, & !elastic deformation gradient of my current neighbor Fp_ne, & !plastic deformation gradient of my current neighbor dF_ne, & !deformation gradient of my current neighbor @@ -874,7 +875,7 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar !***check if all my neighbors have the same phase as me vld_Nneighbors = 0 - PHASECHECK DO n_phasecheck = 1_pInt, Nneighbors + PHASECHECK: DO n_phasecheck = 1_pInt, Nneighbors !******for each of my neighbor neighbor_el = mesh_ipNeighborhood( 1, n_phasecheck, ip, el ) neighbor_ip = mesh_ipNeighborhood( 2, n_phasecheck, ip, el ) @@ -905,7 +906,7 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar tau_slip = dot_product(Tstar_v(1:6, ipc, ip, el),lattice_Sslip_v(1:6,1,index_myFamily+i,ph)) sum_gdot = sum_gdot + & plastic_phenoplus_gdot0_slip(instance)* & - ((abs(tau_slip)/(state(instance)%s_slip(j,of))) & + ((abs(tau_slip)/(plasticState(ph)%state(j,of))) & **plastic_phenoplus_n_slip(instance))*sign(1.0_pReal,tau_slip) ENDDO slipSystems ENDDO slipFamilies @@ -934,14 +935,14 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar j = 0_pInt slipFamiliesNeighbor: DO f_ne = 1_pInt,lattice_maxNslipFamily index_myFamily = sum(lattice_NslipSystem(1:f_ne-1_pInt,neighbor_ph)) ! at which index starts my family - slipSystemsNeighbor: DO i_ne = 1_pInt,plastic_phenopowerlaw_Nslip(f_ne,neighbor_instance) + slipSystemsNeighbor: DO i_ne = 1_pInt,plastic_phenoplus_Nslip(f_ne,neighbor_instance) j = j+1_pInt - tau_slip = dot_product(Tstar_v(1:6, neighbor_ipc, neighbor_ip, neighbor_el), + tau_slip = dot_product(Tstar_v(1:6, neighbor_ipc, neighbor_ip, neighbor_el), & lattice_Sslip_v(1:6,1,index_myFamily+i_ne,neighbor_ph)) sum_gdot = sum_gdot & - +plastic_phenopowerlaw_gdot0_slip(neighbor_instance) & - *((abs(tau_slip)/(state(neighbor_instance)%s_slip(j,neighbor_of))) & - **plastic_phenopowerlaw_n_slip(neighbor_instance))*sign(1.0_pReal,tau_slip) + +plastic_phenoplus_gdot0_slip(neighbor_instance) & + *((abs(tau_slip)/(plasticState(neighbor_ph)%state(j,neighbor_of))) & + **plastic_phenoplus_n_slip(neighbor_instance))*sign(1.0_pReal,tau_slip) ENDDO slipSystemsNeighbor ENDDO slipFamiliesNeighbor taylor_ne = d_vonstrain / sum_gdot @@ -950,11 +951,11 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar ENDDO LOOPCALCTAYLOR !***Only perform necessary calculation if high contrast interface is detected - IF (max(d_taylors) > dtaylor_cut) THEN + IF (maxval(d_taylors) > dtaylor_cut) THEN !*****calculate kappa per slip system base - LOOPMYSLIP DO me_slip = 1_pInt, ns + LOOPMYSLIP: DO me_slip = 1_pInt, ns ne_mprimes = 0.0_pReal !initialize max m' to 0 for all neighbors - LOOPMYNEIGHBORS DO n=1_pInt, Nneighbors + LOOPMYNEIGHBORS: DO n=1_pInt, Nneighbors !*******only consider neighbor at the high contrast interface IF (d_taylors(n) > dtaylor_cut) THEN neighbor_el = mesh_ipNeighborhood( 1, n_calcTaylor, ip, el ) @@ -975,14 +976,15 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar *abs(math_mul3x3(slipDirect(1:3,me_slip), & math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) ENDDO LOOPNEIGHBORSLIP - ne_mprimes(n) = max(m_primes) - ENDIF - !*******check if one of the neighbor already can provide a kick for this slip system - IF ( max(ne_mprimes) > mprime_cut ) THEN - plasticState(ph)%state(index_kappa+me_slip, of) = 1.5_pReal - EXIT + ne_mprimes(n) = maxval(m_primes) ENDIF ENDDO LOOPMYNEIGHBORS + !*******check if one of the neighbor already can provide a kick for this slip system + IF ( maxval(ne_mprimes) > mprime_cut ) THEN + plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal + 0.2_pReal*maxval(ne_mprimes) + ELSE + plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal - 0.1_pReal*maxval(ne_mprimes) + ENDIF ENDDO LOOPMYSLIP ENDIF From 62008cb4b4048037148e851e1c6726870afe2d15 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Fri, 15 Apr 2016 16:26:43 -0400 Subject: [PATCH 059/183] add support for prefix&suffix --- CMakeLists.txt | 11 ++++++----- build_FEM.sh | 4 ++++ build_spectral.sh | 7 +++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f76631a61..255c8a6ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -424,16 +424,17 @@ set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_FLAGS}" ) -# Finalizing -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") -set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") +# Finalizing, adding PREFIX and SUFFIX to compiler chain +set (CMAKE_Fortran_FLAGS_RELEASE "${DAMASK_PREFIX} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${DAMASK_SUFFIX}") +set (CMAKE_Fortran_FLAGS_DEBUG "${DAMASK_PREFIX} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${DAMASK_SUFFIX}") set (CMAKE_LINKER "${PETSC_LINKER}") + if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE - "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB}") + "${DAMASK_PREFIX} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB} ${DAMASK_SUFFIX}") else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE - "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") + "${DAMASK_PREFIX} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB} ${DAMASK_SUFFIX}") endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") diff --git a/build_FEM.sh b/build_FEM.sh index 56e26c45b..2333bc16c 100755 --- a/build_FEM.sh +++ b/build_FEM.sh @@ -26,6 +26,7 @@ cd FEM # PETSC_DIR | PETSC directory # DAMASK_V | DAMASK current revision # CMAKE_BUILD_TYPE | Default set to release (no debugging output) +# CMAKE_VERBOSE_MAKEFILE | [ON/OFF] toggle makefile verbose output # OPENMP | [ON/OFF] # OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] # DAMASK_DRIVER | [SPECTRAL, FEM] @@ -34,10 +35,13 @@ cd FEM cmake -D PETSC_DIR=${PETSC_DIR} \ -D DAMASK_V=${DAMASKVERSION} \ -D CMAKE_BUILD_TYPE=RELEASE \ + -D CMAKE_VERBOSE_MAKEFILE=OFF \ -D OPENMP=ON \ -D OPTIMIZATION=DEFENSIVE \ -D DAMASK_DRIVER=FEM \ -D DAMASK_INSTALL=${HOME}/bin \ + -D DAMASK_PREFIX="" \ + -D DAMASK_SUFFIX="-Wl,--verbose" \ ../.. echo diff --git a/build_spectral.sh b/build_spectral.sh index eb614f41c..0034554a5 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -36,17 +36,24 @@ cd $BUILDDIR # PETSC_DIR | PETSC directory # DAMASK_V | DAMASK current revision # CMAKE_BUILD_TYPE | Default set to release (no debugging output) +# CMAKE_VERBOSE_MAKEFILE | [ON/OFF] toggle makefile verbose output # OPENMP | [ON/OFF] # OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] # DAMASK_DRIVER | [SPECTRAL, FEM] # DAMASK_INSTALL | Directory to install binary output +# DAMASK_PREFIX | Compiler prefix +# DAMASK_SUFFIX | Compiler suffix, +# | e.g. DAMASK_SUFFIX="-Wl,--verbose" cmake -D PETSC_DIR=${PETSC_DIR} \ -D DAMASK_V=${DAMASKVERSION} \ -D CMAKE_BUILD_TYPE=RELEASE \ + -D CMAKE_VERBOSE_MAKEFILE=OFF \ -D OPENMP=ON \ -D OPTIMIZATION=DEFENSIVE \ -D DAMASK_DRIVER=SPECTRAL \ -D DAMASK_INSTALL=${HOME}/bin \ + -D DAMASK_PREFIX="" \ + -D DAMASK_SUFFIX="-Wl,--verbose" \ ../.. echo From a7c4cdaa2f8bff7051f635c2c7b3cc80ae576b63 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Mon, 18 Apr 2016 11:14:32 -0400 Subject: [PATCH 060/183] update cmake build system --- CMakeLists.txt | 29 ++++++++++++++++------------- build_spectral.sh | 8 ++++---- code/.gitattributes | 8 -------- code/.gitignore | 3 --- src/CMakeLists.txt | 8 ++++---- src/quit__genmod.f90 | 2 +- 6 files changed, 25 insertions(+), 33 deletions(-) delete mode 100644 code/.gitattributes delete mode 100644 code/.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index 255c8a6ff..6d802b18b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,12 @@ compilerc: linker: \t@echo \${LINKERNAME}") +# Find DAMASK version (DAMASK_V) in DAMASK_ROOT +find_program (CAT_EXECUTABLE NAMES cat) +execute_process(COMMAND ${CAT_EXECUTABLE} ../../VERSION + RESULT_VARIABLE DAMASK_VERSION_RETURN + OUTPUT_VARIABLE DAMASK_V + OUTPUT_STRIP_TRAILING_WHITESPACE) # CMake will execute each target in the ${petsc_config_makefile} # to acquire corresponding PETSc Variables. @@ -69,11 +75,11 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "extlibs" # //its version information is used to identify whether it is INTEL FORTRAN # //or GNU FORTRAN, # //e.g. for PETSc configured with INTEL FORTRAN compiler -# // >>${MPIEXEC} -v +# // >>${MPIFC} -v # // ifort version 14.0.3 --> This line is captured and parsed by CMake execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compilerf" - RESULT_VARIABLE MPIEXEC_RETURN - OUTPUT_VARIABLE MPIEXEC + RESULT_VARIABLE MPIFC_RETURN + OUTPUT_VARIABLE MPIFC OUTPUT_STRIP_TRAILING_WHITESPACE) # PETSc specified linker (MPIF90 + PETSc linking flags) execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "linker" @@ -95,14 +101,14 @@ foreach (exlib ${TMP_LIST}) set(PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} ${exlib}") endforeach(exlib) -set(CMAKE_Fortran_COMPILER "${MPIEXEC}") +set(CMAKE_Fortran_COMPILER "${MPIFC}") project (DAMASK Fortran) 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 FORTRAN MPI COMPILER:\n${MPIEXEC}\n" ) +message("***Found FORTRAN MPI COMPILER:\n${MPIFC}\n" ) # # https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F @@ -116,9 +122,9 @@ set (DAMASK_VERSION_MINOR ${DAMASK_V}) # Built-in options for DAMASK build system # -> can be overwritten from commandline/install_script option(OPENMP "Use OpenMP libaries for DAMASK" ON ) -option(OPTIMIZATION "DAMASK optimization level[NONE,DEFENSIVE,AGGRESSIVE,ULTRA]" "NONE") +option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) -option(FEM "Builb FEM solver for DAMASK" OFF ) +option(FEM "Build FEM solver for DAMASK" OFF ) # COMPILE VARIABLES add_definitions(-DDAMASKVERSION="${DAMASK_V}") @@ -148,7 +154,7 @@ endif() set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") -if ("${OPTIMIZATION}" STREQUAL "NONE") +if ("${OPTIMIZATION}" STREQUAL "OFF") set (OPTIMIZATION_ifort "-O0 -no-ip") set (OPTIMIZATION_gfortran "-O0" ) elseif ("${OPTIMIZATION}" STREQUAL "DEFENSIVE") @@ -157,9 +163,6 @@ elseif ("${OPTIMIZATION}" STREQUAL "DEFENSIVE") elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") #ToDo: this is not fully correct here, check old makefile set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") -elseif ("${OPTIMIZATION}" STREQUAL "ULTRA") - set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" - set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") else() set (OPTIMIZATION_ifort "-O2") set (OPTIMIZATION_gfortran "-O2") @@ -445,10 +448,10 @@ add_subdirectory(src) # INSTALL BUILT BINARIES if (SPECTRAL) - INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASKSpectral.exe + INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_spectral DESTINATION ${CMAKE_INSTALL_PREFIX}) elseif (FEM) - INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM.exe + INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(SPECTRAL) diff --git a/build_spectral.sh b/build_spectral.sh index 0034554a5..874f6d4a8 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -41,8 +41,8 @@ cd $BUILDDIR # OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] # DAMASK_DRIVER | [SPECTRAL, FEM] # DAMASK_INSTALL | Directory to install binary output -# DAMASK_PREFIX | Compiler prefix -# DAMASK_SUFFIX | Compiler suffix, +# BUILDCMD_PRE | Compiler prefix +# BUILDCMD_POST | Compiler suffix, # | e.g. DAMASK_SUFFIX="-Wl,--verbose" cmake -D PETSC_DIR=${PETSC_DIR} \ -D DAMASK_V=${DAMASKVERSION} \ @@ -52,8 +52,8 @@ cmake -D PETSC_DIR=${PETSC_DIR} \ -D OPTIMIZATION=DEFENSIVE \ -D DAMASK_DRIVER=SPECTRAL \ -D DAMASK_INSTALL=${HOME}/bin \ - -D DAMASK_PREFIX="" \ - -D DAMASK_SUFFIX="-Wl,--verbose" \ + -D BUILDCMD_PRE="" \ + -D BUILDCMD_POST="-Wl,--verbose" \ ../.. echo diff --git a/code/.gitattributes b/code/.gitattributes deleted file mode 100644 index 8035e26a7..000000000 --- a/code/.gitattributes +++ /dev/null @@ -1,8 +0,0 @@ -# from https://help.github.com/articles/dealing-with-line-endings/ -# -# always use LF, even if the files are edited on windows, they need to be compiled/used on unix -* text eol=lf - -# Denote all files that are truly binary and should not be modified. -*.png binary -*.jpg binary diff --git a/code/.gitignore b/code/.gitignore deleted file mode 100644 index bc33403b4..000000000 --- a/code/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -DAMASK_marc*.f90 -quit__genmod.f90 -*.marc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 553ad3836..25e56f4ed 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -168,8 +168,8 @@ if (FEM) add_library(DAMASK_FEM_DRIVER "DAMASK_FEM_driver.f90") target_link_libraries(DAMASK_FEM_DRIVER DAMASK_FEM_BASE) - add_executable(DAMASK_FEM.exe "DAMASK_FEM_driver.f90") - target_link_libraries(DAMASK_FEM.exe DAMASK_FEM_DRIVER) + add_executable(DAMASK_FEM "DAMASK_FEM_driver.f90") + target_link_libraries(DAMASK_FEM DAMASK_FEM_DRIVER) endif(FEM) if (SPECTRAL) @@ -193,6 +193,6 @@ if (SPECTRAL) target_link_libraries(DAMASK_EXE DAMASK_SPECTRAL_BASE) target_link_libraries(DAMASK_EXE DAMASK_SPECTRAL_MECH) - add_executable(DAMASKSpectral.exe "DAMASK_spectral.f90") - target_link_libraries(DAMASKSpectral.exe DAMASK_EXE) + add_executable(DAMASK_spectral "DAMASK_spectral.f90") + target_link_libraries(DAMASK_spectral DAMASK_EXE) endif(SPECTRAL) \ No newline at end of file diff --git a/src/quit__genmod.f90 b/src/quit__genmod.f90 index ef0a49bc0..61ef71f67 100644 --- a/src/quit__genmod.f90 +++ b/src/quit__genmod.f90 @@ -1,4 +1,4 @@ - !COMPILER-GENERATED INTERFACE MODULE: Thu Mar 3 12:28:23 2016 + !COMPILER-GENERATED INTERFACE MODULE: Mon Apr 18 09:43:53 2016 MODULE QUIT__genmod INTERFACE SUBROUTINE QUIT(STOP_ID) From 20bae5f91bacf44136bf7f6226eeda8f5a20d97c Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 18 Apr 2016 11:16:59 -0400 Subject: [PATCH 061/183] updating physics in pheno+ --- code/plastic_phenoplus.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/plastic_phenoplus.f90 b/code/plastic_phenoplus.f90 index 6e87b4160..22a816ff2 100644 --- a/code/plastic_phenoplus.f90 +++ b/code/plastic_phenoplus.f90 @@ -981,7 +981,7 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar ENDDO LOOPMYNEIGHBORS !*******check if one of the neighbor already can provide a kick for this slip system IF ( maxval(ne_mprimes) > mprime_cut ) THEN - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal + 0.2_pReal*maxval(ne_mprimes) + plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal + 0.5_pReal*maxval(ne_mprimes) ELSE plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal - 0.1_pReal*maxval(ne_mprimes) ENDIF From 247a6e36c3d8513782211e783bf63db9d0777750 Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Mon, 18 Apr 2016 18:32:08 -0400 Subject: [PATCH 062/183] auto extract PETSC_DIR from env --- CMakeLists.txt | 18 ++++++++++-------- Makefile | 22 +++++++++++----------- build_spectral.sh | 11 +++-------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d802b18b..1e4f830e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,10 +6,12 @@ cmake_minimum_required (VERSION 2.8.0 FATAL_ERROR) # //The rest of the script relies on it to figure out relative position #--------------------------------------------------------------------------------------- -# Find PETSc because the entire build will rely on it -if (NOT DEFINED PETSC_DIR) - message (FATAL_ERROR "PETSC_DIR is not found!") -endif (NOT DEFINED PETSC_DIR) +# Find PETSc from environment +set(PETSC_DIR $ENV{PETSC_DIR}) + +# if (NOT DEFINED PETSC_DIR) +# message (FATAL_ERROR "PETSC_DIR is not found!") +# endif (NOT DEFINED PETSC_DIR) exec_program(mktemp ARGS -d OUTPUT_VARIABLE PETSC_TEMP) @@ -428,16 +430,16 @@ set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortr set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_FLAGS}" ) # Finalizing, adding PREFIX and SUFFIX to compiler chain -set (CMAKE_Fortran_FLAGS_RELEASE "${DAMASK_PREFIX} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${DAMASK_SUFFIX}") -set (CMAKE_Fortran_FLAGS_DEBUG "${DAMASK_PREFIX} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${DAMASK_SUFFIX}") +set (CMAKE_Fortran_FLAGS_RELEASE "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") +set (CMAKE_Fortran_FLAGS_DEBUG "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") set (CMAKE_LINKER "${PETSC_LINKER}") if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE - "${DAMASK_PREFIX} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB} ${DAMASK_SUFFIX}") + "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE - "${DAMASK_PREFIX} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB} ${DAMASK_SUFFIX}") + "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") diff --git a/Makefile b/Makefile index 4e7286eff..561b13bd9 100755 --- a/Makefile +++ b/Makefile @@ -3,11 +3,15 @@ SHELL = /bin/sh # Makefile for the installation of DAMASK ######################################################################################## .PHONY: all -all: spectral marc processing +all: spectral FEM -.PHONY: spectral -spectral: - $(MAKE) DAMASK_spectral.exe -C src + +spectral: build + @if [ ! -d build/spectral ]; then mkdir build/spectral; fi + (cd build/spectral; cmake ../../ ;) + +build: + mkdir build .PHONY: FEM FEM: @@ -32,11 +36,7 @@ tidy: @$(MAKE) tidy -C src >/dev/null .PHONY: clean + + clean: - @$(MAKE) cleanDAMASK -C src >/dev/null - -.PHONY: install -install: - @./installation/symlink_Code.py ${MAKEFLAGS} - @./installation/symlink_Processing.py ${MAKEFLAGS} - + rm -rvf build diff --git a/build_spectral.sh b/build_spectral.sh index 874f6d4a8..2c57830be 100755 --- a/build_spectral.sh +++ b/build_spectral.sh @@ -11,7 +11,6 @@ else DAMASK_ROOT=${STAT##* } fi -DAMASKVERSION=$(cat VERSION) BUILDROOT=$DAMASK_ROOT/build BUILDDIR=spectral @@ -34,7 +33,6 @@ cd $BUILDDIR ## # CMake call # PETSC_DIR | PETSC directory -# DAMASK_V | DAMASK current revision # CMAKE_BUILD_TYPE | Default set to release (no debugging output) # CMAKE_VERBOSE_MAKEFILE | [ON/OFF] toggle makefile verbose output # OPENMP | [ON/OFF] @@ -45,7 +43,6 @@ cd $BUILDDIR # BUILDCMD_POST | Compiler suffix, # | e.g. DAMASK_SUFFIX="-Wl,--verbose" cmake -D PETSC_DIR=${PETSC_DIR} \ - -D DAMASK_V=${DAMASKVERSION} \ -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_VERBOSE_MAKEFILE=OFF \ -D OPENMP=ON \ @@ -56,8 +53,6 @@ cmake -D PETSC_DIR=${PETSC_DIR} \ -D BUILDCMD_POST="-Wl,--verbose" \ ../.. -echo -echo "Please move to the build directory using" -echo " cd build/spectral" -echo "Using the following command to build DAMASK spectral solver" -echo " make clean all install" +echo "Start compiling DAMASK_spectral" +make +make install \ No newline at end of file From 2135aaa83c6f478715f2eb8a9080226fdb337c3f Mon Sep 17 00:00:00 2001 From: Chen Zhang Date: Tue, 19 Apr 2016 14:52:36 -0400 Subject: [PATCH 063/183] try to prevent make msg mess up cmake config --- CMakeLists.txt | 46 +++++++++++++++++++++------------------------- Makefile | 14 ++++++++++---- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e4f830e5..ffa940d37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,23 +1,28 @@ ######################################################################################## # CMAKE for build the Material subroutine for BVP solution ######################################################################################## +project (DAMASK Fortran) cmake_minimum_required (VERSION 2.8.0 FATAL_ERROR) -# PROJECT DEFINITION HAS TO BE ON TOP -# //The rest of the script relies on it to figure out relative position #--------------------------------------------------------------------------------------- -# Find PETSc from environment +# Find PETSc from system environment set(PETSC_DIR $ENV{PETSC_DIR}) +if ("${PETSC_DIR}" STREQUAL "") + message (FATAL_ERROR "PETSC_DIR is not defined in system!") +endif ("${PETSC_DIR}" STREQUAL "") -# if (NOT DEFINED PETSC_DIR) -# message (FATAL_ERROR "PETSC_DIR is not found!") -# endif (NOT DEFINED PETSC_DIR) - -exec_program(mktemp ARGS -d OUTPUT_VARIABLE PETSC_TEMP) +# Find DAMASK version (DAMASK_V) in DAMASK_ROOT +find_program (CAT_EXECUTABLE NAMES cat) +execute_process(COMMAND ${CAT_EXECUTABLE} ../../VERSION + RESULT_VARIABLE DAMASK_VERSION_RETURN + OUTPUT_VARIABLE DAMASK_V + OUTPUT_STRIP_TRAILING_WHITESPACE) # BRUTAL FORCE TO FIND THE VARIABLES DEFINED IN PETSC # ref: # https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake +exec_program(mktemp ARGS -d OUTPUT_VARIABLE PETSC_TEMP) + set(petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") set(petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) # Generate a temporary makerfile to probe the PETSc configuration @@ -34,42 +39,30 @@ INCLUDE_DIRS := \${PETSC_FC_INCLUDES} LIBRARIES := \${PETSC_WITH_EXTERNAL_LIB} COMPILERF ?= \${FC} LINKERNAME ?= \${FLINKER} - includes: \t@echo \${INCLUDE_DIRS} - extlibs: \t@echo \${LIBRARIES} - compilerf: \t@echo \${COMPILERF} - compilerc: \t@echo \${COMPILERC} - linker: \t@echo \${LINKERNAME}") -# Find DAMASK version (DAMASK_V) in DAMASK_ROOT -find_program (CAT_EXECUTABLE NAMES cat) -execute_process(COMMAND ${CAT_EXECUTABLE} ../../VERSION - RESULT_VARIABLE DAMASK_VERSION_RETURN - OUTPUT_VARIABLE DAMASK_V - OUTPUT_STRIP_TRAILING_WHITESPACE) - # CMake will execute each target in the ${petsc_config_makefile} # to acquire corresponding PETSc Variables. # The include path and linking libraries in PETSc usually contains # duplicated entries, which is cleaned up later using CMake list. find_program (MAKE_EXECUTABLE NAMES make gmake) # Find the PETSc includes directory settings -execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "includes" +execute_process(COMMAND ${MAKE_EXECUTABLE} -f --no-print-directory ${petsc_config_makefile} "includes" RESULT_VARIABLE PETSC_INCLUDES_RETURN 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} -f ${petsc_config_makefile} "extlibs" +execute_process(COMMAND ${MAKE_EXECUTABLE} -f --no-print-directory ${petsc_config_makefile} "extlibs" RESULT_VARIABLE PETSC_EXTERNAL_LIB_RETURN OUTPUT_VARIABLE petsc_external_lib OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -79,12 +72,12 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "extlibs" # //e.g. for PETSc configured with INTEL FORTRAN compiler # // >>${MPIFC} -v # // ifort version 14.0.3 --> This line is captured and parsed by CMake -execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "compilerf" +execute_process(COMMAND ${MAKE_EXECUTABLE} -f --no-print-directory ${petsc_config_makefile} "compilerf" RESULT_VARIABLE MPIFC_RETURN OUTPUT_VARIABLE MPIFC OUTPUT_STRIP_TRAILING_WHITESPACE) # PETSc specified linker (MPIF90 + PETSc linking flags) -execute_process(COMMAND ${MAKE_EXECUTABLE} -f ${petsc_config_makefile} "linker" +execute_process(COMMAND ${MAKE_EXECUTABLE} -f --no-print-directory ${petsc_config_makefile} "linker" RESULT_VARIABLE PETSC_LINKER_RETURN OUTPUT_VARIABLE PETSC_LINKER OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -104,7 +97,7 @@ foreach (exlib ${TMP_LIST}) endforeach(exlib) set(CMAKE_Fortran_COMPILER "${MPIFC}") -project (DAMASK Fortran) + message("***Found PETSC_DIR:\n${PETSC_DIR}\n" ) message("***Found PETSC_INCLUDES:\n${PETSC_INCLUDES}\n" ) @@ -127,6 +120,9 @@ option(OPENMP "Use OpenMP libaries for DAMASK" option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) option(FEM "Build FEM solver for DAMASK" OFF ) +option(BUILDCMD_PRE "Prefix for build CMD" "" ) +option(BUILDCMD_POST "Postfix for build CMD" "" ) + # COMPILE VARIABLES add_definitions(-DDAMASKVERSION="${DAMASK_V}") diff --git a/Makefile b/Makefile index 561b13bd9..efef3aa6a 100755 --- a/Makefile +++ b/Makefile @@ -6,12 +6,18 @@ SHELL = /bin/sh all: spectral FEM -spectral: build - @if [ ! -d build/spectral ]; then mkdir build/spectral; fi - (cd build/spectral; cmake ../../ ;) +spectral: build/spectral + @(cd build/spectral; make ) + + +build/spectral: build + @mkdir build/spectral + @(cd build/spectral; cmake -DDAMASK_DRIVER=SPECTRAL ../..;) + build: - mkdir build + @mkdir build + .PHONY: FEM FEM: From 6ce268498eb20942c3d465b3f861bb4786035c3b Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 19 Apr 2016 15:11:48 -0400 Subject: [PATCH 064/183] fix make recursive call problem --- CMakeLists.txt | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ffa940d37..bc5363b59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,6 @@ ######################################################################################## # CMAKE for build the Material subroutine for BVP solution ######################################################################################## -project (DAMASK Fortran) cmake_minimum_required (VERSION 2.8.0 FATAL_ERROR) #--------------------------------------------------------------------------------------- @@ -56,13 +55,13 @@ linker: # duplicated entries, which is cleaned up later using CMake list. find_program (MAKE_EXECUTABLE NAMES make gmake) # Find the PETSc includes directory settings -execute_process(COMMAND ${MAKE_EXECUTABLE} -f --no-print-directory ${petsc_config_makefile} "includes" +execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "includes" RESULT_VARIABLE PETSC_INCLUDES_RETURN 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} -f --no-print-directory ${petsc_config_makefile} "extlibs" +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) @@ -72,12 +71,12 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} -f --no-print-directory ${petsc_confi # //e.g. for PETSc configured with INTEL FORTRAN compiler # // >>${MPIFC} -v # // ifort version 14.0.3 --> This line is captured and parsed by CMake -execute_process(COMMAND ${MAKE_EXECUTABLE} -f --no-print-directory ${petsc_config_makefile} "compilerf" +execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "compilerf" RESULT_VARIABLE MPIFC_RETURN OUTPUT_VARIABLE MPIFC OUTPUT_STRIP_TRAILING_WHITESPACE) # PETSc specified linker (MPIF90 + PETSc linking flags) -execute_process(COMMAND ${MAKE_EXECUTABLE} -f --no-print-directory ${petsc_config_makefile} "linker" +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) @@ -97,7 +96,7 @@ foreach (exlib ${TMP_LIST}) endforeach(exlib) set(CMAKE_Fortran_COMPILER "${MPIFC}") - +project (DAMASK Fortran) message("***Found PETSC_DIR:\n${PETSC_DIR}\n" ) message("***Found PETSC_INCLUDES:\n${PETSC_INCLUDES}\n" ) @@ -426,16 +425,16 @@ set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortr set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_FLAGS}" ) # Finalizing, adding PREFIX and SUFFIX to compiler chain -set (CMAKE_Fortran_FLAGS_RELEASE "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") -set (CMAKE_Fortran_FLAGS_DEBUG "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") +set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") set (CMAKE_LINKER "${PETSC_LINKER}") if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE - "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") + "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB}") else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE - "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") + "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") From 35ab12e8f91ba9fe60b7b1e2970db4f307053149 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 19 Apr 2016 15:45:24 -0400 Subject: [PATCH 065/183] part of fortran flags is still missing --- CMakeLists.txt | 71 +++++++++++++++++++++++++++++++++++++------------- Makefile | 4 +-- 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc5363b59..12c05db7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,9 +119,6 @@ option(OPENMP "Use OpenMP libaries for DAMASK" option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) option(FEM "Build FEM solver for DAMASK" OFF ) -option(BUILDCMD_PRE "Prefix for build CMD" "" ) -option(BUILDCMD_POST "Postfix for build CMD" "" ) - # COMPILE VARIABLES add_definitions(-DDAMASKVERSION="${DAMASK_V}") @@ -146,7 +143,7 @@ elseif ("${DAMASK_DRIVER}" STREQUAL "FEM") set (FEM ON ) add_definitions(-DFEM) set (SPECTRAL OFF) -endif() +endif("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") @@ -160,10 +157,10 @@ elseif ("${OPTIMIZATION}" STREQUAL "DEFENSIVE") elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") #ToDo: this is not fully correct here, check old makefile set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") -else() +else("${OPTIMIZATION}" STREQUAL "OFF") set (OPTIMIZATION_ifort "-O2") set (OPTIMIZATION_gfortran "-O2") -endif() +endif("${OPTIMIZATION}" STREQUAL "OFF") ################################################################################################### @@ -198,7 +195,7 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") if (OPENMP) set (OPENMP_FLAG "-openmp -openmp-report0 -parallel") - endif() + endif(OPENMP) if ("${OPTIMIZATION}" STREQUAL "OFF") set (OPTIMIZATION_FLAG "-O0 -no-ip") @@ -424,18 +421,56 @@ set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_FLAGS}" ) -# Finalizing, adding PREFIX and SUFFIX to compiler chain -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") -set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") -set (CMAKE_LINKER "${PETSC_LINKER}") +# Try to add PREFIX and SUFFIX to compiler chain +if (DEFINED BUILDCMD_PRE AND DEFINED BUILDCMD_POST) + set (CMAKE_Fortran_FLAGS_RELEASE "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") + set (CMAKE_Fortran_FLAGS_DEBUG "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") + set (CMAKE_LINKER "${PETSC_LINKER}") -if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB}") -else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") -endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") + else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") + endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") +elseif(NOT DEFINED BUILDCMD_PRE AND DEFINED BUILDCMD_POST) + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") + set (CMAKE_LINKER "${PETSC_LINKER}") + + if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") + else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") + endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") +elseif(DEFINED BUILDCMD_PRE AND NOT DEFINED BUILDCMD_POST) + set (CMAKE_Fortran_FLAGS_RELEASE "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") + set (CMAKE_Fortran_FLAGS_DEBUG "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") + set (CMAKE_LINKER "${PETSC_LINKER}") + + if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB}") + else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") + endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") +else(DEFINED BUILDCMD_PRE AND DEFINED BUILDCMD_POST) + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") + set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") + set (CMAKE_LINKER "${PETSC_LINKER}") + + if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB}") + else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") + endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") +endif(DEFINED BUILDCMD_PRE AND DEFINED BUILDCMD_POST) message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") message("***LINK FLAGS:\n${CMAKE_EXE_LINKER_FLAGS_RELEASE}\n") diff --git a/Makefile b/Makefile index efef3aa6a..99650f96b 100755 --- a/Makefile +++ b/Makefile @@ -7,12 +7,12 @@ all: spectral FEM spectral: build/spectral - @(cd build/spectral; make ) + @(cd build/spectral; ) build/spectral: build @mkdir build/spectral - @(cd build/spectral; cmake -DDAMASK_DRIVER=SPECTRAL ../..;) + @(cd build/spectral; cmake -Wno-dev -DCMAKE_VERBOSE_MAKEFILE=OFF -DOPENMP=ON -DOPTIMIZATION=DEFENSIVE -DDAMASK_DRIVER=SPECTRAL ../..;) build: From c6d8d42b4d325eb637d80f00e4357187cb4ff7b8 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 19 Apr 2016 16:04:13 -0400 Subject: [PATCH 066/183] now it is possible to call cmake from make --- CMakeLists.txt | 8 +++++++- Makefile | 37 +++++++++---------------------------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 12c05db7c..8444efb75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,6 +120,10 @@ option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) option(FEM "Build FEM solver for DAMASK" OFF ) +if (NOT DEFINED CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif(NOT DEFINED CMAKE_BUILD_TYPE) + # COMPILE VARIABLES add_definitions(-DDAMASKVERSION="${DAMASK_V}") add_definitions(-DPETSc) @@ -139,10 +143,12 @@ if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") set (SPECTRAL ON ) add_definitions(-DSpectral) set (FEM OFF) + message("***Confiugring Spectral Solver") elseif ("${DAMASK_DRIVER}" STREQUAL "FEM") set (FEM ON ) add_definitions(-DFEM) set (SPECTRAL OFF) + message("***Confiugring FEM Solver") endif("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) @@ -473,7 +479,7 @@ else(DEFINED BUILDCMD_PRE AND DEFINED BUILDCMD_POST) endif(DEFINED BUILDCMD_PRE AND DEFINED BUILDCMD_POST) message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") -message("***LINK FLAGS:\n${CMAKE_EXE_LINKER_FLAGS_RELEASE}\n") +message("***LINKER:\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") # MOVE to SOURCE DIRECTORY for BUILDING add_subdirectory(src) diff --git a/Makefile b/Makefile index 99650f96b..c9b07f12c 100755 --- a/Makefile +++ b/Makefile @@ -5,44 +5,25 @@ SHELL = /bin/sh .PHONY: all all: spectral FEM - spectral: build/spectral - @(cd build/spectral; ) - + @(cd build/spectral; make; make install;) build/spectral: build @mkdir build/spectral - @(cd build/spectral; cmake -Wno-dev -DCMAKE_VERBOSE_MAKEFILE=OFF -DOPENMP=ON -DOPTIMIZATION=DEFENSIVE -DDAMASK_DRIVER=SPECTRAL ../..;) + @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=SPECTRAL ../..;) - -build: +build: bin @mkdir build +bin: + @mkdir bin -.PHONY: FEM -FEM: - $(MAKE) DAMASK_FEM.exe -C src +FEM: build/FEM + @(cd build/FEM; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=FEM ../..;) -.PHONY: marc -marc: - @./installation/mods_MarcMentat/apply_DAMASK_modifications.sh ${MAKEFLAGS} - -.PHONY: processing -processing: - @if hash cython 2>/dev/null; then \ - cd ./lib/damask; \ - CC=gcc python setup_corientation.py build_ext --inplace; \ - rm -rv build; \ - rm *.c; \ - fi - @./installation/compile_CoreModule.py ${MAKEFLAGS} - -.PHONY: tidy -tidy: - @$(MAKE) tidy -C src >/dev/null +build/FEM: build + @mkdir build .PHONY: clean - - clean: rm -rvf build From b00b8e82f67a2983b128d46ba4b339a9c88f9708 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 19 Apr 2016 16:33:46 -0400 Subject: [PATCH 067/183] remove obsolete build scripts --- build_FEM.sh | 51 ----------------------------------------- build_marc.sh | 0 build_spectral.sh | 58 ----------------------------------------------- 3 files changed, 109 deletions(-) delete mode 100755 build_FEM.sh delete mode 100644 build_marc.sh delete mode 100755 build_spectral.sh diff --git a/build_FEM.sh b/build_FEM.sh deleted file mode 100755 index 2333bc16c..000000000 --- a/build_FEM.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -cat README -echo -echo "Building FEM solver with ${FC}" -DAMASKVERSION=$(cat VERSION) - -# prepare building directory -# structure: -# BUILD_DIR -# |-BUILD_SPECTRAL -# |-BUILD_FEM -# |-BUILD_MARC -if [ ! -d build ]; then - mkdir build -fi -cd build -if [ -d FEM ] ; then - rm -rf FEM -fi -mkdir FEM -cd FEM - -## -# CMake call -# PETSC_DIR | PETSC directory -# DAMASK_V | DAMASK current revision -# CMAKE_BUILD_TYPE | Default set to release (no debugging output) -# CMAKE_VERBOSE_MAKEFILE | [ON/OFF] toggle makefile verbose output -# OPENMP | [ON/OFF] -# OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] -# DAMASK_DRIVER | [SPECTRAL, FEM] -# DAMASK_INSTALL | Directory to install binary output -# INSTALL_PROCESSING | Build supporting pre/post processing scripts -cmake -D PETSC_DIR=${PETSC_DIR} \ - -D DAMASK_V=${DAMASKVERSION} \ - -D CMAKE_BUILD_TYPE=RELEASE \ - -D CMAKE_VERBOSE_MAKEFILE=OFF \ - -D OPENMP=ON \ - -D OPTIMIZATION=DEFENSIVE \ - -D DAMASK_DRIVER=FEM \ - -D DAMASK_INSTALL=${HOME}/bin \ - -D DAMASK_PREFIX="" \ - -D DAMASK_SUFFIX="-Wl,--verbose" \ - ../.. - -echo -echo "Please move to the build directory using" -echo " cd build/FEM" -echo "Using the following command to build DAMASK spectral solver" -echo " make clean all install" diff --git a/build_marc.sh b/build_marc.sh deleted file mode 100644 index e69de29bb..000000000 diff --git a/build_spectral.sh b/build_spectral.sh deleted file mode 100755 index 2c57830be..000000000 --- a/build_spectral.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - -cat README -echo - -if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == 'linux' ]; then - DAMASK_ROOT=$(readlink -f "`dirname $BASH_SOURCE`") -else - [[ "${BASH_SOURCE::1}" == "/" ]] && BASE="" || BASE="`pwd`/" - STAT=$(stat "`dirname $BASE$BASH_SOURCE`") - DAMASK_ROOT=${STAT##* } -fi - -BUILDROOT=$DAMASK_ROOT/build -BUILDDIR=spectral - -# prepare building directory -# structure: -# BUILD_DIR -# |-BUILD_SPECTRAL -# |-BUILD_FEM -# |-BUILD_MARC -if [ ! -d $BUILDROOT ]; then - mkdir $BUILDROOT -fi -cd $BUILDROOT -if [ -d $BUILDDIR ] ; then - rm -rf $BUILDDIR -fi -mkdir $BUILDDIR -cd $BUILDDIR - -## -# CMake call -# PETSC_DIR | PETSC directory -# CMAKE_BUILD_TYPE | Default set to release (no debugging output) -# CMAKE_VERBOSE_MAKEFILE | [ON/OFF] toggle makefile verbose output -# OPENMP | [ON/OFF] -# OPTIMIZATION | [OFF,DEFENSIVE,AGGRESSIVE,ULTRA] -# DAMASK_DRIVER | [SPECTRAL, FEM] -# DAMASK_INSTALL | Directory to install binary output -# BUILDCMD_PRE | Compiler prefix -# BUILDCMD_POST | Compiler suffix, -# | e.g. DAMASK_SUFFIX="-Wl,--verbose" -cmake -D PETSC_DIR=${PETSC_DIR} \ - -D CMAKE_BUILD_TYPE=RELEASE \ - -D CMAKE_VERBOSE_MAKEFILE=OFF \ - -D OPENMP=ON \ - -D OPTIMIZATION=DEFENSIVE \ - -D DAMASK_DRIVER=SPECTRAL \ - -D DAMASK_INSTALL=${HOME}/bin \ - -D BUILDCMD_PRE="" \ - -D BUILDCMD_POST="-Wl,--verbose" \ - ../.. - -echo "Start compiling DAMASK_spectral" -make -make install \ No newline at end of file From 13a9e49b3986afc6f2704b457fcf0443657f041c Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 20 Apr 2016 08:26:20 -0400 Subject: [PATCH 068/183] fix FEM build target --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c9b07f12c..0127d9d56 100755 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ SHELL = /bin/sh all: spectral FEM spectral: build/spectral - @(cd build/spectral; make; make install;) + @(cd build/spectral; make -s all install;) build/spectral: build @mkdir build/spectral @@ -19,10 +19,11 @@ bin: @mkdir bin FEM: build/FEM - @(cd build/FEM; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=FEM ../..;) + @(cd build/FEM; make -s all install;) build/FEM: build @mkdir build + @(cd build/FEM; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=FEM ../..;) .PHONY: clean clean: From efc65f86b13104c660919a070efdde878c157fc1 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 20 Apr 2016 08:39:40 -0400 Subject: [PATCH 069/183] further suppress message when using make to build spectral/fem solver --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 0127d9d56..7ed9a5131 100755 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ SHELL = /bin/sh all: spectral FEM spectral: build/spectral - @(cd build/spectral; make -s all install;) + @(cd build/spectral; make --no-print-directory -ws all install;) build/spectral: build @mkdir build/spectral @@ -19,7 +19,7 @@ bin: @mkdir bin FEM: build/FEM - @(cd build/FEM; make -s all install;) + @(cd build/FEM; make --no-print-directory -ws all install;) build/FEM: build @mkdir build From aa65425c9aac409da1b77bc834ea92291c1ef863 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 20 Apr 2016 09:31:00 -0400 Subject: [PATCH 070/183] tmp save before switch --- CMakeLists.txt | 18 +++++++++--------- Makefile | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8444efb75..a5e021a2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,13 +10,6 @@ if ("${PETSC_DIR}" STREQUAL "") message (FATAL_ERROR "PETSC_DIR is not defined in system!") endif ("${PETSC_DIR}" STREQUAL "") -# Find DAMASK version (DAMASK_V) in DAMASK_ROOT -find_program (CAT_EXECUTABLE NAMES cat) -execute_process(COMMAND ${CAT_EXECUTABLE} ../../VERSION - RESULT_VARIABLE DAMASK_VERSION_RETURN - OUTPUT_VARIABLE DAMASK_V - OUTPUT_STRIP_TRAILING_WHITESPACE) - # BRUTAL FORCE TO FIND THE VARIABLES DEFINED IN PETSC # ref: # https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake @@ -98,6 +91,13 @@ endforeach(exlib) set(CMAKE_Fortran_COMPILER "${MPIFC}") project (DAMASK Fortran) +# Find DAMASK version (DAMASK_V) in DAMASK_ROOT +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) + 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") @@ -143,12 +143,12 @@ if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") set (SPECTRAL ON ) add_definitions(-DSpectral) set (FEM OFF) - message("***Confiugring Spectral Solver") + message("***Confiugring Spectral Solver\n") elseif ("${DAMASK_DRIVER}" STREQUAL "FEM") set (FEM ON ) add_definitions(-DFEM) set (SPECTRAL OFF) - message("***Confiugring FEM Solver") + message("***Confiugring FEM Solver\n") endif("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) diff --git a/Makefile b/Makefile index 7ed9a5131..1130f36ad 100755 --- a/Makefile +++ b/Makefile @@ -28,3 +28,5 @@ build/FEM: build .PHONY: clean clean: rm -rvf build + rm -rvf testing + rm -rvf bin From 3d0fe2391991d61760b880f22bc93eb791e51e0f Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 20 Apr 2016 12:31:28 -0400 Subject: [PATCH 071/183] tmp store before switch --- src/quit__genmod.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quit__genmod.f90 b/src/quit__genmod.f90 index 61ef71f67..62466058e 100644 --- a/src/quit__genmod.f90 +++ b/src/quit__genmod.f90 @@ -1,4 +1,4 @@ - !COMPILER-GENERATED INTERFACE MODULE: Mon Apr 18 09:43:53 2016 + !COMPILER-GENERATED INTERFACE MODULE: Wed Apr 20 11:10:29 2016 MODULE QUIT__genmod INTERFACE SUBROUTINE QUIT(STOP_ID) From 137706fa2e2118d5fffee5e5714a8421458600be Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 20 Apr 2016 15:01:02 -0400 Subject: [PATCH 072/183] modify makefile to support cleanup for testing build --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 1130f36ad..5c4caa4a5 100755 --- a/Makefile +++ b/Makefile @@ -27,6 +27,6 @@ build/FEM: build .PHONY: clean clean: - rm -rvf build - rm -rvf testing - rm -rvf bin + rm -rvf build # standard build directory + rm -rvf testing # for testing build (testing script in PRIVATE) + rm -rvf bin # default binary store location From 45872e840f064e6745f66ab5466923edccd9dbb3 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Thu, 21 Apr 2016 13:59:07 -0400 Subject: [PATCH 073/183] change default installation dir to home/bin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5c4caa4a5..f0c19b683 100755 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ spectral: build/spectral build/spectral: build @mkdir build/spectral - @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=SPECTRAL ../..;) + @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=SPECTRAL -D DAMASK_INSTALL=${HOME}/bin ../..;) build: bin @mkdir build From 4029346aeddc96cfccc74cb24ac014e76277eae2 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Thu, 21 Apr 2016 14:07:20 -0400 Subject: [PATCH 074/183] remove outdated code in comment --- src/plastic_phenoplus.f90 | 71 --------------------------------------- 1 file changed, 71 deletions(-) diff --git a/src/plastic_phenoplus.f90 b/src/plastic_phenoplus.f90 index 22a816ff2..b12d476ab 100644 --- a/src/plastic_phenoplus.f90 +++ b/src/plastic_phenoplus.f90 @@ -990,77 +990,6 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar ENDIF - - ! !***calculate kappa between me and all my neighbors - ! LOOPMYSLIP: DO me_slip=1_pInt,ns - ! vld_Nneighbors = Nneighbors - ! tmp_myshear_slip = me_acshear(me_slip) - ! tmp_mprime = 0.0_pReal !highest m' from all neighbors - ! tmp_acshear = 0.0_pReal !accumulative shear from highest m' - - ! !***go through my neighbors to find highest m' - ! LOOPNEIGHBORS: DO n=1_pInt,Nneighbors - ! neighbor_el = mesh_ipNeighborhood(1,n,ip,el) - ! neighbor_ip = mesh_ipNeighborhood(2,n,ip,el) - ! neighbor_n = 1 !It is ipc - ! neighbor_of = phasememberAt( neighbor_n, neighbor_ip, neighbor_el) - ! neighbor_ph = phaseAt( neighbor_n, neighbor_ip, neighbor_el) - ! neighbor_tex = material_texture(1,neighbor_ip,neighbor_el) - ! neighbor_orientation = orientation(1:4, neighbor_n, neighbor_ip, neighbor_el) !ipc is always 1. - ! absMisorientation = lattice_qDisorientation(my_orientation, & - ! neighbor_orientation, & - ! 0_pInt) !no need for explicit calculation of symmetry - - ! !***find the accumulative shear for this neighbor - ! LOOPFINDNEISHEAR: DO ne_slip_ac=1_pInt, ns - ! ne_acshear(ne_slip_ac) = plasticState(ph)%state(offset_acshear_slip+ne_slip_ac, & - ! neighbor_of) - ! ENDDO LOOPFINDNEISHEAR - - ! !***calculate the average accumulative shear and use it as cutoff - ! avg_acshear_ne = SUM(ne_acshear)/ns - - ! !*** - ! IF (ph==neighbor_ph) THEN - ! !***walk through all the - ! LOOPNEIGHBORSLIP: DO ne_slip=1_pInt,ns - ! !***only consider slip system that is active (above average accumulative shear) - ! IF (ne_acshear(ne_slip) > avg_acshear_ne) THEN - ! m_primes(ne_slip) = abs(math_mul3x3(slipNormal(1:3,me_slip), & - ! math_qRot(absMisorientation, slipNormal(1:3,ne_slip)))) & - ! *abs(math_mul3x3(slipDirect(1:3,me_slip), & - ! math_qRot(absMisorientation, slipDirect(1:3,ne_slip)))) - ! !***find the highest m' and corresponding accumulative shear - ! IF (m_primes(ne_slip) > tmp_mprime) THEN - ! tmp_mprime = m_primes(ne_slip) - ! tmp_acshear = ne_acshear(ne_slip) - ! ENDIF - ! ENDIF - ! ENDDO LOOPNEIGHBORSLIP - - ! ELSE - ! ne_mprimes(n) = 0.0_pReal - ! vld_Nneighbors = vld_Nneighbors - 1_pInt - ! ENDIF - - ! ENDDO LOOPNEIGHBORS - - ! !***check if this element close to rim - ! IF (vld_Nneighbors < Nneighbors) THEN - ! !***rim voxel, no modification allowed - ! plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal - ! ELSE - ! !***patch voxel, started to calculate push up factor for gamma_dot - ! IF ((tmp_mprime > mprime_cut) .AND. (tmp_acshear > tmp_myshear_slip)) THEN - ! plasticState(ph)%state(index_kappa+me_slip, of) = 1.5_pReal - ! ELSE - ! !***minimum damping factor is 0.5 - ! plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal - ! ENDIF - ! ENDIF - - ! ENDDO LOOPMYSLIP - end subroutine plastic_phenoplus_microstructure From 5fe177e43ba0e72228fabe0a9b6dccf6d64ae3b1 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 25 Apr 2016 09:47:14 -0400 Subject: [PATCH 075/183] remove build target for j2 --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 25e56f4ed..9e5875629 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -79,7 +79,6 @@ add_library(DAMASK_DRIVERS ALIAS DAMASK_LATTICE) add_library (DAMASK_PLASTIC "plastic_dislotwin.f90" "plastic_disloUCLA.f90" "plastic_isotropic.f90" - "plastic_j2.f90" "plastic_phenopowerlaw.f90" "plastic_titanmod.f90" "plastic_nonlocal.f90" From 4eb45708a555c4eae08e8d611b963c7141088479 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 25 Apr 2016 09:55:50 -0400 Subject: [PATCH 076/183] revert to old lattice.f90 file to suport ifrot v15.0 --- src/lattice.f90 | 71 ++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/src/lattice.f90 b/src/lattice.f90 index d08d42c06..05a123125 100644 --- a/src/lattice.f90 +++ b/src/lattice.f90 @@ -94,11 +94,11 @@ module lattice LATTICE_fcc_NcleavageSystem = int([3, 4, 0],pInt) !< total # of cleavage systems per family for fcc integer(pInt), parameter, private :: & - LATTICE_fcc_Nslip = sum(lattice_fcc_NslipSystem), & !< total # of slip systems for fcc - LATTICE_fcc_Ntwin = sum(lattice_fcc_NtwinSystem), & !< total # of twin systems for fcc + LATTICE_fcc_Nslip = 12_pInt, & ! sum(lattice_fcc_NslipSystem), & !< total # of slip systems for fcc + LATTICE_fcc_Ntwin = 12_pInt, & ! sum(lattice_fcc_NtwinSystem) !< total # of twin systems for fcc LATTICE_fcc_NnonSchmid = 0_pInt, & !< total # of non-Schmid contributions for fcc - LATTICE_fcc_Ntrans = sum(lattice_fcc_NtransSystem), & !< total # of transformation systems for fcc - LATTICE_fcc_Ncleavage = sum(lattice_fcc_NcleavageSystem) !< total # of cleavage systems for fcc + LATTICE_fcc_Ntrans = 12_pInt, & !< total # of transformations for fcc + LATTICE_fcc_Ncleavage = 7_pInt !< total # of cleavage systems for fcc real(pReal), dimension(3+3,LATTICE_fcc_Nslip), parameter, private :: & LATTICE_fcc_systemSlip = reshape(real([& @@ -365,7 +365,7 @@ module lattice !-------------------------------------------------------------------------------------------------- ! bcc integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & - LATTICE_bcc_NslipSystem = int([ 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], pInt) !< total # of slip systems per family for bcc + LATTICE_bcc_NslipSystem = int([ 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], pInt) !< total # of slip systems per family for bcc integer(pInt), dimension(LATTICE_maxNtwinFamily), parameter, public :: & LATTICE_bcc_NtwinSystem = int([ 12, 0, 0, 0], pInt) !< total # of twin systems per family for bcc @@ -374,15 +374,16 @@ module lattice LATTICE_bcc_NtransSystem = int([0,0],pInt) !< total # of transformation systems per family for bcc integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & - LATTICE_bcc_NcleavageSystem = int([3,6,0],pInt) !< total # of cleavage systems per family for bcc + LATTICE_bcc_NcleavageSystem = int([3,6,0],pInt) !< total # of cleavage systems per family for bcc integer(pInt), parameter, private :: & - LATTICE_bcc_Nslip = sum(lattice_bcc_NslipSystem), & !< total # of slip systems for bcc - LATTICE_bcc_Ntwin = sum(lattice_bcc_NtwinSystem), & !< total # of twin systems for bcc - LATTICE_bcc_NnonSchmid = 6_pInt, & !< total # of non-Schmid contributions for bcc (A. Koester, A. Ma, A. Hartmaier 2012) - LATTICE_bcc_Ntrans = sum(lattice_bcc_NtransSystem), & !< total # of transformation systems for bcc - LATTICE_bcc_Ncleavage = sum(lattice_bcc_NcleavageSystem) !< total # of cleavage systems for bcc + LATTICE_bcc_Nslip = 24_pInt, & ! sum(lattice_bcc_NslipSystem), & !< total # of slip systems for bcc + LATTICE_bcc_Ntwin = 12_pInt, & ! sum(lattice_bcc_NtwinSystem) !< total # of twin systems for bcc + LATTICE_bcc_NnonSchmid = 6_pInt, & !< # of non-Schmid contributions for bcc. 6 known non schmid contributions for BCC (A. Koester, A. Ma, A. Hartmaier 2012) + LATTICE_bcc_Ntrans = 0_pInt, & !< total # of transformations for bcc + LATTICE_bcc_Ncleavage = 9_pInt !< total # of cleavage systems for bcc + real(pReal), dimension(3+3,LATTICE_bcc_Nslip), parameter, private :: & LATTICE_bcc_systemSlip = reshape(real([& ! Slip direction Plane normal @@ -562,7 +563,7 @@ module lattice !-------------------------------------------------------------------------------------------------- ! hex integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & - lattice_hex_NslipSystem = int([ 3, 3, 3, 6, 12, 6, 0, 0, 0, 0, 0, 0, 0],pInt) !< # of slip systems per family for hex + lattice_hex_NslipSystem = int([ 3, 3, 3, 6, 12, 6, 0, 0, 0, 0, 0, 0, 0],pInt) !< # of slip systems per family for hex integer(pInt), dimension(LATTICE_maxNtwinFamily), parameter, public :: & lattice_hex_NtwinSystem = int([ 6, 6, 6, 6],pInt) !< # of slip systems per family for hex @@ -571,14 +572,14 @@ module lattice LATTICE_hex_NtransSystem = int([0,0],pInt) !< total # of transformation systems per family for hex integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & - LATTICE_hex_NcleavageSystem = int([3,0,0],pInt) !< total # of cleavage systems per family for hex + LATTICE_hex_NcleavageSystem = int([3,0,0],pInt) !< total # of cleavage systems per family for hex - integer(pInt), parameter, private :: & - LATTICE_hex_Nslip = sum(lattice_hex_NslipSystem), & !< total # of slip systems for hex - LATTICE_hex_Ntwin = sum(lattice_hex_NtwinSystem), & !< total # of twin systems for hex - LATTICE_hex_NnonSchmid = 0_pInt, & !< total # of non-Schmid contributions for hex - LATTICE_hex_Ntrans = sum(lattice_hex_NtransSystem), & !< total # of transformation systems for hex - LATTICE_hex_Ncleavage = sum(lattice_hex_NcleavageSystem) !< total # of cleavage systems for hex + integer(pInt), parameter , private :: & + LATTICE_hex_Nslip = 33_pInt, & ! sum(lattice_hex_NslipSystem), !< total # of slip systems for hex + LATTICE_hex_Ntwin = 24_pInt, & ! sum(lattice_hex_NtwinSystem) !< total # of twin systems for hex + LATTICE_hex_NnonSchmid = 0_pInt, & !< # of non-Schmid contributions for hex + LATTICE_hex_Ntrans = 0_pInt, & !< total # of transformations for hex + LATTICE_hex_Ncleavage = 3_pInt !< total # of transformations for hex real(pReal), dimension(4+4,LATTICE_hex_Nslip), parameter, private :: & LATTICE_hex_systemSlip = reshape(real([& @@ -841,6 +842,7 @@ module lattice ],pReal),[ 4_pInt + 4_pInt,LATTICE_hex_Ncleavage]) + !-------------------------------------------------------------------------------------------------- ! bct integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & @@ -854,13 +856,14 @@ module lattice integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & LATTICE_bct_NcleavageSystem = int([0,0,0],pInt) !< total # of cleavage systems per family for bct + - integer(pInt), parameter, private :: & - LATTICE_bct_Nslip = sum(lattice_bct_NslipSystem), & !< total # of slip systems for bct - LATTICE_bct_Ntwin = sum(lattice_bct_NtwinSystem), & !< total # of twin systems for bct - LATTICE_bct_NnonSchmid = 0_pInt, & !< total # of non-Schmid contributions for bct - LATTICE_bct_Ntrans = sum(lattice_bct_NtransSystem), & !< total # of transformation systems for bct - LATTICE_bct_Ncleavage = sum(lattice_bct_NcleavageSystem) !< total # of cleavage systems for bct + integer(pInt), parameter , private :: & + LATTICE_bct_Nslip = 52_pInt, & ! sum(lattice_bct_NslipSystem), !< total # of slip systems for bct + LATTICE_bct_Ntwin = 0_pInt, & ! sum(lattice_bcc_NtwinSystem) !< total # of twin systems for bct + LATTICE_bct_NnonSchmid = 0_pInt, & !< # of non-Schmid contributions for bct + LATTICE_bct_Ntrans = 0_pInt, & !< total # of transformations for bct + LATTICE_bct_Ncleavage = 0_pInt !< total # of transformations for bct real(pReal), dimension(3+3,LATTICE_bct_Nslip), parameter, private :: & LATTICE_bct_systemSlip = reshape(real([& @@ -1004,10 +1007,10 @@ module lattice !-------------------------------------------------------------------------------------------------- ! isotropic integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & - LATTICE_iso_NcleavageSystem = int([3,0,0],pInt) !< total # of cleavage systems per family for iso + LATTICE_iso_NcleavageSystem = int([3,0,0],pInt) !< total # of cleavage systems per family for isotropic integer(pInt), parameter, private :: & - LATTICE_iso_Ncleavage = sum(LATTICE_iso_NcleavageSystem) !< total # of cleavage systems for iso + LATTICE_iso_Ncleavage = 3_pInt !< total # of cleavage systems for bcc real(pReal), dimension(3+3,LATTICE_iso_Ncleavage), parameter, private :: & LATTICE_iso_systemCleavage = reshape(real([& @@ -1020,10 +1023,10 @@ module lattice !-------------------------------------------------------------------------------------------------- ! orthorhombic integer(pInt), dimension(LATTICE_maxNcleavageFamily), parameter, public :: & - LATTICE_ortho_NcleavageSystem = int([1,1,1],pInt) !< total # of cleavage systems per family for ortho + LATTICE_ortho_NcleavageSystem = int([1,1,1],pInt) !< total # of cleavage systems per family for orthotropic integer(pInt), parameter, private :: & - LATTICE_ortho_Ncleavage = sum(LATTICE_ortho_NcleavageSystem) !< total # of cleavage systems for ortho + LATTICE_ortho_Ncleavage = 3_pInt !< total # of cleavage systems for bcc real(pReal), dimension(3+3,LATTICE_ortho_Ncleavage), parameter, private :: & LATTICE_ortho_systemCleavage = reshape(real([& @@ -1033,16 +1036,16 @@ module lattice 1, 0, 0, 0, 0, 1 & ],pReal),[ 3_pInt + 3_pInt,LATTICE_ortho_Ncleavage]) - real(pReal), dimension(:,:,:), allocatable, public, protected :: & + real(pReal), dimension(:,:,:), allocatable, public, protected :: & lattice_C66, lattice_trans_C66 - real(pReal), dimension(:,:,:,:,:), allocatable, public, protected :: & + real(pReal), dimension(:,:,:,:,:), allocatable, public, protected :: & lattice_C3333, lattice_trans_C3333 - real(pReal), dimension(:), allocatable, public, protected :: & + real(pReal), dimension(:), allocatable, public, protected :: & lattice_mu, & lattice_nu, & lattice_trans_mu, & lattice_trans_nu - real(pReal), dimension(:,:,:), allocatable, public, protected :: & + real(pReal), dimension(:,:,:), allocatable, public, protected :: & lattice_thermalConductivity33, & lattice_thermalExpansion33, & lattice_damageDiffusion33, & @@ -1051,7 +1054,7 @@ module lattice lattice_porosityDiffusion33, & lattice_hydrogenfluxDiffusion33, & lattice_hydrogenfluxMobility33 - real(pReal), dimension(:), allocatable, public, protected :: & + real(pReal), dimension(:), allocatable, public, protected :: & lattice_damageMobility, & lattice_porosityMobility, & lattice_massDensity, & From b168317a17cd7148da46eaecd8e2f2cd69f6cbdd Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 25 Apr 2016 15:18:46 -0400 Subject: [PATCH 077/183] modify fomular in pheno+ to remove dampping --- src/plastic_phenoplus.f90 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/plastic_phenoplus.f90 b/src/plastic_phenoplus.f90 index b12d476ab..1646f5f41 100644 --- a/src/plastic_phenoplus.f90 +++ b/src/plastic_phenoplus.f90 @@ -979,13 +979,11 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar ne_mprimes(n) = maxval(m_primes) ENDIF ENDDO LOOPMYNEIGHBORS - !*******check if one of the neighbor already can provide a kick for this slip system - IF ( maxval(ne_mprimes) > mprime_cut ) THEN - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal + 0.5_pReal*maxval(ne_mprimes) - ELSE - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal - 0.1_pReal*maxval(ne_mprimes) - ENDIF + + plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal & + + 0.15_pReal*(1.0_pReal + ERF(10.0_pReal*(maxval(ne_mprimes)-0.8_pReal))) ENDDO LOOPMYSLIP + ENDIF ENDIF From 5e39d38a86489becbb9c2fb08bffdff117c305a0 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Mon, 25 Apr 2016 16:02:56 -0400 Subject: [PATCH 078/183] update formula for strain path modifier --- src/plastic_phenoplus.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plastic_phenoplus.f90 b/src/plastic_phenoplus.f90 index 1646f5f41..047abe33b 100644 --- a/src/plastic_phenoplus.f90 +++ b/src/plastic_phenoplus.f90 @@ -980,8 +980,8 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar ENDIF ENDDO LOOPMYNEIGHBORS - plasticState(ph)%state(index_kappa+me_slip, of) = 1.0_pReal & - + 0.15_pReal*(1.0_pReal + ERF(10.0_pReal*(maxval(ne_mprimes)-0.8_pReal))) + plasticState(ph)%state(index_kappa+me_slip, of) = 1.2_pReal & + + 0.2_pReal*ERF(4.0_pReal * maxval(ne_mprimes) - 4.0_pReal) ENDDO LOOPMYSLIP ENDIF From 8ddb024df342e8dd50da69962bcce7a045aac367 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 27 Apr 2016 08:38:22 -0400 Subject: [PATCH 079/183] lower magnitude of strain path modifier --- src/plastic_phenoplus.f90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plastic_phenoplus.f90 b/src/plastic_phenoplus.f90 index 047abe33b..01fa8e8e5 100644 --- a/src/plastic_phenoplus.f90 +++ b/src/plastic_phenoplus.f90 @@ -980,8 +980,9 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar ENDIF ENDDO LOOPMYNEIGHBORS - plasticState(ph)%state(index_kappa+me_slip, of) = 1.2_pReal & - + 0.2_pReal*ERF(4.0_pReal * maxval(ne_mprimes) - 4.0_pReal) + plasticState(ph)%state(index_kappa+me_slip, of) = & + 1.1_pReal + 0.1_pReal*ERF(4.0_pReal * maxval(ne_mprimes) - 4.0_pReal) + ENDDO LOOPMYSLIP ENDIF From ab4ec134dfc24190b79d78703aae965deb9616d1 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 27 Apr 2016 14:39:35 -0400 Subject: [PATCH 080/183] reduce push up to 2% --- src/plastic_phenoplus.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plastic_phenoplus.f90 b/src/plastic_phenoplus.f90 index 01fa8e8e5..097a9cf1d 100644 --- a/src/plastic_phenoplus.f90 +++ b/src/plastic_phenoplus.f90 @@ -981,7 +981,7 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar ENDDO LOOPMYNEIGHBORS plasticState(ph)%state(index_kappa+me_slip, of) = & - 1.1_pReal + 0.1_pReal*ERF(4.0_pReal * maxval(ne_mprimes) - 4.0_pReal) + 1.02_pReal + 0.02_pReal*ERF(4.0_pReal * maxval(ne_mprimes) - 4.0_pReal) ENDDO LOOPMYSLIP From 88cca8742907f6add53f78233bb5f2267c72e0fe Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Wed, 27 Apr 2016 15:48:27 -0400 Subject: [PATCH 081/183] raise kappa_max to 4% --- src/plastic_phenoplus.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plastic_phenoplus.f90 b/src/plastic_phenoplus.f90 index 097a9cf1d..2e5fd3fcd 100644 --- a/src/plastic_phenoplus.f90 +++ b/src/plastic_phenoplus.f90 @@ -981,7 +981,7 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar ENDDO LOOPMYNEIGHBORS plasticState(ph)%state(index_kappa+me_slip, of) = & - 1.02_pReal + 0.02_pReal*ERF(4.0_pReal * maxval(ne_mprimes) - 4.0_pReal) + 1.04_pReal + 0.04_pReal*ERF(4.0_pReal * maxval(ne_mprimes) - 4.0_pReal) ENDDO LOOPMYSLIP From 7c084f8bf585fed6cea9a921d475ac6acaaed9bb Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Tue, 3 May 2016 10:38:04 -0400 Subject: [PATCH 082/183] lower strain path modifer to 3% --- src/plastic_phenoplus.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plastic_phenoplus.f90 b/src/plastic_phenoplus.f90 index 2e5fd3fcd..38561af60 100644 --- a/src/plastic_phenoplus.f90 +++ b/src/plastic_phenoplus.f90 @@ -981,7 +981,7 @@ subroutine plastic_phenoplus_microstructure(orientation,ipc,ip,el,F0,Fe,Fp,Tstar ENDDO LOOPMYNEIGHBORS plasticState(ph)%state(index_kappa+me_slip, of) = & - 1.04_pReal + 0.04_pReal*ERF(4.0_pReal * maxval(ne_mprimes) - 4.0_pReal) + 1.03_pReal + 0.03_pReal*ERF(4.0_pReal * maxval(ne_mprimes) - 4.0_pReal) ENDDO LOOPMYSLIP From 89db00da0a82bf575da7d08cbce0ac3a154d17b6 Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Fri, 6 May 2016 17:49:36 -0400 Subject: [PATCH 083/183] change default optmizatio schem --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a5e021a2b..b8d344240 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,7 +116,7 @@ set (DAMASK_VERSION_MINOR ${DAMASK_V}) # Built-in options for DAMASK build system # -> can be overwritten from commandline/install_script option(OPENMP "Use OpenMP libaries for DAMASK" ON ) -option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) +option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "AGGRESSIVE" ) option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) option(FEM "Build FEM solver for DAMASK" OFF ) From c6ddfae4e0b78ba0415fc304d23227f657c529ea Mon Sep 17 00:00:00 2001 From: zhangc43 Date: Fri, 6 May 2016 18:26:03 -0400 Subject: [PATCH 084/183] specify OPTIMIZATIO in makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f0c19b683..24b17965f 100755 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ spectral: build/spectral build/spectral: build @mkdir build/spectral - @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=SPECTRAL -D DAMASK_INSTALL=${HOME}/bin ../..;) + @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=SPECTRAL -DOPTIMIZATION=AGGRESSIVE -DDAMASK_INSTALL=${HOME}/bin ../..;) build: bin @mkdir build From 3b843b1dd956d00fe12b34398018417917a14605 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 18 May 2016 08:21:09 +0200 Subject: [PATCH 085/183] linux line endings --- Makefile | 64 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) mode change 100755 => 100644 Makefile diff --git a/Makefile b/Makefile old mode 100755 new mode 100644 index 24b17965f..98236f4ef --- a/Makefile +++ b/Makefile @@ -1,32 +1,32 @@ -SHELL = /bin/sh -######################################################################################## -# Makefile for the installation of DAMASK -######################################################################################## -.PHONY: all -all: spectral FEM - -spectral: build/spectral - @(cd build/spectral; make --no-print-directory -ws all install;) - -build/spectral: build - @mkdir build/spectral - @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=SPECTRAL -DOPTIMIZATION=AGGRESSIVE -DDAMASK_INSTALL=${HOME}/bin ../..;) - -build: bin - @mkdir build - -bin: - @mkdir bin - -FEM: build/FEM - @(cd build/FEM; make --no-print-directory -ws all install;) - -build/FEM: build - @mkdir build - @(cd build/FEM; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=FEM ../..;) - -.PHONY: clean -clean: - rm -rvf build # standard build directory - rm -rvf testing # for testing build (testing script in PRIVATE) - rm -rvf bin # default binary store location +SHELL = /bin/sh +######################################################################################## +# Makefile for the installation of DAMASK +######################################################################################## +.PHONY: all +all: spectral FEM + +spectral: build/spectral + @(cd build/spectral; make --no-print-directory -ws all install;) + +build/spectral: build + @mkdir build/spectral + @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=SPECTRAL -DOPTIMIZATION=AGGRESSIVE -DDAMASK_INSTALL=${HOME}/bin ../..;) + +build: bin + @mkdir build + +bin: + @mkdir bin + +FEM: build/FEM + @(cd build/FEM; make --no-print-directory -ws all install;) + +build/FEM: build + @mkdir build + @(cd build/FEM; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=FEM ../..;) + +.PHONY: clean +clean: + rm -rvf build # standard build directory + rm -rvf testing # for testing build (testing script in PRIVATE) + rm -rvf bin # default binary store location From 5ef9c65cbef8e12453c48e7a2a77ee76b8ee48df Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 18 May 2016 08:54:16 +0200 Subject: [PATCH 086/183] cleaning --- CMakeLists.txt | 160 ++++++++++++++++++++----------------------------- 1 file changed, 66 insertions(+), 94 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8d344240..37f0f9ed9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,17 +11,18 @@ if ("${PETSC_DIR}" STREQUAL "") endif ("${PETSC_DIR}" STREQUAL "") # BRUTAL FORCE TO FIND THE VARIABLES DEFINED IN PETSC -# ref: # https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake exec_program(mktemp ARGS -d OUTPUT_VARIABLE PETSC_TEMP) set(petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") set(petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) -# Generate a temporary makerfile to probe the PETSc configuration +# Generate a temporary makefile to probe the PETSc configuration # This file will be deleted once the setting from PETSc is parsed # into CMake set (petsc_config_makefile "${PETSC_TEMP}/Makefile.petsc") -file (WRITE "${petsc_config_makefile}" + +file (WRITE +"${petsc_config_makefile}" "## This file was auto generated by CMake # PETSC_DIR = ${PETSC_DIR} SHELL = /bin/sh @@ -40,7 +41,8 @@ compilerf: compilerc: \t@echo \${COMPILERC} linker: -\t@echo \${LINKERNAME}") +\t@echo \${LINKERNAME} +") # CMake will execute each target in the ${petsc_config_makefile} # to acquire corresponding PETSc Variables. @@ -58,12 +60,7 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_confi RESULT_VARIABLE PETSC_EXTERNAL_LIB_RETURN OUTPUT_VARIABLE petsc_external_lib OUTPUT_STRIP_TRAILING_WHITESPACE) -# The MPI compiler specified in PETSc -# //its version information is used to identify whether it is INTEL FORTRAN -# //or GNU FORTRAN, -# //e.g. for PETSc configured with INTEL FORTRAN compiler -# // >>${MPIFC} -v -# // ifort version 14.0.3 --> This line is captured and parsed by CMake +# PETSc specified compiler execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "compilerf" RESULT_VARIABLE MPIFC_RETURN OUTPUT_VARIABLE MPIFC @@ -74,7 +71,7 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_confi OUTPUT_VARIABLE PETSC_LINKER OUTPUT_STRIP_TRAILING_WHITESPACE) # Remove temporary makefile, no need to keep it anymore. -file (REMOVE ${petsc_config_makefile}) +file (REMOVE_RECURSE ${PETSC_TEMP}) # REMOVE DUPLICATE FLAGS FOR COMPILER AND LINKING string( REGEX MATCHALL "-I([^\" ]+)" TMP_LIST "${petsc_includes}") @@ -116,7 +113,7 @@ set (DAMASK_VERSION_MINOR ${DAMASK_V}) # Built-in options for DAMASK build system # -> can be overwritten from commandline/install_script option(OPENMP "Use OpenMP libaries for DAMASK" ON ) -option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "AGGRESSIVE" ) +option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) option(FEM "Build FEM solver for DAMASK" OFF ) @@ -143,35 +140,39 @@ if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") set (SPECTRAL ON ) add_definitions(-DSpectral) set (FEM OFF) - message("***Confiugring Spectral Solver\n") + message("***Configuring Spectral Solver\n") elseif ("${DAMASK_DRIVER}" STREQUAL "FEM") set (FEM ON ) add_definitions(-DFEM) set (SPECTRAL OFF) - message("***Confiugring FEM Solver\n") + message("***Configuring FEM Solver\n") endif("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") -if ("${OPTIMIZATION}" STREQUAL "OFF") - set (OPTIMIZATION_ifort "-O0 -no-ip") - set (OPTIMIZATION_gfortran "-O0" ) -elseif ("${OPTIMIZATION}" STREQUAL "DEFENSIVE") - set (OPTIMIZATION_ifort "-O2") - set (OPTIMIZATION_gfortran "-O2") -elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") #ToDo: this is not fully correct here, check old makefile - set (OPTIMIZATION_ifort "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" - set (OPTIMIZATION_gfortran "-O3 -ffast-math -funroll-loops -ftree-vectorize") -else("${OPTIMIZATION}" STREQUAL "OFF") - set (OPTIMIZATION_ifort "-O2") - set (OPTIMIZATION_gfortran "-O2") -endif("${OPTIMIZATION}" STREQUAL "OFF") - - ################################################################################################### +# Intel Compiler +################################################################################################### +if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") + + if (OPENMP) + set (OPENMP_FLAG "-openmp -openmp-report0 -parallel") + endif(OPENMP) + + if ("${OPTIMIZATION}" STREQUAL "OFF") + set (OPTIMIZATION_FLAG "-O0 -no-ip") + elseif("${OPTIMIZATION}" STREQUAL "DEFENSIVE") + set (OPTIMIZATION_FLAG "-O2") + elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") + set (OPTIMIZATION_FLAG "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" + endif() + + set (STANDARD_CHECK "-stand f08 -standard-semantics") + set (LINKER_FLAG " -shared-intel") + +#------------------------------------------------------------------------------------------------ # COMPILE SWITCHES -# -shared-intel: Link against shared Intel libraries instead of static ones # -fpp: preprocessor # -ftz: flush unterflow to zero, automatically set if O<0,1,2,3> >0 # -assume byterecl record length is given in bytes (also set by -standard-semantics) @@ -189,32 +190,12 @@ endif("${OPTIMIZATION}" STREQUAL "OFF") # unused: declared variables that are never used # stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) # -################################################################################################### # MORE OPTIONS FOR DEBUGGING DURING COMPILATION # -warn: enables warnings, where # truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) # uncalled: Determines whether warnings occur when a statement function is never called # all: # -name as_is: case sensitive Fortran! -################################################################################################### -if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") - - if (OPENMP) - set (OPENMP_FLAG "-openmp -openmp-report0 -parallel") - endif(OPENMP) - - if ("${OPTIMIZATION}" STREQUAL "OFF") - set (OPTIMIZATION_FLAG "-O0 -no-ip") - elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") #ToDo: this is not fully correct here, check old makefile - set (OPTIMIZATION_FLAG "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" - elseif ("${OPTIMIZATION}" STREQUAL "ULTRA") - set (OPTIMIZATION_FLAG "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" - else() # this is the default - set (OPTIMIZATION_FLAG "-O2") - endif() - - set (STANDARD_CHECK "-stand f08 -standard-semantics") - set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -assume byterecl,fpe_summary") @@ -226,7 +207,8 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn ignore_loc" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn alignments" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn unused" ) -################################################################################################### + +#------------------------------------------------------------------------------------------------ # COMPILE SWITCHES FOR RUNTIME DEBUGGING # -g: Generate symbolic debugging information in the object file # -traceback: Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. @@ -244,13 +226,12 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") # errors: warnings are changed to errors # stderrors: warnings about Fortran standard violations are changed to errors # information on http://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors/ -################################################################################################### +# # MORE OPTIONS FOR RUNTIME DEBUGGING # -heap-arrays: should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits # -check: checks at runtime, where # arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) # stack: -################################################################################################### set (DEBUG_FLAGS "${DEBUG_FLAGS} -g" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -traceback" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -gen-interfaces" ) @@ -263,14 +244,34 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn stderrors" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -debug-parameters all" ) - set (LINKER_FLAG " -shared-intel") - -################################################################################################### +#------------------------------------------------------------------------------------------------ +# PRECISION SETTINGS #-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) #-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) -################################################################################################### set (PRECISION "-real-size 64 -integer-size 32") + + ################################################################################################### +# GNU Compiler +################################################################################################### +elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") + + if (OPENMP) + set (OPENMP_FLAG "-fopenmp") + endif() + + if ("${OPTIMIZATION}" STREQUAL "OFF") + set (OPTIMIZATION_FLAG "-O0" ) + elseif ("${OPTIMIZATION}" STREQUAL "DEFENSIVE") + set (OPTIMIZATION_FLAG "-O2") + elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") + set (OPTIMIZATION_FLAG "-O3 -ffast-math -funroll-loops -ftree-vectorize") + endif() + + set (STANDARD_CHECK "-std=f2008ts -pedantic-errors" ) + set (LINKER_FLAG " -Wl,-undefined,dynamic_lookup") + +#------------------------------------------------------------------------------------------------ # COMPILE SWITCHES # -shared # -Wl,-undefined,dynamic_lookup:ensure to link against dynamic libraries @@ -339,31 +340,12 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") # -Wunused-but-set-parameter (only with -Wunused or -Wall) # -Wno-globals # -ffpe-summary=all only for newer gfortran -################################################################################################### +# # MORE OPTIONS FOR DEBUGGING DURING COMPILATION # -Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): # -Wimplicit-interface: no interfaces for lapack routines # -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. # -Wstrict-overflow: -################################################################################################### -elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") - - if (OPENMP) - set (OPENMP_FLAG "-fopenmp") - endif() - - if ("${OPTIMIZATION}" STREQUAL "OFF") - set (OPTIMIZATION_FLAG "-O0" ) - elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") #ToDo: this is not fully correct here, check old makefile - set (OPTIMIZATION_FLAG "-O3 -ffast-math -funroll-loops -ftree-vectorize") - elseif ("${OPTIMIZATION}" STREQUAL "ULTRA") - set (OPTIMIZATION_FLAG "-O3 -ffast-math -funroll-loops -ftree-vectorize") - else() # this is the default - set (OPTIMIZATION_FLAG "-O2") - endif() - - set (STANDARD_CHECK "-std=f2008ts -pedantic-errors" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -xf95-cpp-input" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffree-line-length-132" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -fimplicit-none" ) @@ -379,9 +361,7 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-unused-parameter" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -fno-range-check" ) - set (LINKER_FLAG " -Wl,-undefined,dynamic_lookup") - -################################################################################################### +#------------------------------------------------------------------------------------------------ # COMPILE SWITCHES FOR RUNTIME DEBUGGING # -ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) # zero,\ @@ -393,24 +373,24 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # mem # pointer # recursion -################################################################################################### +# # MORE OPTIONS FOR RUNTIME DEBUGGING -# -ffpe-trap=precision,\ -# denormal, \ +# -ffpe-trap=precision, +# denormal, # underflow -################################################################################################### set (DEBUG_FLAGS "${DEBUG_FLAGS} -g" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -fbacktrace" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -fdump-core" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -fcheck=all" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -ffpe-trap=invalid,zero,overflow") -################################################################################################### +#------------------------------------------------------------------------------------------------ +# PRECISION SETTINGS #-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set #-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used #-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) -################################################################################################### set (PRECISION "-fdefault-real-8 -fdefault-double-8") + endif() set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG}" ) @@ -493,11 +473,3 @@ elseif (FEM) DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(SPECTRAL) -## -# ADD TESTING CASES -# add_test (SmokeTestRun -# DAMASK_spectral.exe -g test/test1.geom -l test/test.load) - -# Enable Dashboard scripting -# include (CTest) -# set (CTEST_PROJECT_NAME "DAMASK") From abb686029de0c2544e3ba638c730e0ffed250d0b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 20 May 2016 08:06:06 +0200 Subject: [PATCH 087/183] version was never used and wrong defined --- CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37f0f9ed9..809cd9ea1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,10 +106,6 @@ message("***Found FORTRAN MPI COMPILER:\n${MPIFC}\n" ) #--------------------------------------------------------------------------------------- # Now start to care about DAMASK -# THE VERSION NUMBER. -set (DAMASK_VERSION_MAJOR 1) -set (DAMASK_VERSION_MINOR ${DAMASK_V}) - # Built-in options for DAMASK build system # -> can be overwritten from commandline/install_script option(OPENMP "Use OpenMP libaries for DAMASK" ON ) From f4ddb0f9d235e5e4a92742ce4a37e061eb369a7a Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 20 May 2016 08:09:06 +0200 Subject: [PATCH 088/183] was not doing anything --- src/damask_hdf5.f90 | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 src/damask_hdf5.f90 diff --git a/src/damask_hdf5.f90 b/src/damask_hdf5.f90 deleted file mode 100644 index 34479f9b3..000000000 --- a/src/damask_hdf5.f90 +++ /dev/null @@ -1,16 +0,0 @@ -module HDF5_io - use prec - use IO - use hdf5 - -contains - -subroutine HDF5_init(filename, total_inc, total_time) - integer(pInt), intent(in) :: total_inc - real(pReal), intent(in) :: total_time - - write(6,*) 'pretend to write something' - -end subroutine HDF5_init - -end module HDF5_io \ No newline at end of file From 85cfe670aeb6adfb7bd8e6f96c7c19e2900a1250 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 20 May 2016 08:15:49 +0200 Subject: [PATCH 089/183] same defaults for spectral and FEM solver --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 98236f4ef..e9c242748 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ spectral: build/spectral build/spectral: build @mkdir build/spectral - @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=SPECTRAL -DOPTIMIZATION=AGGRESSIVE -DDAMASK_INSTALL=${HOME}/bin ../..;) + @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=SPECTRAL ../..;) build: bin @mkdir build From a009bfaf08cb4701247558d99d70234cbfdca8e8 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 20 May 2016 08:24:53 +0200 Subject: [PATCH 090/183] renamed _FLAG(S) consistently to _FLAGS removed code doubling --- CMakeLists.txt | 105 ++++++++++++++++--------------------------------- 1 file changed, 33 insertions(+), 72 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 809cd9ea1..bd4bb0748 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,10 +108,10 @@ message("***Found FORTRAN MPI COMPILER:\n${MPIFC}\n" ) # Built-in options for DAMASK build system # -> can be overwritten from commandline/install_script -option(OPENMP "Use OpenMP libaries for DAMASK" ON ) -option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) -option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) -option(FEM "Build FEM solver for DAMASK" OFF ) +option(OPENMP "Use OpenMP libaries for DAMASK" ON ) +option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) +option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) +option(FEM "Build FEM solver for DAMASK" OFF ) if (NOT DEFINED CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) @@ -153,19 +153,19 @@ set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") if (OPENMP) - set (OPENMP_FLAG "-openmp -openmp-report0 -parallel") + set (OPENMP_FLAGS "-openmp -openmp-report0 -parallel") endif(OPENMP) if ("${OPTIMIZATION}" STREQUAL "OFF") - set (OPTIMIZATION_FLAG "-O0 -no-ip") + set (OPTIMIZATION_FLAGS "-O0 -no-ip") elseif("${OPTIMIZATION}" STREQUAL "DEFENSIVE") - set (OPTIMIZATION_FLAG "-O2") + set (OPTIMIZATION_FLAGS "-O2") elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") - set (OPTIMIZATION_FLAG "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" + set (OPTIMIZATION_FLAGS "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" endif() set (STANDARD_CHECK "-stand f08 -standard-semantics") - set (LINKER_FLAG " -shared-intel") + set (LINKER_FLAGS "-shared-intel") #------------------------------------------------------------------------------------------------ # COMPILE SWITCHES @@ -244,7 +244,7 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") # PRECISION SETTINGS #-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) #-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) - set (PRECISION "-real-size 64 -integer-size 32") + set (PRECISION_FLAGS "-real-size 64 -integer-size 32") ################################################################################################### @@ -253,19 +253,19 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") if (OPENMP) - set (OPENMP_FLAG "-fopenmp") + set (OPENMP_FLAGS "-fopenmp") endif() if ("${OPTIMIZATION}" STREQUAL "OFF") - set (OPTIMIZATION_FLAG "-O0" ) + set (OPTIMIZATION_FLAGS "-O0" ) elseif ("${OPTIMIZATION}" STREQUAL "DEFENSIVE") - set (OPTIMIZATION_FLAG "-O2") + set (OPTIMIZATION_FLAGS "-O2") elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") - set (OPTIMIZATION_FLAG "-O3 -ffast-math -funroll-loops -ftree-vectorize") + set (OPTIMIZATION_FLAGS "-O3 -ffast-math -funroll-loops -ftree-vectorize") endif() set (STANDARD_CHECK "-std=f2008ts -pedantic-errors" ) - set (LINKER_FLAG " -Wl,-undefined,dynamic_lookup") + set (LINKER_FLAGS "-Wl,-undefined,dynamic_lookup") #------------------------------------------------------------------------------------------------ # COMPILE SWITCHES @@ -385,74 +385,35 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") #-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set #-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used #-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) - set (PRECISION "-fdefault-real-8 -fdefault-double-8") + set (PRECISION_FLAGS "-fdefault-real-8 -fdefault-double-8") endif() -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAG}" ) -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK}" ) -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPTIMIZATION_FLAG}" ) +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAGS}") +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK}") +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPTIMIZATION_FLAGS}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_FLAGS}") -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION}" ) +set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_FLAGS}") -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAG}" ) +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAGS}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK}") -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_FLAG}" ) -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER_FLAG}" ) +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_FLAGS}" ) +set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS}" ) set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_FLAGS}" ) -# Try to add PREFIX and SUFFIX to compiler chain -if (DEFINED BUILDCMD_PRE AND DEFINED BUILDCMD_POST) - set (CMAKE_Fortran_FLAGS_RELEASE "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") - set (CMAKE_Fortran_FLAGS_DEBUG "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") - set (CMAKE_LINKER "${PETSC_LINKER}") +set (CMAKE_Fortran_FLAGS_RELEASE "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") +set (CMAKE_Fortran_FLAGS_DEBUG "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") +set (CMAKE_LINKER "${PETSC_LINKER}") - if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") - else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") - endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") -elseif(NOT DEFINED BUILDCMD_PRE AND DEFINED BUILDCMD_POST) - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") - set (CMAKE_LINKER "${PETSC_LINKER}") - - if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") - else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") - endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") -elseif(DEFINED BUILDCMD_PRE AND NOT DEFINED BUILDCMD_POST) - set (CMAKE_Fortran_FLAGS_RELEASE "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") - set (CMAKE_Fortran_FLAGS_DEBUG "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") - set (CMAKE_LINKER "${PETSC_LINKER}") - - if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB}") - else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") - endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") -else(DEFINED BUILDCMD_PRE AND DEFINED BUILDCMD_POST) - set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS}") - set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS}") - set (CMAKE_LINKER "${PETSC_LINKER}") - - if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB}") - else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB}") - endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") -endif(DEFINED BUILDCMD_PRE AND DEFINED BUILDCMD_POST) +if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") +else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_LINK_EXECUTABLE + "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") +endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") message("***LINKER:\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") From 8184f1c39ae3c5f9a6e46fc00c3b2f3ab650adca Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 20 May 2016 08:45:22 +0200 Subject: [PATCH 091/183] old Makefile is not needed anymore --- src/Makefile | 698 --------------------------------------------------- 1 file changed, 698 deletions(-) delete mode 100644 src/Makefile diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index e4ea81379..000000000 --- a/src/Makefile +++ /dev/null @@ -1,698 +0,0 @@ -SHELL = /bin/sh -######################################################################################## -# Makefile to compile the Material subroutine for BVP solution using spectral method -######################################################################################## -# Be sure to remove all files compiled with different options by using "make clean" -######################################################################################## -# OPTIONS = standard (alternative): meaning -#------------------------------------------------------------- -# F90 = ifort (gfortran): compiler type, choose Intel or GNU -# COMPILERNAME = name of the compiler executable (if not the same as the ype), e.g. using mpich-g90 instead of ifort -# PORTABLE = TRUE (FALSE): decision, if executable is optimized for the machine on which it was built. -# OPTIMIZATION = DEFENSIVE (OFF,AGGRESSIVE,ULTRA): Optimization mode: O2, O0, O3 + further options for most files, O3 + further options for all files -# OPENMP = TRUE (FALSE): OpenMP multiprocessor support -# PREFIX = arbitrary prefix (before compilername) -# OPTION = arbitrary option (just before file to compile) -# SUFFIX = arbitrary suffix (after file to compile) -# STANDARD_CHECK = checking for Fortran 2008, compiler dependend -######################################################################################## -# including PETSc files. PETSC_ARCH is loaded from these files. -DAMASKVERSION :=$(shell cat ../VERSION) - -include ${PETSC_DIR}/lib/petsc/conf/variables -include ${PETSC_DIR}/lib/petsc/conf/rules - -INCLUDE_DIRS := $(PETSC_FC_INCLUDES) -DPETSc -I../lib -LIBRARIES := $(PETSC_WITH_EXTERNAL_LIB) -COMPILERNAME ?= $(FC) -LINKERNAME ?= $(FLINKER) - -# -# setting up for HDF5 support (hard link for now) -# 1. Location of HDF5 binaries (with include/ and lib/ underneath) -HDF5 = /mnt/research/CMM/opt/hdf5 -# 2. Location of External Libraries (missing in the 1.8.12 version) -LIBZ = /mnt/research/CMM/opt/hdf5/lib/libz.a -LIBSZ = /mnt/research/CMM/opt/hdf5/lib/libszip.a -# 3. Set libraries for HDF5 (LIBS: shared lib, LIBZ: external lib) -HDFLIBS = -I$(HDF5)/include -L$(HDF5)/lib -HDFLIBZ = -L$(LIBZ) -L$(LIBSZ) - -# MPI compiler wrappers will tell if they are pointing to ifort or gfortran -COMPILEROUT :=$(shell $(FC) -show) -# search in FC or COMPILEROUT for gfortran/ifort if not defined -ifeq ($(strip $(F90)),) - F90 :=$(findstring gfortran,$(FC) $(COMPILEROUT)) -endif -ifeq ($(strip $(F90)),) - F90 :=$(findstring ifort,$(FC) $(COMPILEROUT)) -endif - -OPENMP ?= ON -OPTIMIZATION ?= DEFENSIVE - -ifeq "$(OPTIMIZATION)" "OFF" -OPTI := OFF -MAXOPTI := OFF -endif -ifeq "$(OPTIMIZATION)" "DEFENSIVE" -OPTI := DEFENSIVE -MAXOPTI := DEFENSIVE -endif -ifeq "$(OPTIMIZATION)" "AGGRESSIVE" -OPTI := AGGRESSIVE -MAXOPTI := DEFENSIVE -endif -ifeq "$(OPTIMIZATION)" "ULTRA" -OPTI := AGGRESSIVE -MAXOPTI := AGGRESSIVE -endif - -ifndef OPTI -OPTI := DEFENSIVE -MAXOPTI := DEFENSIVE -endif - -# settings for shared memory multicore support -ifeq "$(OPENMP)" "ON" -OPENMP_FLAG_ifort =-openmp -openmp-report0 -parallel -OPENMP_FLAG_gfortran =-fopenmp -endif - -ifdef STANDARD_CHECK -STANDARD_CHECK_ifort =$(STANDARD_CHECK) -STANDARD_CHECK_gfortran =$(STANDARD_CHECK) -endif - -STANDARD_CHECK_ifort ?=-stand f08 -standard-semantics -STANDARD_CHECK_gfortran ?=-std=f2008ts -pedantic-errors - -#-pedantic: more strict on standard, enables some warnings -# -pedantic-errors: like pedantic, but errors instead of warnings -OPTIMIZATION_OFF_ifort :=-O0 -no-ip -OPTIMIZATION_OFF_gfortran :=-O0 -OPTIMIZATION_DEFENSIVE_ifort :=-O2 -OPTIMIZATION_DEFENSIVE_gfortran :=-O2 -OPTIMIZATION_AGGRESSIVE_ifort :=-ipo -O3 -no-prec-div -fp-model fast=2 -xHost #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost -OPTIMIZATION_AGGRESSIVE_gfortran :=-O3 -ffast-math -funroll-loops -ftree-vectorize - - -LINK_OPTIONS_ifort :=-shared-intel -COMPILE_OPTIONS_ifort :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ - -fpp\ - -ftz\ - -assume byterecl,fpe_summary\ - -diag-disable 5268\ - -warn declarations\ - -warn general\ - -warn usage\ - -warn interfaces\ - -warn ignore_loc\ - -warn alignments\ - -warn unused - -################################################################################################### -#COMPILE SWITCHES -#-shared-intel: Link against shared Intel libraries instead of static ones -#-fpp: preprocessor -#-ftz: flush unterflow to zero, automatically set if O<0,1,2,3> >0 -#-assume byterecl record length is given in bytes (also set by -standard-semantics) -# fpe_summary print list of floating point exceptions occured during execution -#-fimplicit-none: assume "implicit-none" even if not present in source -#-diag-disable: disables warnings, where -# warning ID 5268: the text exceeds right hand column allowed on the line (we have only comments there) -#-warn: enables warnings, where -# declarations: any undeclared names (alternative name: -implicitnone) -# general: warning messages and informational messages are issued by the compiler -# usage: questionable programming practices -# interfaces: checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks -# ignore_loc: %LOC is stripped from an actual argument -# alignments: data that is not naturally aligned -# unused: declared variables that are never used -# stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) -# -################################################################################################### -#MORE OPTIONS FOR DEBUGGING DURING COMPILATION -#-warn: enables warnings, where -# truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) -# uncalled: Determines whether warnings occur when a statement function is never called -# all: -# -name as_is: case sensitive Fortran! - -DEBUG_OPTIONS_ifort :=-g\ - -traceback\ - -gen-interfaces\ - -fp-stack-check\ - -fp-model strict\ - -check bounds,format,output_conversion,pointers,uninit\ - -ftrapuv\ - -fpe-all0\ - -warn errors\ - -warn stderrors\ - -debug-parameters all - -################################################################################################### -#COMPILE SWITCHES FOR RUNTIME DEBUGGING -#-g: Generate symbolic debugging information in the object file -#-traceback: Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. -#-gen-interfaces: Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ -#-fp-stack-check: Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. -#-ftrapuv Trap uninitalized variables -#-check: checks at runtime, where -# bounds: check if an array index is too small (<1) or too large! -# format: Checking for the data type of an item being formatted for output. -# output_conversion: Checking for the fit of data items within a designated format descriptor field. -# pointers: Checking for certain disassociated or uninitialized pointers or unallocated allocatable objects. -# uninit: Checking for uninitialized variables. -#-fpe-all0 capture all floating-point exceptions, sets -ftz automatically -#-warn: enables warnings, where -# errors: warnings are changed to errors -# stderrors: warnings about Fortran standard violations are changed to errors -# information on http://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors/ -################################################################################################### -#MORE OPTIONS FOR RUNTIME DEBUGGING -#-heap-arrays: should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits -#-check: checks at runtime, where -# arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) -# stack: -LINK_OPTIONS_gfortran :=-Wl,-undefined,dynamic_lookup -COMPILE_OPTIONS_gfortran :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ - -xf95-cpp-input\ - -ffree-line-length-132\ - -fimplicit-none\ - -fmodule-private\ - -Wall\ - -Wextra\ - -Wcharacter-truncation\ - -Wunderflow\ - -Wsuggest-attribute=pure\ - -Wsuggest-attribute=noreturn\ - -Wconversion-extra\ - -Wimplicit-procedure\ - -Wno-unused-parameter -#-ffpe-summary=all only for newer gfortran -################################################################################################### -#COMPILE SWITCHES -#-shared -#-Wl,-undefined,dynamic_lookup:ensure to link against dynamic libraries -#-xf95-cpp-input: preprocessor -#-ffree-line-length-132: restrict line length to the standard 132 characters -#-ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) -#-fimplicit-none: assume "implicit-none" even if not present in source -#-fmodule-private: assume "private" even if not present in source -#-Wcharacter-truncation: warn if character expressions (strings) are truncated -#-Wunderflow: produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation -#-Wsuggest-attribute=pure: -#-Wsuggest-attribute=noreturn: -#-Wconversion-extra -#-Wimplicit-procedure -#-Wall: sets the following Fortran options: -# -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. -# -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line -# -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime -# -Wconversion: warn about implicit conversions between different type -# -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. -# -Wc-binding-type: -# -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error -# -Wno-tabs: do not allow tabs in source -# -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic -# -Wline-truncation: -# -Wtarget-lifetime: -# -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter -# -Wunused: a number of unused-xxx warnings -# these are general (non -Fortran options) implied by -Wall -# -Waddress -# -Warray-bounds (only with -O2) -# -Wc++11-compat -# -Wchar-subscripts -# -Wcomment -# -Wformat -# -Wmaybe-uninitialized -# -Wnonnull -# -Wparentheses -# -Wpointer-sign -# -Wreorder -# -Wreturn-type -# -Wsequence-point -# -Wstrict-aliasing -# -Wstrict-overflow=1 -# -Wswitch -# -Wtrigraphs -# -Wuninitialized -# -Wunknown-pragmas -# -Wunused-function -# -Wunused-label -# -Wunused-value -# -Wunused-variable -# -Wvolatile-register-var -#-Wextra: sets the following Fortran options: -# -Wunuses-parameter: -# -Wcompare-reals: -# these are general (non -Fortran options) implied by -Wextra -# -Wclobbered -# -Wempty-body -# -Wignored-qualifiers -# -Wmissing-field-initializers -# -Woverride-init -# -Wsign-compare -# -Wtype-limits -# -Wuninitialized -# -Wunused-but-set-parameter (only with -Wunused or -Wall) -# -Wno-globals - -################################################################################################### -#MORE OPTIONS FOR DEBUGGING DURING COMPILATION -#-Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): -#-Wimplicit-interface: no interfaces for lapack routines -#-Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. -#-Wstrict-overflow: - -DEBUG_OPTIONS_gfortran :=-g\ - -fbacktrace\ - -fdump-core\ - -fcheck=all\ - -ffpe-trap=invalid,zero,overflow - -################################################################################################### -#COMPILE SWITCHES FOR RUNTIME DEBUGGING -#-ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) -# zero,\ -# overflow -#-fcheck=all: sets the following Fortran options: -#array-temps -#bounds -#do -#mem -#pointer -#recursion -################################################################################################### -#MORE OPTIONS FOR RUNTIME DEBUGGING -#-ffpe-trap=precision,\ -# denormal, \ -# underflow - -ifeq "$(DEBUG)" "ON" -COMPILE_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) -LINK_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) -endif -LINK_OPTIONS_$(F90) += $(OPTIMIZATION_$(MAXOPTI)_$(F90)) - -PRECISION_ifort :=-real-size 64 -integer-size 32 -DFLOAT=8 -DINT=4 -#-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) -#-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) -PRECISION_gfortran :=-fdefault-real-8 -fdefault-double-8 -DFLOAT=8 -DINT=4 -#-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set -#-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used -#-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) - -################################################################################################### -COMPILE =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(OPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) -COMPILE_MAXOPTI =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) -################################################################################################### -SOURCE_FILES = \ - source_thermal_dissipation.o source_thermal_externalheat.o \ - source_damage_isoBrittle.o source_damage_isoDuctile.o source_damage_anisoBrittle.o source_damage_anisoDuctile.o \ - source_vacancy_phenoplasticity.o source_vacancy_irradiation.o source_vacancy_thermalfluc.o - -KINEMATICS_FILES = \ - kinematics_cleavage_opening.o kinematics_slipplane_opening.o \ - kinematics_thermal_expansion.o \ - kinematics_vacancy_strain.o kinematics_hydrogen_strain.o - -PLASTIC_FILES = \ - plastic_dislotwin.o plastic_disloUCLA.o plastic_isotropic.o \ - plastic_phenopowerlaw.o plastic_titanmod.o plastic_nonlocal.o plastic_none.o \ - plastic_phenoplus.o - -THERMAL_FILES = \ - thermal_isothermal.o thermal_adiabatic.o thermal_conduction.o - -DAMAGE_FILES = \ - damage_none.o damage_local.o damage_nonlocal.o - -VACANCYFLUX_FILES = \ - vacancyflux_isoconc.o vacancyflux_isochempot.o vacancyflux_cahnhilliard.o - -POROSITY_FILES = \ - porosity_none.o porosity_phasefield.o - -HYDROGENFLUX_FILES = \ - hydrogenflux_isoconc.o hydrogenflux_cahnhilliard.o - -HOMOGENIZATION_FILES = \ - homogenization_RGC.o homogenization_isostrain.o homogenization_none.o - -##################### -# Spectral Solver -##################### -DAMASK_spectral.exe: IGNORE := \# -DAMASK_spectral.exe: COMPILE += -DSpectral -DAMASK_spectral.exe: COMPILE_MAXOPTI += -DSpectral -DAMASK_spectral.exe: MESHNAME := mesh.f90 -DAMASK_spectral.exe: INTERFACENAME := spectral_interface.f90 - -DAMASK_spectral.o: IGNORE := \# -DAMASK_spectral.o: COMPILE += -DSpectral -DAMASK_spectral.o: COMPILE_MAXOPTI += -DSpectral -DAMASK_spectral.o: MESHNAME := mesh.f90 -DAMASK_spectral.o: INTERFACENAME := spectral_interface.f90 - - -SPECTRAL_SOLVER_FILES = spectral_mech_AL.o spectral_mech_Basic.o spectral_mech_Polarisation.o \ - spectral_thermal.o spectral_damage.o - -SPECTRAL_FILES = prec.o DAMASK_interface.o IO.o libs.o numerics.o debug.o math.o damask_hdf5.o \ - FEsolving.o mesh.o material.o lattice.o \ - $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ - crystallite.o \ - $(THERMAL_FILES) $(DAMAGE_FILES) $(VACANCYFLUX_FILES) $(HYDROGENFLUX_FILES) $(POROSITY_FILES) \ - $(HOMOGENIZATION_FILES) homogenization.o \ - CPFEM2.o \ - spectral_utilities.o \ - $(SPECTRAL_SOLVER_FILES) - -DAMASK_spectral.exe: DAMASK_spectral.o \ - $(SPECTRAL_FILES) - $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ - -o DAMASK_spectral.exe DAMASK_spectral.o \ - $(SPECTRAL_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) - - -DAMASK_spectral.o: DAMASK_spectral.f90 \ - $(SPECTRAL_SOLVER_FILES) - $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c DAMASK_spectral.f90 $(SUFFIX) - -spectral_mech_AL.o: spectral_mech_AL.f90 \ - spectral_utilities.o - -spectral_mech_Polarisation.o: spectral_mech_Polarisation.f90 \ - spectral_utilities.o - -spectral_mech_Basic.o: spectral_mech_Basic.f90 \ - spectral_utilities.o - -spectral_thermal.o: spectral_thermal.f90 \ - spectral_utilities.o - -spectral_damage.o: spectral_damage.f90 \ - spectral_utilities.o - -spectral_utilities.o: spectral_utilities.f90 \ - CPFEM2.o - -##################### -# FEM Solver -##################### -VPATH := ../private/FEM/code -DAMASK_FEM.exe: COMPILE += -DFEM -DAMASK_FEM.exe: COMPILE_MAXOPTI += -DFEM -DAMASK_FEM.exe: MESHNAME := ../private/FEM/code/meshFEM.f90 -DAMASK_FEM.exe: INTERFACENAME := ../private/FEM/code/DAMASK_FEM_interface.f90 -DAMASK_FEM.exe: INCLUDE_DIRS += -I./ - -FEM_SOLVER_FILES = FEM_mech.o FEM_thermal.o FEM_damage.o FEM_vacancyflux.o FEM_porosity.o FEM_hydrogenflux.o - -FEM_FILES = prec.o DAMASK_interface.o FEZoo.o IO.o libs.o numerics.o debug.o math.o \ - FEsolving.o mesh.o material.o lattice.o \ - $(SOURCE_FILES) $(KINEMATICS_FILES) $(PLASTIC_FILES) constitutive.o \ - crystallite.o \ - $(THERMAL_FILES) $(DAMAGE_FILES) $(VACANCYFLUX_FILES) $(HYDROGENFLUX_FILES) $(POROSITY_FILES) \ - $(HOMOGENIZATION_FILES) homogenization.o \ - CPFEM.o \ - FEM_utilities.o $(FEM_SOLVER_FILES) - -DAMASK_FEM.exe: DAMASK_FEM_driver.o - $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ - -o DAMASK_FEM.exe DAMASK_FEM_driver.o \ - $(FEM_FILES) $(LIBRARIES) $(HDFLIBS) $(HDFLIBZ) $(SUFFIX) - -DAMASK_FEM_driver.o: DAMASK_FEM_driver.f90 $(FEM_SOLVER_FILES) - $(PREFIX) $(COMPILERNAME) $(COMPILE_MAXOPTI) -c ../private/FEM/code/DAMASK_FEM_driver.f90 $(SUFFIX) - -FEM_mech.o: FEM_mech.f90 \ - FEM_utilities.o - -FEM_thermal.o: FEM_thermal.f90 \ - FEM_utilities.o - -FEM_damage.o: FEM_damage.f90 \ - FEM_utilities.o - -FEM_vacancyflux.o: FEM_vacancyflux.f90 \ - FEM_utilities.o - -FEM_porosity.o: FEM_porosity.f90 \ - FEM_utilities.o - -FEM_hydrogenflux.o: FEM_hydrogenflux.f90 \ - FEM_utilities.o - -FEM_utilities.o: FEM_utilities.f90 \ - CPFEM.o - -FEZoo.o: $(wildcard FEZoo.f90) \ - IO.o - $(IGNORE) $(PREFIX) $(COMPILERNAME) $(COMPILE) -c ../private/FEM/code/FEZoo.f90 $(SUFFIX) - touch FEZoo.o - -CPFEM.o: CPFEM.f90 \ - homogenization.o - -CPFEM2.o: CPFEM2.f90 \ - homogenization.o - -homogenization.o: homogenization.f90 \ - $(THERMAL_FILES) \ - $(DAMAGE_FILES) \ - $(VACANCYFLUX_FILES) \ - $(POROSITY_FILES) \ - $(HYDROGENFLUX_FILES) \ - $(HOMOGENIZATION_FILES) - -thermal_isothermal.o: thermal_isothermal.f90 \ - crystallite.o - -thermal_adiabatic.o: thermal_adiabatic.f90 \ - crystallite.o - -thermal_conduction.o: thermal_conduction.f90 \ - crystallite.o - -damage_none.o: damage_none.f90 \ - crystallite.o - -damage_local.o: damage_local.f90 \ - crystallite.o - -damage_nonlocal.o: damage_nonlocal.f90 \ - crystallite.o - -thermal_conduction.o: thermal_conduction.f90 \ - crystallite.o - -vacancyflux_isoconc.o: vacancyflux_isoconc.f90 \ - crystallite.o - -vacancyflux_isochempot.o: vacancyflux_isochempot.f90 \ - crystallite.o - -vacancyflux_cahnhilliard.o: vacancyflux_cahnhilliard.f90 \ - crystallite.o - -porosity_none.o: porosity_none.f90 \ - crystallite.o - -porosity_phasefield.o: porosity_phasefield.f90 \ - crystallite.o - -hydrogenflux_isoconc.o: hydrogenflux_isoconc.f90 \ - crystallite.o - -hydrogenflux_cahnhilliard.o: hydrogenflux_cahnhilliard.f90 \ - crystallite.o - -homogenization_RGC.o: homogenization_RGC.f90 \ - crystallite.o - -homogenization_isostrain.o: homogenization_isostrain.f90 \ - crystallite.o - -homogenization_none.o: homogenization_none.f90 \ - crystallite.o - -crystallite.o: crystallite.f90 \ - constitutive.o - -constitutive.o: constitutive.f90 \ - $(SOURCE_FILES) \ - $(KINEMATICS_FILES) \ - $(PLASTIC_FILES) - -source_thermal_dissipation.o: source_thermal_dissipation.f90 \ - lattice.o - -source_thermal_externalheat.o: source_thermal_externalheat.f90 \ - lattice.o - -source_damage_isoBrittle.o: source_damage_isoBrittle.f90 \ - lattice.o - -source_damage_isoDuctile.o: source_damage_isoDuctile.f90 \ - lattice.o - -source_damage_anisoBrittle.o: source_damage_anisoBrittle.f90 \ - lattice.o - -source_damage_anisoDuctile.o: source_damage_anisoDuctile.f90 \ - lattice.o - -source_vacancy_phenoplasticity.o: source_vacancy_phenoplasticity.f90 \ - lattice.o - -source_vacancy_irradiation.o: source_vacancy_irradiation.f90 \ - lattice.o - -source_vacancy_thermalfluc.o: source_vacancy_thermalfluc.f90 \ - lattice.o - -kinematics_cleavage_opening.o: kinematics_cleavage_opening.f90 \ - lattice.o - -kinematics_slipplane_opening.o: kinematics_slipplane_opening.f90 \ - lattice.o - -kinematics_thermal_expansion.o: kinematics_thermal_expansion.f90 \ - lattice.o - -kinematics_vacancy_strain.o: kinematics_vacancy_strain.f90 \ - lattice.o - -kinematics_hydrogen_strain.o: kinematics_hydrogen_strain.f90 \ - lattice.o - -plastic_nonlocal.o: plastic_nonlocal.f90 \ - lattice.o - -plastic_titanmod.o: plastic_titanmod.f90 \ - lattice.o - -plastic_disloUCLA.o: plastic_disloUCLA.f90 \ - lattice.o - -plastic_dislotwin.o: plastic_dislotwin.f90 \ - lattice.o - -plastic_phenopowerlaw.o: plastic_phenopowerlaw.f90 \ - lattice.o - -plastic_phenoplus.o: plastic_phenoplus.f90 \ - lattice.o - -plastic_isotropic.o: plastic_isotropic.f90 \ - lattice.o - -plastic_none.o: plastic_none.f90 \ - lattice.o -ifeq "$(F90)" "gfortran" -lattice.o: lattice.f90 \ - material.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -ffree-line-length-240 -c lattice.f90 $(SUFFIX) -# long lines for interaction matrix -else -lattice.o: lattice.f90 \ - material.o -endif - -material.o: material.f90 \ - mesh.o - -mesh.o: mesh.f90 \ - $(wildcard meshFEM.f90) \ - FEsolving.o \ - math.o \ - FEZoo.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(MESHNAME) -o mesh.o $(SUFFIX) - -FEsolving.o: FEsolving.f90 \ - debug.o - -math.o: math.f90 \ - debug.o - -debug.o: debug.f90 \ - numerics.o - -numerics.o: numerics.f90 \ - libs.o - -libs.o: libs.f90 \ - IO.o - -damask_hdf5.o: damask_hdf5.f90 \ - prec.o \ - IO.o - - $(PREFIX) $(COMPILERNAME) $(HDFLIBS) $(HDFLIBZ) -c damask_hdf5.f90 $(SUFFIX) -lm - -IO.o: IO.f90 \ - DAMASK_interface.o - -ifeq "$(F90)" "gfortran" -DAMASK_interface.o: spectral_interface.f90 \ - $(wildcard DAMASK_FEM_interface.f90) \ - prec.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -fall-intrinsics -o DAMASK_interface.o $(SUFFIX) -#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored -# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external -# --> allows the use of 'getcwd' -prec.o: prec.f90 - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 -fno-range-check -fall-intrinsics -fno-fast-math $(SUFFIX) -# fno-range-check: Disable range checking on results of simplification of constant expressions during compilation -# --> allows the definition of DAMASK_NaN -#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored -# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external -# --> allows the use of 'isnan' -#-fno-fast-math: -# --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) -else -DAMASK_interface.o: spectral_interface.f90 \ - $(wildcard DAMASK_FEM_interface.f90) \ - prec.o - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -diag-remark 7410 -stand none -warn nostderrors -o DAMASK_interface.o $(SUFFIX) -# -diag-disable 7410 should disable warning about directory statement in inquire function, but does not work. hence the other 2 statements -prec.o: prec.f90 - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c prec.f90 $(SUFFIX) - -endif - -%.o : %.f90 - $(PREFIX) $(COMPILERNAME) $(COMPILE) -c $< $(SUFFIX) - -.PHONY: tidy -tidy: - @rm -rf *.o - @rm -rf *.mod - @rm -rf *.inst.f90 # for instrumentation - @rm -rf *.pomp.f90 # for instrumentation - @rm -rf *.pp.f90 # for instrumentation - @rm -rf *.pdb # for instrumnentation - @rm -rf *.opari.inc # for instrumnentation - -.PHONY: cleanDAMASK -cleanDAMASK: - @rm -rf *.exe - @rm -rf *.marc - @rm -rf *.o - @rm -rf *.mod - @rm -rf *.inst.f90 # for instrumentation - @rm -rf *.pomp.f90 # for instrumentation - @rm -rf *.pp.f90 # for instrumentation - @rm -rf *.pdb # for instrumentation - @rm -rf *.opari.inc # for instrumentation - -.PHONY: help -help: - F90="$(F90)" - COMPILERNAME="$(COMPILERNAME)" - COMPILEROUT="$(COMPILEROUT)" - From b4ecea564f6a1c6a9fa6d8e7f8e052d2ec390342 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 20 May 2016 08:50:02 +0200 Subject: [PATCH 092/183] also not needed anymore (still to decide how to set bin directory for processing scripts) --- configure | 295 ------------------------------------------------------ 1 file changed, 295 deletions(-) delete mode 100755 configure diff --git a/configure b/configure deleted file mode 100755 index 017d28b04..000000000 --- a/configure +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env python -import os,re,sys,string,subprocess,shutil - -from optparse import OptionParser, Option - -# ----------------------------- -class extendableOption(Option): -# ----------------------------- -# used for definition of new option parser action 'extend', which enables to take multiple option arguments -# taken from online tutorial http://docs.python.org/library/optparse.html - - ACTIONS = Option.ACTIONS + ("extend",) - STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",) - TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",) - ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",) - - def take_action(self, action, dest, opt, value, values, parser): - if action == "extend": - lvalue = value.split(",") - values.ensure_value(dest, []).extend(lvalue) - else: - Option.take_action(self, action, dest, opt, value, values, parser) - - - -# ----------------------------- -def filePresent(paths,files,warning=False): - - for path in paths: - for file in files: - if os.path.isfile(os.path.join(path,file)): return True - - if warning: print "Warning: %s not found in %s"%(','.join(files),','.join(paths)) - - return False - - -######################################################## -# MAIN -######################################################## - -parser = OptionParser(option_class=extendableOption, usage='%prog options', description = """ -Configures the compilation and installation of DAMASK - -""" + string.replace('$Id$','\n','\\n') -) - -#--- determine default compiler ---------------------------------------------------------------------- -compiler = os.getenv('F90') -if compiler == None: - compiler = 'ifort' if subprocess.call(['which', 'ifort'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0 \ - else 'gfortran' - -#--- default option values -------------------------------------------------------------------------- -BLAS_order = ['IMKL','ACML','LAPACK','OPENBLAS'] - -defaults={'DAMASK_BIN':'depending on access rights', - 'F90':compiler, - 'FFTW_ROOT':'/usr', - 'MSC_ROOT' :'/msc', - 'DAMASK_NUM_THREADS':4, - 'MARC_VERSION':'2015', - 'blasType':'LAPACK', - 'blasRoot':{'LAPACK' :'/usr', - 'ACML' :'/opt/acml6.1.0', - 'IMKL' : os.getenv('MKLROOT') if os.getenv('MKLROOT') else '/opt/intel/composerxe/mkl', - 'OPENBLAS' :'/usr', - }, - 'spectralOptions':{}, - } - - - -#--- if local config file exists, read, otherwise assume global config file ------------------------ -configFile = os.path.join(os.getenv('HOME'),'.damask/damask.conf') \ - if os.path.isfile(os.path.join(os.getenv('HOME'),'.damask/damask.conf')) \ - else '/etc/damask.conf' - -#--- set default values according to read in values ------------------------------------------------ -try: - with open(configFile,'r') as f: - print('\n<<<<< reading default values from %s\n'%configFile) - for line in f: - line = line.strip() - if line.startswith('#') or line == '': - pass - - [key,value] = (re.split('[= ]',line)+[None,None])[:2] - - if key == 'DAMASK_NUM_THREADS': - defaults['DAMASK_NUM_THREADS'] = int(value) - if key == 'DAMASK_BIN': - defaults['DAMASK_BIN'] = value - if key in ['F90','FFTW_ROOT','MSC_ROOT','spectralOptions','MARC_VERSION']: - defaults[key] = value - for theKey in reversed(BLAS_order): - if key == theKey+'_ROOT' and value != None and value != '': - defaults['blasType'] = theKey - defaults['blasRoot'][theKey] = value -except IOError: - pass - -parser.add_option('--prefix', dest='prefix', metavar='string', - help='location of (links to) DAMASK executables [%default]') -parser.add_option('--with-FC','--with-fc', - dest='compiler', metavar='string', - help='F90 compiler [%default]') -parser.add_option('--with-FFTW-dir','--with-fftw-dir', - dest='fftwRoot', metavar='string', - help='root directory of FFTW [%default]') -parser.add_option('--with-MSC-dir','--with-msc-dir', - dest='mscRoot', metavar='string', - help='root directory of MSC.Marc/Mentat [%default]') -parser.add_option('--with-MARC-version','--with-marc-version', - dest='marcVersion', metavar='string', - help='version of MSC.Marc/Mentat [%default]') -parser.add_option('--with-OMP-threads','--with-omp-threads', - dest='threads', type='int', metavar='int', - help='number of openMP threads [%default]') -parser.add_option('--with-BLAS-type','--with-blas-type', - dest='blasType', metavar='string', - help='type of BLAS/LAPACK library [%default] {{{}}}'.format(','.join(BLAS_order))) -parser.add_option('--with-BLAS-dir','--with-blas-dir', - dest='blasRoot',metavar='string', - help='root directory of BLAS/LAPACK library [%default]') -parser.add_option('--with-spectral-options', dest='spectraloptions', action='extend', metavar='', - help='options for compilation of spectral solver') - -parser.set_defaults(prefix = defaults['DAMASK_BIN']) -parser.set_defaults(compiler = defaults['F90']) -parser.set_defaults(fftwRoot = defaults['FFTW_ROOT']) -parser.set_defaults(mscRoot = defaults['MSC_ROOT']) -parser.set_defaults(marcVersion = defaults['MARC_VERSION']) -parser.set_defaults(threads = defaults['DAMASK_NUM_THREADS']) -parser.set_defaults(blasType = defaults['blasType']) - -#--- set default for blasRoot depending on current option (or default) for blasType -------------------- -blasType = defaults['blasType'].upper() -for i, arg in enumerate(sys.argv): - if arg.lower().startswith('--with-blas-type'): - if arg.lower().endswith('--with-blas-type'): - blasType = sys.argv[i+1].upper() - else: - blasType = sys.argv[i][17:].upper() -if blasType not in BLAS_order: - blasType = defaults['blasType'].upper() - -parser.set_defaults(blasRoot = defaults['blasRoot'][blasType]) -parser.set_defaults(spectraloptions = []) - -(options,filenames) = parser.parse_args() - -#--- consistency checks -------------------------------------------------------------------------------- -options.compiler = options.compiler.lower() -options.blasType = options.blasType.upper() -options.fftwRoot = os.path.normpath(options.fftwRoot) -options.mscRoot = os.path.normpath(options.mscRoot) -options.blasRoot = os.path.normpath(options.blasRoot) - -locations = { - 'FFTW' : [os.path.join(options.fftwRoot,'lib64'),os.path.join(options.fftwRoot,'lib')], - 'LAPACK' : [os.path.join(options.blasRoot,'lib64'),os.path.join(options.blasRoot,'lib')], - 'OPENBLAS': [os.path.join(options.blasRoot,'lib64'),os.path.join(options.blasRoot,'lib')], - 'ACML' : [os.path.join(options.blasRoot,'%s64/lib'%options.compiler)], - 'ACML_mp' : [os.path.join(options.blasRoot,'%s64_mp/lib'%options.compiler)], - 'IMKL' : [os.path.join(options.blasRoot,'lib/intel64')], -} - -libraries = { - 'FFTW' : [ - 'libfftw3.so','libfftw3.a', - 'libfftw3_threads.so','libfftw3_threads.a', - ], - 'LAPACK' : [ - 'liblapack.so','liblapack.a','liblapack.dylib', - ], - 'OPENBLAS' : [ - 'libopenblas.so','libopenblas.a','libopenblas.dylib', - ], - 'ACML' : [ - 'libacml.so','libacml.a', - ], - 'ACML_mp' : [ - 'libacml_mp.so','libacml_mp.a', - ], - 'IMKL' : [ - 'libmkl_core.so','libmkl_core.a', - 'libmkl_sequential.so','libmkl_sequential.a', - 'libmkl_intel_thread.so','libmkl_intel_thread.a', - 'libmkl_intel_lp64.so','libmkl_intel_lp64.a', - 'libmkl_gnu_thread.so','libmkl_gnu_thread.a', - 'libmkl_gf_lp64.so','libmkl_gf_lp64.a', - ], - - } -if options.compiler not in ['ifort','gfortran']: - print('Error: Unknown compiler option: %s'%options.compiler) - sys.exit(1) - -if not subprocess.call(['which', options.compiler], stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0: - print('Compiler Warning: executable %s not found!'%options.compiler) - -if not os.path.isdir(options.mscRoot): - print('Warning: MSC root directory %s not found!'%options.mscRoot) - - -filePresent(locations['FFTW'],libraries['FFTW'],warning=True) - -if options.blasType in ['LAPACK','OPENBLAS','IMKL']: - filePresent(locations[options.blasType],libraries[options.blasType],warning=True) -elif options.blasType == 'ACML': - filePresent(locations[options.blasType],libraries[options.blasType],warning=True) - filePresent(locations[options.blasType+'_mp'],libraries[options.blasType+'_mp'],warning=True) -else: - print('Error: Unknown BLAS/LAPACK library: %s'%options.blasType) - sys.exit(1) - -#--- read config file if present to keep comments and order --------------------------------------- -output = [] -try: - with open(configFile,'r') as f: - for line in f: - line = line.strip() - items = re.split('[= ]',line) - - if (not line or items[0].startswith('#')): - pass - if items[0] == 'DAMASK_BIN': - line = '%s=%s'%(items[0],options.prefix) - options.prefix ='depending on access rights' - if items[0] == 'F90': - line = '%s=%s'%(items[0],options.compiler) - options.compiler ='' - if items[0] == 'FFTW_ROOT': - line = '%s=%s'%(items[0],options.fftwRoot) - options.fftwRoot ='' - if items[0] == 'MSC_ROOT': - line = '%s=%s'%(items[0],options.mscRoot) - options.mscRoot ='' - if items[0] == 'MARC_VERSION': - line = '%s=%s'%(items[0],options.marcVersion) - options.marcVersion ='' - if items[0] == 'DAMASK_NUM_THREADS': - line = '%s=%s'%(items[0],options.threads) - options.threads ='' - for blasType in defaults['blasRoot'].keys(): - if items[0] == '%s_ROOT'%blasType and items[0] == '%s_ROOT'%options.blasType: - line = '%s=%s'%(items[0],options.blasRoot) - options.blasType='' - elif items[0] == '#%s_ROOT'%blasType and items[0] == '#%s_ROOT'%options.blasType: - line = '%s=%s'%(items[0][1:],options.blasRoot) - options.blasType='' - elif items[0] == '%s_ROOT'%blasType: line = '#'+line - for spectralOption in options.spectraloptions: - [key,value] = re.split('[= ]',spectralOption)[0:2] - if key == items[0]: - line = '%s=%s'%(items[0],value) - options.spectraloptions.remove(spectralOption) - output.append(line) -except IOError: - pass - -#--- write remaining options -------------------------------------------------------------------------- -for opt, value in options.__dict__.items(): - if opt == 'prefix' and value != 'depending on access rights': - output.append('DAMASK_BIN=%s'%value) - if opt == 'compiler' and value != '': - output.append('F90=%s'%value) - if opt == 'fftwRoot' and value != '': - output.append('FFTW_ROOT=%s'%value) - if opt == 'mscRoot' and value != '': - output.append('MSC_ROOT=%s'%value) - if opt == 'marcVersion' and value != '': - output.append('MARC_VERSION=%s'%value) - if opt == 'threads' and value != '': - output.append('DAMASK_NUM_THREADS=%s'%value) - if opt == 'blasType' and value != '': - output.append('%s_ROOT=%s'%(options.blasType,options.blasRoot)) - -for spectralOption in options.spectraloptions: - output.append(spectralOption) - -#--- decide where do save the data ------------------------------------------------------------------- -configDir = '/etc' if os.access('/etc/', os.W_OK) \ - else os.path.join(os.getenv('HOME'),'.damask') # use system-wide config if possible -configFileNew = os.path.join(configDir,'damask.conf') - -if not os.path.isdir(configDir): - os.mkdir(configDir) - -print('\n>>>>> writing values to %s\n'%configFileNew) -with open(configFileNew,'w') as f: - for line in output: - print(line) - f.write(line+'\n') From 475c864ea37af47c584a020881f0a12cedb8014e Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 20 May 2016 11:51:50 +0200 Subject: [PATCH 093/183] using different CMAKE projects for FEM/Spectral --- CMakeLists.txt | 26 +++++++++++--------------- src/CMakeLists.txt | 15 +++++++-------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37f0f9ed9..31768bbb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,17 @@ foreach (exlib ${TMP_LIST}) endforeach(exlib) set(CMAKE_Fortran_COMPILER "${MPIFC}") -project (DAMASK Fortran) + +# DAMASK DRIVER SELECTION +if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") + project(DAMASK_spectral Fortran) + add_definitions(-DSpectral) + message("***Configuring Spectral Solver\n") +elseif ("${DAMASK_DRIVER}" STREQUAL "FEM") + project(DAMASK_FEM Fortran) + add_definitions(-DFEM) + message("***Configuring FEM Solver\n") +endif() # Find DAMASK version (DAMASK_V) in DAMASK_ROOT find_program (CAT_EXECUTABLE NAMES cat) @@ -114,8 +124,6 @@ set (DAMASK_VERSION_MINOR ${DAMASK_V}) # -> can be overwritten from commandline/install_script option(OPENMP "Use OpenMP libaries for DAMASK" ON ) option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) -option(SPECTRAL "Build spectral sovler for DAMASAK" OFF ) -option(FEM "Build FEM solver for DAMASK" OFF ) if (NOT DEFINED CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) @@ -135,18 +143,6 @@ else(DEFINED DAMASK_INSTALL) endif(DEFINED DAMASK_INSTALL) message("\n***The binary will be installed at\n${CMAKE_INSTALL_PREFIX}\n") -# DAMASK DRIVER SELECTION -if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") - set (SPECTRAL ON ) - add_definitions(-DSpectral) - set (FEM OFF) - message("***Configuring Spectral Solver\n") -elseif ("${DAMASK_DRIVER}" STREQUAL "FEM") - set (FEM ON ) - add_definitions(-DFEM) - set (SPECTRAL OFF) - message("***Configuring FEM Solver\n") -endif("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e5875629..b2fc87418 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,11 +29,11 @@ endif() add_library(DAMASK_PREC "prec.f90") -if (SPECTRAL) +if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") add_library(DAMASK_INTERFACE "spectral_interface.f90") -elseif(FEM) +elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") add_library(DAMASK_INTERFACE "DAMASK_FEM_interface.f90") -endif(SPECTRAL) +endif() target_link_libraries(DAMASK_INTERFACE DAMASK_PREC) add_library(DAMASK_IO "IO.f90") @@ -56,16 +56,15 @@ target_link_libraries(DAMASK_MATH DAMASK_FEsolving) # SPECTRAL solver and FEM solver use different mesh # source files -if (SPECTRAL) +if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") add_library(DAMASK_MESH "mesh.f90") target_link_libraries(DAMASK_MESH DAMASK_MATH) -endif(SPECTRAL) -if (FEM) +elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") add_library(DAMASK_FEZoo "FEZoo.f90") target_link_libraries(DAMASK_FEZoo DAMASK_MATH) add_library(DAMASK_MESH "meshFEM.f90") target_link_libraries(DAMASK_MESH DAMASK_FEZoo) -endif(FEM) +endif() add_library(DAMASK_MATERIAL "material.f90") @@ -194,4 +193,4 @@ if (SPECTRAL) add_executable(DAMASK_spectral "DAMASK_spectral.f90") target_link_libraries(DAMASK_spectral DAMASK_EXE) -endif(SPECTRAL) \ No newline at end of file +endif(SPECTRAL) From e3d8d48990873a8964aeb8f2ed278488ed09f74d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 21 May 2016 15:06:01 +0200 Subject: [PATCH 094/183] currently, only BUILD_CMD_TYPE release works --- CMakeLists.txt | 160 ++++++++++++++--------------- Makefile | 4 +- src/CMakeLists.txt | 246 ++++++++++++++++++++++----------------------- 3 files changed, 200 insertions(+), 210 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 75b11ede9..ff6992b8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,8 +30,9 @@ include ${petsc_conf_rules} include ${petsc_conf_variables} INCLUDE_DIRS := \${PETSC_FC_INCLUDES} LIBRARIES := \${PETSC_WITH_EXTERNAL_LIB} -COMPILERF ?= \${FC} -LINKERNAME ?= \${FLINKER} +COMPILERF := \${FC} +COMPILERC := \${CC} +LINKERNAME := \${FLINKER} includes: \t@echo \${INCLUDE_DIRS} extlibs: @@ -60,10 +61,15 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_confi RESULT_VARIABLE PETSC_EXTERNAL_LIB_RETURN OUTPUT_VARIABLE petsc_external_lib OUTPUT_STRIP_TRAILING_WHITESPACE) -# PETSc specified compiler +# PETSc specified fortran compiler execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "compilerf" - RESULT_VARIABLE MPIFC_RETURN - OUTPUT_VARIABLE MPIFC + 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 (MPIF90 + PETSc linking flags) execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "linker" @@ -85,51 +91,37 @@ foreach (exlib ${TMP_LIST}) set(PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} ${exlib}") endforeach(exlib) -set(CMAKE_Fortran_COMPILER "${MPIFC}") -# DAMASK DRIVER SELECTION -if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") - project(DAMASK_spectral Fortran) - add_definitions(-DSpectral) - message("***Configuring Spectral Solver\n") -elseif ("${DAMASK_DRIVER}" STREQUAL "FEM") - project(DAMASK_FEM Fortran) - add_definitions(-DFEM) - message("***Configuring FEM Solver\n") -endif() - -# Find DAMASK version (DAMASK_V) in DAMASK_ROOT -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) +# 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}") +set(CMAKE_LINKER "${PETSC_LINKER}") 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 FORTRAN MPI COMPILER:\n${MPIFC}\n" ) +message("***Found MPI FORTRAN COMPILER:\n${PETSC_MPIFC}\n" ) +message("***Found MPI C COMPILER:\n${PETSC_MPICC}\n" ) - -# # https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F #--------------------------------------------------------------------------------------- # Now start to care about DAMASK +# DAMASK Solver selection +if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") + project(DAMASK_spectral Fortran C) + add_definitions(-DSpectral) + message("***Configuring Spectral Solver\n") +elseif ("${DAMASK_DRIVER}" STREQUAL "FEM") + project(DAMASK_FEM Fortran C) + add_definitions(-DFEM) + message("***Configuring FEM Solver\n") +endif() + # Built-in options for DAMASK build system # -> can be overwritten from commandline/install_script option(OPENMP "Use OpenMP libaries for DAMASK" ON ) option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) -if (NOT DEFINED CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) -endif(NOT DEFINED CMAKE_BUILD_TYPE) - -# COMPILE VARIABLES -add_definitions(-DDAMASKVERSION="${DAMASK_V}") -add_definitions(-DPETSc) -add_definitions(-DFLOAT=8) -add_definitions(-DINT=4) - # Setting installation prefix if (DEFINED DAMASK_INSTALL) set (CMAKE_INSTALL_PREFIX "${DAMASK_INSTALL}") @@ -138,6 +130,23 @@ else(DEFINED DAMASK_INSTALL) endif(DEFINED DAMASK_INSTALL) message("\n***The binary will be installed at\n${CMAKE_INSTALL_PREFIX}\n") +# Set build options +if (NOT DEFINED CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif(NOT DEFINED CMAKE_BUILD_TYPE) + +# Find DAMASK version (DAMASK_V) in DAMASK_ROOT +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) +add_definitions(-DFLOAT=8) +add_definitions(-DINT=4) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") @@ -164,8 +173,6 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") #------------------------------------------------------------------------------------------------ # COMPILE SWITCHES -# -fpp: preprocessor -# -ftz: flush unterflow to zero, automatically set if O<0,1,2,3> >0 # -assume byterecl record length is given in bytes (also set by -standard-semantics) # fpe_summary print list of floating point exceptions occured during execution # -fimplicit-none: assume "implicit-none" even if not present in source @@ -181,14 +188,9 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") # unused: declared variables that are never used # stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) # -# MORE OPTIONS FOR DEBUGGING DURING COMPILATION -# -warn: enables warnings, where -# truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) -# uncalled: Determines whether warnings occur when a statement function is never called -# all: -# -name as_is: case sensitive Fortran! - set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz" ) + + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp" )# preprocessor + set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz" )# flush unterflow to zero, automatically set if O<0,1,2,3> >0 set (COMPILE_FLAGS "${COMPILE_FLAGS} -assume byterecl,fpe_summary") set (COMPILE_FLAGS "${COMPILE_FLAGS} -diag-disable 5268" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn declarations" ) @@ -198,42 +200,37 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn ignore_loc" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn alignments" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn unused" ) +# MORE OPTIONS FOR DEBUGGING DURING COMPILATION +# -warn: enables warnings, where +# truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) +# uncalled: Determines whether warnings occur when a statement function is never called +# all: +# -name as_is: case sensitive Fortran! #------------------------------------------------------------------------------------------------ # COMPILE SWITCHES FOR RUNTIME DEBUGGING -# -g: Generate symbolic debugging information in the object file -# -traceback: Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. -# -gen-interfaces: Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ -# -fp-stack-check: Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. -# -ftrapuv Trap uninitalized variables -# -check: checks at runtime, where -# bounds: check if an array index is too small (<1) or too large! -# format: Checking for the data type of an item being formatted for output. -# output_conversion: Checking for the fit of data items within a designated format descriptor field. -# pointers: Checking for certain disassociated or uninitialized pointers or unallocated allocatable objects. -# uninit: Checking for uninitialized variables. -# -fpe-all0 capture all floating-point exceptions, sets -ftz automatically -# -warn: enables warnings, where -# errors: warnings are changed to errors -# stderrors: warnings about Fortran standard violations are changed to errors -# information on http://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors/ -# + set (DEBUG_FLAGS "${DEBUG_FLAGS} -g" )# Generate symbolic debugging information in the object file + set (DEBUG_FLAGS "${DEBUG_FLAGS} -traceback" )# Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. + set (DEBUG_FLAGS "${DEBUG_FLAGS} -gen-interfaces" )# Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-stack-check" )# Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-model strict" )# Trap uninitalized variables + set (DEBUG_FLAGS "${DEBUG_FLAGS} -check bounds,format,output_conversion,pointers,uninit" )# Checks at runtime, where + # bounds: if an array index is too small (<1) or too large! + # format: for the data type of an item being formatted for output. + # output_conversion: for the fit of data items within a designated format descriptor field. + # pointers: for certain disassociated or uninitialized pointers or unallocated allocatable objects. + # uninit: for uninitialized variables. + set (DEBUG_FLAGS "${DEBUG_FLAGS} -ftrapuv" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all0" )# Capture all floating-point exceptions, sets -ftz automatically + set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn errors,stderrors" )# Configures warnings, where + # errors: warnings are changed to errors + # stderrors: warnings about Fortran standard violations are changed to errors + set (DEBUG_FLAGS "${DEBUG_FLAGS} -debug-parameters all" ) # MORE OPTIONS FOR RUNTIME DEBUGGING -# -heap-arrays: should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits -# -check: checks at runtime, where +# -heap-arrays: Should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits +# -check: Checks at runtime, where # arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) # stack: - set (DEBUG_FLAGS "${DEBUG_FLAGS} -g" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -traceback" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -gen-interfaces" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-stack-check" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-model strict" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -check bounds,format,output_conversion,pointers,uninit" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -ftrapuv" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all0" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn errors" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn stderrors" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -debug-parameters all" ) #------------------------------------------------------------------------------------------------ # PRECISION SETTINGS @@ -384,12 +381,12 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") endif() + set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAGS}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPTIMIZATION_FLAGS}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_FLAGS}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_FLAGS}") - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAGS}" ) set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK}") set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_FLAGS}" ) @@ -400,7 +397,7 @@ set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_FLAGS set (CMAKE_Fortran_FLAGS_RELEASE "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") set (CMAKE_Fortran_FLAGS_DEBUG "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") -set (CMAKE_LINKER "${PETSC_LINKER}") + if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (CMAKE_Fortran_LINK_EXECUTABLE @@ -417,11 +414,10 @@ message("***LINKER:\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") add_subdirectory(src) # INSTALL BUILT BINARIES -if (SPECTRAL) +if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_spectral DESTINATION ${CMAKE_INSTALL_PREFIX}) -elseif (FEM) +elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM DESTINATION ${CMAKE_INSTALL_PREFIX}) -endif(SPECTRAL) - +endif("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") diff --git a/Makefile b/Makefile index e9c242748..4d2d9bf74 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ spectral: build/spectral build/spectral: build @mkdir build/spectral - @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=SPECTRAL ../..;) + @(cd build/spectral; cmake -Wno-dev -DDAMASK_DRIVER=SPECTRAL ../..;) build: bin @mkdir build @@ -23,7 +23,7 @@ FEM: build/FEM build/FEM: build @mkdir build - @(cd build/FEM; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_DRIVER=FEM ../..;) + @(cd build/FEM; cmake -Wno-dev -DDAMASK_DRIVER=FEM ../..;) .PHONY: clean clean: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b2fc87418..8b4ee59f3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,13 +1,5 @@ -# The dependency detection in CMake is not functioning for Fortran -# !!! EXPLICIT DEPENDENCY DECLARATION !!! - # SOME FILES REQUIRE SPECIAL FLAGS -if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") - # -diag-disable 7410 should disable warning about directory statement - # in inquire function, but does not work. hence the other 2 statements - SET_SOURCE_FILES_PROPERTIES( "spectral_interface.f90" PROPERTIES - COMPILE_FLAGS "-diag-remark 7410 -stand none -warn nostderrors" ) -elseif (${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") +if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # fno-range-check: Disable range checking on results of simplification of constant expressions during compilation # --> allows the definition of DAMASK_NaN #-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored @@ -17,138 +9,165 @@ elseif (${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) SET_SOURCE_FILES_PROPERTIES( "prec.f90" PROPERTIES COMPILE_FLAGS "-fno-range-check -fall-intrinsics -fno-fast-math") - #-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored - # and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external - # --> allows the use of 'getcwd' - SET_SOURCE_FILES_PROPERTIES( "spectral_interface.f90" PROPERTIES - COMPILE_FLAGS "-fall-intrinsics") # long lines for interaction matrix SET_SOURCE_FILES_PROPERTIES( "lattice.f90" PROPERTIES COMPILE_FLAGS "-ffree-line-length-240") endif() -add_library(DAMASK_PREC "prec.f90") +# The dependency detection in CMake is not functioning for Fortran, +# hence we declare the dependencies from top to bottom in the following + +add_library(C_ROUTINES "C_routines.c") + +add_library(SYSTEM_ROUTINES "system_routines.f90") +target_link_libraries(SYSTEM_ROUTINES C_ROUTINES) + +add_library(PREC "prec.f90") +target_link_libraries(PREC SYSTEM_ROUTINES) if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") add_library(DAMASK_INTERFACE "spectral_interface.f90") elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") add_library(DAMASK_INTERFACE "DAMASK_FEM_interface.f90") endif() -target_link_libraries(DAMASK_INTERFACE DAMASK_PREC) +target_link_libraries(DAMASK_INTERFACE PREC) -add_library(DAMASK_IO "IO.f90") -target_link_libraries(DAMASK_IO DAMASK_INTERFACE) +add_library(IO "IO.f90") +target_link_libraries(IO DAMASK_INTERFACE) -add_library(DAMASK_LIBS "libs.f90") -target_link_libraries(DAMASK_LIBS DAMASK_IO) +add_library(EXTERNALLIBS "libs.f90") +target_link_libraries(EXTERNALLIBS IO) -add_library(DAMASK_NUMERICS "numerics.f90") -target_link_libraries(DAMASK_NUMERICS DAMASK_LIBS) +add_library(NUMERICS "numerics.f90") +target_link_libraries(NUMERICS EXTERNALLIBS) -add_library(DAMASK_DEBUG "debug.f90") -target_link_libraries(DAMASK_DEBUG DAMASK_NUMERICS) +add_library(DEBUG "debug.f90") +target_link_libraries(DEBUG NUMERICS) -add_library(DAMASK_FEsolving "FEsolving.f90") -target_link_libraries(DAMASK_FEsolving DAMASK_DEBUG) +add_library(FEsolving "FEsolving.f90") +target_link_libraries(FEsolving DEBUG) add_library(DAMASK_MATH "math.f90") -target_link_libraries(DAMASK_MATH DAMASK_FEsolving) +target_link_libraries(DAMASK_MATH FEsolving) # SPECTRAL solver and FEM solver use different mesh # source files if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") - add_library(DAMASK_MESH "mesh.f90") - target_link_libraries(DAMASK_MESH DAMASK_MATH) + add_library(MESH "mesh.f90") + target_link_libraries(MESH DAMASK_MATH) elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") - add_library(DAMASK_FEZoo "FEZoo.f90") - target_link_libraries(DAMASK_FEZoo DAMASK_MATH) - add_library(DAMASK_MESH "meshFEM.f90") - target_link_libraries(DAMASK_MESH DAMASK_FEZoo) + add_library(FEZoo "FEZoo.f90") + target_link_libraries(FEZoo DAMASK_MATH) + add_library(MESH "meshFEM.f90") + target_link_libraries(MESH FEZoo) endif() +add_library(MATERIAL "material.f90") +target_link_libraries(MATERIAL MESH) -add_library(DAMASK_MATERIAL "material.f90") -target_link_libraries(DAMASK_MATERIAL DAMASK_MESH) - -add_library(DAMASK_LATTICE "lattice.f90") -target_link_libraries(DAMASK_LATTICE DAMASK_MATERIAL) -add_library(DAMASK_DRIVERS ALIAS DAMASK_LATTICE) +add_library(LATTICE "lattice.f90") +target_link_libraries(LATTICE MATERIAL) +add_library(DAMASK_HELPERS ALIAS LATTICE) # For each modular section -add_library (DAMASK_PLASTIC "plastic_dislotwin.f90" - "plastic_disloUCLA.f90" - "plastic_isotropic.f90" - "plastic_phenopowerlaw.f90" - "plastic_titanmod.f90" - "plastic_nonlocal.f90" - "plastic_none.f90" - "plastic_phenoplus.f90") -target_link_libraries(DAMASK_PLASTIC DAMASK_DRIVERS) +add_library (PLASTIC + "plastic_dislotwin.f90" + "plastic_disloUCLA.f90" + "plastic_isotropic.f90" + "plastic_phenopowerlaw.f90" + "plastic_titanmod.f90" + "plastic_nonlocal.f90" + "plastic_none.f90" + "plastic_phenoplus.f90") +target_link_libraries(PLASTIC DAMASK_HELPERS) -add_library (DAMASK_KINEMATICS "kinematics_cleavage_opening.f90" - "kinematics_slipplane_opening.f90" - "kinematics_thermal_expansion.f90" - "kinematics_vacancy_strain.f90" - "kinematics_hydrogen_strain.f90") -target_link_libraries(DAMASK_KINEMATICS DAMASK_DRIVERS) +add_library (KINEMATICS + "kinematics_cleavage_opening.f90" + "kinematics_slipplane_opening.f90" + "kinematics_thermal_expansion.f90" + "kinematics_vacancy_strain.f90" + "kinematics_hydrogen_strain.f90") +target_link_libraries(KINEMATICS DAMASK_HELPERS) -add_library (DAMASK_SOURCE "source_thermal_dissipation.f90" - "source_thermal_externalheat.f90" - "source_damage_isoBrittle.f90" - "source_damage_isoDuctile.f90" - "source_damage_anisoBrittle.f90" - "source_damage_anisoDuctile.f90" - "source_vacancy_phenoplasticity.f90" - "source_vacancy_irradiation.f90" - "source_vacancy_thermalfluc.f90") -target_link_libraries(DAMASK_SOURCE DAMASK_DRIVERS) +add_library (SOURCE + "source_thermal_dissipation.f90" + "source_thermal_externalheat.f90" + "source_damage_isoBrittle.f90" + "source_damage_isoDuctile.f90" + "source_damage_anisoBrittle.f90" + "source_damage_anisoDuctile.f90" + "source_vacancy_phenoplasticity.f90" + "source_vacancy_irradiation.f90" + "source_vacancy_thermalfluc.f90") +target_link_libraries(SOURCE DAMASK_HELPERS) -add_library(DAMASK_CONSTITUTIVE "constitutive.f90") -target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_PLASTIC ) -target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_KINEMATICS) -target_link_libraries(DAMASK_CONSTITUTIVE DAMASK_SOURCE ) +add_library(CONSTITUTIVE "constitutive.f90") +target_link_libraries(CONSTITUTIVE PLASTIC) +target_link_libraries(CONSTITUTIVE KINEMATICS) +target_link_libraries(CONSTITUTIVE SOURCE) -add_library(DAMASK_CRYSTALLITE "crystallite.f90") -target_link_libraries(DAMASK_CRYSTALLITE DAMASK_CONSTITUTIVE) +add_library(CRYSTALLITE "crystallite.f90") +target_link_libraries(CRYSTALLITE CONSTITUTIVE) -add_library(DAMASK_HOMOGENIZATION "homogenization_RGC.f90" - "homogenization_isostrain.f90" - "homogenization_none.f90") -target_link_libraries(DAMASK_HOMOGENIZATION DAMASK_CRYSTALLITE) +add_library(HOMOGENIZATION + "homogenization_RGC.f90" + "homogenization_isostrain.f90" + "homogenization_none.f90") +target_link_libraries(HOMOGENIZATION CRYSTALLITE) -add_library(DAMASK_HYDROGENFLUX "hydrogenflux_isoconc.f90" - "hydrogenflux_cahnhilliard.f90") -target_link_libraries(DAMASK_HYDROGENFLUX DAMASK_CRYSTALLITE) +add_library(HYDROGENFLUX + "hydrogenflux_isoconc.f90" + "hydrogenflux_cahnhilliard.f90") +target_link_libraries(HYDROGENFLUX CRYSTALLITE) -add_library(DAMASK_POROSITY "porosity_none.f90" - "porosity_phasefield.f90") -target_link_libraries(DAMASK_POROSITY DAMASK_CRYSTALLITE) +add_library(POROSITY + "porosity_none.f90" + "porosity_phasefield.f90") +target_link_libraries(POROSITY CRYSTALLITE) -add_library(DAMASK_VACANCYFLUX "vacancyflux_isoconc.f90" - "vacancyflux_isochempot.f90" - "vacancyflux_cahnhilliard.f90") -target_link_libraries(DAMASK_VACANCYFLUX DAMASK_CRYSTALLITE) +add_library(VACANCYFLUX + "vacancyflux_isoconc.f90" + "vacancyflux_isochempot.f90" + "vacancyflux_cahnhilliard.f90") +target_link_libraries(VACANCYFLUX CRYSTALLITE) -add_library(DAMASK_DAMAGE "damage_none.f90" - "damage_local.f90" - "damage_nonlocal.f90") -target_link_libraries(DAMASK_DAMAGE DAMASK_CRYSTALLITE) +add_library(DAMAGE + "damage_none.f90" + "damage_local.f90" + "damage_nonlocal.f90") +target_link_libraries(DAMAGE CRYSTALLITE) -add_library(DAMASK_THERMAL "thermal_isothermal.f90" - "thermal_adiabatic.f90" - "thermal_conduction.f90") -target_link_libraries(DAMASK_THERMAL DAMASK_CRYSTALLITE) +add_library(THERMAL + "thermal_isothermal.f90" + "thermal_adiabatic.f90" + "thermal_conduction.f90") +target_link_libraries(THERMAL CRYSTALLITE) add_library(DAMASK_ENGINE "homogenization.f90") -target_link_libraries(DAMASK_ENGINE DAMASK_THERMAL ) -target_link_libraries(DAMASK_ENGINE DAMASK_DAMAGE ) -target_link_libraries(DAMASK_ENGINE DAMASK_VACANCYFLUX ) -target_link_libraries(DAMASK_ENGINE DAMASK_POROSITY ) -target_link_libraries(DAMASK_ENGINE DAMASK_HYDROGENFLUX ) -target_link_libraries(DAMASK_ENGINE DAMASK_HOMOGENIZATION) +target_link_libraries(DAMASK_ENGINE THERMAL ) +target_link_libraries(DAMASK_ENGINE DAMAGE ) +target_link_libraries(DAMASK_ENGINE VACANCYFLUX ) +target_link_libraries(DAMASK_ENGINE POROSITY ) +target_link_libraries(DAMASK_ENGINE HYDROGENFLUX ) +target_link_libraries(DAMASK_ENGINE HOMOGENIZATION) -if (FEM) +if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") + add_library(DAMASK_CPFE "CPFEM2.f90") + target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) + + add_library(SPECTRAL_UTILITIES spectral_utilities.f90) + target_link_libraries(SPECTRAL_UTILITIES DAMASK_CPFE) + + add_library(SPECTRAL_SOLVER "spectral_thermal.f90" + "spectral_damage.f90" + "spectral_mech_AL.f90" + "spectral_mech_Polarisation.f90" + "spectral_mech_Basic.f90") + target_link_libraries(SPECTRAL_SOLVER SPECTRAL_UTILITIES) + add_executable(DAMASK_spectral "DAMASK_spectral.f90") + target_link_libraries(DAMASK_spectral SPECTRAL_SOLVER) +elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") add_library(DAMASK_CPFE "CPFEM.f90") target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) @@ -167,30 +186,5 @@ if (FEM) target_link_libraries(DAMASK_FEM_DRIVER DAMASK_FEM_BASE) add_executable(DAMASK_FEM "DAMASK_FEM_driver.f90") - target_link_libraries(DAMASK_FEM DAMASK_FEM_DRIVER) -endif(FEM) - -if (SPECTRAL) - add_library(DAMASK_CPFE "CPFEM2.f90") - target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) - - add_library(DAMASK_SPECTRAL_UTILITY spectral_utilities.f90) - target_link_libraries(DAMASK_SPECTRAL_UTILITY DAMASK_CPFE) - - add_library(DAMASK_SPECTRAL_BASE "spectral_thermal.f90" - "spectral_damage.f90") - target_link_libraries(DAMASK_SPECTRAL_BASE DAMASK_SPECTRAL_UTILITY) - - add_library(DAMASK_SPECTRAL_MECH "spectral_mech_AL.f90" - "spectral_mech_Polarisation.f90" - "spectral_mech_Basic.f90") - target_link_libraries(DAMASK_SPECTRAL_MECH DAMASK_SPECTRAL_UTILITY) - - add_library(DAMASK_EXE "DAMASK_spectral.f90") - target_link_libraries(DAMASK_EXE DAMASK_CPFE ) - target_link_libraries(DAMASK_EXE DAMASK_SPECTRAL_BASE) - target_link_libraries(DAMASK_EXE DAMASK_SPECTRAL_MECH) - - add_executable(DAMASK_spectral "DAMASK_spectral.f90") - target_link_libraries(DAMASK_spectral DAMASK_EXE) -endif(SPECTRAL) + target_link_libraries(DAMASK_FEM DAMASK_FEM_EXE) +endif() From 13782f4ee063580bd4da9aa63c8ba36cc50d142a Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 21 May 2016 16:51:12 +0200 Subject: [PATCH 095/183] simplified --- CMakeLists.txt | 101 +++++++++++++++------------------------------ Makefile | 6 +-- src/CMakeLists.txt | 2 +- 3 files changed, 38 insertions(+), 71 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff6992b8d..c8fb18602 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,11 +91,6 @@ foreach (exlib ${TMP_LIST}) set(PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} ${exlib}") endforeach(exlib) -# 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}") -set(CMAKE_LINKER "${PETSC_LINKER}") - 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") @@ -107,16 +102,22 @@ message("***Found MPI C COMPILER:\n${PETSC_MPICC}\n" ) # Now start to care about DAMASK # DAMASK Solver selection -if ("${DAMASK_DRIVER}" STREQUAL "SPECTRAL") +if ("${DAMASK_SOLVER}" STREQUAL "SPECTRAL") project(DAMASK_spectral Fortran C) add_definitions(-DSpectral) message("***Configuring Spectral Solver\n") -elseif ("${DAMASK_DRIVER}" STREQUAL "FEM") +elseif ("${DAMASK_SOLVER}" STREQUAL "FEM") project(DAMASK_FEM Fortran C) add_definitions(-DFEM) message("***Configuring FEM Solver\n") endif() +# set compiler and linker commands (need to be done after 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}") +set(CMAKE_LINKER "${PETSC_LINKER}") + # Built-in options for DAMASK build system # -> can be overwritten from commandline/install_script option(OPENMP "Use OpenMP libaries for DAMASK" ON ) @@ -130,11 +131,6 @@ else(DEFINED DAMASK_INSTALL) endif(DEFINED DAMASK_INSTALL) message("\n***The binary will be installed at\n${CMAKE_INSTALL_PREFIX}\n") -# Set build options -if (NOT DEFINED CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) -endif(NOT DEFINED CMAKE_BUILD_TYPE) - # Find DAMASK version (DAMASK_V) in DAMASK_ROOT find_program (CAT_EXECUTABLE NAMES cat) execute_process(COMMAND ${CAT_EXECUTABLE} ${PROJECT_SOURCE_DIR}/VERSION @@ -257,23 +253,15 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") endif() set (STANDARD_CHECK "-std=f2008ts -pedantic-errors" ) - set (LINKER_FLAGS "-Wl,-undefined,dynamic_lookup") + set (LINKER_FLAGS "-Wl,-undefined,dynamic_lookup" )# ensure to link against dynamic libraries #------------------------------------------------------------------------------------------------ # COMPILE SWITCHES -# -shared -# -Wl,-undefined,dynamic_lookup:ensure to link against dynamic libraries -# -xf95-cpp-input: preprocessor -# -ffree-line-length-132: restrict line length to the standard 240 characters (lattice.f90 require larger) -# -ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) -# -fimplicit-none: assume "implicit-none" even if not present in source -# -fmodule-private: assume "private" even if not present in source -# -Wcharacter-truncation: warn if character expressions (strings) are truncated -# -Wunderflow: produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation -# -Wsuggest-attribute=pure: -# -Wsuggest-attribute=noreturn: -# -Wconversion-extra -# -Wimplicit-procedure + set (COMPILE_FLAGS "${COMPILE_FLAGS} -xf95-cpp-input" )# preprocessor + set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffree-line-length-132" )# restrict line length to the standard 132 characters (lattice.f90 require larger) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fimplicit-none" )# assume "implicit-none" even if not present in source + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fmodule-private" )# assume "private" even if not present in source + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wall" ) # -Wall: sets the following Fortran options: # -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. # -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line @@ -313,6 +301,7 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # -Wunused-value # -Wunused-variable # -Wvolatile-register-var + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wextra" ) # -Wextra: sets the following Fortran options: # -Wunuses-parameter: # -Wcompare-reals: @@ -327,27 +316,20 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # -Wuninitialized # -Wunused-but-set-parameter (only with -Wunused or -Wall) # -Wno-globals -# -ffpe-summary=all only for newer gfortran -# -# MORE OPTIONS FOR DEBUGGING DURING COMPILATION -# -Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): -# -Wimplicit-interface: no interfaces for lapack routines -# -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. -# -Wstrict-overflow: - set (COMPILE_FLAGS "${COMPILE_FLAGS} -xf95-cpp-input" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffree-line-length-132" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -fimplicit-none" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -fmodule-private" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wall" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wextra" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wcharacter-truncation" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wunderflow" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wcharacter-truncation" )# warn if character expressions (strings) are truncated + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wunderflow" )# produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=pure" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=noreturn") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wconversion-extra" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wimplicit-procedure" ) set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-unused-parameter" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -fno-range-check" ) +# MORE OPTIONS FOR DEBUGGING DURING COMPILATION +# -Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): +# -Wimplicit-interface: no interfaces for lapack routines +# -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. +# -ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) +# -ffpe-summary=all: only for newer gfortran + #------------------------------------------------------------------------------------------------ # COMPILE SWITCHES FOR RUNTIME DEBUGGING @@ -378,36 +360,21 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") #-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used #-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) set (PRECISION_FLAGS "-fdefault-real-8 -fdefault-double-8") +endif() +set (CMAKE_Fortran_FLAGS "${BUILDCMD_PRE} ${OPENMP_FLAGS} ${STANDARD_CHECK} ${OPTIMIZATION_FLAGS} ${COMPILE_FLAGS} ${PRECISION_FLAGS}") +set (CMAKE_Fortran_LINK_EXECUTABLE "${BUILDCMD_PRE} ${CMAKE_LINKER} ${OPENMP_FLAGS} ${OPTIMIZATION_FLAGS} ${LINKER_FLAGS}") + +if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DEBUG_FLAGS}") + set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} ${DEBUG_FLAGS}") endif() -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPENMP_FLAGS}") -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${STANDARD_CHECK}") -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${OPTIMIZATION_FLAGS}") -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${COMPILE_FLAGS}") -set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} ${PRECISION_FLAGS}") -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPENMP_FLAGS}" ) -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${STANDARD_CHECK}") -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${OPTIMIZATION_FLAGS}" ) -set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS}" ) +set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") +set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") -set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${CMAKE_Fortran_FLAGS_RELEASE}") -set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} ${DEBUG_FLAGS}" ) - -set (CMAKE_Fortran_FLAGS_RELEASE "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_RELEASE} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") -set (CMAKE_Fortran_FLAGS_DEBUG "${BUILDCMD_PRE} ${CMAKE_Fortran_FLAGS_DEBUG} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") - - -if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_RELEASE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") -else("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - set (CMAKE_Fortran_LINK_EXECUTABLE - "${BUILDCMD_PRE} ${CMAKE_LINKER} ${CMAKE_EXE_LINKER_FLAGS_DEBUG} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") -endif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") - -message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS_RELEASE}\n") +message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS}\n") message("***LINKER:\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") # MOVE to SOURCE DIRECTORY for BUILDING diff --git a/Makefile b/Makefile index 4d2d9bf74..9721b7722 100644 --- a/Makefile +++ b/Makefile @@ -6,11 +6,11 @@ SHELL = /bin/sh all: spectral FEM spectral: build/spectral - @(cd build/spectral; make --no-print-directory -ws all install;) + @(cd build/spectral; make --no-print-directory -ws all install VERBOSE=1;) build/spectral: build @mkdir build/spectral - @(cd build/spectral; cmake -Wno-dev -DDAMASK_DRIVER=SPECTRAL ../..;) + @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_SOLVER=SPECTRAL ../..;) build: bin @mkdir build @@ -23,7 +23,7 @@ FEM: build/FEM build/FEM: build @mkdir build - @(cd build/FEM; cmake -Wno-dev -DDAMASK_DRIVER=FEM ../..;) + @(cd build/FEM; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_SOLVER=FEM ../..;) .PHONY: clean clean: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b4ee59f3..c3f742ed2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,7 @@ if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") SET_SOURCE_FILES_PROPERTIES( "lattice.f90" PROPERTIES COMPILE_FLAGS "-ffree-line-length-240") endif() - +set( CMAKE_VERBOSE_MAKEFILE on ) # The dependency detection in CMake is not functioning for Fortran, # hence we declare the dependencies from top to bottom in the following From 0eb4c4867ef3877a0c81946fcd5a999c1a17c8c6 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 21 May 2016 16:52:53 +0200 Subject: [PATCH 096/183] build files should be ignored --- src/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/.gitignore diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 000000000..f6c59903c --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,2 @@ +Makefile +cmake_install.cmake From 21ad810209eea8fcd4678dd0800ae7f8d31daa11 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 24 May 2016 21:35:16 +0200 Subject: [PATCH 097/183] changed to compile object files rather than libraries --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 201 ++++++++++++++++++++++++--------------------- 2 files changed, 109 insertions(+), 94 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c8fb18602..649ca1559 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ ######################################################################################## # CMAKE for build the Material subroutine for BVP solution ######################################################################################## -cmake_minimum_required (VERSION 2.8.0 FATAL_ERROR) +cmake_minimum_required (VERSION 2.8.8 FATAL_ERROR) #--------------------------------------------------------------------------------------- # Find PETSc from system environment diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c3f742ed2..63ed04138 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,61 +16,72 @@ endif() set( CMAKE_VERBOSE_MAKEFILE on ) # The dependency detection in CMake is not functioning for Fortran, # hence we declare the dependencies from top to bottom in the following +add_library(C_ROUTINES OBJECT "C_routines.c") +set(OBJECTFILES $) -add_library(C_ROUTINES "C_routines.c") +add_library(SYSTEM_ROUTINES OBJECT "system_routines.f90") +add_dependencies(SYSTEM_ROUTINES C_ROUTINES) +list(APPEND OBJECTFILES $) -add_library(SYSTEM_ROUTINES "system_routines.f90") -target_link_libraries(SYSTEM_ROUTINES C_ROUTINES) - -add_library(PREC "prec.f90") -target_link_libraries(PREC SYSTEM_ROUTINES) +add_library(PREC OBJECT "prec.f90") +add_dependencies(PREC SYSTEM_ROUTINES) +list(APPEND OBJECTFILES $) if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") - add_library(DAMASK_INTERFACE "spectral_interface.f90") + add_library(DAMASK_INTERFACE OBJECT "spectral_interface.f90") elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") - add_library(DAMASK_INTERFACE "DAMASK_FEM_interface.f90") + add_library(DAMASK_INTERFACE OBJECT "DAMASK_FEM_interface.f90") endif() -target_link_libraries(DAMASK_INTERFACE PREC) +add_dependencies(DAMASK_INTERFACE PREC) +list(APPEND OBJECTFILES $) -add_library(IO "IO.f90") -target_link_libraries(IO DAMASK_INTERFACE) +add_library(IO OBJECT "IO.f90") +add_dependencies(IO DAMASK_INTERFACE) +list(APPEND OBJECTFILES $) -add_library(EXTERNALLIBS "libs.f90") -target_link_libraries(EXTERNALLIBS IO) +add_library(NUMERICS OBJECT "numerics.f90") +add_dependencies(NUMERICS IO) +list(APPEND OBJECTFILES $) -add_library(NUMERICS "numerics.f90") -target_link_libraries(NUMERICS EXTERNALLIBS) +add_library(DEBUG OBJECT "debug.f90") +add_dependencies(DEBUG NUMERICS) +list(APPEND OBJECTFILES $) -add_library(DEBUG "debug.f90") -target_link_libraries(DEBUG NUMERICS) +add_library(FEsolving OBJECT "FEsolving.f90") +add_dependencies(FEsolving DEBUG) +list(APPEND OBJECTFILES $) -add_library(FEsolving "FEsolving.f90") -target_link_libraries(FEsolving DEBUG) +add_library(EXTERNAL_LIBS OBJECT "libs.f90") +list(APPEND OBJECTFILES $) -add_library(DAMASK_MATH "math.f90") -target_link_libraries(DAMASK_MATH FEsolving) +add_library(DAMASK_MATH OBJECT "math.f90") +add_dependencies(DAMASK_MATH FEsolving EXTERNAL_LIBS) +list(APPEND OBJECTFILES $) -# SPECTRAL solver and FEM solver use different mesh -# source files +# SPECTRAL solver and FEM solver use different mesh files if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") - add_library(MESH "mesh.f90") - target_link_libraries(MESH DAMASK_MATH) + add_library(MESH OBJECT "mesh.f90") + add_dependencies(MESH DAMASK_MATH) + list(APPEND OBJECTFILES $) elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") - add_library(FEZoo "FEZoo.f90") - target_link_libraries(FEZoo DAMASK_MATH) - add_library(MESH "meshFEM.f90") - target_link_libraries(MESH FEZoo) + add_library(FEZoo OBJECT "FEZoo.f90") + add_dependencies(FEZoo DAMASK_MATH) + list(APPEND OBJECTFILES $) + add_library(MESH OBJECT "meshFEM.f90") + add_dependencies(MESH FEZoo) + list(APPEND OBJECTFILES $) endif() -add_library(MATERIAL "material.f90") -target_link_libraries(MATERIAL MESH) +add_library(MATERIAL OBJECT "material.f90") +add_dependencies(MATERIAL MESH) +list(APPEND OBJECTFILES $) -add_library(LATTICE "lattice.f90") -target_link_libraries(LATTICE MATERIAL) -add_library(DAMASK_HELPERS ALIAS LATTICE) +add_library(DAMASK_HELPERS OBJECT "lattice.f90") +add_dependencies(DAMASK_HELPERS MATERIAL) +list(APPEND OBJECTFILES $) # For each modular section -add_library (PLASTIC +add_library (PLASTIC OBJECT "plastic_dislotwin.f90" "plastic_disloUCLA.f90" "plastic_isotropic.f90" @@ -79,17 +90,19 @@ add_library (PLASTIC "plastic_nonlocal.f90" "plastic_none.f90" "plastic_phenoplus.f90") -target_link_libraries(PLASTIC DAMASK_HELPERS) +add_dependencies(PLASTIC DAMASK_HELPERS) +list(APPEND OBJECTFILES $) -add_library (KINEMATICS +add_library (KINEMATICS OBJECT "kinematics_cleavage_opening.f90" "kinematics_slipplane_opening.f90" "kinematics_thermal_expansion.f90" "kinematics_vacancy_strain.f90" "kinematics_hydrogen_strain.f90") -target_link_libraries(KINEMATICS DAMASK_HELPERS) +add_dependencies(KINEMATICS DAMASK_HELPERS) +list(APPEND OBJECTFILES $) -add_library (SOURCE +add_library (SOURCE OBJECT "source_thermal_dissipation.f90" "source_thermal_externalheat.f90" "source_damage_isoBrittle.f90" @@ -99,92 +112,94 @@ add_library (SOURCE "source_vacancy_phenoplasticity.f90" "source_vacancy_irradiation.f90" "source_vacancy_thermalfluc.f90") -target_link_libraries(SOURCE DAMASK_HELPERS) +add_dependencies(SOURCE DAMASK_HELPERS) +list(APPEND OBJECTFILES $) -add_library(CONSTITUTIVE "constitutive.f90") -target_link_libraries(CONSTITUTIVE PLASTIC) -target_link_libraries(CONSTITUTIVE KINEMATICS) -target_link_libraries(CONSTITUTIVE SOURCE) +add_library(CONSTITUTIVE OBJECT "constitutive.f90") +add_dependencies(CONSTITUTIVE PLASTIC KINEMATICS SOURCE) +list(APPEND OBJECTFILES $) -add_library(CRYSTALLITE "crystallite.f90") -target_link_libraries(CRYSTALLITE CONSTITUTIVE) +add_library(CRYSTALLITE OBJECT "crystallite.f90") +add_dependencies(CRYSTALLITE CONSTITUTIVE) +list(APPEND OBJECTFILES $) -add_library(HOMOGENIZATION +add_library(HOMOGENIZATION OBJECT "homogenization_RGC.f90" "homogenization_isostrain.f90" "homogenization_none.f90") -target_link_libraries(HOMOGENIZATION CRYSTALLITE) +add_dependencies(HOMOGENIZATION CRYSTALLITE) +list(APPEND OBJECTFILES $) -add_library(HYDROGENFLUX +add_library(HYDROGENFLUX OBJECT "hydrogenflux_isoconc.f90" "hydrogenflux_cahnhilliard.f90") -target_link_libraries(HYDROGENFLUX CRYSTALLITE) +add_dependencies(HYDROGENFLUX CRYSTALLITE) +list(APPEND OBJECTFILES $) -add_library(POROSITY +add_library(POROSITY OBJECT "porosity_none.f90" "porosity_phasefield.f90") -target_link_libraries(POROSITY CRYSTALLITE) +add_dependencies(POROSITY CRYSTALLITE) +list(APPEND OBJECTFILES $) -add_library(VACANCYFLUX +add_library(VACANCYFLUX OBJECT "vacancyflux_isoconc.f90" "vacancyflux_isochempot.f90" "vacancyflux_cahnhilliard.f90") -target_link_libraries(VACANCYFLUX CRYSTALLITE) +add_dependencies(VACANCYFLUX CRYSTALLITE) +list(APPEND OBJECTFILES $) -add_library(DAMAGE +add_library(DAMAGE OBJECT "damage_none.f90" "damage_local.f90" "damage_nonlocal.f90") -target_link_libraries(DAMAGE CRYSTALLITE) +add_dependencies(DAMAGE CRYSTALLITE) +list(APPEND OBJECTFILES $) -add_library(THERMAL +add_library(THERMAL OBJECT "thermal_isothermal.f90" "thermal_adiabatic.f90" "thermal_conduction.f90") -target_link_libraries(THERMAL CRYSTALLITE) +add_dependencies(THERMAL CRYSTALLITE) +list(APPEND OBJECTFILES $) -add_library(DAMASK_ENGINE "homogenization.f90") -target_link_libraries(DAMASK_ENGINE THERMAL ) -target_link_libraries(DAMASK_ENGINE DAMAGE ) -target_link_libraries(DAMASK_ENGINE VACANCYFLUX ) -target_link_libraries(DAMASK_ENGINE POROSITY ) -target_link_libraries(DAMASK_ENGINE HYDROGENFLUX ) -target_link_libraries(DAMASK_ENGINE HOMOGENIZATION) +add_library(DAMASK_ENGINE OBJECT "homogenization.f90") +add_dependencies(DAMASK_ENGINE THERMAL DAMAGE VACANCYFLUX POROSITY HYDROGENFLUX HOMOGENIZATION) +list(APPEND OBJECTFILES $) +add_library(DAMASK_CPFE OBJECT "CPFEM2.f90") +add_dependencies(DAMASK_CPFE DAMASK_ENGINE) +list(APPEND OBJECTFILES $) if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") - add_library(DAMASK_CPFE "CPFEM2.f90") - target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) + add_library(SPECTRAL_UTILITIES OBJECT "spectral_utilities.f90") + add_dependencies(SPECTRAL_UTILITIES DAMASK_CPFE) + list(APPEND OBJECTFILES $) - add_library(SPECTRAL_UTILITIES spectral_utilities.f90) - target_link_libraries(SPECTRAL_UTILITIES DAMASK_CPFE) + add_library(SPECTRAL_SOLVER OBJECT + "spectral_thermal.f90" + "spectral_damage.f90" + "spectral_mech_AL.f90" + "spectral_mech_Polarisation.f90" + "spectral_mech_Basic.f90") + add_dependencies(SPECTRAL_SOLVER SPECTRAL_UTILITIES) + list(APPEND OBJECTFILES $) - add_library(SPECTRAL_SOLVER "spectral_thermal.f90" - "spectral_damage.f90" - "spectral_mech_AL.f90" - "spectral_mech_Polarisation.f90" - "spectral_mech_Basic.f90") - target_link_libraries(SPECTRAL_SOLVER SPECTRAL_UTILITIES) - add_executable(DAMASK_spectral "DAMASK_spectral.f90") - target_link_libraries(DAMASK_spectral SPECTRAL_SOLVER) + add_executable(DAMASK_spectral "DAMASK_spectral.f90" ${OBJECTFILES}) + add_dependencies(DAMASK_spectral SPECTRAL_SOLVER) elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") - add_library(DAMASK_CPFE "CPFEM.f90") - target_link_libraries(DAMASK_CPFE DAMASK_ENGINE) + add_library(FEM_UTILITIES OBJECT "FEM_utilities.f90") + add_dependencies(FEM_UTILITIES DAMASK_CPFE) - add_library(DAMASK_FEM_UTILITY "FEM_utilities.f90") - target_link_libraries(DAMASK_FEM_UTILITY DAMASK_CPFE) - - add_library(DAMASK_FEM_BASE "FEM_hydrogenflux.f90" - "FEM_porosity.f90" - "FEM_vacancyflux.f90" - "FEM_damage.f90" - "FEM_thermal.f90" - "FEM_mech.f90") - target_link_libraries(DAMASK_FEM_BASE DAMASK_FEM_UTILITY) - - add_library(DAMASK_FEM_DRIVER "DAMASK_FEM_driver.f90") - target_link_libraries(DAMASK_FEM_DRIVER DAMASK_FEM_BASE) + add_library(FEM_SOLVER OBJECT + "FEM_hydrogenflux.f90" + "FEM_porosity.f90" + "FEM_vacancyflux.f90" + "FEM_damage.f90" + "FEM_thermal.f90" + "FEM_mech.f90") + add_dependencies(FEM_SOLVER FEM_UTILITIES) add_executable(DAMASK_FEM "DAMASK_FEM_driver.f90") - target_link_libraries(DAMASK_FEM DAMASK_FEM_EXE) + add_dependencies(DAMASK_FEM FEM_SOLVER) endif() From 94ff2bd116e33a14d6d0cf77a7214c82e84ed5ec Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 25 May 2016 07:02:45 +0200 Subject: [PATCH 098/183] restructuring comments --- CMakeLists.txt | 136 +++++++++++++++++++++++-------------------------- 1 file changed, 63 insertions(+), 73 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 649ca1559..061469154 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,33 +169,24 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") #------------------------------------------------------------------------------------------------ # COMPILE SWITCHES -# -assume byterecl record length is given in bytes (also set by -standard-semantics) -# fpe_summary print list of floating point exceptions occured during execution # -fimplicit-none: assume "implicit-none" even if not present in source -# -diag-disable: disables warnings, where -# warning ID 5268: the text exceeds right hand column allowed on the line (we have only comments there) -# -warn: enables warnings, where -# declarations: any undeclared names (alternative name: -implicitnone) -# general: warning messages and informational messages are issued by the compiler -# usage: questionable programming practices -# interfaces: checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks -# ignore_loc: %LOC is stripped from an actual argument -# alignments: data that is not naturally aligned -# unused: declared variables that are never used # stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) -# - set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp" )# preprocessor - set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz" )# flush unterflow to zero, automatically set if O<0,1,2,3> >0 - set (COMPILE_FLAGS "${COMPILE_FLAGS} -assume byterecl,fpe_summary") - set (COMPILE_FLAGS "${COMPILE_FLAGS} -diag-disable 5268" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn declarations" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn general" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn usage" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn interfaces" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn ignore_loc" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn alignments" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn unused" ) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp") # preprocessor + set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz") # flush unterflow to zero, automatically set if O<0,1,2,3> >0 + set (COMPILE_FLAGS "${COMPILE_FLAGS} -assume") # assume + set (COMPILE_FLAGS "${COMPILE_FLAGS} byterecl,") # record length is given in bytes (also set by -standard-semantics) + set (COMPILE_FLAGS "${COMPILE_FLAGS} ,fpe_summary") # print list of floating point exceptions occured during execution + set (COMPILE_FLAGS "${COMPILE_FLAGS} -diag-disable") # disables warnings, where + set (COMPILE_FLAGS "${COMPILE_FLAGS} 5268") # the text exceeds right hand column allowed on the line (we have only comments there) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn") # enables warnings, where + set (COMPILE_FLAGS "${COMPILE_FLAGS} declarations") # any undeclared names (alternative name: -implicitnone) + set (COMPILE_FLAGS "${COMPILE_FLAGS} ,general") # warning messages and informational messages are issued by the compiler + set (COMPILE_FLAGS "${COMPILE_FLAGS} ,usage") # questionable programming practices + set (COMPILE_FLAGS "${COMPILE_FLAGS} ,interfaces") # checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks + set (COMPILE_FLAGS "${COMPILE_FLAGS} ,ignore_loc") # %LOC is stripped from an actual argument + set (COMPILE_FLAGS "${COMPILE_FLAGS} ,alignments") # data that is not naturally aligned + set (COMPILE_FLAGS "${COMPILE_FLAGS} ,unused") # declared variables that are never used # MORE OPTIONS FOR DEBUGGING DURING COMPILATION # -warn: enables warnings, where # truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) @@ -259,48 +250,47 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # COMPILE SWITCHES set (COMPILE_FLAGS "${COMPILE_FLAGS} -xf95-cpp-input" )# preprocessor set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffree-line-length-132" )# restrict line length to the standard 132 characters (lattice.f90 require larger) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -fimplicit-none" )# assume "implicit-none" even if not present in source + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fimplicit-none" )# assume "implicit none" even if not present in source set (COMPILE_FLAGS "${COMPILE_FLAGS} -fmodule-private" )# assume "private" even if not present in source - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wall" ) -# -Wall: sets the following Fortran options: -# -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. -# -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line -# -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime -# -Wconversion: warn about implicit conversions between different type -# -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. -# -Wc-binding-type: -# -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error -# -Wno-tabs: do not allow tabs in source -# -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic -# -Wline-truncation: -# -Wtarget-lifetime: -# -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter -# -Wunused: a number of unused-xxx warnings -# these are general (non -Fortran options) implied by -Wall -# -Waddress -# -Warray-bounds (only with -O2) -# -Wc++11-compat -# -Wchar-subscripts -# -Wcomment -# -Wformat -# -Wmaybe-uninitialized -# -Wnonnull -# -Wparentheses -# -Wpointer-sign -# -Wreorder -# -Wreturn-type -# -Wsequence-point -# -Wstrict-aliasing -# -Wstrict-overflow=1 -# -Wswitch -# -Wtrigraphs -# -Wuninitialized -# -Wunknown-pragmas -# -Wunused-function -# -Wunused-label -# -Wunused-value -# -Wunused-variable -# -Wvolatile-register-var + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wall" )# sets the following Fortran options: + # -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. + # -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line + # -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime + # -Wconversion: warn about implicit conversions between different type + # -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. + # -Wc-binding-type: + # -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error + # -Wno-tabs: do not allow tabs in source + # -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic + # -Wline-truncation: + # -Wtarget-lifetime: + # -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter + # -Wunused: a number of unused-xxx warnings + # these are general (non -Fortran options) implied by -Wall + # -Waddress + # -Warray-bounds (only with -O2) + # -Wc++11-compat + # -Wchar-subscripts + # -Wcomment + # -Wformat + # -Wmaybe-uninitialized + # -Wnonnull + # -Wparentheses + # -Wpointer-sign + # -Wreorder + # -Wreturn-type + # -Wsequence-point + # -Wstrict-aliasing + # -Wstrict-overflow=1 + # -Wswitch + # -Wtrigraphs + # -Wuninitialized + # -Wunknown-pragmas + # -Wunused-function + # -Wunused-label + # -Wunused-value + # -Wunused-variable + # -Wvolatile-register-var set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wextra" ) # -Wextra: sets the following Fortran options: # -Wunuses-parameter: @@ -325,7 +315,7 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-unused-parameter" ) # MORE OPTIONS FOR DEBUGGING DURING COMPILATION # -Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): -# -Wimplicit-interface: no interfaces for lapack routines +# -Wimplicit-interface: no interfaces for lapack/MPI routines # -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. # -ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) # -ffpe-summary=all: only for newer gfortran @@ -336,13 +326,6 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # -ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) # zero,\ # overflow -# -fcheck=all: sets the following Fortran options: -# array-temps -# bounds -# do -# mem -# pointer -# recursion # # MORE OPTIONS FOR RUNTIME DEBUGGING # -ffpe-trap=precision, @@ -352,6 +335,13 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") set (DEBUG_FLAGS "${DEBUG_FLAGS} -fbacktrace" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -fdump-core" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -fcheck=all" ) +# -fcheck=all: sets the following Fortran options: +# array-temps +# bounds +# do +# mem +# pointer +# recursion set (DEBUG_FLAGS "${DEBUG_FLAGS} -ffpe-trap=invalid,zero,overflow") #------------------------------------------------------------------------------------------------ From fd41681b196431ae5c893d36d38a2c30d4f121b6 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 3 Feb 2017 19:55:30 +0100 Subject: [PATCH 099/183] not needed --- src/.gitignore | 1 + src/quit__genmod.f90 | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 src/quit__genmod.f90 diff --git a/src/.gitignore b/src/.gitignore index f6c59903c..bd6d66f85 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,2 +1,3 @@ Makefile cmake_install.cmake +quit__genmod.f90 diff --git a/src/quit__genmod.f90 b/src/quit__genmod.f90 deleted file mode 100644 index 62466058e..000000000 --- a/src/quit__genmod.f90 +++ /dev/null @@ -1,8 +0,0 @@ - !COMPILER-GENERATED INTERFACE MODULE: Wed Apr 20 11:10:29 2016 - MODULE QUIT__genmod - INTERFACE - SUBROUTINE QUIT(STOP_ID) - INTEGER(KIND=4), INTENT(IN) :: STOP_ID - END SUBROUTINE QUIT - END INTERFACE - END MODULE QUIT__genmod From cf36d4534f850d6b1ae58df7c752bc72bc0f6aea Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 3 Feb 2017 20:16:25 +0100 Subject: [PATCH 100/183] adjusting to development branch --- src/.gitignore | 2 ++ src/lattice.f90 | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/.gitignore b/src/.gitignore index bd6d66f85..c90e213cf 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,5 @@ +DAMASK_marc*.f90 Makefile cmake_install.cmake quit__genmod.f90 +*.marc diff --git a/src/lattice.f90 b/src/lattice.f90 index 88f2ca007..184c85937 100644 --- a/src/lattice.f90 +++ b/src/lattice.f90 @@ -835,7 +835,6 @@ module lattice ],pReal),[ 4_pInt + 4_pInt,LATTICE_hex_Ncleavage]) - !-------------------------------------------------------------------------------------------------- ! body centered tetragonal integer(pInt), dimension(LATTICE_maxNslipFamily), parameter, public :: & From d202e7dbd51d8c2ee33f06f93969904c5ecf000b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 3 Feb 2017 20:19:02 +0100 Subject: [PATCH 101/183] no dirty tricks needed --- src/crystallite.f90 | 48 +++++++-------------------------------------- 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index b8117e6b4..efeab9dcd 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -434,11 +434,7 @@ subroutine crystallite_init call constitutive_microstructure(crystallite_orientation, & ! pass orientation to constitutive module crystallite_Fe(1:3,1:3,c,i,e), & crystallite_Fp(1:3,1:3,c,i,e), & - c,i,e, & - crystallite_F0, & - crystallite_Fe, & - crystallite_Fp, & - crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states + c,i,e) ! update dependent state variables to be consistent with basic states enddo enddo enddo @@ -1432,15 +1428,10 @@ subroutine crystallite_integrateStateRK4() !$OMP DO do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains if (crystallite_todo(g,i,e)) & - !***dirty way to pass orientation information call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, & - crystallite_F0, & - crystallite_Fe, & - crystallite_Fp, & - crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states + g, i, e) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -1762,15 +1753,10 @@ subroutine crystallite_integrateStateRKCK45() !$OMP DO do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains if (crystallite_todo(g,i,e)) & - !***dirty way to pass orientations to constitutive_microstructure call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, & - crystallite_F0, & - crystallite_Fe, & - crystallite_Fp, & - crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states + g, i, e) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -1986,15 +1972,10 @@ subroutine crystallite_integrateStateRKCK45() !$OMP DO do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains if (crystallite_todo(g,i,e)) & - !***dirty way to pass orientations to constitutive_microstructure call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, & - crystallite_F0, & - crystallite_Fe, & - crystallite_Fp, & - crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states + g, i, e) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO @@ -2225,15 +2206,10 @@ subroutine crystallite_integrateStateAdaptiveEuler() !$OMP DO do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains if (crystallite_todo(g,i,e)) & - !***dirty way to pass orientations to constitutive_microstructure call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, & - crystallite_F0, & - crystallite_Fe, & - crystallite_Fp, & - crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states + g, i, e) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO !$OMP END PARALLEL @@ -2573,15 +2549,10 @@ eIter = FEsolving_execElem(1:2) !$OMP DO do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) & - !***dirty way to pass orientations to constitutive_microstructure call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, & - crystallite_F0, & - crystallite_Fe, & - crystallite_Fp, & - crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states + g, i, e) ! update dependent state variables to be consistent with basic states enddo; enddo; enddo !$OMP ENDDO !$OMP END PARALLEL @@ -2822,15 +2793,10 @@ subroutine crystallite_integrateStateFPI() !$OMP DO PRIVATE(p,c) do e = eIter(1),eIter(2); do i = iIter(1,e),iIter(2,e); do g = gIter(1,e),gIter(2,e) ! iterate over elements, ips and grains if (crystallite_todo(g,i,e) .and. .not. crystallite_converged(g,i,e)) & - !***dirty way to pass orientations to constitutive_micrsotructure call constitutive_microstructure(crystallite_orientation, & crystallite_Fe(1:3,1:3,g,i,e), & crystallite_Fp(1:3,1:3,g,i,e), & - g, i, e, & - crystallite_F0, & - crystallite_Fe, & - crystallite_Fp, & - crystallite_Tstar_v) ! update dependent state variables to be consistent with basic states + g, i, e) ! update dependent state variables to be consistent with basic states p = phaseAt(g,i,e) c = phasememberAt(g,i,e) plasticState(p)%previousDotState2(:,c) = plasticState(p)%previousDotState(:,c) From 2116226407a897a37dd3a511351b8aa4dc60f146 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 3 Feb 2017 20:35:05 +0100 Subject: [PATCH 102/183] status from development branch --- src/constitutive.f90 | 14 +++----------- src/plastic_phenoplus.f90 | 1 - 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/constitutive.f90 b/src/constitutive.f90 index 35137438d..de8f61c2a 100644 --- a/src/constitutive.f90 +++ b/src/constitutive.f90 @@ -423,7 +423,7 @@ end function constitutive_homogenizedC !-------------------------------------------------------------------------------------------------- !> @brief calls microstructure function of the different constitutive models !-------------------------------------------------------------------------------------------------- -subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el, F0s,Fes,Fps,Tstar_vs) +subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el) use prec, only: & pReal use material, only: & @@ -460,15 +460,7 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el, F0s,Fe ho, & !< homogenization tme !< thermal member position real(pReal), intent(in), dimension(:,:,:,:) :: & - orientations - - real(pReal), intent(in), dimension(:,:,:,:,:) :: & - F0s, & - Fes, & - Fps - - real(pReal), intent(in), dimension(:,:,:,:) :: & - Tstar_vs !< crystal orientations as quaternions + orientations !< crystal orientations as quaternions ho = material_homog(ip,el) tme = thermalMapping(ho)%p(ip,el) @@ -483,7 +475,7 @@ subroutine constitutive_microstructure(orientations, Fe, Fp, ipc, ip, el, F0s,Fe case (PLASTICITY_NONLOCAL_ID) plasticityType call plastic_nonlocal_microstructure (Fe,Fp,ip,el) case (PLASTICITY_PHENOPLUS_ID) plasticityType - call plastic_phenoplus_microstructure(orientations,ipc,ip,el,F0s,Fes,Fps,Tstar_vs) + call plastic_phenoplus_microstructure(orientations,ipc,ip,el) end select plasticityType end subroutine constitutive_microstructure diff --git a/src/plastic_phenoplus.f90 b/src/plastic_phenoplus.f90 index c9b5eead9..105a64b34 100644 --- a/src/plastic_phenoplus.f90 +++ b/src/plastic_phenoplus.f90 @@ -166,7 +166,6 @@ subroutine plastic_phenoplus_init(fileUnit) line = '' real(pReal), dimension(:), allocatable :: tempPerSlip - write(6,'(/,a)') ' <<<+- constitutive_'//PLASTICITY_PHENOPLUS_label//' init -+>>>' write(6,'(a15,a)') ' Current time: ',IO_timeStamp() #include "compilation_info.f90" From 3914dfbec4d18586f409dd78ac2d828ecd358d24 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 3 Feb 2017 20:35:32 +0100 Subject: [PATCH 103/183] reordering and cleaning --- Makefile | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index e0e29181f..b0bc31539 100644 --- a/Makefile +++ b/Makefile @@ -11,25 +11,19 @@ build/spectral: build @mkdir build/spectral @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_SOLVER=SPECTRAL ../..;) -build: bin - @mkdir build - -bin: - @mkdir bin - FEM: build/FEM @(cd build/FEM; make --no-print-directory -ws all install;) build/FEM: build @mkdir build @(cd build/FEM; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_SOLVER=FEM ../..;) -.PHONY: spectral -spectral: - $(MAKE) DAMASK_spectral.exe -C code -.PHONY: FEM -FEM: - $(MAKE) DAMASK_FEM.exe -C code +build: bin + @mkdir build + +bin: + @mkdir bin + .PHONY: marc marc: From 3e7ab76582c1698879c021c39f8f0326c953ea4b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 3 Feb 2017 23:23:55 +0100 Subject: [PATCH 104/183] adding functionality from previous build system --- CMakeLists.txt | 408 ++++++++++++++++++++--------------- Makefile | 37 ++-- installation/symlink_Code.py | 30 --- src/CMakeLists.txt | 19 +- 4 files changed, 257 insertions(+), 237 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 061469154..8c151a260 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,23 +1,22 @@ ######################################################################################## -# CMAKE for build the Material subroutine for BVP solution -######################################################################################## +# Compiler options for building DAMASK cmake_minimum_required (VERSION 2.8.8 FATAL_ERROR) #--------------------------------------------------------------------------------------- # Find PETSc from system environment set(PETSC_DIR $ENV{PETSC_DIR}) if ("${PETSC_DIR}" STREQUAL "") - message (FATAL_ERROR "PETSC_DIR is not defined in system!") + message (FATAL_ERROR "PETSC_DIR is not defined") endif ("${PETSC_DIR}" STREQUAL "") -# BRUTAL FORCE TO FIND THE VARIABLES DEFINED IN PETSC +# Use existing variables from PETSc # https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake exec_program(mktemp ARGS -d OUTPUT_VARIABLE PETSC_TEMP) set(petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") set(petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) # Generate a temporary makefile to probe the PETSc configuration -# This file will be deleted once the setting from PETSc is parsed +# This file will be deleted once the settings from PETSc are parsed # into CMake set (petsc_config_makefile "${PETSC_TEMP}/Makefile.petsc") @@ -47,8 +46,6 @@ linker: # CMake will execute each target in the ${petsc_config_makefile} # to acquire corresponding PETSc Variables. -# The include path and linking libraries in PETSc usually contains -# duplicated entries, which is cleaned up later using CMake list. find_program (MAKE_EXECUTABLE NAMES make gmake) # Find the PETSc includes directory settings execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "includes" @@ -79,7 +76,7 @@ execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_confi # Remove temporary makefile, no need to keep it anymore. file (REMOVE_RECURSE ${PETSC_TEMP}) -# REMOVE DUPLICATE FLAGS FOR COMPILER AND LINKING +# Remove duplicate compiler and linker flags string( REGEX MATCHALL "-I([^\" ]+)" TMP_LIST "${petsc_includes}") list(REMOVE_DUPLICATES TMP_LIST) foreach (dir ${TMP_LIST}) @@ -91,12 +88,12 @@ foreach (exlib ${TMP_LIST}) set(PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} ${exlib}") 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" ) +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" ) #--------------------------------------------------------------------------------------- # Now start to care about DAMASK @@ -105,11 +102,11 @@ message("***Found MPI C COMPILER:\n${PETSC_MPICC}\n" ) if ("${DAMASK_SOLVER}" STREQUAL "SPECTRAL") project(DAMASK_spectral Fortran C) add_definitions(-DSpectral) - message("***Configuring Spectral Solver\n") + message("Configuring Spectral Solver\n") elseif ("${DAMASK_SOLVER}" STREQUAL "FEM") project(DAMASK_FEM Fortran C) add_definitions(-DFEM) - message("***Configuring FEM Solver\n") + message("Configuring FEM Solver\n") endif() # set compiler and linker commands (need to be done after defining the project) @@ -123,15 +120,32 @@ set(CMAKE_LINKER "${PETSC_LINKER}") option(OPENMP "Use OpenMP libaries for DAMASK" ON ) option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) -# Setting installation prefix -if (DEFINED DAMASK_INSTALL) - set (CMAKE_INSTALL_PREFIX "${DAMASK_INSTALL}") -else(DEFINED DAMASK_INSTALL) - set (CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/bin") -endif(DEFINED DAMASK_INSTALL) -message("\n***The binary will be installed at\n${CMAKE_INSTALL_PREFIX}\n") +if("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") + set (OPENMP "OFF") + set (OPTIMIZATION "OFF") +endif("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") -# Find DAMASK version (DAMASK_V) in DAMASK_ROOT +# Parse DAMASK_BIN from CONFIG file +file(READ "CONFIG" CONFIGFILE) +STRING(REGEX REPLACE ";" "\\\\;" CONFIGFILE "${CONFIGFILE}") +STRING(REGEX REPLACE "\n" ";" CONFIGFILE "${CONFIGFILE}") +FOREACH(item ${CONFIGFILE}) + STRING(REGEX MATCH ".+DAMASK_BIN.+" item ${item}) + IF(item) + message("${item}") + string(REGEX REPLACE "set" "" item "${item}") + message("${item}") + string(REGEX REPLACE "=" " " item "${item}") + message("${item}") + string(REGEX REPLACE "\\\${DAMASK_ROOT}" "${CMAKE_CURRENT_SOURCE_DIR}" item "${item}") + message("${item}") + string(REPLACE "DAMASK_BIN" ";" STRING_LIST ${item}) + list(GET STRING_LIST 1 item) + string(STRIP "${item}" CMAKE_INSTALL_PREFIX) + ENDIF(item) +ENDFOREACH(item ${CONFIGFILE}) + +# 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 @@ -153,7 +167,7 @@ set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") if (OPENMP) - set (OPENMP_FLAGS "-openmp -openmp-report0 -parallel") + set (OPENMP_FLAGS "-qopenmp -parallel") endif(OPENMP) if ("${OPTIMIZATION}" STREQUAL "OFF") @@ -161,69 +175,104 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") elseif("${OPTIMIZATION}" STREQUAL "DEFENSIVE") set (OPTIMIZATION_FLAGS "-O2") elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") - set (OPTIMIZATION_FLAGS "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" + set (OPTIMIZATION_FLAGS "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) + # -fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" endif() set (STANDARD_CHECK "-stand f08 -standard-semantics") - set (LINKER_FLAGS "-shared-intel") + set (LINKER_FLAGS "${LINKER_FLAGS} -shared-intel") + # Link against shared Intel libraries instead of static ones #------------------------------------------------------------------------------------------------ -# COMPILE SWITCHES -# -fimplicit-none: assume "implicit-none" even if not present in source -# stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) +# Fine tuning compilation options + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp") + # preprocessor + set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz") + # flush unterflow to zero, automatically set if O<0,1,2,3> >0 + set (COMPILE_FLAGS "${COMPILE_FLAGS} -assume") + # assume + set (COMPILE_FLAGS "${COMPILE_FLAGS}byterecl") + # record length is given in bytes (also set by -standard-semantics) + set (COMPILE_FLAGS "${COMPILE_FLAGS},fpe_summary") + # print list of floating point exceptions occured during execution + set (COMPILE_FLAGS "${COMPILE_FLAGS} -diag-disable") + # disables warnings, where + set (COMPILE_FLAGS "${COMPILE_FLAGS}5268") + # the text exceeds right hand column allowed on the line (we have only comments there) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn") + # enables warnings, where + set (COMPILE_FLAGS "${COMPILE_FLAGS}declarations") + # any undeclared names (alternative name: -implicitnone) + set (COMPILE_FLAGS "${COMPILE_FLAGS},general") + # warning messages and informational messages are issued by the compiler + set (COMPILE_FLAGS "${COMPILE_FLAGS},usage") + # questionable programming practices + set (COMPILE_FLAGS "${COMPILE_FLAGS},interfaces") + # checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks + set (COMPILE_FLAGS "${COMPILE_FLAGS},ignore_loc") + # %LOC is stripped from an actual argument + set (COMPILE_FLAGS "${COMPILE_FLAGS},alignments") + # data that is not naturally aligned + set (COMPILE_FLAGS "${COMPILE_FLAGS},unused") + # declared variables that are never used - set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp") # preprocessor - set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz") # flush unterflow to zero, automatically set if O<0,1,2,3> >0 - set (COMPILE_FLAGS "${COMPILE_FLAGS} -assume") # assume - set (COMPILE_FLAGS "${COMPILE_FLAGS} byterecl,") # record length is given in bytes (also set by -standard-semantics) - set (COMPILE_FLAGS "${COMPILE_FLAGS} ,fpe_summary") # print list of floating point exceptions occured during execution - set (COMPILE_FLAGS "${COMPILE_FLAGS} -diag-disable") # disables warnings, where - set (COMPILE_FLAGS "${COMPILE_FLAGS} 5268") # the text exceeds right hand column allowed on the line (we have only comments there) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn") # enables warnings, where - set (COMPILE_FLAGS "${COMPILE_FLAGS} declarations") # any undeclared names (alternative name: -implicitnone) - set (COMPILE_FLAGS "${COMPILE_FLAGS} ,general") # warning messages and informational messages are issued by the compiler - set (COMPILE_FLAGS "${COMPILE_FLAGS} ,usage") # questionable programming practices - set (COMPILE_FLAGS "${COMPILE_FLAGS} ,interfaces") # checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks - set (COMPILE_FLAGS "${COMPILE_FLAGS} ,ignore_loc") # %LOC is stripped from an actual argument - set (COMPILE_FLAGS "${COMPILE_FLAGS} ,alignments") # data that is not naturally aligned - set (COMPILE_FLAGS "${COMPILE_FLAGS} ,unused") # declared variables that are never used -# MORE OPTIONS FOR DEBUGGING DURING COMPILATION -# -warn: enables warnings, where -# truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) -# uncalled: Determines whether warnings occur when a statement function is never called -# all: -# -name as_is: case sensitive Fortran! + # Additional options + # -warn: enables warnings, where + # truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. + # (too many warnings because we have comments beyond character 132) + # uncalled: Determines whether warnings occur when a statement function is never called + # all: + # -name as_is: case sensitive Fortran! #------------------------------------------------------------------------------------------------ -# COMPILE SWITCHES FOR RUNTIME DEBUGGING - set (DEBUG_FLAGS "${DEBUG_FLAGS} -g" )# Generate symbolic debugging information in the object file - set (DEBUG_FLAGS "${DEBUG_FLAGS} -traceback" )# Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. - set (DEBUG_FLAGS "${DEBUG_FLAGS} -gen-interfaces" )# Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ - set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-stack-check" )# Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. - set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-model strict" )# Trap uninitalized variables - set (DEBUG_FLAGS "${DEBUG_FLAGS} -check bounds,format,output_conversion,pointers,uninit" )# Checks at runtime, where - # bounds: if an array index is too small (<1) or too large! - # format: for the data type of an item being formatted for output. - # output_conversion: for the fit of data items within a designated format descriptor field. - # pointers: for certain disassociated or uninitialized pointers or unallocated allocatable objects. - # uninit: for uninitialized variables. - set (DEBUG_FLAGS "${DEBUG_FLAGS} -ftrapuv" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all0" )# Capture all floating-point exceptions, sets -ftz automatically - set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn errors,stderrors" )# Configures warnings, where - # errors: warnings are changed to errors - # stderrors: warnings about Fortran standard violations are changed to errors +# Runtime debugging + set (DEBUG_FLAGS "${DEBUG_FLAGS} -g") + # Generate symbolic debugging information in the object file + set (DEBUG_FLAGS "${DEBUG_FLAGS} -traceback") + # Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. + set (DEBUG_FLAGS "${DEBUG_FLAGS} -gen-interfaces") + # Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-stack-check") + # Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-model strict") + # Trap uninitalized variables + set (DEBUG_FLAGS "${DEBUG_FLAGS} -check" ) + # Checks at runtime, where + set (DEBUG_FLAGS "${DEBUG_FLAGS}bounds") + # if an array index is too small (<1) or too large! + set (DEBUG_FLAGS "${DEBUG_FLAGS},format") + # for the data type of an item being formatted for output. + set (DEBUG_FLAGS "${DEBUG_FLAGS},output_conversion") + # for the fit of data items within a designated format descriptor field. + set (DEBUG_FLAGS "${DEBUG_FLAGS},pointers") + # for certain disassociated or uninitialized pointers or unallocated allocatable objects. + set (DEBUG_FLAGS "${DEBUG_FLAGS},uninit") + # for uninitialized variables. + set (DEBUG_FLAGS "${DEBUG_FLAGS} -ftrapuv") + # initializes stack local variables to an unusual value to aid error detection + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all0") + # capture all floating-point exceptions, sets -ftz automatically + set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn") + # enables warnings, where + set (DEBUG_FLAGS "${DEBUG_FLAGS}errors") + # warnings are changed to errors + set (DEBUG_FLAGS "${DEBUG_FLAGS},stderrors") + # warnings about Fortran standard violations are changed to errors set (DEBUG_FLAGS "${DEBUG_FLAGS} -debug-parameters all" ) -# MORE OPTIONS FOR RUNTIME DEBUGGING -# -heap-arrays: Should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits -# -check: Checks at runtime, where -# arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) -# stack: + # generate debug information for parameters + + # Additional options + # -heap-arrays: Should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits + # -check: Checks at runtime, where + # arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) + # stack: #------------------------------------------------------------------------------------------------ -# PRECISION SETTINGS -#-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) -#-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) - set (PRECISION_FLAGS "-real-size 64 -integer-size 32") +# precision settings + set (PRECISION_FLAGS "${PRECISION_FLAGS} -real-size 64") + # set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) + set (PRECISION_FLAGS "${PRECISION_FLAGS} -integer-size 32") + # set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) ################################################################################################### @@ -244,130 +293,135 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") endif() set (STANDARD_CHECK "-std=f2008ts -pedantic-errors" ) - set (LINKER_FLAGS "-Wl,-undefined,dynamic_lookup" )# ensure to link against dynamic libraries + set (LINKER_FLAGS "${LINKER_FLAGS} -Wl") + # options parsed directly to the linker + set (LINKER_FLAGS "${LINKER_FLAGS},-undefined") + set (LINKER_FLAGS "${LINKER_FLAGS},-dynamic_lookup" ) + # ensure to link against dynamic libraries #------------------------------------------------------------------------------------------------ -# COMPILE SWITCHES - set (COMPILE_FLAGS "${COMPILE_FLAGS} -xf95-cpp-input" )# preprocessor - set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffree-line-length-132" )# restrict line length to the standard 132 characters (lattice.f90 require larger) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -fimplicit-none" )# assume "implicit none" even if not present in source - set (COMPILE_FLAGS "${COMPILE_FLAGS} -fmodule-private" )# assume "private" even if not present in source - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wall" )# sets the following Fortran options: - # -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. - # -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line - # -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime - # -Wconversion: warn about implicit conversions between different type - # -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. - # -Wc-binding-type: - # -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error - # -Wno-tabs: do not allow tabs in source - # -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic - # -Wline-truncation: - # -Wtarget-lifetime: - # -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter - # -Wunused: a number of unused-xxx warnings - # these are general (non -Fortran options) implied by -Wall - # -Waddress - # -Warray-bounds (only with -O2) - # -Wc++11-compat - # -Wchar-subscripts - # -Wcomment - # -Wformat - # -Wmaybe-uninitialized - # -Wnonnull - # -Wparentheses - # -Wpointer-sign - # -Wreorder - # -Wreturn-type - # -Wsequence-point - # -Wstrict-aliasing - # -Wstrict-overflow=1 - # -Wswitch - # -Wtrigraphs - # -Wuninitialized - # -Wunknown-pragmas - # -Wunused-function - # -Wunused-label - # -Wunused-value - # -Wunused-variable - # -Wvolatile-register-var - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wextra" ) -# -Wextra: sets the following Fortran options: -# -Wunuses-parameter: -# -Wcompare-reals: -# these are general (non -Fortran options) implied by -Wextra -# -Wclobbered -# -Wempty-body -# -Wignored-qualifiers -# -Wmissing-field-initializers -# -Woverride-init -# -Wsign-compare -# -Wtype-limits -# -Wuninitialized -# -Wunused-but-set-parameter (only with -Wunused or -Wall) -# -Wno-globals - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wcharacter-truncation" )# warn if character expressions (strings) are truncated - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wunderflow" )# produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=pure" ) +# Fine tuning compilation options + set (COMPILE_FLAGS "${COMPILE_FLAGS} -xf95-cpp-input") + # preprocessor + set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffree-line-length-132") + # restrict line length to the standard 132 characters (lattice.f90 require more characters) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fimplicit-none") + # assume "implicit none" even if not present in source + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fmodule-private") + # assume "private" even if not present in source + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wall") + # sets the following Fortran options: + # -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. + # -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line + # -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime + # -Wconversion: warn about implicit conversions between different type + # -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. + # -Wc-binding-type: + # -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error + # -Wno-tabs: do not allow tabs in source + # -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic + # -Wline-truncation: + # -Wtarget-lifetime: + # -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter + # -Wunused: a number of unused-xxx warnings + # and sets the general (non-Fortran options) options: + # -Waddress + # -Warray-bounds (only with -O2) + # -Wc++11-compat + # -Wchar-subscripts + # -Wcomment + # -Wformat + # -Wmaybe-uninitialized + # -Wnonnull + # -Wparentheses + # -Wpointer-sign + # -Wreorder + # -Wreturn-type + # -Wsequence-point + # -Wstrict-aliasing + # -Wstrict-overflow=1 + # -Wswitch + # -Wtrigraphs + # -Wuninitialized + # -Wunknown-pragmas + # -Wunused-function + # -Wunused-label + # -Wunused-value + # -Wunused-variable + # -Wvolatile-register-var + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wextra") + # sets the following Fortran options: + # -Wunuses-parameter: + # -Wcompare-reals: + # and sets the general (non-Fortran options) options: + # -Wclobbered + # -Wempty-body + # -Wignored-qualifiers + # -Wmissing-field-initializers + # -Woverride-init + # -Wsign-compare + # -Wtype-limits + # -Wuninitialized + # -Wunused-but-set-parameter (only with -Wunused or -Wall) + # -Wno-globals + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wcharacter-truncation") + # warn if character expressions (strings) are truncated + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wunderflow") + # produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=pure") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=noreturn") - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wconversion-extra" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wimplicit-procedure" ) - set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-unused-parameter" ) -# MORE OPTIONS FOR DEBUGGING DURING COMPILATION -# -Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): -# -Wimplicit-interface: no interfaces for lapack/MPI routines -# -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. -# -ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) -# -ffpe-summary=all: only for newer gfortran + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wconversion-extra") + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wimplicit-procedure") + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-unused-parameter") + set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffpe-summary=all") + # print summary of floating point exeptions (invalid,zero,overflow,underflow,inexact,denormal) + # Additional options + # -Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): + # -Wimplicit-interface: no interfaces for lapack/MPI routines + # -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. #------------------------------------------------------------------------------------------------ -# COMPILE SWITCHES FOR RUNTIME DEBUGGING -# -ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) -# zero,\ -# overflow -# -# MORE OPTIONS FOR RUNTIME DEBUGGING -# -ffpe-trap=precision, -# denormal, -# underflow - set (DEBUG_FLAGS "${DEBUG_FLAGS} -g" ) +# Runtime debugging + set (DEBUG_FLAGS "${DEBUG_FLAGS} -ffpe-trap=invalid,zero,overflow") + # stop execution if floating point exception is detected (NaN is silent) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -g") + # Generate symbolic debugging information in the object file set (DEBUG_FLAGS "${DEBUG_FLAGS} -fbacktrace" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -fdump-core" ) set (DEBUG_FLAGS "${DEBUG_FLAGS} -fcheck=all" ) -# -fcheck=all: sets the following Fortran options: -# array-temps -# bounds -# do -# mem -# pointer -# recursion - set (DEBUG_FLAGS "${DEBUG_FLAGS} -ffpe-trap=invalid,zero,overflow") + # checks for (array-temps,bounds,do,mem,pointer,recursion) + # Additional options + # -ffpe-trap=precision,denormal,underflow #------------------------------------------------------------------------------------------------ -# PRECISION SETTINGS -#-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set -#-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used -#-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) - set (PRECISION_FLAGS "-fdefault-real-8 -fdefault-double-8") +# precision settings + set (PRECISION_FLAGS "${PRECISION_FLAGS} -fdefault-real-8") + # set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set + set (PRECISION_FLAGS "${PRECISION_FLAGS} -fdefault-double-8") + # set precision to 8 bytes for double real, would be 16 bytes if -fdefault-real-8 is used + + # Additional options + # -fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) endif() set (CMAKE_Fortran_FLAGS "${BUILDCMD_PRE} ${OPENMP_FLAGS} ${STANDARD_CHECK} ${OPTIMIZATION_FLAGS} ${COMPILE_FLAGS} ${PRECISION_FLAGS}") set (CMAKE_Fortran_LINK_EXECUTABLE "${BUILDCMD_PRE} ${CMAKE_LINKER} ${OPENMP_FLAGS} ${OPTIMIZATION_FLAGS} ${LINKER_FLAGS}") -if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") +if("${CMAKE_BUILD_TYPE}" STREQUAL "") + set (CMAKE_BUILD_TYPE "RELEASE") +elseif("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DEBUG_FLAGS}") set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} ${DEBUG_FLAGS}") endif() - set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") -message("***COMPILE FLAGS:\n${CMAKE_Fortran_FLAGS}\n") -message("***LINKER:\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") +message("Compiler Flags (Fortran):\n${CMAKE_Fortran_FLAGS}\n") +message("Linker Flags (Fortran):\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") -# MOVE to SOURCE DIRECTORY for BUILDING +# location of code add_subdirectory(src) # INSTALL BUILT BINARIES diff --git a/Makefile b/Makefile index b0bc31539..29d76afee 100644 --- a/Makefile +++ b/Makefile @@ -3,43 +3,38 @@ SHELL = /bin/sh # Makefile for the installation of DAMASK ######################################################################################## .PHONY: all -all: spectral FEM marc +all: spectral FEM marc processing spectral: build/spectral - @(cd build/spectral; make --no-print-directory -ws all install VERBOSE=1;) - -build/spectral: build - @mkdir build/spectral - @(cd build/spectral; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_SOLVER=SPECTRAL ../..;) + @(cd build/spectral;make --no-print-directory -ws all install VERBOSE=1;) FEM: build/FEM @(cd build/FEM; make --no-print-directory -ws all install;) + +OPTIONS="-Wno-dev -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE={BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP}" + +build/spectral: build + @mkdir -p build/spectral + @(cd build/spectral; cmake -DDAMASK_SOLVER=SPECTRAL ${OPTIONS} ../..;) + build/FEM: build - @mkdir build - @(cd build/FEM; cmake -Wno-dev -DCMAKE_BUILD_TYPE=RELEASE -DDAMASK_SOLVER=FEM ../..;) + @mkdir -p build/FEM + @(cd build/FEM; cmake -DDAMASK_SOLVER=FEM ${OPTIONS} ../..;) -build: bin - @mkdir build - -bin: - @mkdir bin +build: + @mkdir -p build .PHONY: marc marc: + @./installation/symLink_Code.sh @./installation/mods_MarcMentat/apply_DAMASK_modifications.sh ${MAKEFLAGS} - -.PHONY: tidy -tidy: - @$(MAKE) tidy -C code >/dev/null - .PHONY: clean clean: - @$(MAKE) cleanDAMASK -C code >/dev/null + @rm -rf build -.PHONY: install +.PHONY: processing install: - @./installation/symlink_Code.py ${MAKEFLAGS} @./installation/symlink_Processing.py ${MAKEFLAGS} diff --git a/installation/symlink_Code.py b/installation/symlink_Code.py index c215a841e..5e790ca0b 100755 --- a/installation/symlink_Code.py +++ b/installation/symlink_Code.py @@ -4,13 +4,6 @@ import os,sys import damask -bin_link = { \ - '.' : [ - 'DAMASK_spectral.exe', - 'DAMASK_FEM.exe' - ], - } - MarcReleases =[ \ '2014', '2014.2', @@ -25,29 +18,6 @@ binDir = damaskEnv.options['DAMASK_BIN'] if not os.path.isdir(binDir): os.mkdir(binDir) -sys.stdout.write('\nsymbolic linking...\n') - -for subDir in bin_link: - theDir = os.path.abspath(os.path.join(baseDir,subDir)) - sys.stdout.write('\n'+binDir+' ->\n'+theDir+damask.util.deemph(' ...')+'\n') - - for theFile in bin_link[subDir]: - theName,theExt = os.path.splitext(theFile) - src = os.path.abspath(os.path.join(theDir,theFile)) - - if os.path.exists(src): - sym_link = os.path.abspath(os.path.join(binDir,subDir if theFile == '' else theName)) - - if os.path.lexists(sym_link): - os.remove(sym_link) - output = theName+damask.util.deemph(theExt) - else: - output = damask.util.emph(theName)+damask.util.deemph(theExt) - - sys.stdout.write(damask.util.deemph('... ')+output+'\n') - os.symlink(src,sym_link) - - sys.stdout.write('\nMSC.Marc versioning...\n\n') theMaster = 'DAMASK_marc.f90' diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63ed04138..8b7cc44bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,8 @@ -# SOME FILES REQUIRE SPECIAL FLAGS +# special flags for some files if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") + + SET_SOURCE_FILES_PROPERTIES( "prec.f90" PROPERTIES + COMPILE_FLAGS "-fno-range-check -fall-intrinsics -fno-fast-math") # fno-range-check: Disable range checking on results of simplification of constant expressions during compilation # --> allows the definition of DAMASK_NaN #-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored @@ -7,13 +10,14 @@ if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # --> allows the use of 'isnan' #-fno-fast-math: # --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) - SET_SOURCE_FILES_PROPERTIES( "prec.f90" PROPERTIES - COMPILE_FLAGS "-fno-range-check -fall-intrinsics -fno-fast-math") - # long lines for interaction matrix + SET_SOURCE_FILES_PROPERTIES( "lattice.f90" PROPERTIES COMPILE_FLAGS "-ffree-line-length-240") + # long lines for interaction matrix endif() + set( CMAKE_VERBOSE_MAKEFILE on ) + # The dependency detection in CMake is not functioning for Fortran, # hence we declare the dependencies from top to bottom in the following add_library(C_ROUTINES OBJECT "C_routines.c") @@ -30,7 +34,7 @@ list(APPEND OBJECTFILES $) if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") add_library(DAMASK_INTERFACE OBJECT "spectral_interface.f90") elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") - add_library(DAMASK_INTERFACE OBJECT "DAMASK_FEM_interface.f90") + add_library(DAMASK_INTERFACE OBJECT "FEM_interface.f90") endif() add_dependencies(DAMASK_INTERFACE PREC) list(APPEND OBJECTFILES $) @@ -51,11 +55,8 @@ add_library(FEsolving OBJECT "FEsolving.f90") add_dependencies(FEsolving DEBUG) list(APPEND OBJECTFILES $) -add_library(EXTERNAL_LIBS OBJECT "libs.f90") -list(APPEND OBJECTFILES $) - add_library(DAMASK_MATH OBJECT "math.f90") -add_dependencies(DAMASK_MATH FEsolving EXTERNAL_LIBS) +add_dependencies(DAMASK_MATH FEsolving) list(APPEND OBJECTFILES $) # SPECTRAL solver and FEM solver use different mesh files From b67f4dd324e28a2c5efa1956fcb906dddf4dbca1 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 4 Feb 2017 01:01:42 +0100 Subject: [PATCH 105/183] Default cases seem to work --- CMakeLists.txt | 65 ++++++++++++++++++++++++++++++---------------- Makefile | 5 ++-- src/CMakeLists.txt | 7 ++--- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c151a260..400a34cd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,16 +115,33 @@ set(CMAKE_Fortran_COMPILER "${PETSC_MPIFC}") set(CMAKE_C_COMPILER "${PETSC_MPICC}") set(CMAKE_LINKER "${PETSC_LINKER}") -# Built-in options for DAMASK build system -# -> can be overwritten from commandline/install_script -option(OPENMP "Use OpenMP libaries for DAMASK" ON ) -option(OPTIMIZATION "DAMASK optimization level [OFF,DEFENSIVE,AGGRESSIVE]" "DEFENSIVE" ) - -if("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") - set (OPENMP "OFF") - set (OPTIMIZATION "OFF") +# Predefined sets for OPTIMIZATION/OPENMP based on BUILD_TYPE +if("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG" OR "${CMAKE_BUILD_TYPE}" STREQUAL "SYNTAXONLY" ) + set (PARALLEL "OFF") + set (OPTI "OFF") + set (BUILDCMD_POST "${BUILDCMD_POST} -fsyntax-only") +elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set (PARALLEL "ON") + set (OPTI "DEFENSIVE") +elseif("${CMAKE_BUILD_TYPE}" STREQUAL "PERFORMANCE") + set (PARALLEL "ON") + set (OPTI "AGGRESSIVE") endif("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") +# overwrite optimization if given +if("${OPTIMIZATION}" STREQUAL "") + set(OPTIMIZATION "${OPTI}") +else("${OPTIMIZATION}" STREQUAL "") + set(OPTIMIZATION "${OPTIMIZATION}") +endif("${OPTIMIZATION}" STREQUAL "") + +# overwrite optimization if given +if("${OPENMP}" STREQUAL "") + set(OPENMP "${PARALLEL}") +else("${OPENMP}" STREQUAL "") + set(OPENMP "${OPENMP}") +endif("${OPENMP}" STREQUAL "") + # Parse DAMASK_BIN from CONFIG file file(READ "CONFIG" CONFIGFILE) STRING(REGEX REPLACE ";" "\\\\;" CONFIGFILE "${CONFIGFILE}") @@ -132,13 +149,9 @@ STRING(REGEX REPLACE "\n" ";" CONFIGFILE "${CONFIGFILE}") FOREACH(item ${CONFIGFILE}) STRING(REGEX MATCH ".+DAMASK_BIN.+" item ${item}) IF(item) - message("${item}") string(REGEX REPLACE "set" "" item "${item}") - message("${item}") string(REGEX REPLACE "=" " " item "${item}") - message("${item}") - string(REGEX REPLACE "\\\${DAMASK_ROOT}" "${CMAKE_CURRENT_SOURCE_DIR}" item "${item}") - message("${item}") + string(REGEX REPLACE "\\\${DAMASK_ROOT}" "${PROJECT_SOURCE_DIR}" item "${item}") string(REPLACE "DAMASK_BIN" ";" STRING_LIST ${item}) list(GET STRING_LIST 1 item) string(STRIP "${item}" CMAKE_INSTALL_PREFIX) @@ -387,9 +400,9 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # stop execution if floating point exception is detected (NaN is silent) set (DEBUG_FLAGS "${DEBUG_FLAGS} -g") # Generate symbolic debugging information in the object file - set (DEBUG_FLAGS "${DEBUG_FLAGS} -fbacktrace" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -fdump-core" ) - set (DEBUG_FLAGS "${DEBUG_FLAGS} -fcheck=all" ) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fbacktrace") + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fdump-core") + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fcheck=all") # checks for (array-temps,bounds,do,mem,pointer,recursion) # Additional options @@ -425,10 +438,16 @@ message("Linker Flags (Fortran):\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") add_subdirectory(src) # INSTALL BUILT BINARIES -if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") - INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_spectral - DESTINATION ${CMAKE_INSTALL_PREFIX}) -elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") - INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM - DESTINATION ${CMAKE_INSTALL_PREFIX}) -endif("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") +if ("${BUILD_TYPE}" STREQUAL SYNTAXONLY) + if ("${PROJECT_NAME}" STREQUAL DAMASK_spectral) + INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_spectral + DESTINATION ${CMAKE_INSTALL_PREFIX}) + elseif ("${PROJECT_NAME}" STREQUAL DAMASK_FEM) + INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM + DESTINATION ${CMAKE_INSTALL_PREFIX}) + endif("${PROJECT_NAME}" STREQUAL DAMASK_spectral) +else("${BUILD_TYPE}" STREQUAL SYNTAXONLY) + exec_program(mktemp ARGS -d OUTPUT_VARIABLE BLACK_HOLE) + INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/prec.mod + DESTINATION ${BLACK_HOLE}) +endif() diff --git a/Makefile b/Makefile index 29d76afee..b8cdfd71c 100644 --- a/Makefile +++ b/Makefile @@ -11,15 +11,14 @@ FEM: build/FEM @(cd build/FEM; make --no-print-directory -ws all install;) -OPTIONS="-Wno-dev -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE={BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP}" build/spectral: build @mkdir -p build/spectral - @(cd build/spectral; cmake -DDAMASK_SOLVER=SPECTRAL ${OPTIONS} ../..;) + @(cd build/spectral; cmake -Wno-dev -DDAMASK_SOLVER=SPECTRAL -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} ../../;) build/FEM: build @mkdir -p build/FEM - @(cd build/FEM; cmake -DDAMASK_SOLVER=FEM ${OPTIONS} ../..;) + @(cd build/FEM; cmake -Wno-dev -DDAMASK_SOLVER=FEM -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} ../../;) build: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b7cc44bb..56309a821 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -185,9 +185,10 @@ if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") "spectral_mech_Basic.f90") add_dependencies(SPECTRAL_SOLVER SPECTRAL_UTILITIES) list(APPEND OBJECTFILES $) - - add_executable(DAMASK_spectral "DAMASK_spectral.f90" ${OBJECTFILES}) - add_dependencies(DAMASK_spectral SPECTRAL_SOLVER) + if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL SYNTAXONLY) + add_executable(DAMASK_spectral "DAMASK_spectral.f90" ${OBJECTFILES}) + add_dependencies(DAMASK_spectral SPECTRAL_SOLVER) + endif() elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") add_library(FEM_UTILITIES OBJECT "FEM_utilities.f90") add_dependencies(FEM_UTILITIES DAMASK_CPFE) From 5cf5fdb36a8a6a449c76f2376556362e808d6af7 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 4 Feb 2017 01:02:05 +0100 Subject: [PATCH 106/183] not needed anymore --- code/Makefile | 740 -------------------------------------------------- 1 file changed, 740 deletions(-) delete mode 100644 code/Makefile diff --git a/code/Makefile b/code/Makefile deleted file mode 100644 index 49ce9c50e..000000000 --- a/code/Makefile +++ /dev/null @@ -1,740 +0,0 @@ -SHELL = /bin/sh -######################################################################################## -# Makefile to compile the Material subroutine for BVP solution using spectral method -######################################################################################## -# Be sure to remove all files compiled with different options by using "make clean" -######################################################################################## -# OPTIONS = standard (alternative): meaning -#------------------------------------------------------------- -# F90 = ifort (gfortran): compiler type, choose Intel or GNU -# FCOMPILERNAME = name of the compiler executable (if not the same as the type), e.g. using mpich-g90 instead of ifort -# PORTABLE = TRUE (FALSE): decision, if executable is optimized for the machine on which it was built. -# OPTIMIZATION = DEFENSIVE (OFF,AGGRESSIVE,ULTRA): Optimization mode: O2, O0, O3 + further options for most files, O3 + further options for all files -# OPENMP = TRUE (FALSE): OpenMP multiprocessor support -# PREFIX = arbitrary prefix (before FCOMPILERNAME) -# OPTION = arbitrary option (just before file to compile) -# SUFFIX = arbitrary suffix (after file to compile) -# STANDARD_CHECK = checking for Fortran 2008, compiler dependend -######################################################################################## -# including PETSc files. PETSC_ARCH is loaded from these files. -DAMASKVERSION :=$(shell cat ../VERSION) - -include ${PETSC_DIR}/lib/petsc/conf/variables -include ${PETSC_DIR}/lib/petsc/conf/rules - -INCLUDE_DIRS := $(PETSC_FC_INCLUDES) -DPETSc -LIBRARIES := $(PETSC_WITH_EXTERNAL_LIB) -FCOMPILERNAME ?= $(FC) -CCOMPILERNAME ?= $(CC) -LINKERNAME ?= $(FLINKER) - -# MPI compiler wrappers will tell if they are pointing to ifort or gfortran -COMPILEROUT :=$(shell $(FC) -show) -# search in FC or COMPILEROUT for gfortran/ifort if not defined -ifeq ($(strip $(F90)),) - F90 :=$(findstring gfortran,$(FC) $(COMPILEROUT)) -endif -ifeq ($(strip $(F90)),) - F90 :=$(findstring ifort,$(FC) $(COMPILEROUT)) -endif - -OPENMP ?= ON -OPTIMIZATION ?= DEFENSIVE - -ifeq "$(OPTIMIZATION)" "OFF" -OPTI := OFF -MAXOPTI := OFF -endif -ifeq "$(OPTIMIZATION)" "DEFENSIVE" -OPTI := DEFENSIVE -MAXOPTI := DEFENSIVE -endif -ifeq "$(OPTIMIZATION)" "AGGRESSIVE" -OPTI := AGGRESSIVE -MAXOPTI := DEFENSIVE -endif -ifeq "$(OPTIMIZATION)" "ULTRA" -OPTI := AGGRESSIVE -MAXOPTI := AGGRESSIVE -endif - -ifndef OPTI -OPTI := DEFENSIVE -MAXOPTI := DEFENSIVE -endif - -# settings for shared memory multicore support -ifeq "$(OPENMP)" "ON" -OPENMP_FLAG_ifort =-qopenmp -parallel -OPENMP_FLAG_gfortran =-fopenmp -endif - -ifdef STANDARD_CHECK -STANDARD_CHECK_ifort =$(STANDARD_CHECK) -STANDARD_CHECK_gfortran =$(STANDARD_CHECK) -endif - -STANDARD_CHECK_ifort ?=-stand f08 -standard-semantics -STANDARD_CHECK_gfortran ?=-std=f2008ts -pedantic-errors - -#-pedantic: more strict on standard, enables some warnings -# -pedantic-errors: like pedantic, but errors instead of warnings -OPTIMIZATION_OFF_ifort :=-O0 -no-ip -OPTIMIZATION_OFF_gfortran :=-O0 -OPTIMIZATION_DEFENSIVE_ifort :=-O2 -OPTIMIZATION_DEFENSIVE_gfortran :=-O2 -OPTIMIZATION_AGGRESSIVE_ifort :=-ipo -O3 -no-prec-div -fp-model fast=2 -xHost #-fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost -OPTIMIZATION_AGGRESSIVE_gfortran :=-O3 -ffast-math -funroll-loops -ftree-vectorize - - -LINK_OPTIONS_ifort :=-shared-intel -COMPILE_OPTIONS_ifort :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ - -fpp\ - -ftz\ - -assume byterecl,fpe_summary\ - -diag-disable 5268\ - -warn declarations\ - -warn general\ - -warn usage\ - -warn interfaces\ - -warn ignore_loc\ - -warn alignments\ - -warn unused - -################################################################################################### -#COMPILE SWITCHES -#-shared-intel: Link against shared Intel libraries instead of static ones -#-fpp: preprocessor -#-ftz: flush unterflow to zero, automatically set if O<0,1,2,3> >0 -#-assume byterecl record length is given in bytes (also set by -standard-semantics) -# fpe_summary print list of floating point exceptions occured during execution -#-fimplicit-none: assume "implicit-none" even if not present in source -#-diag-disable: disables warnings, where -# warning ID 5268: the text exceeds right hand column allowed on the line (we have only comments there) -#-warn: enables warnings, where -# declarations: any undeclared names (alternative name: -implicitnone) -# general: warning messages and informational messages are issued by the compiler -# usage: questionable programming practices -# interfaces: checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks -# ignore_loc: %LOC is stripped from an actual argument -# alignments: data that is not naturally aligned -# unused: declared variables that are never used -# stderrors: warnings about Fortran standard violations are changed to errors (STANDARD_CHECK) -# -################################################################################################### -#MORE OPTIONS FOR DEBUGGING DURING COMPILATION -#-warn: enables warnings, where -# truncated_source: Determines whether warnings occur when source exceeds the maximum column width in fixed-format files. (too many warnings because we have comments beyond character 132) -# uncalled: Determines whether warnings occur when a statement function is never called -# all: -# -name as_is: case sensitive Fortran! - -DEBUG_OPTIONS_ifort :=-g\ - -traceback\ - -gen-interfaces\ - -fp-stack-check\ - -fp-model strict\ - -check bounds,format,output_conversion,pointers,uninit\ - -ftrapuv\ - -fpe-all0\ - -warn errors\ - -warn stderrors\ - -debug-parameters all - -################################################################################################### -#COMPILE SWITCHES FOR RUNTIME DEBUGGING -#-g: Generate symbolic debugging information in the object file -#-traceback: Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. -#-gen-interfaces: Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ -#-fp-stack-check: Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. -#-ftrapuv Trap uninitalized variables -#-check: checks at runtime, where -# bounds: check if an array index is too small (<1) or too large! -# format: Checking for the data type of an item being formatted for output. -# output_conversion: Checking for the fit of data items within a designated format descriptor field. -# pointers: Checking for certain disassociated or uninitialized pointers or unallocated allocatable objects. -# uninit: Checking for uninitialized variables. -#-fpe-all0 capture all floating-point exceptions, sets -ftz automatically -#-warn: enables warnings, where -# errors: warnings are changed to errors -# stderrors: warnings about Fortran standard violations are changed to errors -# information on http://software.intel.com/en-us/articles/determining-root-cause-of-sigsegv-or-sigbus-errors/ -################################################################################################### -#MORE OPTIONS FOR RUNTIME DEBUGGING -#-heap-arrays: should not be done for OpenMP, but set "ulimit -s unlimited" on shell. Probably it helps also to unlimit other limits -#-check: checks at runtime, where -# arg_temp_created: will cause a lot of warnings because we create a bunch of temporary arrays (performance?) -# stack: -LINK_OPTIONS_gfortran :=-Wl,-undefined,dynamic_lookup -COMPILE_OPTIONS_gfortran :=-DDAMASKVERSION=\"${DAMASKVERSION}\"\ - -xf95-cpp-input\ - -ffree-line-length-132\ - -fimplicit-none\ - -fmodule-private\ - -Wall\ - -Wextra\ - -Wcharacter-truncation\ - -Wunderflow\ - -Wsuggest-attribute=pure\ - -Wsuggest-attribute=noreturn\ - -Wconversion-extra\ - -Wimplicit-procedure\ - -Wno-unused-parameter -#-ffpe-summary=all only for newer gfortran -################################################################################################### -#COMPILE SWITCHES -#-shared -#-Wl,-undefined,dynamic_lookup:ensure to link against dynamic libraries -#-xf95-cpp-input: preprocessor -#-ffree-line-length-132: restrict line length to the standard 132 characters -#-ffpe-summary: print summary of floating point exeptions (‘invalid’, ‘zero’, ‘overflow’, ‘underflow’, ‘inexact’ and ‘denormal’) -#-fimplicit-none: assume "implicit-none" even if not present in source -#-fmodule-private: assume "private" even if not present in source -#-Wcharacter-truncation: warn if character expressions (strings) are truncated -#-Wunderflow: produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation -#-Wsuggest-attribute=pure: -#-Wsuggest-attribute=noreturn: -#-Wconversion-extra -#-Wimplicit-procedure -#-Wall: sets the following Fortran options: -# -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. -# -Wampersand: checks if a character expression is continued proberly by an ampersand at the end of the line and at the beginning of the new line -# -Warray-bounds: checks if array reference is out of bounds at compile time. use -fcheck-bounds to also check during runtime -# -Wconversion: warn about implicit conversions between different type -# -Wsurprising: warn when "suspicious" code constructs are encountered. While technically legal these usually indicate that an error has been made. -# -Wc-binding-type: -# -Wintrinsics-std: only standard intrisics are available, e.g. "call flush(6)" will cause an error -# -Wno-tabs: do not allow tabs in source -# -Wintrinsic-shadow: warn if a user-defined procedure or module procedure has the same name as an intrinsic -# -Wline-truncation: -# -Wtarget-lifetime: -# -Wreal-q-constant: warn about real-literal-constants with 'q' exponent-letter -# -Wunused: a number of unused-xxx warnings -# these are general (non -Fortran options) implied by -Wall -# -Waddress -# -Warray-bounds (only with -O2) -# -Wc++11-compat -# -Wchar-subscripts -# -Wcomment -# -Wformat -# -Wmaybe-uninitialized -# -Wnonnull -# -Wparentheses -# -Wpointer-sign -# -Wreorder -# -Wreturn-type -# -Wsequence-point -# -Wstrict-aliasing -# -Wstrict-overflow=1 -# -Wswitch -# -Wtrigraphs -# -Wuninitialized -# -Wunknown-pragmas -# -Wunused-function -# -Wunused-label -# -Wunused-value -# -Wunused-variable -# -Wvolatile-register-var -#-Wextra: sets the following Fortran options: -# -Wunuses-parameter: -# -Wcompare-reals: -# these are general (non -Fortran options) implied by -Wextra -# -Wclobbered -# -Wempty-body -# -Wignored-qualifiers -# -Wmissing-field-initializers -# -Woverride-init -# -Wsign-compare -# -Wtype-limits -# -Wuninitialized -# -Wunused-but-set-parameter (only with -Wunused or -Wall) -# -Wno-globals - -################################################################################################### -#MORE OPTIONS FOR DEBUGGING DURING COMPILATION -#-Warray-temporarieswarnings: because we have many temporary arrays (performance issue?): -#-Wimplicit-interface: no interfaces for lapack routines -#-Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions. -#-Wstrict-overflow: - -DEBUG_OPTIONS_gfortran :=-g \ - -fbacktrace \ - -fdump-core \ - -fcheck=all \ - -ffpe-trap=invalid,zero,overflow - -################################################################################################### -#COMPILE SWITCHES FOR RUNTIME DEBUGGING -#-ffpe-trap=invalid,\ stop execution if floating point exception is detected (NaN is silent) -# zero,\ -# overflow -#-fcheck=all: sets the following Fortran options: -#array-temps -#bounds -#do -#mem -#pointer -#recursion -################################################################################################### -#MORE OPTIONS FOR RUNTIME DEBUGGING -#-ffpe-trap=precision,\ -# denormal, \ -# underflow - -ifeq "$(DEBUG)" "ON" -COMPILE_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) -LINK_OPTIONS_$(F90) +=$(DEBUG_OPTIONS_$(F90)) -endif -LINK_OPTIONS_$(F90) += $(OPTIMIZATION_$(MAXOPTI)_$(F90)) - -PRECISION_ifort :=-real-size 64 -integer-size 32 -DFLOAT=8 -DINT=4 -#-real-size 32: set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) -#-integer-size 16: set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) -PRECISION_gfortran :=-fdefault-real-8 -fdefault-double-8 -DFLOAT=8 -DINT=4 -#-fdefault-real-8: set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set -#-fdefault-double-8: set precision to 8 bytes for double real, would be 16 bytes because -fdefault-real-8 is used -#-fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) - -################################################################################################### -COMPILE =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(OPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) -COMPILE_MAXOPTI =$(OPENMP_FLAG_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) $(COMPILE_OPTIONS_$(F90)) $(INCLUDE_DIRS) $(PRECISION_$(F90)) -################################################################################################### -SOURCE_FILES = \ - source_thermal_dissipation.o \ - source_thermal_externalheat.o \ - source_damage_isoBrittle.o \ - source_damage_isoDuctile.o \ - source_damage_anisoBrittle.o \ - source_damage_anisoDuctile.o \ - source_vacancy_phenoplasticity.o \ - source_vacancy_irradiation.o \ - source_vacancy_thermalfluc.o - -KINEMATICS_FILES = \ - kinematics_cleavage_opening.o \ - kinematics_slipplane_opening.o \ - kinematics_thermal_expansion.o \ - kinematics_vacancy_strain.o \ - kinematics_hydrogen_strain.o - -PLASTIC_FILES = \ - plastic_dislotwin.o \ - plastic_disloUCLA.o \ - plastic_isotropic.o \ - plastic_phenopowerlaw.o \ - plastic_titanmod.o \ - plastic_nonlocal.o \ - plastic_none.o \ - plastic_phenoplus.o - -THERMAL_FILES = \ - thermal_isothermal.o \ - thermal_adiabatic.o \ - thermal_conduction.o - -DAMAGE_FILES = \ - damage_none.o \ - damage_local.o \ - damage_nonlocal.o - -VACANCYFLUX_FILES = \ - vacancyflux_isoconc.o \ - vacancyflux_isochempot.o \ - vacancyflux_cahnhilliard.o - -POROSITY_FILES = \ - porosity_none.o \ - porosity_phasefield.o - -HYDROGENFLUX_FILES = \ - hydrogenflux_isoconc.o \ - hydrogenflux_cahnhilliard.o - -HOMOGENIZATION_FILES = \ - homogenization_RGC.o \ - homogenization_isostrain.o \ - homogenization_none.o - -##################### -# Spectral Solver -##################### -DAMASK_spectral.exe: IGNORE := \# -DAMASK_spectral.exe: COMPILE += -DSpectral -DAMASK_spectral.exe: COMPILE_MAXOPTI += -DSpectral -DAMASK_spectral.exe: MESHNAME := mesh.f90 -DAMASK_spectral.exe: INTERFACENAME := spectral_interface.f90 - -DAMASK_spectral.o: IGNORE := \# -DAMASK_spectral.o: COMPILE += -DSpectral -DAMASK_spectral.o: COMPILE_MAXOPTI += -DSpectral -DAMASK_spectral.o: MESHNAME := mesh.f90 -DAMASK_spectral.o: INTERFACENAME := spectral_interface.f90 - - -SPECTRAL_SOLVER_FILES = spectral_mech_AL.o spectral_mech_Basic.o spectral_mech_Polarisation.o \ - spectral_thermal.o spectral_damage.o - -SPECTRAL_FILES = C_routines.o \ - system_routines.o \ - prec.o \ - DAMASK_interface.o \ - IO.o \ - numerics.o \ - debug.o \ - math.o \ - FEsolving.o \ - mesh.o \ - material.o \ - lattice.o \ - $(SOURCE_FILES) \ - $(KINEMATICS_FILES) \ - $(PLASTIC_FILES) \ - constitutive.o \ - crystallite.o \ - $(THERMAL_FILES) \ - $(DAMAGE_FILES) \ - $(VACANCYFLUX_FILES) \ - $(HYDROGENFLUX_FILES) \ - $(POROSITY_FILES) \ - $(HOMOGENIZATION_FILES) homogenization.o \ - CPFEM2.o \ - spectral_utilities.o \ - $(SPECTRAL_SOLVER_FILES) - -DAMASK_spectral.exe: DAMASK_spectral.o - $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ - -o DAMASK_spectral.exe DAMASK_spectral.o \ - $(SPECTRAL_FILES) $(LIBRARIES) $(SUFFIX) - - -DAMASK_spectral.o: DAMASK_spectral.f90 \ - $(SPECTRAL_SOLVER_FILES) - $(PREFIX) $(FCOMPILERNAME) $(COMPILE_MAXOPTI) -c DAMASK_spectral.f90 $(SUFFIX) - -spectral_mech_AL.o: spectral_mech_AL.f90 \ - spectral_utilities.o - -spectral_mech_Polarisation.o: spectral_mech_Polarisation.f90 \ - spectral_utilities.o - -spectral_mech_Basic.o: spectral_mech_Basic.f90 \ - spectral_utilities.o - -spectral_thermal.o: spectral_thermal.f90 \ - spectral_utilities.o - -spectral_damage.o: spectral_damage.f90 \ - spectral_utilities.o - -spectral_utilities.o: spectral_utilities.f90 \ - CPFEM2.o - -##################### -# FEM Solver -##################### -VPATH := ../private/FEM/code -DAMASK_FEM.exe: COMPILE += -DFEM -DAMASK_FEM.exe: COMPILE_MAXOPTI += -DFEM -DAMASK_FEM.exe: MESHNAME := ../private/FEM/code/meshFEM.f90 -DAMASK_FEM.exe: INTERFACENAME := ../private/FEM/code/DAMASK_FEM_interface.f90 -DAMASK_FEM.exe: INCLUDE_DIRS += -I./ - -FEM_SOLVER_FILES = FEM_mech.o FEM_thermal.o FEM_damage.o FEM_vacancyflux.o FEM_porosity.o FEM_hydrogenflux.o - -FEM_FILES = prec.o \ - DAMASK_interface.o \ - FEZoo.o \ - IO.o \ - numerics.o \ - debug.o \ - math.o \ - FEsolving.o \ - mesh.o \ - material.o \ - lattice.o \ - $(SOURCE_FILES) \ - $(KINEMATICS_FILES) \ - $(PLASTIC_FILES) \ - constitutive.o \ - crystallite.o \ - $(THERMAL_FILES) \ - $(DAMAGE_FILES) \ - $(VACANCYFLUX_FILES) \ - $(HYDROGENFLUX_FILES) \ - $(POROSITY_FILES) \ - $(HOMOGENIZATION_FILES) homogenization.o \ - CPFEM.o \ - FEM_utilities.o \ - $(FEM_SOLVER_FILES) - -DAMASK_FEM.exe: DAMASK_FEM_driver.o - $(PREFIX) $(LINKERNAME) $(OPENMP_FLAG_$(F90)) $(LINK_OPTIONS_$(F90)) $(STANDARD_CHECK_$(F90)) $(OPTIMIZATION_$(MAXOPTI)_$(F90)) \ - -o DAMASK_FEM.exe DAMASK_FEM_driver.o \ - $(FEM_FILES) $(LIBRARIES) $(SUFFIX) - -DAMASK_FEM_driver.o: DAMASK_FEM_driver.f90 $(FEM_SOLVER_FILES) - $(PREFIX) $(FCOMPILERNAME) $(COMPILE_MAXOPTI) -c ../private/FEM/code/DAMASK_FEM_driver.f90 $(SUFFIX) - -FEM_mech.o: FEM_mech.f90 \ - FEM_utilities.o - -FEM_thermal.o: FEM_thermal.f90 \ - FEM_utilities.o - -FEM_damage.o: FEM_damage.f90 \ - FEM_utilities.o - -FEM_vacancyflux.o: FEM_vacancyflux.f90 \ - FEM_utilities.o - -FEM_porosity.o: FEM_porosity.f90 \ - FEM_utilities.o - -FEM_hydrogenflux.o: FEM_hydrogenflux.f90 \ - FEM_utilities.o - -FEM_utilities.o: FEM_utilities.f90 \ - CPFEM.o - -FEZoo.o: $(wildcard FEZoo.f90) \ - IO.o - $(IGNORE) $(PREFIX) $(FCOMPILERNAME) $(COMPILE) -c ../private/FEM/code/FEZoo.f90 $(SUFFIX) - touch FEZoo.o - -CPFEM.o: CPFEM.f90 \ - homogenization.o - -CPFEM2.o: CPFEM2.f90 \ - homogenization.o - -homogenization.o: homogenization.f90 \ - $(THERMAL_FILES) \ - $(DAMAGE_FILES) \ - $(VACANCYFLUX_FILES) \ - $(POROSITY_FILES) \ - $(HYDROGENFLUX_FILES) \ - $(HOMOGENIZATION_FILES) - -thermal_isothermal.o: thermal_isothermal.f90 \ - crystallite.o - -thermal_adiabatic.o: thermal_adiabatic.f90 \ - crystallite.o - -thermal_conduction.o: thermal_conduction.f90 \ - crystallite.o - -damage_none.o: damage_none.f90 \ - crystallite.o - -damage_local.o: damage_local.f90 \ - crystallite.o - -damage_nonlocal.o: damage_nonlocal.f90 \ - crystallite.o - -thermal_conduction.o: thermal_conduction.f90 \ - crystallite.o - -vacancyflux_isoconc.o: vacancyflux_isoconc.f90 \ - crystallite.o - -vacancyflux_isochempot.o: vacancyflux_isochempot.f90 \ - crystallite.o - -vacancyflux_cahnhilliard.o: vacancyflux_cahnhilliard.f90 \ - crystallite.o - -porosity_none.o: porosity_none.f90 \ - crystallite.o - -porosity_phasefield.o: porosity_phasefield.f90 \ - crystallite.o - -hydrogenflux_isoconc.o: hydrogenflux_isoconc.f90 \ - crystallite.o - -hydrogenflux_cahnhilliard.o: hydrogenflux_cahnhilliard.f90 \ - crystallite.o - -homogenization_RGC.o: homogenization_RGC.f90 \ - crystallite.o - -homogenization_isostrain.o: homogenization_isostrain.f90 \ - crystallite.o - -homogenization_none.o: homogenization_none.f90 \ - crystallite.o - -crystallite.o: crystallite.f90 \ - constitutive.o - -constitutive.o: constitutive.f90 \ - $(SOURCE_FILES) \ - $(KINEMATICS_FILES) \ - $(PLASTIC_FILES) - -source_thermal_dissipation.o: source_thermal_dissipation.f90 \ - lattice.o - -source_thermal_externalheat.o: source_thermal_externalheat.f90 \ - lattice.o - -source_damage_isoBrittle.o: source_damage_isoBrittle.f90 \ - lattice.o - -source_damage_isoDuctile.o: source_damage_isoDuctile.f90 \ - lattice.o - -source_damage_anisoBrittle.o: source_damage_anisoBrittle.f90 \ - lattice.o - -source_damage_anisoDuctile.o: source_damage_anisoDuctile.f90 \ - lattice.o - -source_vacancy_phenoplasticity.o: source_vacancy_phenoplasticity.f90 \ - lattice.o - -source_vacancy_irradiation.o: source_vacancy_irradiation.f90 \ - lattice.o - -source_vacancy_thermalfluc.o: source_vacancy_thermalfluc.f90 \ - lattice.o - -kinematics_cleavage_opening.o: kinematics_cleavage_opening.f90 \ - lattice.o - -kinematics_slipplane_opening.o: kinematics_slipplane_opening.f90 \ - lattice.o - -kinematics_thermal_expansion.o: kinematics_thermal_expansion.f90 \ - lattice.o - -kinematics_vacancy_strain.o: kinematics_vacancy_strain.f90 \ - lattice.o - -kinematics_hydrogen_strain.o: kinematics_hydrogen_strain.f90 \ - lattice.o - -plastic_nonlocal.o: plastic_nonlocal.f90 \ - lattice.o - -plastic_titanmod.o: plastic_titanmod.f90 \ - lattice.o - -plastic_disloUCLA.o: plastic_disloUCLA.f90 \ - lattice.o - -plastic_dislotwin.o: plastic_dislotwin.f90 \ - lattice.o - -plastic_phenopowerlaw.o: plastic_phenopowerlaw.f90 \ - lattice.o - -plastic_phenoplus.o: plastic_phenoplus.f90 \ - lattice.o - -plastic_isotropic.o: plastic_isotropic.f90 \ - lattice.o - -plastic_none.o: plastic_none.f90 \ - lattice.o -ifeq "$(F90)" "gfortran" -lattice.o: lattice.f90 \ - material.o - $(PREFIX) $(FCOMPILERNAME) $(COMPILE) -ffree-line-length-240 -c lattice.f90 $(SUFFIX) -# long lines for interaction matrix -else -lattice.o: lattice.f90 \ - material.o -endif - -material.o: material.f90 \ - mesh.o - -mesh.o: mesh.f90 \ - $(wildcard meshFEM.f90) \ - FEsolving.o \ - math.o \ - FEZoo.o - $(PREFIX) $(FCOMPILERNAME) $(COMPILE) -c $(MESHNAME) -o mesh.o $(SUFFIX) - -FEsolving.o: FEsolving.f90 \ - debug.o - -math.o: math.f90 \ - debug.o - -debug.o: debug.f90 \ - numerics.o - -numerics.o: numerics.f90 \ - IO.o - -IO.o: IO.f90 \ - DAMASK_interface.o - -DAMASK_interface.o: spectral_interface.f90 \ - $(wildcard DAMASK_FEM_interface.f90) \ - prec.o - $(PREFIX) $(FCOMPILERNAME) $(COMPILE) -c $(INTERFACENAME) -o DAMASK_interface.o $(SUFFIX) - -ifeq "$(F90)" "gfortran" -prec.o: prec.f90 \ - system_routines.o - $(PREFIX) $(FCOMPILERNAME) $(COMPILE) -c prec.f90 -fno-range-check -fall-intrinsics -fno-fast-math $(SUFFIX) -# fno-range-check: Disable range checking on results of simplification of constant expressions during compilation -# --> allows the definition of DAMASK_NaN -#-fall-intrinsics: all intrinsic procedures (including the GNU-specific extensions) are accepted. -Wintrinsics-std will be ignored -# and no user-defined procedure with the same name as any intrinsic will be called except when it is explicitly declared external -# --> allows the use of 'isnan' -#-fno-fast-math: -# --> otherwise, when setting -ffast-math, isnan always evaluates to false (I would call it a bug) -else - -prec.o: prec.f90 \ - system_routines.o -endif - -system_routines.o: system_routines.f90 \ - C_routines.o - -C_routines.o: C_routines.c - - -%.o : %.f90 - $(PREFIX) $(FCOMPILERNAME) $(COMPILE) -c $< $(SUFFIX) - -%.o : %.c - $(CCOMPILERNAME) -c $< - -.PHONY: tidy -tidy: - @rm -rf *.o - @rm -rf *.mod - @rm -rf *.optrpt - @rm -rf *.inst.f90 # for instrumentation - @rm -rf *.pomp.f90 # for instrumentation - @rm -rf *.pp.f90 # for instrumentation - @rm -rf *.pdb # for instrumentation - @rm -rf *.opari.inc # for instrumentation - -.PHONY: cleanDAMASK -cleanDAMASK: - @rm -rf *.exe - @rm -rf *.marc - @rm -rf *.o - @rm -rf *.mod - @rm -rf *.optrpt - @rm -rf *.inst.f90 # for instrumentation - @rm -rf *.pomp.f90 # for instrumentation - @rm -rf *.pp.f90 # for instrumentation - @rm -rf *.pdb # for instrumentation - @rm -rf *.opari.inc # for instrumentation - -.PHONY: help -help: - F90="$(F90)" - FCOMPILERNAME="$(FCOMPILERNAME)" - COMPILEROUT="$(COMPILEROUT)" - From 27063043b9d6343fec109a7e4f3a0c796408ced8 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Feb 2017 19:32:20 +0100 Subject: [PATCH 107/183] needs to follow rename of code folder, old Marc not supported any more --- lib/damask/solver/marc.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/damask/solver/marc.py b/lib/damask/solver/marc.py index 873d08cdb..16f3c8451 100644 --- a/lib/damask/solver/marc.py +++ b/lib/damask/solver/marc.py @@ -13,9 +13,6 @@ class Marc(Solver): '2015': ['linux64',''], '2014.2':['linux64',''], '2014' :['linux64',''], - '2013.1':['linux64',''], - '2013': ['linux64',''], - '2012': ['linux64',''], } @@ -86,13 +83,13 @@ class Marc(Solver): damaskEnv = damask.environment.Environment() - user = os.path.join(damaskEnv.relPath('code/'),'DAMASK_marc') # might be updated if special version (symlink) is found + user = os.path.join(damaskEnv.relPath('src/'),'DAMASK_marc') # might be updated if special version (symlink) is found if compile: - if os.path.isfile(os.path.join(damaskEnv.relPath('code/'),'DAMASK_marc%s.f90'%release)): - user = os.path.join(damaskEnv.relPath('code/'),'DAMASK_marc%s'%release) + if os.path.isfile(os.path.join(damaskEnv.relPath('src/'),'DAMASK_marc%s.f90'%release)): + user = os.path.join(damaskEnv.relPath('src/'),'DAMASK_marc%s'%release) else: - if os.path.isfile(os.path.join(damaskEnv.relPath('code/'),'DAMASK_marc%s.marc'%release)): - user = os.path.join(damaskEnv.relPath('code/'),'DAMASK_marc%s'%release) + if os.path.isfile(os.path.join(damaskEnv.relPath('src/'),'DAMASK_marc%s.marc'%release)): + user = os.path.join(damaskEnv.relPath('src/'),'DAMASK_marc%s'%release) # Define options [see Marc Installation and Operation Guide, pp 23] script = 'run_damask%s'%({False:'',True:'_'}[optimization!='' or openMP]) From 89be6d0b08295467557431c435e5a4df8e3035f4 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Feb 2017 19:44:19 +0100 Subject: [PATCH 108/183] intent(in/out) is self-explanatory --- src/mesh.f90 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/mesh.f90 b/src/mesh.f90 index 7da3d4968..f60fde905 100644 --- a/src/mesh.f90 +++ b/src/mesh.f90 @@ -3353,15 +3353,10 @@ end function FE_mapElemtype subroutine mesh_faceMatch(elem, face ,matchingElem, matchingFace) implicit none -!*** output variables integer(pInt), intent(out) :: matchingElem, & ! matching CP element ID matchingFace ! matching face ID - -!*** input variables integer(pInt), intent(in) :: face, & ! face ID elem ! CP elem ID - -!*** local variables integer(pInt), dimension(FE_NmatchingNodesPerFace(face,FE_geomtype(mesh_element(2,elem)))) :: & myFaceNodes ! global node ids on my face integer(pInt) :: myType, & From e3a22a6e1f757fc4f3860706ecafab3509f97ea2 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Feb 2017 19:58:46 +0100 Subject: [PATCH 109/183] might exist during transition time --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a15b81a7f..87bc986f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +code *.pyc *.mod *.o From a248a242504499b1f19f111ccac6dbba4dbbdc75 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Feb 2017 20:01:42 +0100 Subject: [PATCH 110/183] consistent with other routines --- src/math.f90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/math.f90 b/src/math.f90 index 315da2642..e592ae1a9 100644 --- a/src/math.f90 +++ b/src/math.f90 @@ -452,7 +452,6 @@ pure function math_tensorproduct(A,B) implicit none real(pReal), dimension(:), intent(in) :: A,B real(pReal), dimension(size(A,1),size(B,1)) :: math_tensorproduct - integer(pInt) :: i,j forall (i=1_pInt:size(A,1),j=1_pInt:size(B,1)) math_tensorproduct(i,j) = A(i)*B(j) From 491fa522630554707df945fe51c5e179f3ef77b3 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Wed, 15 Mar 2017 16:40:44 -0500 Subject: [PATCH 111/183] syntax polishing --- CMakeLists.txt | 323 ++++++++++++++++++++++++++----------------------- 1 file changed, 173 insertions(+), 150 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 400a34cd8..c3fa9b239 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,19 +7,20 @@ cmake_minimum_required (VERSION 2.8.8 FATAL_ERROR) set(PETSC_DIR $ENV{PETSC_DIR}) if ("${PETSC_DIR}" STREQUAL "") message (FATAL_ERROR "PETSC_DIR is not defined") -endif ("${PETSC_DIR}" STREQUAL "") +endif + +set (petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") +set (petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) # Use existing variables from PETSc # https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake -exec_program(mktemp ARGS -d OUTPUT_VARIABLE PETSC_TEMP) -set(petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") -set(petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) # Generate a temporary makefile to probe the PETSc configuration -# This file will be deleted once the settings from PETSc are parsed -# into CMake -set (petsc_config_makefile "${PETSC_TEMP}/Makefile.petsc") +# This file will be deleted +# once the settings from PETSc are parsed into CMake +exec_program (mktemp ARGS -d OUTPUT_VARIABLE TEMPDIR) +set (petsc_config_makefile "${TEMPDIR}/Makefile.petsc") file (WRITE "${petsc_config_makefile}" "## This file was auto generated by CMake @@ -48,149 +49,149 @@ linker: # to acquire corresponding PETSc Variables. find_program (MAKE_EXECUTABLE NAMES make gmake) # Find the PETSc includes directory settings -execute_process(COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "includes" - RESULT_VARIABLE PETSC_INCLUDES_RETURN - OUTPUT_VARIABLE petsc_includes - OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "includes" + RESULT_VARIABLE PETSC_INCLUDES_RETURN + 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) +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) +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) +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 (MPIF90 + 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) +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 ${PETSC_TEMP}) +file (REMOVE_RECURSE ${TEMPDIR}) # Remove duplicate compiler and linker flags -string( REGEX MATCHALL "-I([^\" ]+)" TMP_LIST "${petsc_includes}") -list(REMOVE_DUPLICATES TMP_LIST) +string (REGEX MATCHALL "-I([^\" ]+)" TMP_LIST "${petsc_includes}") +list (REMOVE_DUPLICATES TMP_LIST) foreach (dir ${TMP_LIST}) - set(PETSC_INCLUDES "${PETSC_INCLUDES} ${dir}") -endforeach(dir) -string( REGEX MATCHALL "-[lLW]([^\" ]+)" TMP_LIST "${petsc_external_lib}") -list(REMOVE_DUPLICATES TMP_LIST) + set (PETSC_INCLUDES "${PETSC_INCLUDES} ${dir}") +endforeach (dir) +string (REGEX MATCHALL "-[lLW]([^\" ]+)" TMP_LIST "${petsc_external_lib}") +list (REMOVE_DUPLICATES TMP_LIST) foreach (exlib ${TMP_LIST}) - set(PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} ${exlib}") -endforeach(exlib) + set (PETSC_EXTERNAL_LIB "${PETSC_EXTERNAL_LIB} ${exlib}") +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" ) +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" ) #--------------------------------------------------------------------------------------- # Now start to care about DAMASK -# DAMASK Solver selection +# DAMASK solver defines project to build if ("${DAMASK_SOLVER}" STREQUAL "SPECTRAL") - project(DAMASK_spectral Fortran C) - add_definitions(-DSpectral) - message("Configuring Spectral Solver\n") + project (DAMASK_spectral Fortran C) + add_definitions (-DSpectral) + message ("Building Spectral Solver\n") elseif ("${DAMASK_SOLVER}" STREQUAL "FEM") - project(DAMASK_FEM Fortran C) - add_definitions(-DFEM) - message("Configuring FEM Solver\n") -endif() + project (DAMASK_FEM Fortran C) + add_definitions (-DFEM) + message ("Building FEM Solver\n") +endif # set compiler and linker commands (need to be done after 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}") -set(CMAKE_LINKER "${PETSC_LINKER}") +set (CMAKE_Fortran_COMPILER "${PETSC_MPIFC}") +set (CMAKE_C_COMPILER "${PETSC_MPICC}") +set (CMAKE_LINKER "${PETSC_LINKER}") # Predefined sets for OPTIMIZATION/OPENMP based on BUILD_TYPE -if("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG" OR "${CMAKE_BUILD_TYPE}" STREQUAL "SYNTAXONLY" ) +if ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG" OR "${CMAKE_BUILD_TYPE}" STREQUAL "SYNTAXONLY" ) set (PARALLEL "OFF") set (OPTI "OFF") set (BUILDCMD_POST "${BUILDCMD_POST} -fsyntax-only") -elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") +elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (PARALLEL "ON") set (OPTI "DEFENSIVE") -elseif("${CMAKE_BUILD_TYPE}" STREQUAL "PERFORMANCE") +elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "PERFORMANCE") set (PARALLEL "ON") set (OPTI "AGGRESSIVE") -endif("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") +endif -# overwrite optimization if given -if("${OPTIMIZATION}" STREQUAL "") - set(OPTIMIZATION "${OPTI}") -else("${OPTIMIZATION}" STREQUAL "") - set(OPTIMIZATION "${OPTIMIZATION}") -endif("${OPTIMIZATION}" STREQUAL "") +# $OPTIMIZATION takes precedence over $BUILD_TYPE defaults +if ("${OPTIMIZATION}" STREQUAL "") + set (OPTIMIZATION "${OPTI}") +else + set (OPTIMIZATION "${OPTIMIZATION}") +endif -# overwrite optimization if given -if("${OPENMP}" STREQUAL "") - set(OPENMP "${PARALLEL}") -else("${OPENMP}" STREQUAL "") +# $OPENMP takes precedence over $BUILD_TYPE defaults +if ("${OPENMP}" STREQUAL "") + set (OPENMP "${PARALLEL}") +else set(OPENMP "${OPENMP}") -endif("${OPENMP}" STREQUAL "") +endif # Parse DAMASK_BIN from CONFIG file -file(READ "CONFIG" CONFIGFILE) -STRING(REGEX REPLACE ";" "\\\\;" CONFIGFILE "${CONFIGFILE}") -STRING(REGEX REPLACE "\n" ";" CONFIGFILE "${CONFIGFILE}") -FOREACH(item ${CONFIGFILE}) - STRING(REGEX MATCH ".+DAMASK_BIN.+" item ${item}) - IF(item) - string(REGEX REPLACE "set" "" item "${item}") - string(REGEX REPLACE "=" " " item "${item}") - string(REGEX REPLACE "\\\${DAMASK_ROOT}" "${PROJECT_SOURCE_DIR}" item "${item}") - string(REPLACE "DAMASK_BIN" ";" STRING_LIST ${item}) - list(GET STRING_LIST 1 item) - string(STRIP "${item}" CMAKE_INSTALL_PREFIX) - ENDIF(item) -ENDFOREACH(item ${CONFIGFILE}) +file (READ "CONFIG" CONFIGFILE) +string (REGEX REPLACE ";" "\\\\;" CONFIGFILE "${CONFIGFILE}") +string (REGEX REPLACE "\n" ";" CONFIGFILE "${CONFIGFILE}") +foreach (item ${CONFIGFILE}) + string (REGEX MATCH ".+DAMASK_BIN.+" item ${item}) + if (item) + string (REGEX REPLACE "set" "" item "${item}") + string (REGEX REPLACE "=" " " item "${item}") + string (REGEX REPLACE "\\\${DAMASK_ROOT}" "${PROJECT_SOURCE_DIR}" item "${item}") + string (REPLACE "DAMASK_BIN" ";" STRING_LIST ${item}) + list (GET STRING_LIST 1 item) + string (STRIP "${item}" CMAKE_INSTALL_PREFIX) + endif +endforeach(item ${CONFIGFILE}) # 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}") +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) -add_definitions(-DFLOAT=8) -add_definitions(-DINT=4) +add_definitions (-DPETSc) +add_definitions (-DFLOAT=8) +add_definitions (-DINT=4) -set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}" ) +set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}") set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") ################################################################################################### # Intel Compiler ################################################################################################### -if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") +if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") if (OPENMP) set (OPENMP_FLAGS "-qopenmp -parallel") - endif(OPENMP) + endif if ("${OPTIMIZATION}" STREQUAL "OFF") set (OPTIMIZATION_FLAGS "-O0 -no-ip") - elseif("${OPTIMIZATION}" STREQUAL "DEFENSIVE") + elseif ("${OPTIMIZATION}" STREQUAL "DEFENSIVE") set (OPTIMIZATION_FLAGS "-O2") elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") - set (OPTIMIZATION_FLAGS "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost" ) + set (OPTIMIZATION_FLAGS "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost") # -fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" - endif() + endif set (STANDARD_CHECK "-stand f08 -standard-semantics") set (LINKER_FLAGS "${LINKER_FLAGS} -shared-intel") @@ -200,34 +201,38 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") # Fine tuning compilation options set (COMPILE_FLAGS "${COMPILE_FLAGS} -fpp") # preprocessor + set (COMPILE_FLAGS "${COMPILE_FLAGS} -ftz") - # flush unterflow to zero, automatically set if O<0,1,2,3> >0 + # flush underflow to zero, automatically set if -O[1,2,3] + set (COMPILE_FLAGS "${COMPILE_FLAGS} -assume") - # assume - set (COMPILE_FLAGS "${COMPILE_FLAGS}byterecl") - # record length is given in bytes (also set by -standard-semantics) + # assume ... + set (COMPILE_FLAGS "${COMPILE_FLAGS} byterecl") + # ... record length is given in bytes (also set by -standard-semantics) set (COMPILE_FLAGS "${COMPILE_FLAGS},fpe_summary") - # print list of floating point exceptions occured during execution + # ... print list of floating point exceptions occured during execution + set (COMPILE_FLAGS "${COMPILE_FLAGS} -diag-disable") - # disables warnings, where - set (COMPILE_FLAGS "${COMPILE_FLAGS}5268") - # the text exceeds right hand column allowed on the line (we have only comments there) + # disables warnings ... + set (COMPILE_FLAGS "${COMPILE_FLAGS} 5268") + # ... the text exceeds right hand column allowed on the line (we have only comments there) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -warn") - # enables warnings, where - set (COMPILE_FLAGS "${COMPILE_FLAGS}declarations") - # any undeclared names (alternative name: -implicitnone) + # enables warnings ... + set (COMPILE_FLAGS "${COMPILE_FLAGS} declarations") + # ... any undeclared names (alternative name: -implicitnone) set (COMPILE_FLAGS "${COMPILE_FLAGS},general") - # warning messages and informational messages are issued by the compiler + # ... warning messages and informational messages are issued by the compiler set (COMPILE_FLAGS "${COMPILE_FLAGS},usage") - # questionable programming practices + # ... questionable programming practices set (COMPILE_FLAGS "${COMPILE_FLAGS},interfaces") - # checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks + # ... checks the interfaces of all SUBROUTINEs called and FUNCTIONs invoked in your compilation against an external set of interface blocks set (COMPILE_FLAGS "${COMPILE_FLAGS},ignore_loc") - # %LOC is stripped from an actual argument + # ... %LOC is stripped from an actual argument set (COMPILE_FLAGS "${COMPILE_FLAGS},alignments") - # data that is not naturally aligned + # ... data that is not naturally aligned set (COMPILE_FLAGS "${COMPILE_FLAGS},unused") - # declared variables that are never used + # ... declared variables that are never used # Additional options # -warn: enables warnings, where @@ -241,37 +246,44 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") # Runtime debugging set (DEBUG_FLAGS "${DEBUG_FLAGS} -g") # Generate symbolic debugging information in the object file + set (DEBUG_FLAGS "${DEBUG_FLAGS} -traceback") - # Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time. + # Generate extra information in the object file to provide source file traceback information when a severe error occurs at run time + set (DEBUG_FLAGS "${DEBUG_FLAGS} -gen-interfaces") # Generate an interface block for each routine. http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again/ + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-stack-check") - # Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state. + # Generate extra code after every function call to ensure that the floating-point (FP) stack is in the expected state + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fp-model strict") # Trap uninitalized variables + set (DEBUG_FLAGS "${DEBUG_FLAGS} -check" ) - # Checks at runtime, where - set (DEBUG_FLAGS "${DEBUG_FLAGS}bounds") - # if an array index is too small (<1) or too large! + # Checks at runtime ... + set (DEBUG_FLAGS "${DEBUG_FLAGS} bounds") + # ... if an array index is too small (<1) or too large! set (DEBUG_FLAGS "${DEBUG_FLAGS},format") - # for the data type of an item being formatted for output. + # ... for the data type of an item being formatted for output. set (DEBUG_FLAGS "${DEBUG_FLAGS},output_conversion") - # for the fit of data items within a designated format descriptor field. + # ... for the fit of data items within a designated format descriptor field. set (DEBUG_FLAGS "${DEBUG_FLAGS},pointers") - # for certain disassociated or uninitialized pointers or unallocated allocatable objects. + # ... for certain disassociated or uninitialized pointers or unallocated allocatable objects. set (DEBUG_FLAGS "${DEBUG_FLAGS},uninit") - # for uninitialized variables. + # ... for uninitialized variables. set (DEBUG_FLAGS "${DEBUG_FLAGS} -ftrapuv") - # initializes stack local variables to an unusual value to aid error detection + # ... initializes stack local variables to an unusual value to aid error detection set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all0") - # capture all floating-point exceptions, sets -ftz automatically + # ... capture all floating-point exceptions, sets -ftz automatically + set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn") - # enables warnings, where - set (DEBUG_FLAGS "${DEBUG_FLAGS}errors") - # warnings are changed to errors + # enables warnings ... + set (DEBUG_FLAGS "${DEBUG_FLAGS} errors") + # ... warnings are changed to errors set (DEBUG_FLAGS "${DEBUG_FLAGS},stderrors") - # warnings about Fortran standard violations are changed to errors - set (DEBUG_FLAGS "${DEBUG_FLAGS} -debug-parameters all" ) + # ... warnings about Fortran standard violations are changed to errors + + set (DEBUG_FLAGS "${DEBUG_FLAGS} -debug-parameters all") # generate debug information for parameters # Additional options @@ -283,9 +295,9 @@ if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") #------------------------------------------------------------------------------------------------ # precision settings set (PRECISION_FLAGS "${PRECISION_FLAGS} -real-size 64") - # set precision to one of those 32/64/128 (= 4/8/16 bytes) for standard real (=8 for pReal) + # set precision for standard real to 32 | 64 | 128 (= 4 | 8 | 16 bytes, type pReal is always 8 bytes) set (PRECISION_FLAGS "${PRECISION_FLAGS} -integer-size 32") - # set precision to one of those 16/32/64 (= 2/4/8 bytes) for standard integer (=4 for pInt) + # set precision for standard int to 16 | 32 | 64 (= 2 | 4 | 8 bytes, type pInt is always 4 bytes) ################################################################################################### @@ -295,7 +307,7 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") if (OPENMP) set (OPENMP_FLAGS "-fopenmp") - endif() + endif if ("${OPTIMIZATION}" STREQUAL "OFF") set (OPTIMIZATION_FLAGS "-O0" ) @@ -303,7 +315,7 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") set (OPTIMIZATION_FLAGS "-O2") elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") set (OPTIMIZATION_FLAGS "-O3 -ffast-math -funroll-loops -ftree-vectorize") - endif() + endif set (STANDARD_CHECK "-std=f2008ts -pedantic-errors" ) set (LINKER_FLAGS "${LINKER_FLAGS} -Wl") @@ -316,12 +328,16 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # Fine tuning compilation options set (COMPILE_FLAGS "${COMPILE_FLAGS} -xf95-cpp-input") # preprocessor + set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffree-line-length-132") # restrict line length to the standard 132 characters (lattice.f90 require more characters) + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fimplicit-none") # assume "implicit none" even if not present in source + set (COMPILE_FLAGS "${COMPILE_FLAGS} -fmodule-private") # assume "private" even if not present in source + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wall") # sets the following Fortran options: # -Waliasing: warn about possible aliasing of dummy arguments. Specifically, it warns if the same actual argument is associated with a dummy argument with "INTENT(IN)" and a dummy argument with "INTENT(OUT)" in a call with an explicit interface. @@ -362,6 +378,7 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # -Wunused-value # -Wunused-variable # -Wvolatile-register-var + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wextra") # sets the following Fortran options: # -Wunuses-parameter: @@ -377,10 +394,13 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # -Wuninitialized # -Wunused-but-set-parameter (only with -Wunused or -Wall) # -Wno-globals + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wcharacter-truncation") # warn if character expressions (strings) are truncated + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wunderflow") # produce a warning when numerical constant expressions are encountered, which yield an UNDERFLOW during compilation + set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=pure") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=noreturn") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wconversion-extra") @@ -398,8 +418,10 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # Runtime debugging set (DEBUG_FLAGS "${DEBUG_FLAGS} -ffpe-trap=invalid,zero,overflow") # stop execution if floating point exception is detected (NaN is silent) + set (DEBUG_FLAGS "${DEBUG_FLAGS} -g") # Generate symbolic debugging information in the object file + set (DEBUG_FLAGS "${DEBUG_FLAGS} -fbacktrace") set (DEBUG_FLAGS "${DEBUG_FLAGS} -fdump-core") set (DEBUG_FLAGS "${DEBUG_FLAGS} -fcheck=all") @@ -411,43 +433,44 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # precision settings set (PRECISION_FLAGS "${PRECISION_FLAGS} -fdefault-real-8") # set precision to 8 bytes for standard real (=8 for pReal). Will set size of double to 16 bytes as long as -fdefault-double-8 is not set + set (PRECISION_FLAGS "${PRECISION_FLAGS} -fdefault-double-8") # set precision to 8 bytes for double real, would be 16 bytes if -fdefault-real-8 is used # Additional options # -fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) -endif() +endif set (CMAKE_Fortran_FLAGS "${BUILDCMD_PRE} ${OPENMP_FLAGS} ${STANDARD_CHECK} ${OPTIMIZATION_FLAGS} ${COMPILE_FLAGS} ${PRECISION_FLAGS}") set (CMAKE_Fortran_LINK_EXECUTABLE "${BUILDCMD_PRE} ${CMAKE_LINKER} ${OPENMP_FLAGS} ${OPTIMIZATION_FLAGS} ${LINKER_FLAGS}") -if("${CMAKE_BUILD_TYPE}" STREQUAL "") +if ("${CMAKE_BUILD_TYPE}" STREQUAL "") set (CMAKE_BUILD_TYPE "RELEASE") -elseif("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") +elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DEBUG_FLAGS}") set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} ${DEBUG_FLAGS}") -endif() +endif set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") -message("Compiler Flags (Fortran):\n${CMAKE_Fortran_FLAGS}\n") -message("Linker Flags (Fortran):\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") +message ("Fortran Compiler Flags:\n${CMAKE_Fortran_FLAGS}\n") +message ("Fortran Linker Flags:\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") # location of code -add_subdirectory(src) +add_subdirectory (src) # INSTALL BUILT BINARIES if ("${BUILD_TYPE}" STREQUAL SYNTAXONLY) if ("${PROJECT_NAME}" STREQUAL DAMASK_spectral) - INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_spectral - DESTINATION ${CMAKE_INSTALL_PREFIX}) + install (PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_spectral + DESTINATION ${CMAKE_INSTALL_PREFIX}) elseif ("${PROJECT_NAME}" STREQUAL DAMASK_FEM) - INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM - DESTINATION ${CMAKE_INSTALL_PREFIX}) - endif("${PROJECT_NAME}" STREQUAL DAMASK_spectral) -else("${BUILD_TYPE}" STREQUAL SYNTAXONLY) - exec_program(mktemp ARGS -d OUTPUT_VARIABLE BLACK_HOLE) - INSTALL(PROGRAMS ${PROJECT_BINARY_DIR}/src/prec.mod - DESTINATION ${BLACK_HOLE}) -endif() + install (PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM + DESTINATION ${CMAKE_INSTALL_PREFIX}) + endif +else + exec_program(mktemp ARGS -d OUTPUT_VARIABLE BLACK_HOLE) + install (PROGRAMS ${PROJECT_BINARY_DIR}/src/prec.mod + DESTINATION ${BLACK_HOLE}) +endif From defbf0cd120c99abc34cadbf45669ce26237d8db Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Wed, 15 Mar 2017 17:05:58 -0500 Subject: [PATCH 112/183] fixed else/endif () glitch --- CMakeLists.txt | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c3fa9b239..18b2587dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required (VERSION 2.8.8 FATAL_ERROR) set(PETSC_DIR $ENV{PETSC_DIR}) if ("${PETSC_DIR}" STREQUAL "") message (FATAL_ERROR "PETSC_DIR is not defined") -endif +endif () set (petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") set (petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules" ) @@ -108,7 +108,7 @@ elseif ("${DAMASK_SOLVER}" STREQUAL "FEM") project (DAMASK_FEM Fortran C) add_definitions (-DFEM) message ("Building FEM Solver\n") -endif +endif () # set compiler and linker commands (need to be done after defining the project) # https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F @@ -127,21 +127,21 @@ elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "PERFORMANCE") set (PARALLEL "ON") set (OPTI "AGGRESSIVE") -endif +endif () # $OPTIMIZATION takes precedence over $BUILD_TYPE defaults if ("${OPTIMIZATION}" STREQUAL "") set (OPTIMIZATION "${OPTI}") -else +else () set (OPTIMIZATION "${OPTIMIZATION}") -endif +endif () # $OPENMP takes precedence over $BUILD_TYPE defaults if ("${OPENMP}" STREQUAL "") set (OPENMP "${PARALLEL}") -else +else () set(OPENMP "${OPENMP}") -endif +endif () # Parse DAMASK_BIN from CONFIG file file (READ "CONFIG" CONFIGFILE) @@ -156,7 +156,7 @@ foreach (item ${CONFIGFILE}) string (REPLACE "DAMASK_BIN" ";" STRING_LIST ${item}) list (GET STRING_LIST 1 item) string (STRIP "${item}" CMAKE_INSTALL_PREFIX) - endif + endif () endforeach(item ${CONFIGFILE}) # Parse DAMASK version from VERSION file @@ -182,7 +182,7 @@ if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") if (OPENMP) set (OPENMP_FLAGS "-qopenmp -parallel") - endif + endif () if ("${OPTIMIZATION}" STREQUAL "OFF") set (OPTIMIZATION_FLAGS "-O0 -no-ip") @@ -191,7 +191,7 @@ if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") set (OPTIMIZATION_FLAGS "-ipo -O3 -no-prec-div -fp-model fast=2 -xHost") # -fast = -ipo, -O3, -no-prec-div, -static, -fp-model fast=2, and -xHost" - endif + endif () set (STANDARD_CHECK "-stand f08 -standard-semantics") set (LINKER_FLAGS "${LINKER_FLAGS} -shared-intel") @@ -307,7 +307,7 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") if (OPENMP) set (OPENMP_FLAGS "-fopenmp") - endif + endif () if ("${OPTIMIZATION}" STREQUAL "OFF") set (OPTIMIZATION_FLAGS "-O0" ) @@ -315,13 +315,12 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") set (OPTIMIZATION_FLAGS "-O2") elseif ("${OPTIMIZATION}" STREQUAL "AGGRESSIVE") set (OPTIMIZATION_FLAGS "-O3 -ffast-math -funroll-loops -ftree-vectorize") - endif + endif () set (STANDARD_CHECK "-std=f2008ts -pedantic-errors" ) set (LINKER_FLAGS "${LINKER_FLAGS} -Wl") # options parsed directly to the linker - set (LINKER_FLAGS "${LINKER_FLAGS},-undefined") - set (LINKER_FLAGS "${LINKER_FLAGS},-dynamic_lookup" ) + set (LINKER_FLAGS "${LINKER_FLAGS},-undefined,dynamic_lookup" ) # ensure to link against dynamic libraries #------------------------------------------------------------------------------------------------ @@ -439,7 +438,7 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # Additional options # -fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) -endif +endif () set (CMAKE_Fortran_FLAGS "${BUILDCMD_PRE} ${OPENMP_FLAGS} ${STANDARD_CHECK} ${OPTIMIZATION_FLAGS} ${COMPILE_FLAGS} ${PRECISION_FLAGS}") set (CMAKE_Fortran_LINK_EXECUTABLE "${BUILDCMD_PRE} ${CMAKE_LINKER} ${OPENMP_FLAGS} ${OPTIMIZATION_FLAGS} ${LINKER_FLAGS}") @@ -449,7 +448,7 @@ if ("${CMAKE_BUILD_TYPE}" STREQUAL "") elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DEBUG_FLAGS}") set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} ${DEBUG_FLAGS}") -endif +endif () set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") @@ -468,9 +467,9 @@ if ("${BUILD_TYPE}" STREQUAL SYNTAXONLY) elseif ("${PROJECT_NAME}" STREQUAL DAMASK_FEM) install (PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM DESTINATION ${CMAKE_INSTALL_PREFIX}) - endif -else + endif () +else () exec_program(mktemp ARGS -d OUTPUT_VARIABLE BLACK_HOLE) install (PROGRAMS ${PROJECT_BINARY_DIR}/src/prec.mod DESTINATION ${BLACK_HOLE}) -endif +endif () From e94f518dc7c5832350203c5a0ee305750f9dc9ac Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Wed, 15 Mar 2017 17:33:47 -0500 Subject: [PATCH 113/183] switched to correct actions for build_type --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 18b2587dc..ac7ffbcee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -461,6 +461,10 @@ add_subdirectory (src) # INSTALL BUILT BINARIES if ("${BUILD_TYPE}" STREQUAL SYNTAXONLY) + exec_program (mktemp ARGS -d OUTPUT_VARIABLE BLACK_HOLE) + install (PROGRAMS ${PROJECT_BINARY_DIR}/src/prec.mod + DESTINATION ${BLACK_HOLE}) +else () if ("${PROJECT_NAME}" STREQUAL DAMASK_spectral) install (PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_spectral DESTINATION ${CMAKE_INSTALL_PREFIX}) @@ -468,8 +472,4 @@ if ("${BUILD_TYPE}" STREQUAL SYNTAXONLY) install (PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM DESTINATION ${CMAKE_INSTALL_PREFIX}) endif () -else () - exec_program(mktemp ARGS -d OUTPUT_VARIABLE BLACK_HOLE) - install (PROGRAMS ${PROJECT_BINARY_DIR}/src/prec.mod - DESTINATION ${BLACK_HOLE}) endif () From 4bf11b20c936ba0b721ca260c1b40c343db85b0f Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Wed, 15 Mar 2017 18:43:04 -0500 Subject: [PATCH 114/183] hypela cloning as part of specific Marc modification; Makefile corrections/improvements --- Makefile | 17 +++++---- .../apply_DAMASK_modifications.sh | 32 ++++++++++++----- installation/symlink_Code.py | 35 ------------------- 3 files changed, 31 insertions(+), 53 deletions(-) delete mode 100755 installation/symlink_Code.py diff --git a/Makefile b/Makefile index b8cdfd71c..891d4b5f2 100644 --- a/Makefile +++ b/Makefile @@ -4,26 +4,25 @@ SHELL = /bin/sh ######################################################################################## .PHONY: all all: spectral FEM marc processing + +.PHONY: spectral spectral: build/spectral @(cd build/spectral;make --no-print-directory -ws all install VERBOSE=1;) +.PHONY: FEM FEM: build/FEM @(cd build/FEM; make --no-print-directory -ws all install;) - - -build/spectral: build +.PHONY: build/spectral +build/spectral: @mkdir -p build/spectral @(cd build/spectral; cmake -Wno-dev -DDAMASK_SOLVER=SPECTRAL -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} ../../;) -build/FEM: build +.PHONY: build/FEM +build/FEM: @mkdir -p build/FEM @(cd build/FEM; cmake -Wno-dev -DDAMASK_SOLVER=FEM -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} ../../;) - -build: - @mkdir -p build - .PHONY: marc marc: @./installation/symLink_Code.sh @@ -34,6 +33,6 @@ clean: @rm -rf build .PHONY: processing -install: +processing: @./installation/symlink_Processing.py ${MAKEFLAGS} diff --git a/installation/mods_MarcMentat/apply_DAMASK_modifications.sh b/installation/mods_MarcMentat/apply_DAMASK_modifications.sh index f52b70e36..ff49ba368 100755 --- a/installation/mods_MarcMentat/apply_DAMASK_modifications.sh +++ b/installation/mods_MarcMentat/apply_DAMASK_modifications.sh @@ -54,7 +54,7 @@ echo "Editor: $EDITOR" # tools echo '' -echo 'copying Marc tools...' +echo 'adapting Marc tools...' theDIR=$INSTALLDIR/marc$VERSION/tools for filename in 'comp_damask' \ 'comp_damask_l' \ @@ -77,7 +77,7 @@ done # Mentat scripts echo '' -echo 'copying Mentat scripts...' +echo 'adapting Mentat scripts...' theDIR=$INSTALLDIR/mentat$VERSION/bin for filename in 'edit_window' \ 'submit4' \ @@ -101,7 +101,7 @@ done # Mentat scripts echo '' -echo 'copying Mentat menus...' +echo 'adapting Mentat menus...' theDIR=$INSTALLDIR/mentat$VERSION/menus for filename in 'job_run.ms'; do cp $SCRIPTLOCATION/$VERSION/Mentat_menus/$filename $theDIR @@ -112,16 +112,20 @@ done # compile menus echo '' -echo 'compiling menus...' -$INSTALLDIR/mentat$VERSION/bin/mentat -compile $INSTALLDIR/mentat$VERSION/menus/linux64/main.msb +echo 'compiling Mentat menu binaries...' +$(which xvfb-run 2>/dev/null) $INSTALLDIR/mentat$VERSION/bin/mentat -compile $INSTALLDIR/mentat$VERSION/menus/linux64/main.msb +[[ $? != 0 ]] && echo '...failed. Try installing xvfb-run on your system.' # setting access rights echo '' echo 'setting file access rights...' -chmod 755 $INSTALLDIR/marc$VERSION/tools/run_damask* -chmod 755 $INSTALLDIR/marc$VERSION/tools/comp_damask* -chmod 755 $INSTALLDIR/mentat$VERSION/bin/submit{4..9} -chmod 755 $INSTALLDIR/mentat$VERSION/bin/kill{4..9} +for filename in marc$VERSION/tools/run_damask* \ + marc$VERSION/tools/comp_damask* \ + mentat$VERSION/bin/submit{4..9} \ + mentat$VERSION/bin/kill{4..9} \ + + chmod 755 $INSTALLDIR/${filename} +done #creating symlinks for run_damask_scripts in /usr/local/bin @@ -152,5 +156,15 @@ if [ -d "$BIN_DIR" ]; then esac fi +# cloning user subroutine +echo '' +echo 'cloning $VERSION HYPELA2 user subroutine...' +ln -s DAMASK_marc.f90 ${DAMASK_ROOT}/src/DAMASK_marc${VERSION}.f90 + +# precompiling user subroutine +echo '' +echo 'precompiling $VERSION HYPELA2 user subroutine...' +echo 'not yet implemented..!' + echo '' echo 'done.' diff --git a/installation/symlink_Code.py b/installation/symlink_Code.py deleted file mode 100755 index 5e790ca0b..000000000 --- a/installation/symlink_Code.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python2.7 -# -*- coding: UTF-8 no BOM -*- - -import os,sys -import damask - -MarcReleases =[ \ - '2014', - '2014.2', - '2015', - '2016' - ] - -damaskEnv = damask.Environment() -baseDir = damaskEnv.relPath('code/') -binDir = damaskEnv.options['DAMASK_BIN'] - -if not os.path.isdir(binDir): - os.mkdir(binDir) - -sys.stdout.write('\nMSC.Marc versioning...\n\n') -theMaster = 'DAMASK_marc.f90' - -for version in MarcReleases: - src = os.path.abspath(os.path.join(baseDir,theMaster)) - if os.path.exists(src): - sym_link = os.path.abspath(os.path.join(baseDir,'DAMASK_marc{}.f90'.format(version))) - if os.path.lexists(sym_link): - os.remove(sym_link) - output = version - else: - output = damask.util.emph(version) - - sys.stdout.write(' '+output+'\n') - os.symlink(theMaster,sym_link) From 4bcefa992bf8dbf0077b24b6293b9c7b310e208b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 12 Apr 2017 23:30:33 +0200 Subject: [PATCH 115/183] trying to avoid conflicts when updating master and development, only one pipeline at the same time --- .gitlab-ci.yml | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bcd694974..7ee1d6884 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,6 +16,7 @@ stages: - example - updateMaster - createDocumentation + - clean ################################################################################################### before_script: @@ -78,11 +79,14 @@ variables: checkout: stage: prepareAll before_script: - - echo 'Do nothing' + - $HOME/wait.sh + - echo $CI_PIPELINE_ID > $HOME/GitLabCI.lock script: - mkdir -p $DAMASKROOT - - git clone -b GitLabRunner git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT - - git clone git@magit1.mpie.de:damask/PRIVATE.git $DAMASKROOT/PRIVATE + - git clone git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT + - cd $DAMASKROOT + - git checkout $CI_COMMIT_SHA git@magit1.mpie.de:damask/DAMASK.git + - git clone git@magit1.mpie.de:damask/PRIVATE.git - eval 'source $DAMASKROOT/DAMASK_env.sh' - make -C $DAMASKROOT install @@ -304,15 +308,16 @@ mergeIntoMaster: only: - development script: - - eval 'cd $DAMASKROOT' - - export DEVREV=$(git describe) - - git commit VERSION -m "[skip ci] updated version information after successful test of $DEVREV" + - cd $DAMASKROOT + - export TESTEDREV=$(git describe) # might be detached from development branch + - git commit VERSION -m "[skip ci] updated version information after successful test of $TESTEDREV" + - export UPDATEDREV=$(git describe) # tested state + 1 commit - git checkout master - - git merge development - - git status - - git push origin master + - git merge $UPDATEDREV + - git push origin master # master is now tested version and has updated VERSION file - git checkout development - - git push origin development + - git merge master -s ours # only possible conflict is in VERSION file + - git push origin development # development is unchanged (as master is based on it) but has updated VERSION file ################################################################################################### AbaqusExp: @@ -338,3 +343,11 @@ Spectral: script: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel $Doxygen - $DAMASKROOT/PRIVATE/documenting/runDoxygen.sh $DAMASKROOT spectral + +################################################################################################### +removeLock: + stage: clean + before_script: + - echo 'Do nothing' + when: always + script: rm $HOME/GitLabCI.lock From 75a00d53e7fa47029b4709d2a7030ad7ffd1c0aa Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 12 Apr 2017 23:36:04 +0200 Subject: [PATCH 116/183] COMMIT_SHA was not set --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7ee1d6884..47c9c0f6d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -85,6 +85,8 @@ checkout: - mkdir -p $DAMASKROOT - git clone git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT - cd $DAMASKROOT + - export CI_COMMIT_SHA + - echo $CI_COMMIT_SHA - git checkout $CI_COMMIT_SHA git@magit1.mpie.de:damask/DAMASK.git - git clone git@magit1.mpie.de:damask/PRIVATE.git - eval 'source $DAMASKROOT/DAMASK_env.sh' From 5a1f907903331f983f8aa54c49e7f35387f102bd Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 12 Apr 2017 23:38:44 +0200 Subject: [PATCH 117/183] wrong arguments --- .gitlab-ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 47c9c0f6d..963f7f63c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -85,9 +85,7 @@ checkout: - mkdir -p $DAMASKROOT - git clone git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT - cd $DAMASKROOT - - export CI_COMMIT_SHA - - echo $CI_COMMIT_SHA - - git checkout $CI_COMMIT_SHA git@magit1.mpie.de:damask/DAMASK.git + - git checkout $CI_COMMIT_SHA - git clone git@magit1.mpie.de:damask/PRIVATE.git - eval 'source $DAMASKROOT/DAMASK_env.sh' - make -C $DAMASKROOT install From e7f8e57221ced02ddd1461b8bcbeb1b9d2ac5ddd Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 12 Apr 2017 23:51:02 +0200 Subject: [PATCH 118/183] absolute path not working --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 963f7f63c..2e23f4122 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -87,6 +87,7 @@ checkout: - cd $DAMASKROOT - git checkout $CI_COMMIT_SHA - git clone git@magit1.mpie.de:damask/PRIVATE.git + - echo $DAMASKROOT - eval 'source $DAMASKROOT/DAMASK_env.sh' - make -C $DAMASKROOT install From 6039c51910004cd88b4ef064f05e9b4f9505c854 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 12 Apr 2017 23:54:42 +0200 Subject: [PATCH 119/183] fixing path --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2e23f4122..60554dfcd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -88,8 +88,8 @@ checkout: - git checkout $CI_COMMIT_SHA - git clone git@magit1.mpie.de:damask/PRIVATE.git - echo $DAMASKROOT - - eval 'source $DAMASKROOT/DAMASK_env.sh' - - make -C $DAMASKROOT install + - eval 'source DAMASK_env.sh' + - make install ################################################################################################### OrientationRelationship: From 50eac331811151166b91e00b9602e9ce0e34a9f0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 00:00:11 +0200 Subject: [PATCH 120/183] still failing --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 60554dfcd..291b263d9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -88,7 +88,8 @@ checkout: - git checkout $CI_COMMIT_SHA - git clone git@magit1.mpie.de:damask/PRIVATE.git - echo $DAMASKROOT - - eval 'source DAMASK_env.sh' + - ls + - eval 'source ./DAMASK_env.sh' - make install ################################################################################################### From 53ba9f24977aee2c4f593b0c984f3564445cd96a Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 00:14:15 +0200 Subject: [PATCH 121/183] still failing --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 291b263d9..a8637bbd9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -88,8 +88,8 @@ checkout: - git checkout $CI_COMMIT_SHA - git clone git@magit1.mpie.de:damask/PRIVATE.git - echo $DAMASKROOT - - ls - eval 'source ./DAMASK_env.sh' + - echo p $PYTHONPATH - make install ################################################################################################### From 39732f0ad1ad6e4b74c61e383ddbe3d902040c55 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 07:17:57 +0200 Subject: [PATCH 122/183] debugging source --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a8637bbd9..81d024645 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -86,9 +86,9 @@ checkout: - git clone git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT - cd $DAMASKROOT - git checkout $CI_COMMIT_SHA - - git clone git@magit1.mpie.de:damask/PRIVATE.git + #- git clone git@magit1.mpie.de:damask/PRIVATE.git - echo $DAMASKROOT - - eval 'source ./DAMASK_env.sh' + - eval 'source ./DAMASK_env.sh > /tmp/log' - echo p $PYTHONPATH - make install From f759dd0204cf588def0f15d0d556b5b60d54a801 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 07:20:56 +0200 Subject: [PATCH 123/183] debugging source1 --- .gitlab-ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 81d024645..9ab2e87ef 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -88,7 +88,9 @@ checkout: - git checkout $CI_COMMIT_SHA #- git clone git@magit1.mpie.de:damask/PRIVATE.git - echo $DAMASKROOT - - eval 'source ./DAMASK_env.sh > /tmp/log' + - echo $PWD + - cat DAMASK_env.sh + - eval 'source $DAMASKROOT/DAMASK_env.sh > /tmp/log' - echo p $PYTHONPATH - make install From 043d96f9027bf9b797f8b10b0e01ff0228748a53 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 07:23:27 +0200 Subject: [PATCH 124/183] debugging source statement --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9ab2e87ef..19e16a5ac 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -90,7 +90,7 @@ checkout: - echo $DAMASKROOT - echo $PWD - cat DAMASK_env.sh - - eval 'source $DAMASKROOT/DAMASK_env.sh > /tmp/log' + - source $DAMASKROOT/DAMASK_env.sh > /tmp/log - echo p $PYTHONPATH - make install From 75c3fff355c498c43e8e06611f244feeb55d2692 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 07:31:57 +0200 Subject: [PATCH 125/183] debugging source statement1 --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 19e16a5ac..19f43afce 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -89,7 +89,11 @@ checkout: #- git clone git@magit1.mpie.de:damask/PRIVATE.git - echo $DAMASKROOT - echo $PWD + - type source + - type . + - type cd - cat DAMASK_env.sh + - . $DAMASKROOT/DAMASK_env.sh > /tmp/log - source $DAMASKROOT/DAMASK_env.sh > /tmp/log - echo p $PYTHONPATH - make install From 1b71b098d45e39bd7bbd17507a5d15d3a26e71b4 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 07:35:21 +0200 Subject: [PATCH 126/183] debugging source statement2 --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 19f43afce..ce914318f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -93,6 +93,8 @@ checkout: - type . - type cd - cat DAMASK_env.sh + - echo $SHELL + - echo $0 - . $DAMASKROOT/DAMASK_env.sh > /tmp/log - source $DAMASKROOT/DAMASK_env.sh > /tmp/log - echo p $PYTHONPATH From 4d80f7f8ac1ff21bf651ca0836da053f5c0c04c4 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 07:43:36 +0200 Subject: [PATCH 127/183] working around cd --- .gitlab-ci.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ce914318f..f8fa9095f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -83,16 +83,14 @@ checkout: - echo $CI_PIPELINE_ID > $HOME/GitLabCI.lock script: - mkdir -p $DAMASKROOT - - git clone git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT - - cd $DAMASKROOT - - git checkout $CI_COMMIT_SHA - #- git clone git@magit1.mpie.de:damask/PRIVATE.git + - git clone -b $CI_COMMIT_SHA git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT + #- git clone -q git@magit1.mpie.de:damask/PRIVATE.git - echo $DAMASKROOT - echo $PWD - type source - type . - type cd - - cat DAMASK_env.sh + - cat $DAMASKROOT/DAMASK_env.sh - echo $SHELL - echo $0 - . $DAMASKROOT/DAMASK_env.sh > /tmp/log From 8f08c2e8438fe8178ea277c6fd0c4a70bffd3e1b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 07:50:53 +0200 Subject: [PATCH 128/183] working around cd2 --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f8fa9095f..134bdea21 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -83,7 +83,8 @@ checkout: - echo $CI_PIPELINE_ID > $HOME/GitLabCI.lock script: - mkdir -p $DAMASKROOT - - git clone -b $CI_COMMIT_SHA git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT + - git clone git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT + - git checkout $CI_COMMIT_SHA --git-dir=$DAMASKROOT/.git #- git clone -q git@magit1.mpie.de:damask/PRIVATE.git - echo $DAMASKROOT - echo $PWD From 6d82566920b9ff239d5fa7e31d5d44cc90a5ea8f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 07:55:37 +0200 Subject: [PATCH 129/183] working around source statement --- .gitlab-ci.yml | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 134bdea21..c25691d46 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -84,18 +84,10 @@ checkout: script: - mkdir -p $DAMASKROOT - git clone git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT - - git checkout $CI_COMMIT_SHA --git-dir=$DAMASKROOT/.git + - cd $DAMASKROOT + - git checkout $CI_COMMIT_SHA #- git clone -q git@magit1.mpie.de:damask/PRIVATE.git - - echo $DAMASKROOT - - echo $PWD - - type source - - type . - - type cd - - cat $DAMASKROOT/DAMASK_env.sh - - echo $SHELL - - echo $0 - - . $DAMASKROOT/DAMASK_env.sh > /tmp/log - - source $DAMASKROOT/DAMASK_env.sh > /tmp/log + - export PYTHONPATH=$PYTHONPATH:$DAMASKROOT/lib - echo p $PYTHONPATH - make install From 92ce58bcf1a24ac56d00dd63a614b010c4b8746d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 08:09:07 +0200 Subject: [PATCH 130/183] trying non-NFS location --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c25691d46..94c78a1d6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,7 +20,7 @@ stages: ################################################################################################### before_script: - - eval 'source $DAMASKROOT/DAMASK_env.sh' + - source $DAMASKROOT/DAMASK_env.sh - module purge - cd $DAMASKROOT/PRIVATE/testing @@ -34,7 +34,7 @@ variables: #================================================================================================ # Shortcut names #================================================================================================ - DAMASKROOT: "$HOME/GitlabCI_Pipeline_$CI_PIPELINE_ID/DAMASK" + DAMASKROOT: "/tmp/GitlabCI_Pipeline_$CI_PIPELINE_ID/DAMASK" #================================================================================================ # Names of module files to load From 50b35239276a0365d71912f6e1d37815c613c74d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 08:11:40 +0200 Subject: [PATCH 131/183] reverting --- .gitlab-ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 94c78a1d6..2cef795fd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,7 +20,7 @@ stages: ################################################################################################### before_script: - - source $DAMASKROOT/DAMASK_env.sh + - eval 'source $DAMASKROOT/DAMASK_env.sh' - module purge - cd $DAMASKROOT/PRIVATE/testing @@ -87,8 +87,7 @@ checkout: - cd $DAMASKROOT - git checkout $CI_COMMIT_SHA #- git clone -q git@magit1.mpie.de:damask/PRIVATE.git - - export PYTHONPATH=$PYTHONPATH:$DAMASKROOT/lib - - echo p $PYTHONPATH + - eval 'source $DAMASKROOT/DAMASK_env.sh' - make install ################################################################################################### From 11a3d9c3330f6442ab1044a8e9c7ef2dd0797ec0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 08:15:01 +0200 Subject: [PATCH 132/183] error in DAMASK_env.sh seems to be the reason --- .gitlab-ci.yml | 6 +++--- DAMASK_env.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2cef795fd..3409c8dbc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,7 +20,7 @@ stages: ################################################################################################### before_script: - - eval 'source $DAMASKROOT/DAMASK_env.sh' + - source $DAMASKROOT/DAMASK_env.sh - module purge - cd $DAMASKROOT/PRIVATE/testing @@ -34,7 +34,7 @@ variables: #================================================================================================ # Shortcut names #================================================================================================ - DAMASKROOT: "/tmp/GitlabCI_Pipeline_$CI_PIPELINE_ID/DAMASK" + DAMASKROOT: "$HOME/GitlabCI_Pipeline_$CI_PIPELINE_ID/DAMASK" #================================================================================================ # Names of module files to load @@ -87,7 +87,7 @@ checkout: - cd $DAMASKROOT - git checkout $CI_COMMIT_SHA #- git clone -q git@magit1.mpie.de:damask/PRIVATE.git - - eval 'source $DAMASKROOT/DAMASK_env.sh' + - source $DAMASKROOT/DAMASK_env.sh - make install ################################################################################################### diff --git a/DAMASK_env.sh b/DAMASK_env.sh index fa3171c48..078dd582b 100644 --- a/DAMASK_env.sh +++ b/DAMASK_env.sh @@ -25,11 +25,11 @@ if [[ "x$DAMASK_BIN" != "x" && ! $(echo ":$PATH:" | grep $DAMASK_BIN:) ]]; then export PATH=$DAMASK_BIN:$PATH fi -SOLVER=$(which DAMASK_spectral 2>/dev/null) +SOLVER=$(which DAMASK_spectral || true 2>/dev/null) if [ "x$SOLVER" == "x" ]; then SOLVER='Not found!' fi -PROCESSING=$(which postResults 2>/dev/null) +PROCESSING=$(which postResults || true 2>/dev/null) if [ "x$PROCESSING" == "x" ]; then PROCESSING='Not found!' fi From 97d19320ce1ba11c8e38f18b0a3004f9fbc809c2 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 08:20:30 +0200 Subject: [PATCH 133/183] fixed .zsh script as well, checking out PRIVATE repo again --- .gitlab-ci.yml | 4 ++-- DAMASK_env.zsh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3409c8dbc..bdafe9d72 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -83,10 +83,10 @@ checkout: - echo $CI_PIPELINE_ID > $HOME/GitLabCI.lock script: - mkdir -p $DAMASKROOT - - git clone git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT + - git clone -q git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT - cd $DAMASKROOT - git checkout $CI_COMMIT_SHA - #- git clone -q git@magit1.mpie.de:damask/PRIVATE.git + - git clone -q git@magit1.mpie.de:damask/PRIVATE.git - source $DAMASKROOT/DAMASK_env.sh - make install diff --git a/DAMASK_env.zsh b/DAMASK_env.zsh index dbb781894..0d043c390 100644 --- a/DAMASK_env.zsh +++ b/DAMASK_env.zsh @@ -19,8 +19,8 @@ if [[ ( "x$DAMASK_BIN" != "x" ) && ( "x$MATCH" = "x" ) ]]; then export PATH=$DAMASK_BIN:$PATH fi -SOLVER=`which DAMASK_spectral 2>/dev/null` -PROCESSING=`which postResults 2>/dev/null` +SOLVER=`which DAMASK_spectral || True 2>/dev/null` +PROCESSING=`which postResults || True 2>/dev/null` if [ "x$DAMASK_NUM_THREADS" = "x" ]; then DAMASK_NUM_THREADS=1 fi From aaa41b8232e95c3b14d3a42ddb4982340f1619c3 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 7 Mar 2017 10:44:39 +0100 Subject: [PATCH 134/183] not needed anymore --- installation/mods_Abaqus/abaqus_v6.env | 2 +- installation/mods_Abaqus/abaqus_v6_serial.env | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/installation/mods_Abaqus/abaqus_v6.env b/installation/mods_Abaqus/abaqus_v6.env index d30554d41..0bc5063a1 100644 --- a/installation/mods_Abaqus/abaqus_v6.env +++ b/installation/mods_Abaqus/abaqus_v6.env @@ -31,7 +31,7 @@ fortCmd = "ifort" # -integer-size 32 -DINT=4 assume size of integer to be 4 bytes, matches our definition of pInt compile_fortran = (fortCmd + " -c -fPIC -auto -shared-intel " + - "-I%I -I../lib -free -O1 -fpp -openmp " + + "-I%I -free -O1 -fpp -openmp " + "-ftz -diag-disable 5268 " + "-implicitnone -assume byterecl -stand f08 -standard-semantics " + "-real-size 64 -integer-size 32 -DFLOAT=8 -DINT=4 " + diff --git a/installation/mods_Abaqus/abaqus_v6_serial.env b/installation/mods_Abaqus/abaqus_v6_serial.env index 8cf9778f2..0469dc5f9 100644 --- a/installation/mods_Abaqus/abaqus_v6_serial.env +++ b/installation/mods_Abaqus/abaqus_v6_serial.env @@ -31,7 +31,7 @@ fortCmd = "ifort" # -integer-size 32 -DINT=4 assume size of integer to be 4 bytes, matches our definition of pInt compile_fortran = (fortCmd + " -c -fPIC -auto -shared-intel " + - "-I%I -I../lib -free -O1 -fpp " + + "-I%I -free -O1 -fpp " + "-ftz -diag-disable 5268 " + "-implicitnone -assume byterecl -stand f08 -standard-semantics " + "-real-size 64 -integer-size 32 -DFLOAT=8 -DINT=4 " + From dc387b4060a7919a7a7cb5b1b41213b1f1fc0e29 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Mar 2017 18:00:13 +0100 Subject: [PATCH 135/183] removed unused parameters. Why was shearbanding on in for HMs TWIP steel? --- .../Phase_Dislotwin_TWIP-Steel-FeMnC.config | 2 +- examples/ConfigFiles/Phase_None_Orthorombic.config | 2 +- .../Phase_Phenopowerlaw_BCC-Ferrite.config | 3 --- .../Phase_Phenopowerlaw_BCC-Martensite.config | 3 --- examples/ConfigFiles/Phase_Phenopowerlaw_Gold.config | 11 ----------- .../ConfigFiles/Phase_Phenopowerlaw_multiField.config | 10 ---------- examples/ConfigFiles/Source_Damage_IsoBrittle.config | 2 +- examples/ConfigFiles/Texture_Gauss_001.config | 2 +- examples/ConfigFiles/Texture_Gauss_101.config | 2 +- examples/ConfigFiles/Texture_Gauss_111.config | 2 +- examples/ConfigFiles/Texture_Gauss_123.config | 2 +- .../ConfigFiles/Texture_RandomSingleCrystals.config | 2 +- 12 files changed, 8 insertions(+), 35 deletions(-) diff --git a/examples/ConfigFiles/Phase_Dislotwin_TWIP-Steel-FeMnC.config b/examples/ConfigFiles/Phase_Dislotwin_TWIP-Steel-FeMnC.config index 2570b1b95..e7c9d4e19 100644 --- a/examples/ConfigFiles/Phase_Dislotwin_TWIP-Steel-FeMnC.config +++ b/examples/ConfigFiles/Phase_Dislotwin_TWIP-Steel-FeMnC.config @@ -50,7 +50,7 @@ interactionSlipSlip 0.122 0.122 0.625 0.07 0.137 0.122 # Interaction coefficient ### Shearband parameters ### shearbandresistance 180e6 -shearbandvelocity 1e-4 # set to zero to turn shear banding of +shearbandvelocity 0e-4 # set to zero to turn shear banding of QedgePerSbSystem 3.7e-19 # Activation energy for shear banding [J] p_shearband 1.0 # p-exponent in glide velocity q_shearband 1.0 # q-exponent in glide velocity diff --git a/examples/ConfigFiles/Phase_None_Orthorombic.config b/examples/ConfigFiles/Phase_None_Orthorombic.config index 006b0e048..d7955cf2a 100644 --- a/examples/ConfigFiles/Phase_None_Orthorombic.config +++ b/examples/ConfigFiles/Phase_None_Orthorombic.config @@ -12,4 +12,4 @@ c13 60.41e9 c23 60.41e9 c44 28.34e9 c55 28.34e9 -c66 28.34e9 \ No newline at end of file +c66 28.34e9 diff --git a/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Ferrite.config b/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Ferrite.config index 6efd84f65..594c5dc22 100644 --- a/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Ferrite.config +++ b/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Ferrite.config @@ -18,8 +18,5 @@ tau0_slip 95.e6 97.e6 # per family, optimization long tausat_slip 222.e6 412.7e6 # per family, optimization long simplex 109 h0_slipslip 1000.0e6 interaction_slipslip 1 1 1.4 1.4 1.4 1.4 -interaction_sliptwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -interaction_twinslip 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -interaction_twintwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 w0_slip 2.0 (output) totalshear diff --git a/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Martensite.config b/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Martensite.config index 89ae0339b..6e005f251 100644 --- a/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Martensite.config +++ b/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Martensite.config @@ -18,8 +18,5 @@ tau0_slip 405.8e6 456.7e6 # per family tausat_slip 872.9e6 971.2e6 # per family h0_slipslip 563.0e9 interaction_slipslip 1 1 1.4 1.4 1.4 1.4 -interaction_sliptwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -interaction_twinslip 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -interaction_twintwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 w0_slip 2.0 (output) totalshear diff --git a/examples/ConfigFiles/Phase_Phenopowerlaw_Gold.config b/examples/ConfigFiles/Phase_Phenopowerlaw_Gold.config index fdae9c8e7..a2e06fc07 100644 --- a/examples/ConfigFiles/Phase_Phenopowerlaw_Gold.config +++ b/examples/ConfigFiles/Phase_Phenopowerlaw_Gold.config @@ -35,18 +35,7 @@ tausat_slip 53.00e6 # per family a_slip 1.0 gdot0_twin 0.001 n_twin 20 -tau0_twin 0 # per family -s_pr 0 # push-up factor for slip saturation due to twinning -twin_b 0 -twin_c 0 -twin_d 0 -twin_e 0 h0_slipslip 75e6 -h0_twinslip 0 -h0_twintwin 0 interaction_slipslip 1 1 1.4 1.4 1.4 1.4 -interaction_sliptwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -interaction_twinslip 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -interaction_twintwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 atol_resistance 1 diff --git a/examples/ConfigFiles/Phase_Phenopowerlaw_multiField.config b/examples/ConfigFiles/Phase_Phenopowerlaw_multiField.config index 4436564cc..05503a6e7 100644 --- a/examples/ConfigFiles/Phase_Phenopowerlaw_multiField.config +++ b/examples/ConfigFiles/Phase_Phenopowerlaw_multiField.config @@ -29,18 +29,8 @@ a_slip 2.25 gdot0_twin 0.001 n_twin 20 tau0_twin 31e6 # per family -s_pr 0 # push-up factor for slip saturation due to twinning -twin_b 0 -twin_c 0 -twin_d 0 -twin_e 0 h0_slipslip 75e6 -h0_twinslip 0 -h0_twintwin 0 interaction_slipslip 1 1 1.4 1.4 1.4 1.4 -interaction_sliptwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -interaction_twinslip 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -interaction_twintwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 atol_resistance 1 (stiffness_degradation) damage diff --git a/examples/ConfigFiles/Source_Damage_IsoBrittle.config b/examples/ConfigFiles/Source_Damage_IsoBrittle.config index b248bb8fc..b36165ab4 100644 --- a/examples/ConfigFiles/Source_Damage_IsoBrittle.config +++ b/examples/ConfigFiles/Source_Damage_IsoBrittle.config @@ -2,4 +2,4 @@ isobrittle_criticalStrainEnergy 1400000.0 isobrittle_atol 0.01 isobrittle_N 1.0 -(output) isoBrittle_DrivingForce \ No newline at end of file +(output) isoBrittle_DrivingForce diff --git a/examples/ConfigFiles/Texture_Gauss_001.config b/examples/ConfigFiles/Texture_Gauss_001.config index 153fab381..4711c4135 100644 --- a/examples/ConfigFiles/Texture_Gauss_001.config +++ b/examples/ConfigFiles/Texture_Gauss_001.config @@ -1,2 +1,2 @@ [001] -(gauss) phi1 0.000 Phi 0.000 phi2 0.000 scatter 0.000 fraction 1.000 \ No newline at end of file +(gauss) phi1 0.000 Phi 0.000 phi2 0.000 scatter 0.000 fraction 1.000 diff --git a/examples/ConfigFiles/Texture_Gauss_101.config b/examples/ConfigFiles/Texture_Gauss_101.config index 28351eece..79457aeac 100644 --- a/examples/ConfigFiles/Texture_Gauss_101.config +++ b/examples/ConfigFiles/Texture_Gauss_101.config @@ -1,2 +1,2 @@ [101] -(gauss) phi1 0.000 Phi 45.000 phi2 90.000 scatter 0.000 fraction 1.000 \ No newline at end of file +(gauss) phi1 0.000 Phi 45.000 phi2 90.000 scatter 0.000 fraction 1.000 diff --git a/examples/ConfigFiles/Texture_Gauss_111.config b/examples/ConfigFiles/Texture_Gauss_111.config index e4dc139f8..8204bfb69 100644 --- a/examples/ConfigFiles/Texture_Gauss_111.config +++ b/examples/ConfigFiles/Texture_Gauss_111.config @@ -1,2 +1,2 @@ [111] -(gauss) phi1 0.000 Phi 54.7356 phi2 45.000 scatter 0.000 fraction 1.000 \ No newline at end of file +(gauss) phi1 0.000 Phi 54.7356 phi2 45.000 scatter 0.000 fraction 1.000 diff --git a/examples/ConfigFiles/Texture_Gauss_123.config b/examples/ConfigFiles/Texture_Gauss_123.config index 374674e09..32d28442f 100644 --- a/examples/ConfigFiles/Texture_Gauss_123.config +++ b/examples/ConfigFiles/Texture_Gauss_123.config @@ -1,2 +1,2 @@ [123] -(gauss) phi1 209.805 Phi 29.206 phi2 63.435 scatter 0.000 fraction 1.000 \ No newline at end of file +(gauss) phi1 209.805 Phi 29.206 phi2 63.435 scatter 0.000 fraction 1.000 diff --git a/examples/ConfigFiles/Texture_RandomSingleCrystals.config b/examples/ConfigFiles/Texture_RandomSingleCrystals.config index fac65ae20..6e1f98a3d 100644 --- a/examples/ConfigFiles/Texture_RandomSingleCrystals.config +++ b/examples/ConfigFiles/Texture_RandomSingleCrystals.config @@ -1,2 +1,2 @@ [RandomSingleCrystals] -(random) scatter 0.000 fraction 1.000 \ No newline at end of file +(random) scatter 0.000 fraction 1.000 From 95a982e00207d5b006f8ca411d36d5d38f654c10 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Mar 2017 18:46:53 +0100 Subject: [PATCH 136/183] default type for muliple arguments (not extend) is tuple, not list --- processing/pre/geom_addPrimitive.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/processing/pre/geom_addPrimitive.py b/processing/pre/geom_addPrimitive.py index 51dc1db3c..607e5facd 100755 --- a/processing/pre/geom_addPrimitive.py +++ b/processing/pre/geom_addPrimitive.py @@ -51,23 +51,22 @@ parser.add_option( '--nonperiodic', dest='periodic', action='store_false', parser.add_option( '--voxelspace', dest='voxelspace', action='store_true', help = '-c and -d are given in (0 to grid) coordinates instead of (origin to origin+size) \ coordinates [%default]') -parser.set_defaults(center = [0,0,0], +parser.set_defaults(center = (.0,.0,.0), fill = 0, - quaternion = [], - angleaxis = [], degrees = False, - exponent = [1e10,1e10,1e10], # box shape by default + exponent = (1e10,1e10,1e10), # box shape by default periodic = True, voxelspace = False ) (options, filenames) = parser.parse_args() - -if options.angleaxis != []: +if options.dimension is None: + parser.error('no dimension specified.') +if options.angleaxis is not None: options.angleaxis = map(float,options.angleaxis) rotation = damask.Quaternion().fromAngleAxis(np.radians(options.angleaxis[0]) if options.degrees else options.angleaxis[0], options.angleaxis[1:4]) -elif options.quaternion != []: +elif options.quaternion is not None: options.quaternion = map(float,options.quaternion) rotation = damask.Quaternion(options.quaternion) else: @@ -125,7 +124,7 @@ for name in filenames: # coordinates given in real space (default) vs voxel space if not options.voxelspace: - options.center += info['origin'] + options.center += info['origin'] options.center *= np.array(info['grid']) / np.array(info['size']) options.dimension *= np.array(info['grid']) / np.array(info['size']) From 101913a944cbd6bc7984842665283dc5d6efcc9d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 8 Mar 2017 19:12:05 +0100 Subject: [PATCH 137/183] rel tol of 0.0 useful when looking for absolute value only --- code/numerics.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/numerics.f90 b/code/numerics.f90 index 6569d7cb4..4358624de 100644 --- a/code/numerics.f90 +++ b/code/numerics.f90 @@ -694,9 +694,9 @@ subroutine numerics_init .not. memory_efficient) call IO_error(error_ID = 847_pInt) if (err_stress_tolrel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_stress_tolRel') if (err_stress_tolabs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_stress_tolAbs') - if (err_div_tolRel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_div_tolRel') + if (err_div_tolRel < 0.0_pReal) call IO_error(301_pInt,ext_msg='err_div_tolRel') if (err_div_tolAbs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_div_tolAbs') - if (err_curl_tolRel <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_curl_tolRel') + if (err_curl_tolRel < 0.0_pReal) call IO_error(301_pInt,ext_msg='err_curl_tolRel') if (err_curl_tolAbs <= 0.0_pReal) call IO_error(301_pInt,ext_msg='err_curl_tolAbs') if (polarAlpha <= 0.0_pReal .or. & polarAlpha > 2.0_pReal) call IO_error(301_pInt,ext_msg='polarAlpha') From bdbbcdb908b66da140e0438dc8a321af63bda88c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 13:02:55 +0200 Subject: [PATCH 138/183] parameters not needed --- examples/SpectralMethod/material.config | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/examples/SpectralMethod/material.config b/examples/SpectralMethod/material.config index 14437c5d8..978e0f511 100644 --- a/examples/SpectralMethod/material.config +++ b/examples/SpectralMethod/material.config @@ -52,22 +52,8 @@ n_slip 20 tau0_slip 31e6 # per family tausat_slip 63e6 # per family a_slip 2.25 -gdot0_twin 0.001 -n_twin 20 -tau0_twin 31e6 # per family -s_pr 0 # push-up factor for slip saturation due to twinning -twin_b 0 -twin_c 0 -twin_d 0 -twin_e 0 h0_slipslip 75e6 -h0_sliptwin 0 -h0_twinslip 0 -h0_twintwin 0 interaction_slipslip 1 1 1.4 1.4 1.4 1.4 -interaction_sliptwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -interaction_twinslip 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -interaction_twintwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 atol_resistance 1 From f1c6524c34a4c052e1e690a4483b2504a49d416f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 13:07:38 +0200 Subject: [PATCH 139/183] debugging update procedure --- .gitlab-ci.yml | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bdafe9d72..7cda5b9e9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,19 +1,19 @@ stages: - prepareAll - - preprocessing - - postprocessing - - compileSpectralIntel - - compileSpectralGNU - - prepareSpectral - - spectral - - compileMarc2014 - - compileMarc2014.2 - - compileMarc2015 - - compileMarc2016 - - marc - - compileAbaqus2016 - - compileAbaqus2017 - - example + #- preprocessing + #- postprocessing + #- compileSpectralIntel + #- compileSpectralGNU + #- prepareSpectral + #- spectral + #- compileMarc2014 + #- compileMarc2014.2 + #- compileMarc2015 + #- compileMarc2016 + #- marc + #- compileAbaqus2016 + #- compileAbaqus2017 + #- example - updateMaster - createDocumentation - clean @@ -310,6 +310,7 @@ mergeIntoMaster: script: - cd $DAMASKROOT - export TESTEDREV=$(git describe) # might be detached from development branch + - echo $TESTEDREV > VERSION - git commit VERSION -m "[skip ci] updated version information after successful test of $TESTEDREV" - export UPDATEDREV=$(git describe) # tested state + 1 commit - git checkout master From bf7b4f2af52d1b02425e66d18a5b144842af7c9c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 13:21:38 +0200 Subject: [PATCH 140/183] debugging update procedure2 --- .gitlab-ci.yml | 424 ++++++++++++++++++++++++------------------------- 1 file changed, 212 insertions(+), 212 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7cda5b9e9..ad8f5d13a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -90,218 +90,218 @@ checkout: - source $DAMASKROOT/DAMASK_env.sh - make install -################################################################################################### -OrientationRelationship: - stage: preprocessing - script: OrientationRelationship/test.py - -Pre_SeedGeneration: - stage: preprocessing - script: PreProcessing_SeedGeneration/test.py - -Pre_GeomGeneration: - stage: preprocessing - script: PreProcessing_GeomGeneration/test.py - -Pre_GeomModification: - stage: preprocessing - script: PreProcessing_GeomModification/test.py - -Pre_General: - stage: preprocessing - script: PreProcessing/test.py - -Spectral_geometryPacking: - stage: preprocessing - script: Spectral_geometryPacking/test.py - -################################################################################################### -Post_General: - stage: postprocessing - script: PostProcessing/test.py - -Post_GeometryReconstruction: - stage: postprocessing - script: Spectral_geometryReconstruction/test.py - -Post_addCurl: - stage: postprocessing - script: addCurl/test.py - -Post_addDivergence: - stage: postprocessing - script: addDivergence/test.py - -Post_addGradient: - stage: postprocessing - script: addGradient/test.py - -Post_ParaviewRelated: - stage: postprocessing - script: ParaviewRelated/test.py - -################################################################################################### -Compile_Intel: - stage: compileSpectralIntel - script: - - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - - SpectralAll_compileIfort/test.py - -################################################################################################### -Compile_GNU: - stage: compileSpectralGNU - script: - - module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU - - SpectralAll_compileGfortran/test.py - -################################################################################################### -Compile_Intel_Prepare: - stage: prepareSpectral - script: - - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - - make -C $DAMASKROOT clean spectral install tidy - -################################################################################################### -Spectral_PackedGeometry: - stage: spectral - script: Spectral_PackedGeometry/test.py - -Spectral_parsingArguments: - stage: spectral - script: Spectral_parsingArguments/test.py - -StateIntegration_compareVariants: - stage: spectral - script: StateIntegration_compareVariants/test.py - -nonlocal_densityConservation: - stage: spectral - script: nonlocal_densityConservation/test.py - -Spectral_ipNeighborhood: - stage: spectral - script: Spectral_ipNeighborhood/test.py - -Nonlocal_Damage_DetectChanges: - stage: spectral - script: Nonlocal_Damage_DetectChanges/test.py - -SpectralAll_restart: - stage: spectral - script: SpectralAll_restart/test.py - -SpectralAll_parsingLoadCase: - stage: spectral - script: SpectralAll_parsingLoadCase/test.py - -SpectralBasic_loadCaseRotation: - stage: spectral - script: SpectralBasic_loadCaseRotation/test.py - -Spectral_MPI: - stage: spectral - script: - - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - - Spectral_MPI/test.py - -Plasticity_DetectChanges: - stage: spectral - script: Plasticity_DetectChanges/test.py - -Homogenization: - stage: spectral - script: Homogenization/test.py - -Phenopowerlaw_singleSlip: - stage: spectral - script: Phenopowerlaw_singleSlip/test.py - -HybridIA: - stage: spectral - script: HybridIA/test.py - -################################################################################################### -Marc_compileIfort2014: - stage: compileMarc2014 - script: - - module load $IntelCompiler16_0 $MSC2014 - - Marc_compileIfort/test.py -m 2014 - -################################################################################################### -Marc_compileIfort2014.2: - stage: compileMarc2014.2 - script: - - module load $IntelCompiler16_0 $MSC2014_2 - - Marc_compileIfort/test.py -m 2014.2 - -################################################################################################### -Marc_compileIfort2015: - stage: compileMarc2015 - script: - - module load $IntelCompiler16_0 $MSC2015 - - Marc_compileIfort/test.py -m 2015 - -################################################################################################### -Marc_compileIfort2016: - stage: compileMarc2016 - script: - - module load $IntelCompiler16_0 $MSC2016 - - Marc_compileIfort/test.py -m 2016 - -################################################################################################### -Hex_elastic: - stage: marc - script: - - module load $IntelCompiler16_0 $MSC - - Hex_elastic/test.py - -CubicFCC_elastic: - stage: marc - script: - - module load $IntelCompiler16_0 $MSC - - CubicFCC_elastic/test.py - -CubicBCC_elastic: - stage: marc - script: - - module load $IntelCompiler16_0 $MSC - - CubicBCC_elastic/test.py - -J2_plasticBehavior: - stage: marc - script: - - module load $IntelCompiler16_0 $MSC - - J2_plasticBehavior/test.py - -################################################################################################### -Abaqus_compile2016: - stage: compileAbaqus2016 - script: - - module load $IntelCompiler16_0 $Abaqus2016 - - Abaqus_compileIfort/test.py -a 2016 - -################################################################################################### -Abaqus_compile2017: - stage: compileAbaqus2017 - script: - - module load $IntelCompiler16_0 $Abaqus2017 - - Abaqus_compileIfort/test.py -a 2017 - -################################################################################################### -SpectralExample: - stage: example - only: - - development - script: SpectralAll_example/test.py - -AbaqusExample: - stage: example - only: - - development - script: - - module load $IntelCompiler16_0 $Abaqus - - Abaqus_example/test.py - +#################################################################################################### +#OrientationRelationship: +# stage: preprocessing +# script: OrientationRelationship/test.py +# +#Pre_SeedGeneration: +# stage: preprocessing +# script: PreProcessing_SeedGeneration/test.py +# +#Pre_GeomGeneration: +# stage: preprocessing +# script: PreProcessing_GeomGeneration/test.py +# +#Pre_GeomModification: +# stage: preprocessing +# script: PreProcessing_GeomModification/test.py +# +#Pre_General: +# stage: preprocessing +# script: PreProcessing/test.py +# +#Spectral_geometryPacking: +# stage: preprocessing +# script: Spectral_geometryPacking/test.py +# +#################################################################################################### +#Post_General: +# stage: postprocessing +# script: PostProcessing/test.py +# +#Post_GeometryReconstruction: +# stage: postprocessing +# script: Spectral_geometryReconstruction/test.py +# +#Post_addCurl: +# stage: postprocessing +# script: addCurl/test.py +# +#Post_addDivergence: +# stage: postprocessing +# script: addDivergence/test.py +# +#Post_addGradient: +# stage: postprocessing +# script: addGradient/test.py +# +#Post_ParaviewRelated: +# stage: postprocessing +# script: ParaviewRelated/test.py +# +#################################################################################################### +#Compile_Intel: +# stage: compileSpectralIntel +# script: +# - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel +# - SpectralAll_compileIfort/test.py +# +#################################################################################################### +#Compile_GNU: +# stage: compileSpectralGNU +# script: +# - module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU +# - SpectralAll_compileGfortran/test.py +# +#################################################################################################### +#Compile_Intel_Prepare: +# stage: prepareSpectral +# script: +# - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel +# - make -C $DAMASKROOT clean spectral install tidy +# +#################################################################################################### +#Spectral_PackedGeometry: +# stage: spectral +# script: Spectral_PackedGeometry/test.py +# +#Spectral_parsingArguments: +# stage: spectral +# script: Spectral_parsingArguments/test.py +# +#StateIntegration_compareVariants: +# stage: spectral +# script: StateIntegration_compareVariants/test.py +# +#nonlocal_densityConservation: +# stage: spectral +# script: nonlocal_densityConservation/test.py +# +#Spectral_ipNeighborhood: +# stage: spectral +# script: Spectral_ipNeighborhood/test.py +# +#Nonlocal_Damage_DetectChanges: +# stage: spectral +# script: Nonlocal_Damage_DetectChanges/test.py +# +#SpectralAll_restart: +# stage: spectral +# script: SpectralAll_restart/test.py +# +#SpectralAll_parsingLoadCase: +# stage: spectral +# script: SpectralAll_parsingLoadCase/test.py +# +#SpectralBasic_loadCaseRotation: +# stage: spectral +# script: SpectralBasic_loadCaseRotation/test.py +# +#Spectral_MPI: +# stage: spectral +# script: +# - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel +# - Spectral_MPI/test.py +# +#Plasticity_DetectChanges: +# stage: spectral +# script: Plasticity_DetectChanges/test.py +# +#Homogenization: +# stage: spectral +# script: Homogenization/test.py +# +#Phenopowerlaw_singleSlip: +# stage: spectral +# script: Phenopowerlaw_singleSlip/test.py +# +#HybridIA: +# stage: spectral +# script: HybridIA/test.py +# +#################################################################################################### +#Marc_compileIfort2014: +# stage: compileMarc2014 +# script: +# - module load $IntelCompiler16_0 $MSC2014 +# - Marc_compileIfort/test.py -m 2014 +# +#################################################################################################### +#Marc_compileIfort2014.2: +# stage: compileMarc2014.2 +# script: +# - module load $IntelCompiler16_0 $MSC2014_2 +# - Marc_compileIfort/test.py -m 2014.2 +# +#################################################################################################### +#Marc_compileIfort2015: +# stage: compileMarc2015 +# script: +# - module load $IntelCompiler16_0 $MSC2015 +# - Marc_compileIfort/test.py -m 2015 +# +#################################################################################################### +#Marc_compileIfort2016: +# stage: compileMarc2016 +# script: +# - module load $IntelCompiler16_0 $MSC2016 +# - Marc_compileIfort/test.py -m 2016 +# +#################################################################################################### +#Hex_elastic: +# stage: marc +# script: +# - module load $IntelCompiler16_0 $MSC +# - Hex_elastic/test.py +# +#CubicFCC_elastic: +# stage: marc +# script: +# - module load $IntelCompiler16_0 $MSC +# - CubicFCC_elastic/test.py +# +#CubicBCC_elastic: +# stage: marc +# script: +# - module load $IntelCompiler16_0 $MSC +# - CubicBCC_elastic/test.py +# +#J2_plasticBehavior: +# stage: marc +# script: +# - module load $IntelCompiler16_0 $MSC +# - J2_plasticBehavior/test.py +# +#################################################################################################### +#Abaqus_compile2016: +# stage: compileAbaqus2016 +# script: +# - module load $IntelCompiler16_0 $Abaqus2016 +# - Abaqus_compileIfort/test.py -a 2016 +# +#################################################################################################### +#Abaqus_compile2017: +# stage: compileAbaqus2017 +# script: +# - module load $IntelCompiler16_0 $Abaqus2017 +# - Abaqus_compileIfort/test.py -a 2017 +# +#################################################################################################### +#SpectralExample: +# stage: example +# only: +# - development +# script: SpectralAll_example/test.py +# +#AbaqusExample: +# stage: example +# only: +# - development +# script: +# - module load $IntelCompiler16_0 $Abaqus +# - Abaqus_example/test.py +# ################################################################################################### mergeIntoMaster: stage: updateMaster From 73ce3c01b72d510e20b8a7107be4f80014eac15f Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 13 Apr 2017 13:23:07 +0200 Subject: [PATCH 141/183] [skip ci] updated version information after successful test of v2.0.1-447-gbf7b4f2 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1d89fa753..82fb0985b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-414-g81d0752 +v2.0.1-447-gbf7b4f2 From d595ad56166a1f0d2ba190cf28c8c434facaedd9 Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 13 Apr 2017 13:27:39 +0200 Subject: [PATCH 142/183] [skip ci] updated version information after successful test of v2.0.1-449-g3898995 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1d89fa753..e84d8672e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-414-g81d0752 +v2.0.1-449-g3898995 From e5eea4caec9fe3a95abb67b25ba782b387920e17 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 16:06:35 +0200 Subject: [PATCH 143/183] finished debugging, master and release will never be tested --- .gitlab-ci.yml | 591 ++++++++++++++++++++++++++++++------------------- 1 file changed, 363 insertions(+), 228 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ad8f5d13a..bc8af4d11 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,19 +1,19 @@ stages: - prepareAll - #- preprocessing - #- postprocessing - #- compileSpectralIntel - #- compileSpectralGNU - #- prepareSpectral - #- spectral - #- compileMarc2014 - #- compileMarc2014.2 - #- compileMarc2015 - #- compileMarc2016 - #- marc - #- compileAbaqus2016 - #- compileAbaqus2017 - #- example + - preprocessing + - postprocessing + - compileSpectralIntel + - compileSpectralGNU + - prepareSpectral + - spectral + - compileMarc2014 + - compileMarc2014.2 + - compileMarc2015 + - compileMarc2016 + - marc + - compileAbaqus2016 + - compileAbaqus2017 + - example - updateMaster - createDocumentation - clean @@ -89,224 +89,342 @@ checkout: - git clone -q git@magit1.mpie.de:damask/PRIVATE.git - source $DAMASKROOT/DAMASK_env.sh - make install + except: + - master + - release -#################################################################################################### -#OrientationRelationship: -# stage: preprocessing -# script: OrientationRelationship/test.py -# -#Pre_SeedGeneration: -# stage: preprocessing -# script: PreProcessing_SeedGeneration/test.py -# -#Pre_GeomGeneration: -# stage: preprocessing -# script: PreProcessing_GeomGeneration/test.py -# -#Pre_GeomModification: -# stage: preprocessing -# script: PreProcessing_GeomModification/test.py -# -#Pre_General: -# stage: preprocessing -# script: PreProcessing/test.py -# -#Spectral_geometryPacking: -# stage: preprocessing -# script: Spectral_geometryPacking/test.py -# -#################################################################################################### -#Post_General: -# stage: postprocessing -# script: PostProcessing/test.py -# -#Post_GeometryReconstruction: -# stage: postprocessing -# script: Spectral_geometryReconstruction/test.py -# -#Post_addCurl: -# stage: postprocessing -# script: addCurl/test.py -# -#Post_addDivergence: -# stage: postprocessing -# script: addDivergence/test.py -# -#Post_addGradient: -# stage: postprocessing -# script: addGradient/test.py -# -#Post_ParaviewRelated: -# stage: postprocessing -# script: ParaviewRelated/test.py -# -#################################################################################################### -#Compile_Intel: -# stage: compileSpectralIntel -# script: -# - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel -# - SpectralAll_compileIfort/test.py -# -#################################################################################################### -#Compile_GNU: -# stage: compileSpectralGNU -# script: -# - module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU -# - SpectralAll_compileGfortran/test.py -# -#################################################################################################### -#Compile_Intel_Prepare: -# stage: prepareSpectral -# script: -# - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel -# - make -C $DAMASKROOT clean spectral install tidy -# -#################################################################################################### -#Spectral_PackedGeometry: -# stage: spectral -# script: Spectral_PackedGeometry/test.py -# -#Spectral_parsingArguments: -# stage: spectral -# script: Spectral_parsingArguments/test.py -# -#StateIntegration_compareVariants: -# stage: spectral -# script: StateIntegration_compareVariants/test.py -# -#nonlocal_densityConservation: -# stage: spectral -# script: nonlocal_densityConservation/test.py -# -#Spectral_ipNeighborhood: -# stage: spectral -# script: Spectral_ipNeighborhood/test.py -# -#Nonlocal_Damage_DetectChanges: -# stage: spectral -# script: Nonlocal_Damage_DetectChanges/test.py -# -#SpectralAll_restart: -# stage: spectral -# script: SpectralAll_restart/test.py -# -#SpectralAll_parsingLoadCase: -# stage: spectral -# script: SpectralAll_parsingLoadCase/test.py -# -#SpectralBasic_loadCaseRotation: -# stage: spectral -# script: SpectralBasic_loadCaseRotation/test.py -# -#Spectral_MPI: -# stage: spectral -# script: -# - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel -# - Spectral_MPI/test.py -# -#Plasticity_DetectChanges: -# stage: spectral -# script: Plasticity_DetectChanges/test.py -# -#Homogenization: -# stage: spectral -# script: Homogenization/test.py -# -#Phenopowerlaw_singleSlip: -# stage: spectral -# script: Phenopowerlaw_singleSlip/test.py -# -#HybridIA: -# stage: spectral -# script: HybridIA/test.py -# -#################################################################################################### -#Marc_compileIfort2014: -# stage: compileMarc2014 -# script: -# - module load $IntelCompiler16_0 $MSC2014 -# - Marc_compileIfort/test.py -m 2014 -# -#################################################################################################### -#Marc_compileIfort2014.2: -# stage: compileMarc2014.2 -# script: -# - module load $IntelCompiler16_0 $MSC2014_2 -# - Marc_compileIfort/test.py -m 2014.2 -# -#################################################################################################### -#Marc_compileIfort2015: -# stage: compileMarc2015 -# script: -# - module load $IntelCompiler16_0 $MSC2015 -# - Marc_compileIfort/test.py -m 2015 -# -#################################################################################################### -#Marc_compileIfort2016: -# stage: compileMarc2016 -# script: -# - module load $IntelCompiler16_0 $MSC2016 -# - Marc_compileIfort/test.py -m 2016 -# -#################################################################################################### -#Hex_elastic: -# stage: marc -# script: -# - module load $IntelCompiler16_0 $MSC -# - Hex_elastic/test.py -# -#CubicFCC_elastic: -# stage: marc -# script: -# - module load $IntelCompiler16_0 $MSC -# - CubicFCC_elastic/test.py -# -#CubicBCC_elastic: -# stage: marc -# script: -# - module load $IntelCompiler16_0 $MSC -# - CubicBCC_elastic/test.py -# -#J2_plasticBehavior: -# stage: marc -# script: -# - module load $IntelCompiler16_0 $MSC -# - J2_plasticBehavior/test.py -# -#################################################################################################### -#Abaqus_compile2016: -# stage: compileAbaqus2016 -# script: -# - module load $IntelCompiler16_0 $Abaqus2016 -# - Abaqus_compileIfort/test.py -a 2016 -# -#################################################################################################### -#Abaqus_compile2017: -# stage: compileAbaqus2017 -# script: -# - module load $IntelCompiler16_0 $Abaqus2017 -# - Abaqus_compileIfort/test.py -a 2017 -# -#################################################################################################### -#SpectralExample: -# stage: example -# only: -# - development -# script: SpectralAll_example/test.py -# -#AbaqusExample: -# stage: example -# only: -# - development -# script: -# - module load $IntelCompiler16_0 $Abaqus -# - Abaqus_example/test.py -# ################################################################################################### -mergeIntoMaster: - stage: updateMaster +OrientationRelationship: + stage: preprocessing + script: OrientationRelationship/test.py + except: + - master + - release + +Pre_SeedGeneration: + stage: preprocessing + script: PreProcessing_SeedGeneration/test.py + except: + - master + - release + +Pre_GeomGeneration: + stage: preprocessing + script: PreProcessing_GeomGeneration/test.py + except: + - master + - release + +Pre_GeomModification: + stage: preprocessing + script: PreProcessing_GeomModification/test.py + except: + - master + - release + +Pre_General: + stage: preprocessing + script: PreProcessing/test.py + except: + - master + - release + +Spectral_geometryPacking: + stage: preprocessing + script: Spectral_geometryPacking/test.py + except: + - master + - release + +################################################################################################### +Post_General: + stage: postprocessing + script: PostProcessing/test.py + except: + - master + - release + +Post_GeometryReconstruction: + stage: postprocessing + script: Spectral_geometryReconstruction/test.py + except: + - master + - release + +Post_addCurl: + stage: postprocessing + script: addCurl/test.py + except: + - master + - release + +Post_addDivergence: + stage: postprocessing + script: addDivergence/test.py + except: + - master + - release + +Post_addGradient: + stage: postprocessing + script: addGradient/test.py + except: + - master + - release + +Post_ParaviewRelated: + stage: postprocessing + script: ParaviewRelated/test.py + except: + - master + - release + +################################################################################################### +Compile_Intel: + stage: compileSpectralIntel + script: + - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel + - SpectralAll_compileIfort/test.py + except: + - master + - release + +################################################################################################### +Compile_GNU: + stage: compileSpectralGNU + script: + - module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU + - SpectralAll_compileGfortran/test.py + except: + - master + - release + +################################################################################################### +Compile_Intel_Prepare: + stage: prepareSpectral + script: + - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel + - make -C $DAMASKROOT clean spectral install tidy + except: + - master + - release + +################################################################################################### +Spectral_PackedGeometry: + stage: spectral + script: Spectral_PackedGeometry/test.py + except: + - master + - release + +Spectral_parsingArguments: + stage: spectral + script: Spectral_parsingArguments/test.py + except: + - master + - release + +StateIntegration_compareVariants: + stage: spectral + script: StateIntegration_compareVariants/test.py + except: + - master + - release + +nonlocal_densityConservation: + stage: spectral + script: nonlocal_densityConservation/test.py + except: + - master + - release + +Spectral_ipNeighborhood: + stage: spectral + script: Spectral_ipNeighborhood/test.py + except: + - master + - release + +Nonlocal_Damage_DetectChanges: + stage: spectral + script: Nonlocal_Damage_DetectChanges/test.py + except: + - master + - release + +SpectralAll_restart: + stage: spectral + script: SpectralAll_restart/test.py + except: + - master + - release + +SpectralAll_parsingLoadCase: + stage: spectral + script: SpectralAll_parsingLoadCase/test.py + except: + - master + - release + +SpectralBasic_loadCaseRotation: + stage: spectral + script: SpectralBasic_loadCaseRotation/test.py + except: + - master + - release + +Spectral_MPI: + stage: spectral + script: + - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel + - Spectral_MPI/test.py + except: + - master + - release + +Plasticity_DetectChanges: + stage: spectral + script: Plasticity_DetectChanges/test.py + except: + - master + - release + +Homogenization: + stage: spectral + script: Homogenization/test.py + except: + - master + - release + +Phenopowerlaw_singleSlip: + stage: spectral + script: Phenopowerlaw_singleSlip/test.py + except: + - master + - release + +HybridIA: + stage: spectral + script: HybridIA/test.py + except: + - master + - release + +################################################################################################### +Marc_compileIfort2014: + stage: compileMarc2014 + script: + - module load $IntelCompiler16_0 $MSC2014 + - Marc_compileIfort/test.py -m 2014 + except: + - master + - release + +################################################################################################### +Marc_compileIfort2014.2: + stage: compileMarc2014.2 + script: + - module load $IntelCompiler16_0 $MSC2014_2 + - Marc_compileIfort/test.py -m 2014.2 + except: + - master + - release + +################################################################################################### +Marc_compileIfort2015: + stage: compileMarc2015 + script: + - module load $IntelCompiler16_0 $MSC2015 + - Marc_compileIfort/test.py -m 2015 + except: + - master + - release + +################################################################################################### +Marc_compileIfort2016: + stage: compileMarc2016 + script: + - module load $IntelCompiler16_0 $MSC2016 + - Marc_compileIfort/test.py -m 2016 + except: + - master + - release + +################################################################################################### +Hex_elastic: + stage: marc + script: + - module load $IntelCompiler16_0 $MSC + - Hex_elastic/test.py + except: + - master + - release + +CubicFCC_elastic: + stage: marc + script: + - module load $IntelCompiler16_0 $MSC + - CubicFCC_elastic/test.py + except: + - master + - release + +CubicBCC_elastic: + stage: marc + script: + - module load $IntelCompiler16_0 $MSC + - CubicBCC_elastic/test.py + except: + - master + - release + +J2_plasticBehavior: + stage: marc + script: + - module load $IntelCompiler16_0 $MSC + - J2_plasticBehavior/test.py + except: + - master + - release + +################################################################################################### +Abaqus_compile2016: + stage: compileAbaqus2016 + script: + - module load $IntelCompiler16_0 $Abaqus2016 + - Abaqus_compileIfort/test.py -a 2016 + except: + - master + - release + +################################################################################################### +Abaqus_compile2017: + stage: compileAbaqus2017 + script: + - module load $IntelCompiler16_0 $Abaqus2017 + - Abaqus_compileIfort/test.py -a 2017 + except: + - master + - release + +################################################################################################### +SpectralExample: + stage: example + script: SpectralAll_example/test.py only: - development + +AbaqusExample: + stage: example + script: + - module load $IntelCompiler16_0 $Abaqus + - Abaqus_example/test.py + only: + - development + +################################################################################################## +mergeIntoMaster: + stage: updateMaster script: - cd $DAMASKROOT - export TESTEDREV=$(git describe) # might be detached from development branch @@ -319,6 +437,8 @@ mergeIntoMaster: - git checkout development - git merge master -s ours # only possible conflict is in VERSION file - git push origin development # development is unchanged (as master is based on it) but has updated VERSION file + only: + - development ################################################################################################### AbaqusExp: @@ -326,24 +446,36 @@ AbaqusExp: script: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel $Doxygen - $DAMASKROOT/PRIVATE/documenting/runDoxygen.sh $DAMASKROOT abaqus_exp + except: + - master + - release AbaqusStd: stage: createDocumentation script: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel $Doxygen - $DAMASKROOT/PRIVATE/documenting/runDoxygen.sh $DAMASKROOT abaqus_std + except: + - master + - release Marc: stage: createDocumentation script: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel $Doxygen - $DAMASKROOT/PRIVATE/documenting/runDoxygen.sh $DAMASKROOT marc + except: + - master + - release Spectral: stage: createDocumentation script: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel $Doxygen - $DAMASKROOT/PRIVATE/documenting/runDoxygen.sh $DAMASKROOT spectral + except: + - master + - release ################################################################################################### removeLock: @@ -352,3 +484,6 @@ removeLock: - echo 'Do nothing' when: always script: rm $HOME/GitLabCI.lock + except: + - master + - release From 67d9fb386b489dea9f1c4b0086d5afe4ba84ecaa Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 19:42:59 +0200 Subject: [PATCH 144/183] in-line code for better readability --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bc8af4d11..06f6909b6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -79,7 +79,7 @@ variables: checkout: stage: prepareAll before_script: - - $HOME/wait.sh + - while [ -e $HOME/GitLabCI.lock ]; do sleep 5m; done - echo $CI_PIPELINE_ID > $HOME/GitLabCI.lock script: - mkdir -p $DAMASKROOT From 45f192be09fa9521217c88d4d3f78b036c2c58af Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 19:56:52 +0200 Subject: [PATCH 145/183] safe in case of failing prepareAll --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 06f6909b6..1403b24c5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -483,7 +483,7 @@ removeLock: before_script: - echo 'Do nothing' when: always - script: rm $HOME/GitLabCI.lock + script: if grep -q $CI_PIPELINE_ID $HOME/GitLabCI.lock; then; rm $HOME/GitLabCI.lock; fi except: - master - release From ae3a5187c098fcee7778d2078565aeca8d559ac3 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 13 Apr 2017 21:35:46 +0200 Subject: [PATCH 146/183] syntax error --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1403b24c5..72728cebe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -483,7 +483,7 @@ removeLock: before_script: - echo 'Do nothing' when: always - script: if grep -q $CI_PIPELINE_ID $HOME/GitLabCI.lock; then; rm $HOME/GitLabCI.lock; fi + script: if grep -q $CI_PIPELINE_ID $HOME/GitLabCI.lock; then rm $HOME/GitLabCI.lock; fi except: - master - release From 6114541dba9c8c72f59d72f03cfdfe7e977b6a0f Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Thu, 13 Apr 2017 18:59:52 -0400 Subject: [PATCH 147/183] try unlimited heap and stack first --- DAMASK_env.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/DAMASK_env.sh b/DAMASK_env.sh index 078dd582b..0ae3a2abf 100644 --- a/DAMASK_env.sh +++ b/DAMASK_env.sh @@ -39,12 +39,15 @@ fi # according to http://software.intel.com/en-us/forums/topic/501500 # this seems to make sense for the stack size -FREE=$(which free 2>/dev/null) +FREE=$(type -p free 2>/dev/null) if [ "x$FREE" != "x" ]; then freeMem=$(free -k | grep -E '(Mem|Speicher):' | awk '{print $4;}') # http://superuser.com/questions/220059/what-parameters-has-ulimit - ulimit -d $(expr $freeMem / 2) 2>/dev/null # maximum heap size (kB) - ulimit -s $(expr $freeMem / $DAMASK_NUM_THREADS / 2) 2>/dev/null # maximum stack size (kB) + ulimit -d unlimited 2>/dev/null \ + || ulimit -d $(expr $freeMem / 2) 2>/dev/null # maximum heap size (kB) + ulimit -s unlimited 2>/dev/null \ + || echo "cannot unlimit stack..." \ + && ulimit -s $(expr $freeMem / $DAMASK_NUM_THREADS / 2) 2>/dev/null # maximum stack size (kB) fi ulimit -v unlimited 2>/dev/null # maximum virtual memory size ulimit -m unlimited 2>/dev/null # maximum physical memory size From d1c2e2114d5fe5337ab8a427dcc20d4dfedd52e6 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Thu, 13 Apr 2017 19:00:19 -0400 Subject: [PATCH 148/183] switch auto drawing back on at end of pipeline --- processing/pre/mentat_spectralBox.py | 1 + 1 file changed, 1 insertion(+) diff --git a/processing/pre/mentat_spectralBox.py b/processing/pre/mentat_spectralBox.py index 681aca724..16c982f82 100755 --- a/processing/pre/mentat_spectralBox.py +++ b/processing/pre/mentat_spectralBox.py @@ -247,6 +247,7 @@ for name in filenames: '*identify_sets', '*show_model', '*redraw', + '*draw_automatic', ] outputLocals = {} From 4ffca8f0dcc6e5a2cb20fc5a24f4ee185fc6796c Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Thu, 13 Apr 2017 19:01:42 -0400 Subject: [PATCH 149/183] check for erroneous total phase fraction --- code/IO.f90 | 2 +- code/material.f90 | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/code/IO.f90 b/code/IO.f90 index c55a03b6a..acac40785 100644 --- a/code/IO.f90 +++ b/code/IO.f90 @@ -878,7 +878,7 @@ function IO_spotTagInPart(fileUnit,part,tag,Nsections) IO_spotTagInPart = .false. ! assume to nowhere spot tag section = 0_pInt - line ='' + line = '' rewind(fileUnit) do while (trim(line) /= IO_EOF .and. IO_lc(IO_getTag(line,'<','>')) /= part) ! search for part diff --git a/code/material.f90 b/code/material.f90 index ec5537b00..1945bb7da 100644 --- a/code/material.f90 +++ b/code/material.f90 @@ -758,7 +758,7 @@ subroutine material_parseMicrostructure(fileUnit,myPart) allocate(microstructure_elemhomo(Nsections), source=.false.) if(any(mesh_element(4,1:mesh_NcpElems) > Nsections)) & - call IO_error(155_pInt,ext_msg='Microstructure in geometry > Sections in material.config') + call IO_error(155_pInt,ext_msg='More microstructures in geometry than sections in material.config') forall (e = 1_pInt:mesh_NcpElems) microstructure_active(mesh_element(4,e)) = .true. ! current microstructure used in model? Elementwise view, maximum N operations for N elements @@ -801,7 +801,7 @@ subroutine material_parseMicrostructure(fileUnit,myPart) microstructure_crystallite(section) = IO_intValue(line,chunkPos,2_pInt) case ('(constituent)') constituent = constituent + 1_pInt - do i=2_pInt,6_pInt,2_pInt + do i = 2_pInt,6_pInt,2_pInt tag = IO_lc(IO_stringValue(line,chunkPos,i)) select case (tag) case('phase') @@ -816,6 +816,11 @@ subroutine material_parseMicrostructure(fileUnit,myPart) endif enddo + !sanity check +do section = 1_pInt, Nsections + if (sum(microstructure_fraction(:,section)) /= 1.0_pReal) & + call IO_error(153_pInt,ext_msg=microstructure_name(section)) +enddo end subroutine material_parseMicrostructure From b3066122dcd5be77625897622978d559fa7c5e17 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 14 Apr 2017 08:46:11 +0200 Subject: [PATCH 150/183] [skip ci] updated version information after successful test of v2.0.1-455-gae3a518 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1d89fa753..264798992 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-414-g81d0752 +v2.0.1-455-gae3a518 From a46107ba7f8fa6f7d204338dce33e2319d6148d0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 14 Apr 2017 09:16:21 +0200 Subject: [PATCH 151/183] pull needed to avoid conflicts --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 72728cebe..2767c46dd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -435,6 +435,7 @@ mergeIntoMaster: - git merge $UPDATEDREV - git push origin master # master is now tested version and has updated VERSION file - git checkout development + - git pull - git merge master -s ours # only possible conflict is in VERSION file - git push origin development # development is unchanged (as master is based on it) but has updated VERSION file only: From c34716a0da7fe1a13fcba013ab787039bbd00690 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Fri, 14 Apr 2017 15:07:43 -0400 Subject: [PATCH 152/183] modern form of croaking, added '*draw_automatic' as final output --- processing/pre/mentat_pbcOnBoxMesh.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/processing/pre/mentat_pbcOnBoxMesh.py b/processing/pre/mentat_pbcOnBoxMesh.py index 71bc0d121..f71247618 100755 --- a/processing/pre/mentat_pbcOnBoxMesh.py +++ b/processing/pre/mentat_pbcOnBoxMesh.py @@ -153,34 +153,31 @@ parser.add_option("-p", "--port", type="int", dest="port", metavar='int', help="Mentat connection port [%default]") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="write Mentat command stream also to stdout [%default]") -parser.set_defaults(port = 40007) -parser.set_defaults(verbose = False) +parser.set_defaults(port = 40007, + verbose = False) (options, args) = parser.parse_args() -if options.verbose: - file={'croak':sys.stderr} -else: - file={'croak':sys.stdout} - try: import py_mentat except: - file['croak'].write('error: no valid Mentat release found') + damask.util.croak('error: no valid Mentat release found') sys.exit(-1) outputLocals = {} -file['croak'].write('\033[1m'+scriptName+'\033[0m\n\n') -file['croak'].write( 'waiting to connect...\n') +damask.util.report(scriptName,'waiting to connect...') + try: py_mentat.py_connect('',options.port) -# prevent redrawing in Mentat, should be much faster. Since py_connect has no return value, try this to determine if failed or not +# prevent redrawing in Mentat, should be much faster. +# Since py_connect has no return value, try this to determine if failed or not output(['*draw_manual'],outputLocals,'Mentat') except: - file['croak'].write('Could not connect. Set Tools/Python/"Run as Separate Process" & "Initiate"...\n') + damask.util.croak('Could not connect. Set Tools/Python/"Run as Separate Process" & "Initiate"...') sys.exit() -file['croak'].write( 'connected...\n') + +damask.util.croak('connected...') output(['*remove_all_servos', '*sweep_all', @@ -190,6 +187,10 @@ output(['*remove_all_servos', cmds = servoLink() output(cmds,outputLocals,'Mentat') + +output(['*draw_automatic', + ],outputLocals,'Mentat') # script depends on consecutive numbering of nodes + py_mentat.py_disconnect() if options.verbose: From 62dd57313e9925284037c19bf496e0d6cf1b930d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 15 Apr 2017 12:07:59 +0200 Subject: [PATCH 153/183] queue for runners to retain order --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2767c46dd..d9aec3a0a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,7 +34,7 @@ variables: #================================================================================================ # Shortcut names #================================================================================================ - DAMASKROOT: "$HOME/GitlabCI_Pipeline_$CI_PIPELINE_ID/DAMASK" + DAMASKROOT: "$HOME/GitLabCI_Pipeline_$CI_PIPELINE_ID/DAMASK" #================================================================================================ # Names of module files to load @@ -79,8 +79,8 @@ variables: checkout: stage: prepareAll before_script: - - while [ -e $HOME/GitLabCI.lock ]; do sleep 5m; done - - echo $CI_PIPELINE_ID > $HOME/GitLabCI.lock + - echo $CI_PIPELINE_ID >> $HOME/GitLabCI.queue + - while [ "$(awk '/$CI_PIPELINE_ID/{print NR}' GitLabCI.queue)" -ne 1 ];do sleep 5m; done script: - mkdir -p $DAMASKROOT - git clone -q git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT @@ -484,7 +484,7 @@ removeLock: before_script: - echo 'Do nothing' when: always - script: if grep -q $CI_PIPELINE_ID $HOME/GitLabCI.lock; then rm $HOME/GitLabCI.lock; fi + script: sed -i '/$CI_PIPELINE_ID/d' GitLabCI.queue except: - master - release From d2b6fdd453aae6b3f3c034061cb96e987b922c5f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 15 Apr 2017 12:33:52 +0200 Subject: [PATCH 154/183] corrected path --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d9aec3a0a..f3c5bdba7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -80,7 +80,7 @@ checkout: stage: prepareAll before_script: - echo $CI_PIPELINE_ID >> $HOME/GitLabCI.queue - - while [ "$(awk '/$CI_PIPELINE_ID/{print NR}' GitLabCI.queue)" -ne 1 ];do sleep 5m; done + - while [ "$(awk '/$CI_PIPELINE_ID/{print NR}' $HOME/GitLabCI.queue)" -ne 1 ];do sleep 5m; done script: - mkdir -p $DAMASKROOT - git clone -q git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT @@ -484,7 +484,7 @@ removeLock: before_script: - echo 'Do nothing' when: always - script: sed -i '/$CI_PIPELINE_ID/d' GitLabCI.queue + script: sed -i '/$CI_PIPELINE_ID/d' $HOME/GitLabCI.queue except: - master - release From 65985e3dd788757d70e547ceada161ac2be6e94d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 15 Apr 2017 12:44:02 +0200 Subject: [PATCH 155/183] correct escape --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f3c5bdba7..d6b3f1012 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -80,7 +80,7 @@ checkout: stage: prepareAll before_script: - echo $CI_PIPELINE_ID >> $HOME/GitLabCI.queue - - while [ "$(awk '/$CI_PIPELINE_ID/{print NR}' $HOME/GitLabCI.queue)" -ne 1 ];do sleep 5m; done + - while [ $(awk "/$CI_PIPELINE_ID/{print NR}" $HOME/GitLabCI.queue)" -ne 1 ];do sleep 5m; done script: - mkdir -p $DAMASKROOT - git clone -q git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT @@ -484,7 +484,7 @@ removeLock: before_script: - echo 'Do nothing' when: always - script: sed -i '/$CI_PIPELINE_ID/d' $HOME/GitLabCI.queue + script: sed -i "/$CI_PIPELINE_ID/d" $HOME/GitLabCI.queue except: - master - release From 1344905c7e768e24b264b8057ecbe73445c6003d Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 15 Apr 2017 12:45:11 +0200 Subject: [PATCH 156/183] typo --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d6b3f1012..e65d9df60 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -80,7 +80,7 @@ checkout: stage: prepareAll before_script: - echo $CI_PIPELINE_ID >> $HOME/GitLabCI.queue - - while [ $(awk "/$CI_PIPELINE_ID/{print NR}" $HOME/GitLabCI.queue)" -ne 1 ];do sleep 5m; done + - while [ $(awk "/$CI_PIPELINE_ID/{print NR}" $HOME/GitLabCI.queue) -ne 1 ];do sleep 5m; done script: - mkdir -p $DAMASKROOT - git clone -q git@magit1.mpie.de:damask/DAMASK.git $DAMASKROOT From de48d54201e66874e5b02a4b15eb270bb700d000 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 17 Apr 2017 05:50:41 +0200 Subject: [PATCH 157/183] conflict occured after manual merge+push to master --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e65d9df60..720b19460 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -432,7 +432,7 @@ mergeIntoMaster: - git commit VERSION -m "[skip ci] updated version information after successful test of $TESTEDREV" - export UPDATEDREV=$(git describe) # tested state + 1 commit - git checkout master - - git merge $UPDATEDREV + - git merge $UPDATEDREV -s ours # conflicts occur only for inconsistent state - git push origin master # master is now tested version and has updated VERSION file - git checkout development - git pull From 1dd36c6e28f8d0336a28feb5871aaf9e264c3fb3 Mon Sep 17 00:00:00 2001 From: Test User Date: Mon, 17 Apr 2017 14:56:22 +0200 Subject: [PATCH 158/183] [skip ci] updated version information after successful test of v2.0.1-466-gde48d54 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1d89fa753..81d039704 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-414-g81d0752 +v2.0.1-466-gde48d54 From 32722a3d770d7bfeb9e72adc4350e1818a761660 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 18 Apr 2017 05:29:00 +0200 Subject: [PATCH 159/183] adopting to new installation and test --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e65d9df60..6d912d0da 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -88,7 +88,7 @@ checkout: - git checkout $CI_COMMIT_SHA - git clone -q git@magit1.mpie.de:damask/PRIVATE.git - source $DAMASKROOT/DAMASK_env.sh - - make install + - make processing except: - master - release @@ -184,7 +184,7 @@ Compile_Intel: stage: compileSpectralIntel script: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - - SpectralAll_compileIfort/test.py + - SpectralAll_compile/test.py except: - master - release @@ -194,7 +194,7 @@ Compile_GNU: stage: compileSpectralGNU script: - module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU - - SpectralAll_compileGfortran/test.py + - SpectralAll_compile/test.py except: - master - release @@ -204,7 +204,7 @@ Compile_Intel_Prepare: stage: prepareSpectral script: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - - make -C $DAMASKROOT clean spectral install tidy + - make clean spectral processing except: - master - release From 1768d8f103c384e0dd43991d929eebfffad3090e Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 18 Apr 2017 05:37:36 +0200 Subject: [PATCH 160/183] update of VERSION file should not trigger new GitLabCI --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 720b19460..00b9a5795 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -436,7 +436,7 @@ mergeIntoMaster: - git push origin master # master is now tested version and has updated VERSION file - git checkout development - git pull - - git merge master -s ours # only possible conflict is in VERSION file + - git merge master -s ours -m "[skip ci] Merge branch 'master' into development" # only possible conflict is in VERSION file - git push origin development # development is unchanged (as master is based on it) but has updated VERSION file only: - development From d4c1482690ba0a1d3f8037c4aae9fa344403b026 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 18 Apr 2017 07:14:55 +0200 Subject: [PATCH 161/183] syntax check not for debug --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac7ffbcee..3846e6e22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,7 +120,6 @@ set (CMAKE_LINKER "${PETSC_LINKER}") if ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG" OR "${CMAKE_BUILD_TYPE}" STREQUAL "SYNTAXONLY" ) set (PARALLEL "OFF") set (OPTI "OFF") - set (BUILDCMD_POST "${BUILDCMD_POST} -fsyntax-only") elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") set (PARALLEL "ON") set (OPTI "DEFENSIVE") @@ -143,6 +142,11 @@ else () set(OPENMP "${OPENMP}") endif () +# syntax check only (mainly for pre-receive hook, works only with gfortran) +if ("${CMAKE_BUILD_TYPE}" STREQUAL "SYNTAXONLY" ) + set (BUILDCMD_POST "${BUILDCMD_POST} -fsyntax-only") +endif () + # Parse DAMASK_BIN from CONFIG file file (READ "CONFIG" CONFIGFILE) string (REGEX REPLACE ";" "\\\\;" CONFIGFILE "${CONFIGFILE}") From 7cb2669648a2c23947eb204b14f04a71f84ce97c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 18 Apr 2017 07:38:36 +0200 Subject: [PATCH 162/183] sytaycheck only target was not working --- CMakeLists.txt | 6 +++--- src/CMakeLists.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3846e6e22..134e98dda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -464,15 +464,15 @@ message ("Fortran Linker Flags:\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") add_subdirectory (src) # INSTALL BUILT BINARIES -if ("${BUILD_TYPE}" STREQUAL SYNTAXONLY) +if ("${CMAKE_BUILD_TYPE}" STREQUAL "SYNTAXONLY") exec_program (mktemp ARGS -d OUTPUT_VARIABLE BLACK_HOLE) install (PROGRAMS ${PROJECT_BINARY_DIR}/src/prec.mod DESTINATION ${BLACK_HOLE}) else () - if ("${PROJECT_NAME}" STREQUAL DAMASK_spectral) + if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") install (PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_spectral DESTINATION ${CMAKE_INSTALL_PREFIX}) - elseif ("${PROJECT_NAME}" STREQUAL DAMASK_FEM) + elseif ("${PROJECT_NAME}" STREQUAL "DAMASK_FEM") install (PROGRAMS ${PROJECT_BINARY_DIR}/src/DAMASK_FEM DESTINATION ${CMAKE_INSTALL_PREFIX}) endif () diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 56309a821..a613d2f79 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -185,7 +185,7 @@ if ("${PROJECT_NAME}" STREQUAL "DAMASK_spectral") "spectral_mech_Basic.f90") add_dependencies(SPECTRAL_SOLVER SPECTRAL_UTILITIES) list(APPEND OBJECTFILES $) - if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL SYNTAXONLY) + if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "SYNTAXONLY") add_executable(DAMASK_spectral "DAMASK_spectral.f90" ${OBJECTFILES}) add_dependencies(DAMASK_spectral SPECTRAL_SOLVER) endif() From c5c2c19a2f86f60d35dab49f738c1d52e883c334 Mon Sep 17 00:00:00 2001 From: Test User Date: Tue, 18 Apr 2017 14:41:58 +0200 Subject: [PATCH 163/183] [skip ci] updated version information after successful test of v2.0.1-472-g1768d8f --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1d89fa753..3e0232913 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-414-g81d0752 +v2.0.1-472-g1768d8f From bffccca628e3a342047d17dace0ca225adef3606 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 18 Apr 2017 15:17:37 +0200 Subject: [PATCH 164/183] address changed a while ago --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 6705c13fa..445f14cfb 100644 --- a/README +++ b/README @@ -8,4 +8,4 @@ Max-Planck-Str. 1 Germany Email: DAMASK@mpie.de -http://damask.mpie.de +https://damask.mpie.de From f0f602e1f5f4f464048e3505a736dae27f9311c0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 18 Apr 2017 15:18:23 +0200 Subject: [PATCH 165/183] confused merging strategies --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 00b9a5795..3a2860a67 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -432,11 +432,11 @@ mergeIntoMaster: - git commit VERSION -m "[skip ci] updated version information after successful test of $TESTEDREV" - export UPDATEDREV=$(git describe) # tested state + 1 commit - git checkout master - - git merge $UPDATEDREV -s ours # conflicts occur only for inconsistent state + - git merge $UPDATEDREV -s recursive -X ours # conflicts occur only for inconsistent state - git push origin master # master is now tested version and has updated VERSION file - git checkout development - git pull - - git merge master -s ours -m "[skip ci] Merge branch 'master' into development" # only possible conflict is in VERSION file + - git merge master -s recursive -X ours -m "[skip ci] Merge branch 'master' into development" # only possible conflict is in VERSION file - git push origin development # development is unchanged (as master is based on it) but has updated VERSION file only: - development From c97226a75fe8b1e44d4505ec9d70aeeae19c679d Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 19 Apr 2017 06:40:49 +0200 Subject: [PATCH 166/183] [skip ci] updated version information after successful test of v2.0.1-477-gf0f602e --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1d89fa753..15b675dd6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-414-g81d0752 +v2.0.1-477-gf0f602e From cbaec8bcb9e04c24f453165c044bfd66be1c12fc Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 19 Apr 2017 09:35:19 +0200 Subject: [PATCH 167/183] was in wrong directory --- .gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6d912d0da..f0c5d036d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -202,6 +202,9 @@ Compile_GNU: ################################################################################################### Compile_Intel_Prepare: stage: prepareSpectral + before_script: + - module purge + - cd $DAMASKROOT script: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - make clean spectral processing From b2897210f9a6bf1077608678bc91c1cdaac42dbc Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 19 Apr 2017 10:50:07 +0200 Subject: [PATCH 168/183] source DAMASK_env.sh was missing --- .gitlab-ci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f0c5d036d..9bca3ee31 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,6 @@ stages: ################################################################################################### before_script: - source $DAMASKROOT/DAMASK_env.sh - - module purge - cd $DAMASKROOT/PRIVATE/testing ################################################################################################### @@ -203,10 +202,10 @@ Compile_GNU: Compile_Intel_Prepare: stage: prepareSpectral before_script: - - module purge - - cd $DAMASKROOT - script: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel + script: + - cd $DAMASKROOT + - source DAMASK_env.sh - make clean spectral processing except: - master From e65de758146dd8a8f556443b5220eed10a1a0345 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 19 Apr 2017 15:10:43 +0200 Subject: [PATCH 169/183] fixed pas (was still code) --- lib/damask/solver/abaqus.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/damask/solver/abaqus.py b/lib/damask/solver/abaqus.py index c1777b4bf..04c626eea 100644 --- a/lib/damask/solver/abaqus.py +++ b/lib/damask/solver/abaqus.py @@ -2,6 +2,7 @@ from .solver import Solver import damask +import subprocess,re class Abaqus(Solver): @@ -20,8 +21,6 @@ class Abaqus(Solver): raise Exception('unknown Abaqus solver %'%solver) def return_run_command(self,model): - import subprocess - import re env=damask.Environment() shortVersion = re.sub('[\.,-]', '',self.version) try: @@ -33,4 +32,4 @@ class Abaqus(Solver): detectedVersion = process.stdout.readlines()[1].split()[1] if self.version != detectedVersion: raise Exception('found Abaqus version %s, but requested %s'%(detectedVersion,self.version)) - return '%s -job %s -user %s/code/DAMASK_abaqus_%s interactive'%(cmd,model,env.rootDir(),self.solver) + return '%s -job %s -user %s/src/DAMASK_abaqus_%s interactive'%(cmd,model,env.rootDir(),self.solver) From d49286f54825e3099230ece0b1001769f8b42a81 Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 20 Apr 2017 07:56:20 +0200 Subject: [PATCH 170/183] [skip ci] updated version information after successful test of v2.0.1-624-g718f384 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 15b675dd6..61909879a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-477-gf0f602e +v2.0.1-624-g718f384 From c10c58bf4457551f4a8f31ae5ff9f18a99934535 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 20 Apr 2017 08:26:09 +0200 Subject: [PATCH 171/183] first creating documentation, then doing commit --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aec8f63c4..f41487d2e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,8 +14,8 @@ stages: - compileAbaqus2016 - compileAbaqus2017 - example - - updateMaster - createDocumentation + - updateMaster - clean ################################################################################################### From a64da06c435f0d5a03df3a01bf14f4fc1c1c4dc4 Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 20 Apr 2017 19:17:45 +0200 Subject: [PATCH 172/183] [skip ci] updated version information after successful test of v2.0.1-626-gc10c58b --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 61909879a..af732cfde 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-624-g718f384 +v2.0.1-626-gc10c58b From 611b86da66cdc7870f2235871fde36c7b7e40eb0 Mon Sep 17 00:00:00 2001 From: Franz Roters Date: Mon, 24 Apr 2017 09:10:37 +0200 Subject: [PATCH 173/183] update temperature to FEM provided temperature only in case of thermal_condutcion, i.e. thermo-mechanical FEM simulation --- code/CPFEM.f90 | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/code/CPFEM.f90 b/code/CPFEM.f90 index a1dac9801..532fa3f65 100644 --- a/code/CPFEM.f90 +++ b/code/CPFEM.f90 @@ -302,6 +302,8 @@ subroutine CPFEM_general(mode, parallelExecution, ffn, ffn1, temperature_inp, dt phase_plasticity, & temperature, & thermalMapping, & + thermal_type, & + THERMAL_conduction_ID, & phase_Nsources, & material_homog, & material_Nhomogenization @@ -489,8 +491,11 @@ subroutine CPFEM_general(mode, parallelExecution, ffn, ffn1, temperature_inp, dt !* If no parallel execution is required, there is no need to collect FEM input if (.not. parallelExecution) then - temperature(material_homog(ip,elCP))%p(thermalMapping(material_homog(ip,elCP))%p(ip,elCP)) = & - temperature_inp + chosenThermal: select case (thermal_type(mesh_element(3,el))) + case (THERMAL_conduction_ID) chosenThermal + temperature(material_homog(ip,elCP))%p(thermalMapping(material_homog(ip,elCP))%p(ip,elCP)) = & + temperature_inp + end select chosenThermal materialpoint_F0(1:3,1:3,ip,elCP) = ffn materialpoint_F(1:3,1:3,ip,elCP) = ffn1 @@ -499,8 +504,11 @@ subroutine CPFEM_general(mode, parallelExecution, ffn, ffn1, temperature_inp, dt if (rnd < 0.5_pReal) rnd = rnd - 1.0_pReal CPFEM_cs(1:6,ip,elCP) = rnd * CPFEM_odd_stress CPFEM_dcsde(1:6,1:6,ip,elCP) = CPFEM_odd_jacobian * math_identity2nd(6) - temperature(material_homog(ip,elCP))%p(thermalMapping(material_homog(ip,elCP))%p(ip,elCP)) = & - temperature_inp + chosenThermal: select case (thermal_type(mesh_element(3,el))) + case (THERMAL_conduction_ID) chosenThermal + temperature(material_homog(ip,elCP))%p(thermalMapping(material_homog(ip,elCP))%p(ip,elCP)) = & + temperature_inp + end select chosenThermal materialpoint_F0(1:3,1:3,ip,elCP) = ffn materialpoint_F(1:3,1:3,ip,elCP) = ffn1 CPFEM_calc_done = .false. From a0af68588355b906241c0df2492d7c420d82fc6f Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 25 Apr 2017 12:34:14 +0200 Subject: [PATCH 174/183] compiler complained --- src/lattice.f90 | 2 -- src/material.f90 | 6 ++++-- src/mesh.f90 | 33 +++++++++++++++------------------ src/numerics.f90 | 6 ++---- src/spectral_interface.f90 | 2 ++ 5 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/lattice.f90 b/src/lattice.f90 index 55be144ac..7726c772d 100644 --- a/src/lattice.f90 +++ b/src/lattice.f90 @@ -1266,8 +1266,6 @@ subroutine lattice_init debug_level, & debug_lattice, & debug_levelBasic - use numerics, only: & - worldrank implicit none integer(pInt), parameter :: FILEUNIT = 200_pInt diff --git a/src/material.f90 b/src/material.f90 index 1945bb7da..a77c4871a 100644 --- a/src/material.f90 +++ b/src/material.f90 @@ -729,6 +729,8 @@ end subroutine material_parseHomogenization !> @brief parses the microstructure part in the material configuration file !-------------------------------------------------------------------------------------------------- subroutine material_parseMicrostructure(fileUnit,myPart) + use prec, only: & + dNeq use IO use mesh, only: & mesh_element, & @@ -738,7 +740,6 @@ subroutine material_parseMicrostructure(fileUnit,myPart) character(len=*), intent(in) :: myPart integer(pInt), intent(in) :: fileUnit - integer(pInt), allocatable, dimension(:) :: chunkPos integer(pInt) :: Nsections, section, constituent, e, i character(len=65536) :: & @@ -818,9 +819,10 @@ subroutine material_parseMicrostructure(fileUnit,myPart) !sanity check do section = 1_pInt, Nsections - if (sum(microstructure_fraction(:,section)) /= 1.0_pReal) & + if (dNeq(sum(microstructure_fraction(:,section)),1.0_pReal)) & call IO_error(153_pInt,ext_msg=microstructure_name(section)) enddo + end subroutine material_parseMicrostructure diff --git a/src/mesh.f90 b/src/mesh.f90 index c0d3cf862..b7b1ad8da 100644 --- a/src/mesh.f90 +++ b/src/mesh.f90 @@ -921,24 +921,22 @@ subroutine mesh_build_ipCoordinates integer(pInt) :: e,t,g,c,i,n real(pReal), dimension(3) :: myCoords - if (.not. allocated(mesh_ipCoordinates)) then - allocate(mesh_ipCoordinates(3,mesh_maxNips,mesh_NcpElems)) - mesh_ipCoordinates = 0.0_pReal - endif + if (.not. allocated(mesh_ipCoordinates)) & + allocate(mesh_ipCoordinates(3,mesh_maxNips,mesh_NcpElems),source=0.0_pReal) !$OMP PARALLEL DO PRIVATE(t,g,c,myCoords) - do e = 1_pInt,mesh_NcpElems ! loop over cpElems - t = mesh_element(2_pInt,e) ! get element type - g = FE_geomtype(t) ! get geometry type - c = FE_celltype(g) ! get cell type - do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element - myCoords = 0.0_pReal - do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in this cell - myCoords = myCoords + mesh_cellnode(1:3,mesh_cell(n,i,e)) - enddo - mesh_ipCoordinates(1:3,i,e) = myCoords / FE_NcellnodesPerCell(c) + do e = 1_pInt,mesh_NcpElems ! loop over cpElems + t = mesh_element(2_pInt,e) ! get element type + g = FE_geomtype(t) ! get geometry type + c = FE_celltype(g) ! get cell type + do i = 1_pInt,FE_Nips(g) ! loop over ips=cells in this element + myCoords = 0.0_pReal + do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in this cell + myCoords = myCoords + mesh_cellnode(1:3,mesh_cell(n,i,e)) enddo + mesh_ipCoordinates(1:3,i,e) = myCoords / real(FE_NcellnodesPerCell(c),pReal) enddo + enddo !$OMP END PARALLEL DO end subroutine mesh_build_ipCoordinates @@ -955,7 +953,6 @@ pure function mesh_cellCenterCoordinates(ip,el) real(pReal), dimension(3) :: mesh_cellCenterCoordinates !< x,y,z coordinates of the cell center of the requested IP cell integer(pInt) :: t,g,c,n - t = mesh_element(2_pInt,el) ! get element type g = FE_geomtype(t) ! get geometry type c = FE_celltype(g) ! get cell type @@ -963,7 +960,7 @@ pure function mesh_cellCenterCoordinates(ip,el) do n = 1_pInt,FE_NcellnodesPerCell(c) ! loop over cell nodes in this cell mesh_cellCenterCoordinates = mesh_cellCenterCoordinates + mesh_cellnode(1:3,mesh_cell(n,ip,el)) enddo - mesh_cellCenterCoordinates = mesh_cellCenterCoordinates / FE_NcellnodesPerCell(c) + mesh_cellCenterCoordinates = mesh_cellCenterCoordinates / real(FE_NcellnodesPerCell(c),pReal) end function mesh_cellCenterCoordinates @@ -1511,8 +1508,8 @@ function mesh_nodesAroundCentres(gDim,Favg,centres) result(nodes) shift = sign(abs(iRes+diag-2_pInt*me)/(iRes+diag),iRes+diag-2_pInt*me) lookup = me-diag+shift*iRes wrappedCentres(1:3,i+1_pInt, j+1_pInt, k+1_pInt) = & - centres(1:3,lookup(1)+1_pInt,lookup(2)+1_pInt,lookup(3)+1_pInt) - & - math_mul33x3(Favg, shift*gDim) + centres(1:3,lookup(1)+1_pInt,lookup(2)+1_pInt,lookup(3)+1_pInt) & + - math_mul33x3(Favg, real(shift,pReal)*gDim) endif enddo; enddo; enddo diff --git a/src/numerics.f90 b/src/numerics.f90 index 4358624de..eb974b3c4 100644 --- a/src/numerics.f90 +++ b/src/numerics.f90 @@ -251,10 +251,8 @@ subroutine numerics_init !-------------------------------------------------------------------------------------------------- ! try to open the config file fileExists: if(IO_open_file_stat(FILEUNIT,numerics_configFile)) then - mainProcess2: if (worldrank == 0) then - write(6,'(a,/)') ' using values from config file' - flush(6) - endif mainProcess2 + write(6,'(a,/)') ' using values from config file' + flush(6) !-------------------------------------------------------------------------------------------------- ! read variables from config file and overwrite default parameters if keyword is present diff --git a/src/spectral_interface.f90 b/src/spectral_interface.f90 index f37f083d6..80a109a10 100644 --- a/src/spectral_interface.f90 +++ b/src/spectral_interface.f90 @@ -57,7 +57,9 @@ subroutine DAMASK_interface_init() tag integer :: & i, & +#ifdef _OPENMP threadLevel, & +#endif worldrank = 0, & worldsize = 0 integer, allocatable, dimension(:) :: & From 69dba834cb8257113a41813e9a5e2f2afe255dba Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 25 Apr 2017 12:35:19 +0200 Subject: [PATCH 175/183] build type (and, hence openMP) was not set correctly --- CMakeLists.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 134e98dda..9712ab1d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ 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 +# 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 @@ -110,6 +110,10 @@ elseif ("${DAMASK_SOLVER}" STREQUAL "FEM") message ("Building FEM Solver\n") endif () +if ("${CMAKE_BUILD_TYPE}" STREQUAL "") + set (CMAKE_BUILD_TYPE "RELEASE") +endif () + # set compiler and linker commands (need to be done after defining the project) # https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F set (CMAKE_Fortran_COMPILER "${PETSC_MPIFC}") @@ -177,7 +181,6 @@ add_definitions (-DFLOAT=8) add_definitions (-DINT=4) set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} ${PETSC_INCLUDES}") -set (DAMASK_INCLUDE_FLAGS "${DAMASK_INCLUDE_FLAGS} -I${PROJECT_SOURCE_DIR}/lib") ################################################################################################### # Intel Compiler @@ -447,9 +450,7 @@ endif () set (CMAKE_Fortran_FLAGS "${BUILDCMD_PRE} ${OPENMP_FLAGS} ${STANDARD_CHECK} ${OPTIMIZATION_FLAGS} ${COMPILE_FLAGS} ${PRECISION_FLAGS}") set (CMAKE_Fortran_LINK_EXECUTABLE "${BUILDCMD_PRE} ${CMAKE_LINKER} ${OPENMP_FLAGS} ${OPTIMIZATION_FLAGS} ${LINKER_FLAGS}") -if ("${CMAKE_BUILD_TYPE}" STREQUAL "") - set (CMAKE_BUILD_TYPE "RELEASE") -elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") +if ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DEBUG_FLAGS}") set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} ${DEBUG_FLAGS}") endif () From c5f1574f477be107a6ae38c1d95479cf5d03e46c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 26 Apr 2017 09:40:45 +0200 Subject: [PATCH 176/183] commands depend on build type --- CMakeLists.txt | 17 +++++++++-------- src/CMakeLists.txt | 2 -- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9712ab1d7..2d95f87fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -447,19 +447,20 @@ elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # -fdefault-integer-8: Use it to set precision to 8 bytes for integer, don't use it for the standard case of pInt=4 (there is no -fdefault-integer-4) endif () -set (CMAKE_Fortran_FLAGS "${BUILDCMD_PRE} ${OPENMP_FLAGS} ${STANDARD_CHECK} ${OPTIMIZATION_FLAGS} ${COMPILE_FLAGS} ${PRECISION_FLAGS}") -set (CMAKE_Fortran_LINK_EXECUTABLE "${BUILDCMD_PRE} ${CMAKE_LINKER} ${OPENMP_FLAGS} ${OPTIMIZATION_FLAGS} ${LINKER_FLAGS}") +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} ${CMAKE_LINKER} ${OPENMP_FLAGS} ${OPTIMIZATION_FLAGS} ${LINKER_FLAGS}") if ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") - set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DEBUG_FLAGS}") - set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} ${DEBUG_FLAGS}") + set (CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE}} ${DEBUG_FLAGS}") + set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} ${DEBUG_FLAGS}") endif () -set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") -set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") +set (CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE}} ${DAMASK_INCLUDE_FLAGS} ${BUILDCMD_POST}") +set (CMAKE_Fortran_LINK_EXECUTABLE "${CMAKE_Fortran_LINK_EXECUTABLE} -o ${PETSC_EXTERNAL_LIB} ${BUILDCMD_POST}") -message ("Fortran Compiler Flags:\n${CMAKE_Fortran_FLAGS}\n") -message ("Fortran Linker Flags:\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") +message ("Fortran Compiler Flags:\n${CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE}}\n") +message ("C Compiler Flags:\n${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}}\n") +message ("Fortran Linker Command:\n${CMAKE_Fortran_LINK_EXECUTABLE}\n") # location of code add_subdirectory (src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a613d2f79..83647d8d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,8 +16,6 @@ if (${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") # long lines for interaction matrix endif() -set( CMAKE_VERBOSE_MAKEFILE on ) - # The dependency detection in CMake is not functioning for Fortran, # hence we declare the dependencies from top to bottom in the following add_library(C_ROUTINES OBJECT "C_routines.c") From 175e119d7b988f41af71f2e19bb04ce10d17aba6 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 26 Apr 2017 09:41:25 +0200 Subject: [PATCH 177/183] new PETSc on matesting (inlcuding use of IMKL) --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f41487d2e..c4db3225f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,10 +53,11 @@ variables: MPICH_Intel: "$MPICH3_2Intel17_0" # ++++++++++++ PETSc +++++++++++++++++++++++++++++++++++++++++++++++++ PETSc3_6_4MPICH3_2Intel17_0: "Libraries/PETSc/3.6.4/Intel-17.0-MPICH-3.2" + PETSc3_7_6MPICH3_2Intel17_0: "Libraries/PETSc/3.7.5/Intel-17.0-MPICH-3.2" PETSc3_7_5MPICH3_2Intel17_0: "Libraries/PETSc/3.7.5/Intel-17.0-MPICH-3.2" PETSc3_7_5MPICH3_2GNU5_3: "Libraries/PETSc/3.7.5/GNU-5.3-MPICH-3.2" # ------------ Defaults ---------------------------------------------- - PETSc_MPICH_Intel: "$PETSc3_7_5MPICH3_2Intel17_0" + PETSc_MPICH_Intel: "$PETSc3_7_6MPICH3_2Intel17_0" PETSc_MPICH_GNU: "$PETSc3_7_5MPICH3_2GNU5_3" # ++++++++++++ FEM +++++++++++++++++++++++++++++++++++++++++++++++++++ Abaqus2016: "FEM/Abaqus/2016" From c8889e7408121d90fde5ae23440751d3f8c0829c Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 26 Apr 2017 21:47:45 +0200 Subject: [PATCH 178/183] [skip ci] updated version information after successful test of v2.0.1-631-g175e119 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index af732cfde..60c3c0907 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-626-gc10c58b +v2.0.1-631-g175e119 From d35df1df49bdfa0f4c56eb7431a547d5936d6bf7 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Wed, 26 Apr 2017 17:28:41 -0400 Subject: [PATCH 179/183] Operate on MFD file to apply servo links, not client-server communication Speed up by many orders of magnitude... 64 x 64 x 64 mesh less than a minute! Thanks Brendan! --- processing/pre/mentat_pbcOnBoxMesh.py | 278 ++++++++++++++++---------- 1 file changed, 170 insertions(+), 108 deletions(-) mode change 100755 => 100644 processing/pre/mentat_pbcOnBoxMesh.py diff --git a/processing/pre/mentat_pbcOnBoxMesh.py b/processing/pre/mentat_pbcOnBoxMesh.py old mode 100755 new mode 100644 index f71247618..ee6c817cb --- a/processing/pre/mentat_pbcOnBoxMesh.py +++ b/processing/pre/mentat_pbcOnBoxMesh.py @@ -1,67 +1,103 @@ #!/usr/bin/env python2.7 # -*- coding: UTF-8 no BOM -*- -import sys,os +from __future__ import print_function +import sys,os,re,time,tempfile import numpy as np -from optparse import OptionParser +import argparse import damask +sys.path.append(damask.solver.Marc().libraryPath()) + scriptName = os.path.splitext(os.path.basename(__file__))[0] scriptID = ' '.join([scriptName,damask.version]) -sys.path.append(damask.solver.Marc().libraryPath()) +# Convert .mfd file into a usable format +# Broken into labeled sections (eg. nodes, links, etc) +# Each section has a list of labeled elements with formatted numerical data +def parseMFD(fname): + formatted = [] + with open(fname,'r') as dat: + section = 0 + formatted.append({'label': 'header', 'uid': -1, 'els': []}) + # in between =beg= and =end= part of file + in_block = False + for line in dat: + if in_block: # currently in a section + # lines that start with a space are numerical data + if line[0] == ' ': + formatted[section]['els'].append([]) + + # grab numbers + nums = re.split(r'\s+', line.strip()) + + for num in nums: + # floating point has format ' -x.xxxxxxxxxxxxe+yy' + # scientific notation is used for float + if (len(num) >= 4) and (num[-4] == 'e'): + formatted[section]['els'][-1].append(float(num)) + else: # integer + formatted[section]['els'][-1].append(int(num)) + else: # not numerical data, so it is a label for an element or section end + if line[0] == '=' and re.search(r'=end=$', line) is not None: # End of section, avoiding regex if possible + in_block = False + else: + formatted[section]['els'].append([]) + formatted[section]['els'][-1] = line + + else: # Not in a section, we are looking for a =beg= now + search = re.search(r'=beg=\s+(\d+)\s\((.*?)\)', line) + if search is not None: # found start of a new section + section += 1 + in_block = True + formatted.append({'label': search.group(2), 'uid': int(search.group(1)), 'els': []}) + else: # No =beg= found, probably in the header + # Either header or somthing we didn't plan for - just save the line so it isn't lost + if formatted[section]['uid'] > 0: + section += 1 + formatted.append({'label': '', 'uid': -2, 'els': []}) # make dummy section to store unrecognized data + formatted[section]['els'].append(line) + + return formatted -active=[True,True,True] # directions on which to add PBC -def outMentat(cmd,locals): - if cmd[0:3] == '(!)': - exec(cmd[3:]) - elif cmd[0:3] == '(?)': - cmd = eval(cmd[3:]) - py_mentat.py_send(cmd) - else: - py_mentat.py_send(cmd) - return - -#------------------------------------------------------------------------------------------------- -def outFile(cmd,locals,dest): - if cmd[0:3] == '(!)': - exec(cmd[3:]) - elif cmd[0:3] == '(?)': - cmd = eval(cmd[3:]) - dest.write(cmd+'\n') - else: - dest.write(cmd+'\n') - return - - -#------------------------------------------------------------------------------------------------- -def output(cmds,locals,dest): - for cmd in cmds: - if isinstance(cmd,list): - output(cmd,locals,dest) - else: - if dest == 'Mentat': - outMentat(str(cmd),locals) +def asMFD(mfd_data): + result = '' + for section in mfd_data: + if section['uid'] > 0: + result += '=beg={0:5d} ({1})\n'.format(section['uid'], section['label']) + for el in section['els']: + if type(el) == str: + result += el + elif type(el) == list: + for num in el: + if type(num) == int: + result += '{:20d}'.format(num) + elif type(num) == float: + result += '{:20.12e}'.format(num) + else: + damask.util.croak('WARNING: encountered unknown type: ' + str(type(el))) + result += '\n' else: - outFile(str(cmd),locals,dest) - return + damask.util.croak('WARNING: encountered unknown type: ' + str(type(el))) + if section['uid'] > 0: + result += '=end=\n' + return result.strip() - -def servoLink(): - - cmds = [] +def add_servoLinks(mfd_data,active=[True,True,True]): # directions on which to add PBC base = ['x','y','z'] box = {'min': np.zeros(3,dtype='d'), 'max': np.zeros(3,dtype='d'), 'delta': np.zeros(3,dtype='d'), } - Nnodes = py_mentat.py_get_int("nnodes()") - NodeCoords = np.zeros((Nnodes,3),dtype='d') - for node in range(Nnodes): - NodeCoords[node,0] = py_mentat.py_get_float("node_x(%i)"%(node+1)) - NodeCoords[node,1] = py_mentat.py_get_float("node_y(%i)"%(node+1)) - NodeCoords[node,2] = py_mentat.py_get_float("node_z(%i)"%(node+1)) + + mfd_dict = {} + for i in range(len(mfd_data)): + mfd_dict[mfd_data[i]['label']] = i + + NodeCoords = np.array(mfd_data[mfd_dict['nodes']]['els'][0::4])[:,1:4] + Nnodes = NodeCoords.shape[0] + box['min'] = NodeCoords.min(axis=0) # find the bounding box box['max'] = NodeCoords.max(axis=0) box['delta'] = box['max']-box['min'] @@ -108,9 +144,12 @@ def servoLink(): if any([maxFlag[i] and active[i] for i in range(3)]): linkNodes.append({'id': node+1,'coord': NodeCoords[node], 'faceMember': [maxFlag[i] and active[i] for i in range(3)]}) + mfd_data[mfd_dict['entities']]['els'][0][0] += len(linkNodes) * 3 + baseCorner = baseNode["%.8e"%box['min'][0]]["%.8e"%box['min'][1]]["%.8e"%box['min'][2]] # detect ultimate base node - + links = {'uid': 1705, 'label': 'links', 'els': [[7,0],[9,0]]} + linkID = 0 for node in linkNodes: # loop over all linked nodes linkCoord = [node['coord']] # start list of control node coords with my coords for dir in range(3): # check for each direction @@ -121,77 +160,100 @@ def servoLink(): nLinks = len(linkCoord) for dof in [1,2,3]: - cmds.append([ - "*new_link *link_class servo", - "*link_class servo *tied_node %i"%node['id'], - "*link_class servo *tied_dof %i"%dof, - "*servo_nterms %i"%(1+nLinks), - ]) - for i in range(nLinks): - cmds.append([ - "*link_class servo *servo_ret_node %i %i"\ - %(i+1,baseNode["%.8e"%linkCoord[i][0]]["%.8e"%linkCoord[i][1]]["%.8e"%linkCoord[i][2]]), - "*link_class servo *servo_ret_dof %i %i"%(i+1,dof), - "*link_class servo *servo_ret_coef %i 1"%(i+1), - ]) - cmds.append([ - "*link_class servo *servo_ret_node %i %i"%(1+nLinks,baseCorner), - "*link_class servo *servo_ret_dof %i %i"%(1+nLinks,dof), - "*link_class servo *servo_ret_coef %i -%i"%(1+nLinks,nLinks-1), - ]) - return cmds + tied_node = node['id'] + nterms = 1 + nLinks + + linkID += 1 + # Link header + links['els'].append('link{0}\n'.format(linkID)) + links['els'].append([linkID, 1]) + links['els'].append([0]) + links['els'].append([0]) + links['els'].append([0, 0, 0, tied_node]) + + # these need to be put in groups of four + link_payload = [dof, 0, nterms] + + # Individual node contributions (node, dof, coef.) + for i in range(nterms): + if i == nLinks: + link_payload.append(baseCorner) + else: + link_payload.append(baseNode["%.8e"%linkCoord[i][0]]["%.8e"%linkCoord[i][1]]["%.8e"%linkCoord[i][2]]) + for i in range(nterms): + link_payload.append(dof) + for i in range(nterms): + if i == nLinks: + link_payload.append(1.0 - nLinks) + else: + link_payload.append(1.0) + + # Needs to be formatted 4 data points per row, character width of 20, so 80 total + for j in range(0, len(link_payload), 4): + links['els'].append(link_payload[j:j+4]) + if j+4 < len(link_payload): + links['els'].append(link_payload[j+4:]) + i = 0 + while i < len(mfd_data) and mfd_data[i]['uid'] < 1705: i += 1 + + if mfd_data[i]['uid'] == 1705: del mfd_data[i] + mfd_data.insert(i, links) + #-------------------------------------------------------------------------------------------------- # MAIN #-------------------------------------------------------------------------------------------------- -parser = OptionParser(option_class=damask.extendableOption, usage = '%prog [options]', description = """ -Set up servo linking to achieve periodic boundary conditions for a regular hexahedral mesh presently opened in MSC.Mentat +parser = argparse.ArgumentParser(description = """ +Set up servo linking to achieve periodic boundary conditions for a regular hexahedral mesh. +Use *py_connection to operate on model presently opened in MSC.Mentat. """, version = scriptID) -parser.add_option("-p", "--port", type="int", dest="port", metavar='int', - help="Mentat connection port [%default]") -parser.add_option("-v", "--verbose", action="store_true", dest="verbose", - help="write Mentat command stream also to stdout [%default]") -parser.set_defaults(port = 40007, - verbose = False) +parser.add_argument('-p', '--port', + type = int, metavar = 'int', default = None, + help = 'Mentat connection port') +parser.add_argument('-x', + action = 'store_false', + help = 'no PBC along x direction') +parser.add_argument('-y', + action = 'store_false', + help = 'no PBC along y direction') +parser.add_argument('-z', + action = 'store_false', + help = 'no PBC along z direction') +parser.add_argument('file', nargs='*', + help = 'Mentat formatted data (.mfd) file[s] to add periodic boundary conditions to') -(options, args) = parser.parse_args() +args = parser.parse_args() -try: - import py_mentat -except: - damask.util.croak('error: no valid Mentat release found') - sys.exit(-1) +remote = args.port is not None -outputLocals = {} +if remote: + try: import py_mentat + except: + damask.util.croak('no valid Mentat release found.') + sys.exit(-1) -damask.util.report(scriptName,'waiting to connect...') + damask.util.report(scriptName, 'waiting to connect...') + args.file = [os.path.join(tempfile._get_default_tempdir(), next(tempfile._get_candidate_names()) + '.mfd')] + try: + py_mentat.py_connect('',args.port) + py_mentat.py_send('*set_save_formatted on') + py_mentat.py_send('*save_as_model "{}" yes'.format(args.file[0])) + py_mentat.py_get_int("nnodes()") # hopefully blocks until file is written + except: + damask.util.croak('failed. try setting Tools/Python/"Run as Separate Process" & "Initiate".') + sys.exit() + damask.util.croak( 'connected...') -try: - py_mentat.py_connect('',options.port) -# prevent redrawing in Mentat, should be much faster. -# Since py_connect has no return value, try this to determine if failed or not - output(['*draw_manual'],outputLocals,'Mentat') -except: - damask.util.croak('Could not connect. Set Tools/Python/"Run as Separate Process" & "Initiate"...') - sys.exit() +for mfdfile in args.file: + while remote and not os.path.exists(mfdfile): time.sleep(0.5) # wait for Mentat to write MFD file + damask.util.report(scriptName, mfdfile) + mfd = parseMFD(mfdfile) + add_servoLinks(mfd,[args.x,args.y,args.z]) + with open(mfdfile, 'w') as file: + file.write(asMFD(mfd)) -damask.util.croak('connected...') - -output(['*remove_all_servos', - '*sweep_all', - '*renumber_nodes', - '*set_links off', - ],outputLocals,'Mentat') # script depends on consecutive numbering of nodes - -cmds = servoLink() -output(cmds,outputLocals,'Mentat') - -output(['*draw_automatic', - ],outputLocals,'Mentat') # script depends on consecutive numbering of nodes - -py_mentat.py_disconnect() - -if options.verbose: - output(cmds,outputLocals,sys.stdout) +if remote: + try: py_mentat.py_send('*open_model "{}"'.format(args.file[0])) + except: damask.util.croak('lost connection on sending open command for "{}".'.format(args.file[0])) From 426f04891697d2917c9f53bf5abc4331cea09701 Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 27 Apr 2017 09:02:01 +0200 Subject: [PATCH 180/183] [skip ci] updated version information after successful test of v2.0.1-633-gd35df1d --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 60c3c0907..36675df15 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-631-g175e119 +v2.0.1-633-gd35df1d From ed85ce5bdbc22ad2312a772711193e9663687167 Mon Sep 17 00:00:00 2001 From: Franz Roters Date: Fri, 28 Apr 2017 12:36:10 +0200 Subject: [PATCH 181/183] changed argument handling in line with other scripts now also works with stdin/out --- processing/pre/mentat_pbcOnBoxMesh.py | 144 +++++++++++++------------- 1 file changed, 73 insertions(+), 71 deletions(-) diff --git a/processing/pre/mentat_pbcOnBoxMesh.py b/processing/pre/mentat_pbcOnBoxMesh.py index ee6c817cb..afd8d95f0 100644 --- a/processing/pre/mentat_pbcOnBoxMesh.py +++ b/processing/pre/mentat_pbcOnBoxMesh.py @@ -1,10 +1,9 @@ #!/usr/bin/env python2.7 # -*- coding: UTF-8 no BOM -*- -from __future__ import print_function import sys,os,re,time,tempfile import numpy as np -import argparse +from optparse import OptionParser import damask sys.path.append(damask.solver.Marc().libraryPath()) @@ -15,49 +14,48 @@ scriptID = ' '.join([scriptName,damask.version]) # Convert .mfd file into a usable format # Broken into labeled sections (eg. nodes, links, etc) # Each section has a list of labeled elements with formatted numerical data -def parseMFD(fname): +def parseMFD(dat): formatted = [] - with open(fname,'r') as dat: - section = 0 - formatted.append({'label': 'header', 'uid': -1, 'els': []}) - # in between =beg= and =end= part of file - in_block = False - for line in dat: - if in_block: # currently in a section - # lines that start with a space are numerical data - if line[0] == ' ': + section = 0 + formatted.append({'label': 'header', 'uid': -1, 'els': []}) + # in between =beg= and =end= part of file + in_block = False + for line in dat: + if in_block: # currently in a section + # lines that start with a space are numerical data + if line[0] == ' ': + formatted[section]['els'].append([]) + + # grab numbers + nums = re.split(r'\s+', line.strip()) + + for num in nums: + # floating point has format ' -x.xxxxxxxxxxxxe+yy' + # scientific notation is used for float + if (len(num) >= 4) and (num[-4] == 'e'): + formatted[section]['els'][-1].append(float(num)) + else: # integer + formatted[section]['els'][-1].append(int(num)) + else: # not numerical data, so it is a label for an element or section end + if line[0] == '=' and re.search(r'=end=$', line) is not None: # End of section, avoiding regex if possible + in_block = False + else: formatted[section]['els'].append([]) - - # grab numbers - nums = re.split(r'\s+', line.strip()) - - for num in nums: - # floating point has format ' -x.xxxxxxxxxxxxe+yy' - # scientific notation is used for float - if (len(num) >= 4) and (num[-4] == 'e'): - formatted[section]['els'][-1].append(float(num)) - else: # integer - formatted[section]['els'][-1].append(int(num)) - else: # not numerical data, so it is a label for an element or section end - if line[0] == '=' and re.search(r'=end=$', line) is not None: # End of section, avoiding regex if possible - in_block = False - else: - formatted[section]['els'].append([]) - formatted[section]['els'][-1] = line - - else: # Not in a section, we are looking for a =beg= now - search = re.search(r'=beg=\s+(\d+)\s\((.*?)\)', line) - if search is not None: # found start of a new section + formatted[section]['els'][-1] = line + + else: # Not in a section, we are looking for a =beg= now + search = re.search(r'=beg=\s+(\d+)\s\((.*?)\)', line) + if search is not None: # found start of a new section + section += 1 + in_block = True + formatted.append({'label': search.group(2), 'uid': int(search.group(1)), 'els': []}) + else: # No =beg= found, probably in the header + # Either header or somthing we didn't plan for - just save the line so it isn't lost + if formatted[section]['uid'] > 0: section += 1 - in_block = True - formatted.append({'label': search.group(2), 'uid': int(search.group(1)), 'els': []}) - else: # No =beg= found, probably in the header - # Either header or somthing we didn't plan for - just save the line so it isn't lost - if formatted[section]['uid'] > 0: - section += 1 - formatted.append({'label': '', 'uid': -2, 'els': []}) # make dummy section to store unrecognized data - formatted[section]['els'].append(line) - + formatted.append({'label': '', 'uid': -2, 'els': []}) # make dummy section to store unrecognized data + formatted[section]['els'].append(line) + return formatted def asMFD(mfd_data): @@ -203,30 +201,32 @@ def add_servoLinks(mfd_data,active=[True,True,True]): # directions on which to #-------------------------------------------------------------------------------------------------- # MAIN #-------------------------------------------------------------------------------------------------- -parser = argparse.ArgumentParser(description = """ +parser = OptionParser(option_class=damask.extendableOption, usage='%prog options [file[s]]', description = """ Set up servo linking to achieve periodic boundary conditions for a regular hexahedral mesh. Use *py_connection to operate on model presently opened in MSC.Mentat. """, version = scriptID) -parser.add_argument('-p', '--port', - type = int, metavar = 'int', default = None, - help = 'Mentat connection port') -parser.add_argument('-x', - action = 'store_false', - help = 'no PBC along x direction') -parser.add_argument('-y', - action = 'store_false', - help = 'no PBC along y direction') -parser.add_argument('-z', - action = 'store_false', - help = 'no PBC along z direction') -parser.add_argument('file', nargs='*', - help = 'Mentat formatted data (.mfd) file[s] to add periodic boundary conditions to') +parser.add_option('-p', '--port', + type = int, metavar = 'int', default = None, + help = 'Mentat connection port') +parser.add_option('-x', + action = 'store_false', default = True, + help = 'no PBC along x direction') +parser.add_option('-y', + action = 'store_false', default = True, + help = 'no PBC along y direction') +parser.add_option('-z', + action = 'store_false', default = True, + help = 'no PBC along z direction') -args = parser.parse_args() +(options, filenames) = parser.parse_args() -remote = args.port is not None +remote = options.port is not None + +if remote and filenames != []: + parser.error('file can not be specified when port is given.') +if filenames == []: filenames = [None] if remote: try: import py_mentat @@ -235,25 +235,27 @@ if remote: sys.exit(-1) damask.util.report(scriptName, 'waiting to connect...') - args.file = [os.path.join(tempfile._get_default_tempdir(), next(tempfile._get_candidate_names()) + '.mfd')] + filenames = [os.path.join(tempfile._get_default_tempdir(), next(tempfile._get_candidate_names()) + '.mfd')] try: - py_mentat.py_connect('',args.port) + py_mentat.py_connect('',options.port) py_mentat.py_send('*set_save_formatted on') - py_mentat.py_send('*save_as_model "{}" yes'.format(args.file[0])) + py_mentat.py_send('*save_as_model "{}" yes'.format(filenames[0])) py_mentat.py_get_int("nnodes()") # hopefully blocks until file is written except: damask.util.croak('failed. try setting Tools/Python/"Run as Separate Process" & "Initiate".') sys.exit() damask.util.croak( 'connected...') -for mfdfile in args.file: - while remote and not os.path.exists(mfdfile): time.sleep(0.5) # wait for Mentat to write MFD file - damask.util.report(scriptName, mfdfile) - mfd = parseMFD(mfdfile) - add_servoLinks(mfd,[args.x,args.y,args.z]) - with open(mfdfile, 'w') as file: - file.write(asMFD(mfd)) +for name in filenames: + while remote and not os.path.exists(name): time.sleep(0.5) # wait for Mentat to write MFD file + with open( name,'r') if name is not None else sys.stdin as fileIn: + damask.util.report(scriptName, name) + mfd = parseMFD(fileIn) + + add_servoLinks(mfd,[options.x,options.y,options.z]) + with open( name,'w') if name is not None else sys.stdout as fileOut: + fileOut.write(asMFD(mfd)) if remote: - try: py_mentat.py_send('*open_model "{}"'.format(args.file[0])) - except: damask.util.croak('lost connection on sending open command for "{}".'.format(args.file[0])) + try: py_mentat.py_send('*open_model "{}"'.format(filenames[0])) + except: damask.util.croak('lost connection on sending open command for "{}".'.format(filenames[0])) From 3e52e8b3b252e508bab7e180c60d7f10132f5a33 Mon Sep 17 00:00:00 2001 From: Franz Roters Date: Fri, 28 Apr 2017 12:39:01 +0200 Subject: [PATCH 182/183] fixed syntax errors --- src/CPFEM.f90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/CPFEM.f90 b/src/CPFEM.f90 index 532fa3f65..eef56506f 100644 --- a/src/CPFEM.f90 +++ b/src/CPFEM.f90 @@ -491,11 +491,11 @@ subroutine CPFEM_general(mode, parallelExecution, ffn, ffn1, temperature_inp, dt !* If no parallel execution is required, there is no need to collect FEM input if (.not. parallelExecution) then - chosenThermal: select case (thermal_type(mesh_element(3,el))) - case (THERMAL_conduction_ID) chosenThermal + chosenThermal1: select case (thermal_type(mesh_element(3,elCP))) + case (THERMAL_conduction_ID) chosenThermal1 temperature(material_homog(ip,elCP))%p(thermalMapping(material_homog(ip,elCP))%p(ip,elCP)) = & temperature_inp - end select chosenThermal + end select chosenThermal1 materialpoint_F0(1:3,1:3,ip,elCP) = ffn materialpoint_F(1:3,1:3,ip,elCP) = ffn1 @@ -504,11 +504,11 @@ subroutine CPFEM_general(mode, parallelExecution, ffn, ffn1, temperature_inp, dt if (rnd < 0.5_pReal) rnd = rnd - 1.0_pReal CPFEM_cs(1:6,ip,elCP) = rnd * CPFEM_odd_stress CPFEM_dcsde(1:6,1:6,ip,elCP) = CPFEM_odd_jacobian * math_identity2nd(6) - chosenThermal: select case (thermal_type(mesh_element(3,el))) - case (THERMAL_conduction_ID) chosenThermal + chosenThermal2: select case (thermal_type(mesh_element(3,elCP))) + case (THERMAL_conduction_ID) chosenThermal2 temperature(material_homog(ip,elCP))%p(thermalMapping(material_homog(ip,elCP))%p(ip,elCP)) = & temperature_inp - end select chosenThermal + end select chosenThermal2 materialpoint_F0(1:3,1:3,ip,elCP) = ffn materialpoint_F(1:3,1:3,ip,elCP) = ffn1 CPFEM_calc_done = .false. From f38fe8a6407dc8afcbe7f7f04d8c4066b6117a3c Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 28 Apr 2017 18:54:49 +0200 Subject: [PATCH 183/183] [skip ci] updated version information after successful test of v2.0.1-642-g3e52e8b --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 36675df15..83ef623ec 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.0.1-633-gd35df1d +v2.0.1-642-g3e52e8b

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 IN8MfiA6D4tQ~&?~ diff --git a/lib/damask/corientation.so b/lib/damask/corientation.so deleted file mode 100755 index 76fcf94f92edbc267aeee0192065c08c8458911d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2592705 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 N_!q3|y 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 IN8MfiA6D4tQ~&?~ literal 0 HcmV?d00001 diff --git a/lib/damask/corientation.so b/lib/damask/corientation.so new file mode 100755 index 0000000000000000000000000000000000000000..76fcf94f92edbc267aeee0192065c08c8458911d GIT binary patch literal 2592705 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 N_!q3|y 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